Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Who can help to get data from Jk-BMS via BLE + RPi5. Please HELP ME. #656

Open
RondaYummy opened this issue Jan 8, 2025 · 9 comments
Open

Comments

@RondaYummy
Copy link

RondaYummy commented Jan 8, 2025

I get services and some only characteristics (About the BMS itself) but do not get data on battery power and the rest.
I am writing an application on nestjs + dbus-next.

Here is the code I wrote ( https://codepen.io/Rondo-Yummy/pen/vEBdOyB ):

import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
import * as dbus from 'dbus-next';

@Injectable()
export class BluetoothService implements OnModuleInit {
  private readonly logger = new Logger(BluetoothService.name);
  private systemBus;
  private bluez;

  constructor() {
    try {
      this.systemBus = dbus.systemBus();
      if (!this.systemBus) {
        throw new Error('Failed to initialize systemBus');
      }
    } catch (error) {
      console.error('DBus initialization error:', error);
    }
  }

  async onModuleInit() {
    console.log('Initializing BlueZ interface...');
    try {
      const bluez = await this.systemBus.getProxyObject('org.bluez', '/');
      this.bluez = bluez.getInterface('org.freedesktop.DBus.ObjectManager');
      console.log('BlueZ interface initialized successfully');

      await this.connectToFirstDevice();
    } catch (error) {
      console.error('Failed to initialize BlueZ interface:', error);
    }
  }

  async connectToFirstDevice() {
    console.log('Listing devices...');
    try {
      const objects = await this.bluez.GetManagedObjects();
      const devices = Object.keys(objects).filter((path) =>
        path.includes('/org/bluez/hci0/dev_')
      );
      console.log('Discovered devices:', devices);

      if (devices.length === 0) {
        console.warn('No devices found.');
        return;
      }

      const devicePath = devices[0];
      this.log('Attempting to connect to the first device:', devicePath);

      const deviceProxy = await this.systemBus.getProxyObject('org.bluez', devicePath);
      const deviceInterface = deviceProxy.getInterface('org.bluez.Device1');

      this.log('Connecting to device using retry logic...', devicePath);
      await this.connectWithRetry(deviceInterface, devicePath, 3, 2000);
      this.log('Device connected successfully.', devicePath);
      await new Promise(resolve => setTimeout(resolve, 1000));

      this.log('Reading characteristics...', devicePath);
      await this.readDeviceCharacteristics(deviceProxy, objects);

      await this.readBatterySOC(deviceProxy, devicePath);
    } catch (error) {
      console.error('Failed to connect to device:', error);
    }
  }

  async connectWithRetry(deviceInterface, devicePath: string, retries = 3, delay = 2000) {
    for (let attempt = 1; attempt <= retries; attempt++) {
      try {
        this.log(`Attempt ${attempt} to connect to the device...`, devicePath);
        await deviceInterface.Connect();
        this.log('Device connected successfully.', devicePath);
        return;
      } catch (error) {
        this.log(`Connection attempt ${attempt} failed:`, devicePath, error);
        if (attempt < retries) {
          this.log(`Retrying in ${delay / 1000} seconds...`, devicePath);
          await new Promise((resolve) => setTimeout(resolve, delay));
        } else {
          this.log('All connection attempts failed.', devicePath);
          throw error;
        }
      }
    }
  }

  async readDeviceCharacteristics(deviceProxy, objects) {
    console.log('\x1b[32mReading device characteristics...');
    try {
      const services = Object.keys(objects).filter((path) =>
        path.startsWith(deviceProxy.path) && path.includes('service')
      );
      console.log('Discovered GATT services:', services);

      for (const servicePath of services) {
        if (!objects[servicePath]['org.bluez.GattService1']) continue;

        const serviceProxy = await this.systemBus.getProxyObject('org.bluez', servicePath);
        const serviceProperties = serviceProxy.getInterface('org.freedesktop.DBus.Properties');
        const uuid = await serviceProperties.Get('org.bluez.GattService1', 'UUID');
        console.log(`Service ${servicePath} UUID: ${uuid.value}`);

        const characteristics = Object.keys(objects).filter((path) =>
          path.startsWith(servicePath) && path.includes('char')
        );
        console.log(`Discovered characteristics for service ${servicePath}:`, characteristics);

        for (const charPath of characteristics) {
          if (!objects[charPath]['org.bluez.GattCharacteristic1']) continue;

          const charProxy = await this.systemBus.getProxyObject('org.bluez', charPath);
          const charInterface = charProxy.getInterface('org.bluez.GattCharacteristic1');
          const charProperties = charProxy.getInterface('org.freedesktop.DBus.Properties');
          const charUUID = await charProperties.Get('org.bluez.GattCharacteristic1', 'UUID');
          const flags = await charProperties.Get('org.bluez.GattCharacteristic1', 'Flags');

          console.log(`Inspecting characteristic: ${charPath}, UUID: ${charUUID.value}, Flags: ${flags.value}`);

          if (charUUID.value === 'f000ffc1-0451-4000-b000-000000000000') {
            const activationCommand = Buffer.from([0xDD, 0xA5, 0x03, 0x00, 0xFF, 0xFD, 0x77]);
            await charInterface.WriteValue(activationCommand, {});
            console.log(`Activation command sent to ${charPath}`);
          }

          if (flags.value.includes('notify')) {
            try {
              await charInterface.StartNotify();
              console.log(`Subscribed to notifications for characteristic ${charPath}`);
              charInterface.on('PropertiesChanged', (iface, changed, invalidated) => {
                console.log(`PropertiesChanged event: iface=${iface}, changed=${JSON.stringify(changed)}`);
                if (changed.Value) {
                  console.log(
                    `\x1b[31mNotification from ${charPath}:`,
                    this.bufferToHex(Buffer.from(changed.Value.value))
                  );
                }
              });
            } catch (notifyError) {
              console.error(`Error enabling notifications for ${charPath}:`, notifyError);
            }
          }

          if (flags.value.includes('read')) {
            try {
              const value = await charInterface.ReadValue({});
              console.log(
                `\x1b[31mCharacteristic ${charPath} value (UUID: ${charUUID.value}) | HEX: ${this.bufferToHex(value)}, Int: ${this.bufferToInt(value)}, UTF-8: ${this.bufferToUtf8(value)}`
              );
            } catch (readError) {
              console.error(`Error reading characteristic ${charPath}:`, readError);
            }
          }
        }
      }
    } catch (error) {
      console.error('Failed to read device characteristics:', error);
    }
  }

  private bufferToHex(buffer: Buffer): string {
    return buffer.toString('hex').toUpperCase();
  }

  private bufferToUtf8(buffer: Buffer): string {
    return buffer.toString('utf8');
  }

  private bufferToInt(buffer: Buffer): number {
    return buffer.readUInt8(0);
  }

  async getDeviceName(devicePath: string): Promise<string | null> {
    try {
      const deviceProxy = await this.systemBus.getProxyObject('org.bluez', devicePath);
      const deviceProperties = deviceProxy.getInterface('org.freedesktop.DBus.Properties');
      const name = await deviceProperties.Get('org.bluez.Device1', 'Name');
      return name.value;
    } catch (error) {
      console.error(`Failed to get device name for ${devicePath}:`, error);
      return null;
    }
  }

  private async log(message: string, devicePath: string, ...optionalParams: any[]) {
    const deviceName = await this.getDeviceName(devicePath);
    const deviceInfo = deviceName ? `[${deviceName}]` : '[Unknown Device]';
    this.logger.log(`${deviceInfo} ${message}`, ...optionalParams);
  }

  async readBatterySOC(deviceProxy: any, devicePath: string): Promise<void> {
    try {
      const objects = await this.bluez.GetManagedObjects();
      const characteristics = Object.keys(objects).filter((path) =>
        path.startsWith(devicePath) && path.includes('char')
      );

      for (const charPath of characteristics) {
        if (!objects[charPath]['org.bluez.GattCharacteristic1']) {
          console.warn(`Skipping characteristic ${charPath} as it lacks GattCharacteristic1 interface.`);
          continue;
        }

        const charProxy = await this.systemBus.getProxyObject('org.bluez', charPath);
        const charProperties = charProxy.getInterface('org.freedesktop.DBus.Properties');
        const uuid = await charProperties.Get('org.bluez.GattCharacteristic1', 'UUID');

        if (uuid.value === '00002a19-0000-1000-8000-00805f9b34fb') {
          const charInterface = charProxy.getInterface('org.bluez.GattCharacteristic1');
          this.log('Reading battery level...', devicePath);
          const value = await charInterface.ReadValue({});
          const soc = this.bufferToInt(Buffer.from(value));

          this.log(`Battery SOC: ${soc}%`, devicePath);
          return;
        }
      }

      this.logger.warn('Battery SOC characteristic not found.', devicePath);
    } catch (error) {
      this.logger.error('Failed to read battery SOC:', error);
    }
  }
}

The logs show the following:

0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: Initializing BlueZ interface...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: BlueZ interface initialized successfully
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: Listing devices...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: Discovered devices: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0033',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0032',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002e',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028/desc002a',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0025',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0023',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0021',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001d',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0019',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0017',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0015',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011/desc0013',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char000f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b/desc000d',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_21_34_82',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17:   '/org/bluez/hci0/dev_C8_47_80_21_BC_F4'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: [Nest] 26061  - 08/01/2025, 12:35:17     LOG [BluetoothService] [Andrii 3] Attempting to connect to the first device:
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: [Nest] 26061  - 08/01/2025, 12:35:17     LOG [BluetoothService] [Andrii 3] Connecting to device using retry logic...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: [Nest] 26061  - 08/01/2025, 12:35:17     LOG [BluetoothService] [Andrii 3] Attempt 1 to connect to the device...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: [Nest] 26061  - 08/01/2025, 12:35:17     LOG [BluetoothService] [Andrii 3] Device connected successfully.
0|⛅️ Solar Monitor  | 2025-01-08T12:35:17: [Nest] 26061  - 08/01/2025, 12:35:17     LOG [BluetoothService] [Andrii 3] Device connected successfully.
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Reading device characteristics...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Discovered GATT services: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0033',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0032',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002e',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028/desc002a',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0025',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0023',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0021',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001d',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0019',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0017',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0015',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011/desc0013',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char000f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b/desc000d'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: [Nest] 26061  - 08/01/2025, 12:35:18     LOG [BluetoothService] [Andrii 3] Reading characteristics...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Service /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b UUID: f000ffc0-0451-4000-b000-000000000000
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Discovered characteristics for service /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0033',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0032',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002e'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030, UUID: f000ffc2-0451-4000-b000-000000000000, Flags: write-without-response,write,notify
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Subscribed to notifications for characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c, UUID: f000ffc1-0451-4000-b000-000000000000, Flags: write-without-response,write,notify
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Activation command sent to /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Subscribed to notifications for characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Service /org/bluez/hci0/dev_C8_47_80_12_41_99/service0027 UUID: 0000180f-0000-1000-8000-00805f9b34fb
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Discovered characteristics for service /org/bluez/hci0/dev_C8_47_80_12_41_99/service0027: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028/desc002a'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028, UUID: 00002a19-0000-1000-8000-00805f9b34fb, Flags: read,notify
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Subscribed to notifications for characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0027/char0028 value (UUID: 00002a19-0000-1000-8000-00805f9b34fb) | HEX: 00, Int: 0, UTF-8:
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Service /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014 UUID: 0000180a-0000-1000-8000-00805f9b34fb
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Discovered characteristics for service /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0025',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0023',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0021',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001f',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001d',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0019',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0017',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0015'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0025, UUID: 00002a50-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0025 value (UUID: 00002a50-0000-1000-8000-00805f9b34fb) | HEX: 025E0440000003, Int: 2, UTF-8: ^@
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0023, UUID: 00002a2a-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:18: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0023 value (UUID: 00002a2a-0000-1000-8000-00805f9b34fb) | HEX: FFEEDDCCBBAA, Int: 255, UTF-8: ���̻�
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0021, UUID: 00002a23-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0021 value (UUID: 00002a23-0000-1000-8000-00805f9b34fb) | HEX: 123456FFFE9ABCDE, Int: 18, UTF-8: 4V�����
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001f, UUID: 00002a28-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001f value (UUID: 00002a28-0000-1000-8000-00805f9b34fb) | HEX: 362E332E30, Int: 54, UTF-8: 6.3.0
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001d, UUID: 00002a26-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001d value (UUID: 00002a26-0000-1000-8000-00805f9b34fb) | HEX: 362E312E32, Int: 54, UTF-8: 6.1.2
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001b, UUID: 00002a27-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char001b value (UUID: 00002a27-0000-1000-8000-00805f9b34fb) | HEX: 312E302E30, Int: 49, UTF-8: 1.0.0
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0019, UUID: 00002a25-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0019 value (UUID: 00002a25-0000-1000-8000-00805f9b34fb) | HEX: 312E302E302E302D4C45, Int: 49, UTF-8: 1.0.0.0-LE
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0017, UUID: 00002a24-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0017 value (UUID: 00002a24-0000-1000-8000-00805f9b34fb) | HEX: 424B2D424C452D312E30, Int: 66, UTF-8: BK-BLE-1.0
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0015, UUID: 00002a29-0000-1000-8000-00805f9b34fb, Flags: read
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service0014/char0015 value (UUID: 00002a29-0000-1000-8000-00805f9b34fb) | HEX: 42454B454E20534153, Int: 66, UTF-8: BEKEN SAS
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Service /org/bluez/hci0/dev_C8_47_80_12_41_99/service000e UUID: 0000ffe0-0000-1000-8000-00805f9b34fb
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Discovered characteristics for service /org/bluez/hci0/dev_C8_47_80_12_41_99/service000e: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011/desc0013',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char000f'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011, UUID: 0000ffe1-0000-1000-8000-00805f9b34fb, Flags: write-without-response,write,notify
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Subscribed to notifications for characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char0011
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service000e/char000f, UUID: 0000ffe2-0000-1000-8000-00805f9b34fb, Flags: write-without-response
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Service /org/bluez/hci0/dev_C8_47_80_12_41_99/service000a UUID: 00001801-0000-1000-8000-00805f9b34fb
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Discovered characteristics for service /org/bluez/hci0/dev_C8_47_80_12_41_99/service000a: [
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b',
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19:   '/org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b/desc000d'
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: ]
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Inspecting characteristic: /org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b, UUID: 00002a05-0000-1000-8000-00805f9b34fb, Flags: read,indicate
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service000a/char000b value (UUID: 00002a05-0000-1000-8000-00805f9b34fb) | HEX: 0100FFFF, Int: 1, UTF-8: ��
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Skipping characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0033 as it lacks GattCharacteristic1 interface.
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Skipping characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char0030/desc0032 as it lacks GattCharacteristic1 interface.
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Skipping characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002f as it lacks GattCharacteristic1 interface.
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: Skipping characteristic /org/bluez/hci0/dev_C8_47_80_12_41_99/service002b/char002c/desc002e as it lacks GattCharacteristic1 interface.
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: [Nest] 26061  - 08/01/2025, 12:35:19     LOG [BluetoothService] [Andrii 3] Reading battery level...
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: [Nest] 26061  - 08/01/2025, 12:35:19     LOG [NestApplication] Nest application successfully started +22ms
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: [Nest] 26061  - 08/01/2025, 12:35:19     LOG [Bootstrap] 🟢 Application is running on: http://[::1]:3000
0|⛅️ Solar Monitor  | 2025-01-08T12:35:19: [Nest] 26061  - 08/01/2025, 12:35:19     LOG [BluetoothService] [Andrii 3] Battery SOC: 0%
@RondaYummy RondaYummy changed the title Хто може допомогти отримати дані з Jk-BMS по BLE + RPi5. Please HELP ME. Who can help to get data from Jk-BMS via BLE + RPi5. Please HELP ME. Jan 8, 2025
@syssi
Copy link
Owner

syssi commented Jan 8, 2025

Could you provide some details about your BMS model? The implemented request (0xDD, 0xA5, 0x03, 0x00, 0xFF, 0xFD, 0x77) is from a pretty outdated protocol version / one of the early JK-BMS models (v4?).

@RondaYummy
Copy link
Author

RondaYummy commented Jan 8, 2025

Could you provide some details about your BMS model? The implemented request (0xDD, 0xA5, 0x03, 0x00, 0xFF, 0xFD, 0x77) is from a pretty outdated protocol version / one of the early JK-BMS models (v4?).

How can I do this?
The data I am receiving now about the BMS from the characteristic 00002a25-0000-1000-8000-00805f9b34fb:
BEKEN SAS
BK-BLE-1.0
1.0.0.0.0-LE
1.0.0
6.1.2
6.3.0

I don't really understand what is related to what.
I'm sorry for asking such questions, I've just started to get interested in this topic and it's a bit complicated for me now.
But I need to send an activation code to receive notifications, right? I'm sending outdated code now, as I understand it.

@syssi
Copy link
Owner

syssi commented Jan 8, 2025

Are we talking about anm BMS or Active Balancer? Which Android app do you use to talk to your device?

@RondaYummy
Copy link
Author

RondaYummy commented Jan 8, 2025

Are we talking about anm BMS or Active Balancer? Which Android app do you use to talk to your device?

It is simply called "JK BMS".
https://play.google.com/store/search?q=jk-bms&c=apps&hl=uk

@RondaYummy
Copy link
Author

RondaYummy commented Jan 8, 2025

I would also be grateful if there is some kind of manual on the Internet on how to work with these JK-BMS, receive notifications, and know where and what data it provides. I've searched for a long time and haven't found anything that could help me understand this concept.
If it's helpful, here's a gitHub, I'm using the dbuss.service.ts file because I couldn't get any characteristics at all through @abandonware/noble. Now I get at least the developer information. I will be sincerely grateful for any help, I want to make a status notification on the DBMS for my own use.

https://github.com/RondaYummy/solar_monitor

@syssi
Copy link
Owner

syssi commented Jan 8, 2025

There is no official documentation or protocol description available. It looks like you have implemented the wrong protocol / an unsupported request. Please have a look at the jk_bms_ble/jk_bms_ble.cpp.

@RondaYummy
Copy link
Author

Офіційної документації чи опису протоколу немає. Схоже, ви запровадили неправильний протокол/непідтримуваний запит. Будь ласка, перегляньте jk_bms_ble/jk_bms_ble.cpp.

Unfortunately, I am not familiar with C++.
It is difficult to understand how everything is implemented there. And what activation code is used in new versions of JK-BMS?

@syssi
Copy link
Owner

syssi commented Jan 8, 2025

I will summarize some protocol details tomorrow.

@syssi
Copy link
Owner

syssi commented Jan 9, 2025

JK BMS BLE Protocol Documentation

BLE Service & Characteristic

The BMS is accessible via the following BLE service:

  • Service UUID: 0xFFE0
  • Write Characteristic UUID: 0xFFE1 (handle 0x03) - Used to send commands
  • Notification Characteristic UUID: 0xFFE1 (handle 0x05) - Used to receive notifications

Note: While both characteristics share the same UUID (0xFFE1), they have different handles and purposes:

  • Commands are written to handle 0x03
  • Notifications are received on handle 0x05

Communication Flow

  1. Establish BLE connection
  2. Register for notifications on characteristic 0xFFE1 (handle 0x05)
  3. Send device info command on characteristic 0xFFE1 (handle 0x03)
  4. Send cell info command if no status notification is received

Command Structure

Commands are sent as 20-byte frames with the following format:

Offset Length Description
0-3 4 Header (0xAA 0x55 0x90 0xEB)
4 1 Command byte
5 1 Length byte
6-9 4 Value (32-bit)
10-18 9 Zero padding
19 1 CRC

Command Types

  • Device Info: 0x97
  • Cell Info: 0x96

Example Command Payloads

Device Info Command (0x97)

AA 55 90 EB     # Header
97              # Command
00              # Length
00 00 00 00     # Value
00 00 00 00     # Padding
00 00 00 00     
00 00 00 00
00              # CRC (calculated across bytes 0-18)

Cell Info Command (0x96)

AA 55 90 EB     # Header
96              # Command  
00              # Length
00 00 00 00     # Value
00 00 00 00     # Padding
00 00 00 00     
00 00 00 00
00              # CRC (calculated across bytes 0-18)

Response Handling

Frame Assembly

  • Complete responses range from 300-320 bytes
  • Responses are fragmented due to BLE MTU limitations
  • Each response frame starts with sequence: 0x55 0xAA 0xEB 0x90
  • When start sequence is detected, current frame buffer is cleared
  • Frame validation uses CRC (sum of all bytes except CRC byte)
  • All responses are received as notifications on characteristic 0xFFE1 (handle 0x05)

Response Frame Types

Response type is identified by byte[4]:

  • 0x01: Settings frame
  • 0x02: Cell info frame
  • 0x03: Device info frame

CRC Calculation

The CRC is calculated by summing all bytes in the frame except the CRC byte itself:

uint8_t crc(const uint8_t data[], const uint16_t len) {
  uint8_t crc = 0;
  for (uint16_t i = 0; i < len; i++) {
    crc = crc + data[i];
  }
  return crc;
}

Error Handling

  • Maximum allowed frame size is 320 bytes
  • Frames exceeding this size are dropped
  • CRC validation is performed on assembled frames
  • Frames with invalid CRC are discarded

syssi added a commit that referenced this issue Jan 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants