Issue integrating 100balance BMS with ESPHome via RS-485

Thanks!! Did you wired the bms via UART port directly to ESP32 board ( TX pin 6 and RX pin 5)? Sorry the original thread mentioned RS485. If it’s RS485… i’m guessing you’ll need the TTL → RS485 board in between?

I’m using a UART RS485 converter

1 Like

Nope, not with the default esphome RS485 component

1 Like

@Footz355 @dimksum Can both of you shared your wiring diagram to the 100 balancer I’ve tried setting this up for the past weekend and getting no luck getting any info. For context these are the hardware I’m using along with the 100balance bms port shown previously.

bms - can/485 plug. pin 1 and 2 connect to rs485-uart converter. converter connect to esp (tx-rx, rx-tx)

I have doubts about that.

k i tried that setup and no go…

BMS pin 1 (B - right most pin next to UART plug on BMS) → B on TTL to RS485 Device
BMS pin 2 (A - 2nd right most pin next to UART plug on BMS) → A on TTL to RS485 Device

Then from R0 → ESP GPIO16 (uart 2 rt) and DI → ESP GPIO17 (uart 2 tx)

Also tried
R0 → ESP GPIO17 (uart 2 tx) and DI → ESP GPIO16 (uart 2 rt)

My config

uart:
id: uart_0
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 9600
stop_bits: 1

If you can spot any issues with my setup that’ll be great! thanks for your help. Also if you don’t mine, can you post the model of your ESP32, TTL to RS845 board and etc?

[20:33:03][VV][scheduler:226]: Running interval ‘update’ with interval=5000 last_execution=422417 (now=427418)
[20:33:03][V][modbus_controller:226]: 2 modbus commands already in queue
[20:33:03][VV][modbus_controller:232]: Updating range 0xD457
[20:33:03][V][modbus_controller:195]: Range : D457 Size: 1 (0) skip: 0
[20:33:03][W][modbus_controller:182]: Duplicate modbus command found: type=0x10 address=54359 count=1
[20:33:03][VV][modbus_controller:232]: Updating range 0x30
[20:33:03][V][modbus_controller:195]: Range : 30 Size: 1 (3) skip: 0
[20:33:03][W][modbus_controller:182]: Duplicate modbus command found: type=0x3 address=48 count=1
[20:33:03][VV][api.service:697]: on_ping_request: PingRequest {}
[20:33:04][VV][api.service:043]: send_ping_response: PingResponse {}
[20:33:07][V][modbus_controller:042]: Sending next modbus command to device 129 register 0xD457 count 1
[20:33:07][VV][uart.arduino_esp32:194]: Flushing…
[20:33:07][V][modbus:231]: Modbus write raw: 81.03.00.38.00.0B (6)
[20:33:07][V][modbus_controller:565]: Command sent 0 0xD457 1 send_count: 5
[20:33:07][D][uart_debug:114]: >>> 81:03:00:38:00:0B:9A:00
[20:33:07][D][main:058]: Response data only had 8 bytes!!
[20:33:08][VV][scheduler:226]: Running interval ‘update’ with interval=5000 last_execution=427417 (now=432419)
[20:33:08][V][modbus_controller:226]: 2 modbus commands already in queue
[20:33:08][VV][modbus_controller:232]: Updating range 0xD457
[20:33:08][V][modbus_controller:195]: Range : D457 Size: 1 (0) skip: 0
[20:33:08][W][modbus_controller:182]: Duplicate modbus command found: type=0x10 address=54359 count=1
[20:33:08][VV][modbus_controller:232]: Updating range 0x30
[20:33:08][V][modbus_controller:195]: Range : 30 Size: 1 (3) skip: 0
[20:33:08][W][modbus_controller:182]: Duplicate modbus command found: type=0x3 address=48 count=1
[20:33:12][D][modbus_controller:038]: Modbus command to device=129 register=0xD457 no response received - removed from send queue
[20:33:12][V][modbus_controller:042]: Sending next modbus command to device 129 register 0x30 count 1
[20:33:12][VV][uart.arduino_esp32:194]: Flushing…
[20:33:12][V][modbus:210]: Modbus write: 81.03.00.30.00.01.9B.C5 (8)
[20:33:12][V][modbus_controller:565]: Command sent 3 0x30 1 send_count: 1
[20:33:12][D][uart_debug:114]: >>> 81:03:00:30:00:01:9B:C5
[20:33:12][D][main:058]: Response data only had 8 bytes!!
[20:33:13][VV][scheduler:226]: Running interval ‘update’ with interval=5000 last_execution=432417 (now=437424)
[20:33:13][V][modbus_controller:226]: 1 modbus commands already in queue
[20:33:13][VV][modbus_controller:232]: Updating range 0xD457
[20:33:13][V][modbus_controller:195]: Range : D457 Size: 1 (0) skip: 0
[20:33:13][VV][modbus_controller:232]: Updating range 0x30
[20:33:13][V][modbus_controller:195]: Range : 30 Size: 1 (3) skip: 0
[20:33:13][W][modbus_controller:182]: Duplicate modbus command found: type=0x3 address=48 count=1

Hi What do you mean?

Rs485 converter is not a serial “communicator”, it’s a “translator”, so generally tx is connected to tx pin and rx to rx pin.
Like in yours rx goes to RO pin (receiver out).
In your case you also need to control DE and RE pins.

Add this to Modbus:
flow_control_pin: GPIO4

and make a connection from Gpio4 to both DE and RE.
Also make sure you power your converter at 3.3V, not 5V.

ps. use code tags when posting your code or logs

Ah ok… thanks for the info. I’ll try that… I believe the wiring diagram will be closer to this other post (SRNE integration with HA). I was able to get that one to work last night.

Yep.
Just leave the termination resistor there if you don’t have some evidence that is should be removed.

OH YEA!! it worked… Granted there’s a very limited info that’s being presented…

Do you have more sensors/config you can share?

Hi @Footz355 Can you share the excel file publicly on cloud drive (google drive and etc)?

Just request another range of addresses where you have info that you need.
And then pick them one by one like it was done for these four.

1 Like

Thanks!

K took a while but figure out the pattern… in case this helps others



uart:
  - id: uart_0
    tx_pin: 19
    rx_pin: 18
    baud_rate: 9600
    stop_bits: 1

    debug:
      direction: BOTH
      dummy_receiver: true
      after:
         delimiter: "\n"
      sequence:
          - lambda: |-
              UARTDebug::log_hex(direction, bytes, ':');
              ESP_LOGD("main", "Response data only had %d bytes!!", bytes.size() );
              std::string str(bytes.begin(), bytes.end());

              if (bytes.size() == 27) {
               ESP_LOGD("main", "MATCHED CELL INFO");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           
               
               int tv = (bytes[3] << 8) | bytes[4];
               id(tbv).publish_state(tv);

               int current = ((bytes[5] << 8) | bytes[6]) - 30000;
               id(cd).publish_state(current);

               int so = (bytes[7] << 8) | bytes[8];
               id(soc).publish_state(so);

               ESP_LOGD("main", "PLACE HOLDER 0x3B - 0x3D - life, batt qty, batt temp qty");

               int maxcv = ((bytes[15] << 8) | bytes[16]);
               id(cvmax).publish_state(maxcv);

               int maxci = ((bytes[17] << 8) | bytes[18]);
               id(cimax).publish_state(maxci);

               int mincv = ((bytes[19] << 8) | bytes[20]);
               id(cvmin).publish_state(mincv);

               int minci = ((bytes[21] << 8) | bytes[22]);
               id(cimin).publish_state(minci);

               int di = (bytes[23] << 8) | bytes[24];
               id(dif).publish_state(di);
              }

              if (bytes.size() == 13) { 
               ESP_LOGD("main", "MATCHED MISC INFO");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           
               
               int brc = (bytes[3] << 8) | bytes[4];
               id(battremaincap).publish_state(brc);

               int bct = (bytes[5] << 8) | bytes[6];
               id(battcycletime).publish_state(bct);

               int bs = (bytes[7] << 8) | bytes[8];
               id(balancingstate).publish_state(bs);

               int bc = (bytes[9] << 8) | bytes[10];
               id(balancecurrent).publish_state(bc);
              }

              if (bytes.size() == 23) { 
               ESP_LOGD("main", "MATCHED MISC INFO 2");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           

               int cmstat = (bytes[3] << 8) | bytes[4];
               id(chargingmosstatus).publish_state(cmstat);

               int dmstat = (bytes[5] << 8) | bytes[6];
               id(dischargingmosstatus).publish_state(dmstat);

               int avgv = (bytes[13] << 8) | bytes[14];
               id(cvavg).publish_state(avgv);

               int pow = (bytes[15] << 8) | bytes[16];
               id(power).publish_state(pow);

               int ener = (bytes[17] << 8) | bytes[18];
               id(energy).publish_state(ener);

               int mt = ((((bytes[19] << 8) | bytes[20]) - 40) * 9/5) + 32;
               id(mostemp).publish_state(mt);    
              }

              if (bytes.size() == 61) {
               ESP_LOGD("main", "MATCHED CELLS VOLTAGE");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);               

               int cv1 = (bytes[3] << 8) | bytes[4];
               id(cellv1).publish_state(cv1);
               int cv2 = (bytes[5] << 8) | bytes[6];
               id(cellv2).publish_state(cv2);
               int cv3 = (bytes[7] << 8) | bytes[8];
               id(cellv3).publish_state(cv3);
               int cv4 = (bytes[9] << 8) | bytes[10];
               id(cellv4).publish_state(cv4);
               int cv5 = (bytes[11] << 8) | bytes[12];
               id(cellv5).publish_state(cv5);
               int cv6 = (bytes[13] << 8) | bytes[14];
               id(cellv6).publish_state(cv6);
               int cv7 = (bytes[15] << 8) | bytes[16];
               id(cellv7).publish_state(cv7);
               int cv8 = (bytes[17] << 8) | bytes[18];
               id(cellv8).publish_state(cv8);
               int cv9 = (bytes[19] << 8) | bytes[20];
               id(cellv9).publish_state(cv9);
               int cv10 = (bytes[21] << 8) | bytes[22];
               id(cellv10).publish_state(cv10);
               int cv11 = (bytes[23] << 8) | bytes[24];
               id(cellv11).publish_state(cv11);
               int cv12 = (bytes[25] << 8) | bytes[26];
               id(cellv12).publish_state(cv12);
               int cv13 = (bytes[27] << 8) | bytes[28];
               id(cellv13).publish_state(cv13);
               int cv14 = (bytes[29] << 8) | bytes[30];
               id(cellv14).publish_state(cv14);
               int cv15 = (bytes[31] << 8) | bytes[32];
               id(cellv15).publish_state(cv15);
               int cv16 = (bytes[33] << 8) | bytes[34];
               id(cellv16).publish_state(cv16);
               int cv17 = (bytes[35] << 8) | bytes[36];
               id(cellv17).publish_state(cv17);
               int cv18 = (bytes[37] << 8) | bytes[38];
               id(cellv18).publish_state(cv18);
               int cv19 = (bytes[39] << 8) | bytes[40];
               id(cellv19).publish_state(cv19);
               int cv20 = (bytes[41] << 8) | bytes[42];
               id(cellv20).publish_state(cv20);
               int cv21 = (bytes[43] << 8) | bytes[44];
               id(cellv21).publish_state(cv21);
               int cv22 = (bytes[45] << 8) | bytes[46];
               id(cellv22).publish_state(cv22);
               int cv23 = (bytes[47] << 8) | bytes[48];
               id(cellv23).publish_state(cv23);
               int cv24 = (bytes[49] << 8) | bytes[50];
               id(cellv24).publish_state(cv24);
               
               int t1 = ((((bytes[51] << 8) | bytes[52]) - 40) * 9/5) + 32;
               id(temp1).publish_state(t1);
               int t2 = ((((bytes[53] << 8) | bytes[54]) - 40) * 9/5) + 32;
               id(temp2).publish_state(t2);
               int t3 = ((((bytes[55] << 8) | bytes[56]) - 40) * 9/5) + 32;
               id(temp3).publish_state(t3);
               int t4 = ((((bytes[57] << 8) | bytes[58]) - 40) * 9/5) + 32;
               id(temp4).publish_state(t4);
              } 
              
modbus:
  - id: modbus0
    uart_id: uart_0
    send_wait_time: 1000ms
    disable_crc: true
    flow_control_pin: 4

              #  int at = ((((bytes[73] << 8) | bytes[74]) - 40) * 9/5) + 32; 
              #  id(ambienttemp).publish_state(at);

modbus_controller:
  - id: bms
    address: 0x81
    modbus_id: modbus0
    command_throttle: 5000ms
    update_interval: 2s
    setup_priority: -20

sensor:
  
  - platform: template
    id: tbv
    name: "Voltage" # 0x38 register
    filters:
      - multiply: 0.1
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cd
    name: Current # 0x39 register
    filters:
      - multiply: 0.1
    accuracy_decimals: 1
    unit_of_measurement: "A"
    state_class: measurement
    device_class: current

  - platform: template
    id: soc
    name: SOC # 0x3A register
    filters:
      - multiply: 0.1
    unit_of_measurement: "%"      
    accuracy_decimals: 0
    state_class: measurement
    icon: mdi:battery
    device_class: battery

  - platform: template
    id: cvmax
    name: "Cell Volt Max" # 0x3E register
    filters:
      - multiply: 0.001
    accuracy_decimals: 3
    unit_of_measurement: "V"  
    icon: mdi:sine-wave
    state_class: measurement
    device_class: Voltage

  - platform: template
    id: cimax
    name: "Cell Index Max" # 0x3F register
    accuracy_decimals: 0
    
  - platform: template
    id: cvmin
    name: "Cell Volt Min" # 0x40 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 3
    unit_of_measurement: "V"
    device_class: Voltage
    state_class: measurement
    icon: mdi:sine-wave

  - platform: template
    id: cimin
    name: "Cell Index Min" # 0x41 register
    accuracy_decimals: 0

  - platform: template
    id: dif
    name: "Cell Volt delta" # 0x42 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 3
    unit_of_measurement: "V"
    device_class: Voltage
    state_class: measurement
    icon: mdi:sine-wave
    
  - platform: template
    id: battremaincap
    name: "Battery Remain Capacity" # 0x4B register
    #filters:
    #  - multiply: 0.001
    accuracy_decimals: 1
    unit_of_measurement: "Ah"
    device_class: battery
    state_class: measurement
    icon: mdi:battery

  - platform: template
    id: battcycletime
    name: "Battery Num Cycles" # 0x4C register
    accuracy_decimals: 0
    device_class: battery
    state_class: measurement
    icon: mdi:battery-sync

  - platform: template
    id: balancingstate
    name: "Balancing State [0:off,1:pas,2:act]" # 0x4D register
    accuracy_decimals: 0
    device_class: battery
    icon: mdi:power-plug    

  - platform: template
    id: balancecurrent
    name: "Balance Current" # 0x4E register
    filters:
     - multiply: 0.001
    accuracy_decimals: 0
    unit_of_measurement: "mA" # guessing
    device_class: battery
    state_class: measurement
    icon: mdi:scale-unbalanced
    
    #0x4F-0x51 equilibrium position

  - platform: template
    id: chargingmosstatus
    name: "Charging Mos Status [0:off|1:on]" # 0x52 register
    state_class: measurement
    device_class: battery
    accuracy_decimals: 0

  - platform: template
    id: dischargingmosstatus
    name: "Discharging Mos Status [0:off|1:on]" # 0x53 register
    state_class: measurement
    device_class: battery
    accuracy_decimals: 0

  - platform: template
    id: cvavg
    name: "Cell Volt Avg" # 0x57 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 3
    unit_of_measurement: "V"  
    icon: mdi:sine-wave
    state_class: measurement
    device_class: Voltage

  - platform: template
    id: power
    name: "Power" # 0x58 register
    # filters:
    #  - multiply: 0.001
    accuracy_decimals: 1
    unit_of_measurement: "W"
    device_class: battery
    state_class: measurement
    icon: mdi:flash


  - platform: template
    id: energy
    name: "Energy" # 0x59 register
    # filters:
    #  - multiply: 0.001
    accuracy_decimals: 1
    unit_of_measurement: "Wh"
    device_class: battery
    state_class: measurement
    icon: mdi:meter-electric

  - platform: template
    id: mostemp
    name: "MOS Temp" # 0x5A register
    accuracy_decimals: 1
    unit_of_measurement: "f"
    device_class: temperature
    state_class: measurement
    icon: mdi:thermometer

  # - platform: template
  #   id: ambienttemp
  #   name: "Ambient Temp" # 0x5B register
  #   # filters:
  #   #  - multiply: 0.001
  #   accuracy_decimals: 1
  #   unit_of_measurement: "f"
  #   # device_class: temperature
  #   state_class: measurement
  #   icon: mdi:thermometer
  
  - platform: template
    id: temp1
    name: "Temperature 1" # 0x30 register
    accuracy_decimals: 1
    unit_of_measurement: "f"
    device_class: temperature
    state_class: measurement
    icon: mdi:thermometer
  - platform: template
    id: temp2
    name: "Temperature 2" # 0x32 register
    accuracy_decimals: 1
    unit_of_measurement: "f"
    device_class: temperature
    state_class: measurement
    icon: mdi:thermometer
  - platform: template
    id: temp3
    name: "Temperature 3" # 0x34 register
    accuracy_decimals: 1
    unit_of_measurement: "f"
    device_class: temperature
    state_class: measurement
    icon: mdi:thermometer
  - platform: template
    id: temp4
    name: "Temperature 4" # 0x36 register
    accuracy_decimals: 1
    unit_of_measurement: "f"
    device_class: temperature
    state_class: measurement
    icon: mdi:thermometer

  - platform: template
    id: cellv1
    name: "Cell Volt 01" # 0x00 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv2
    name: "Cell Volt 02" # 0x02 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv3
    name: "Cell Volt 03" # 0x04 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv4
    name: "Cell Volt 04" # 0x06 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv5
    name: "Cell Volt 05" # 0x08 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv6
    name: "Cell Volt 06" # 0x0A register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv7
    name: "Cell Volt 07" # 0x0C register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv8
    name: "Cell Volt 08" # 0x0E register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv9
    name: "Cell Volt 09" # 0x10 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv10
    name: "Cell Volt 10" # 0x12 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv11
    name: "Cell Volt 11" # 0x14 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv12
    name: "Cell Volt 12" # 0x16 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv13
    name: "Cell Volt 13" # 0x18 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv14
    name: "Cell Volt 14" # 0x1A register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv15
    name: "Cell Volt 15" # 0x1C register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv16
    name: "Cell Volt 16" # 0x1E register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv17
    name: "Cell Volt 17" # 0x20 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv18
    name: "Cell Volt 18" # 0x22 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv19
    name: "Cell Volt 19" # 0x24 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv20
    name: "Cell Volt 20" # 0x26 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv21
    name: "Cell Volt 21" # 0x28 register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv22
    name: "Cell Volt 22" # 0x2A register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv23
    name: "Cell Volt 23" # 0x2C register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

  - platform: template
    id: cellv24
    name: "Cell Volt 24" # 0x2E register
    filters:
      - multiply: 0.001
    accuracy_decimals: 2
    unit_of_measurement: "V"
    state_class: measurement
    icon: mdi:meter-electric
    device_class: Voltage

# Get Cell Voltages + temp 0x00 - 0x37 (56 bytes /2 = 28 registers [0x1C]) ) | total bytes = 56 + 5 = 61 Bytes
  - platform: modbus_controller
    modbus_controller_id: bms
    id: custom_cellinfo
    custom_command: [0x81, 0x03, 0x00, 0x00, 0x00, 0x1C]  

# 0x38 first register to read, 0xB = 11 register count (27 byte response [1Byte = ADDR, 1Byte = CMD, 1Byte = Length, 2Bytes = CRC, reminder = register count x 2]) - ORIG
  - platform: modbus_controller
    modbus_controller_id: bms
    id: custom_cellinfo2
    custom_command: [0x81, 0x03, 0x00, 0x38, 0x00, 0x0B]  

  - platform: modbus_controller
    modbus_controller_id: bms
    id: custom_otherinfo
    custom_command: [0x81, 0x03, 0x00, 0x4B, 0x00, 0x04]  

  - platform: modbus_controller
    modbus_controller_id: bms
    id: custom_otherinfo2
    custom_command: [0x81, 0x03, 0x00, 0x52, 0x00, 0x09]
2 Likes

Nice job!!

Thanks, great work. :clap:

Greetings.
Looks like you cracked it, great.
Do you still require the excel file?? Sorry, I don’t visit here to often.
Here is the complete file:

I have just tested it and it works!! Thank you so much!!
As for temperature in Fahrenheit to switch to Celcius I have to change this formula?:

int t1 = ((((bytes[51] << 8) | bytes[52]) - 40) * 9/5) + 32;
               id(temp1).publish_state(t1);
               int t2 = ((((bytes[53] << 8) | bytes[54]) - 40) * 9/5) + 32;
               id(temp2).publish_state(t2);
               int t3 = ((((bytes[55] << 8) | bytes[56]) - 40) * 9/5) + 32;
               id(temp3).publish_state(t3);
               int t4 = ((((bytes[57] << 8) | bytes[58]) - 40) * 9/5) + 32;
               id(temp4).publish_state(t4);

Thanks for figuring this all out. If I just could somehow get you a coffee or something remotely… :star_struck:

Edit:
Did you get the right battery temperatures? I only get -40, the same as you.
Also, do you have your ESP board connected on one RS-485 bus to your inverter and BMS? If so how does your code look like? When I try to integrate both codes for my SMG inverter and BMS I have a bunch of duplicate modbus command notifications in log. When they run from separate boards, they work ok. Managed to merge both SMG II and 100balance configs on one yaml and one ESP32 :slight_smile:

1 Like

Greetings again. I came up with a slight inconvenience using the yaml for bms, merged together with yaml for my inverter:

---
substitutions:
  name: SMG-II
esphome:
  name: smgbalance
  friendly_name: SMGBALANCE
esp32:
  board: esp32dev
  framework:
    type: arduino
    
logger:
  level: DEBUG

api:
  encryption:
    key: IiJ+FkXDMYddK6U7rzfq/XN81rKFmh3iheaVofbNnZo=
ota:
  platform: esphome
  password: 8ab32666264fa56690a9eecb30b7e7c7

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  
  manual_ip:
    static_ip: 192.168.1.86
    gateway: 192.168.1.100
    subnet: 255.255.255.0
  ap:
    ssid: Smgii-62 Fallback Hotspot
    password: HMVA5x3DAjDy

captive_portal: null

uart:
  - id: uart_0
    baud_rate: 9600
    tx_pin: GPIO17
    rx_pin: GPIO16
    stop_bits: 1
    parity: NONE
    debug:
      direction: BOTH
      dummy_receiver: true
      after:
         delimiter: "\n"
      sequence:
          - lambda: |-
              UARTDebug::log_hex(direction, bytes, ':');
              ESP_LOGD("main", "Response data only had %d bytes!!", bytes.size() );
              std::string str(bytes.begin(), bytes.end());

              if (bytes.size() == 27) {
               ESP_LOGD("main", "MATCHED CELL INFO");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           
               
               int tv = (bytes[3] << 8) | bytes[4];
               id(tbv).publish_state(tv);

               int current = ((bytes[5] << 8) | bytes[6]) - 30000;
               id(cd).publish_state(current);

               int so = (bytes[7] << 8) | bytes[8];
               id(soc).publish_state(so);

               ESP_LOGD("main", "PLACE HOLDER 0x3B - 0x3D - life, batt qty, batt temp qty");

               int maxcv = ((bytes[15] << 8) | bytes[16]);
               id(cvmax).publish_state(maxcv);

               int maxci = ((bytes[17] << 8) | bytes[18]);
               id(cimax).publish_state(maxci);

               int mincv = ((bytes[19] << 8) | bytes[20]);
               id(cvmin).publish_state(mincv);

               int minci = ((bytes[21] << 8) | bytes[22]);
               id(cimin).publish_state(minci);

               int di = (bytes[23] << 8) | bytes[24];
               id(dif).publish_state(di);
              }

              if (bytes.size() == 13) { 
               ESP_LOGD("main", "MATCHED MISC INFO");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           
               
               int brc = (((bytes[3] << 8) | bytes[4]) / 10);
               id(battremaincap).publish_state(brc);

               int bct = (bytes[5] << 8) | bytes[6];
               id(battcycletime).publish_state(bct);

               int bs = (bytes[7] << 8) | bytes[8];
               id(balancingstate).publish_state(bs);

               int bc = (bytes[9] << 8) | bytes[10];
               id(balancecurrent).publish_state(bc);
              }

              if (bytes.size() == 23) { 
               ESP_LOGD("main", "MATCHED MISC INFO 2");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           

               int cmstat = (bytes[3] << 8) | bytes[4];
               id(chargingmosstatus).publish_state(cmstat);

               int dmstat = (bytes[5] << 8) | bytes[6];
               id(dischargingmosstatus).publish_state(dmstat);

               int avgv = (bytes[13] << 8) | bytes[14];
               id(cvavg).publish_state(avgv);

               int pow = (bytes[15] << 8) | bytes[16];
               id(power).publish_state(pow);

               int ener = (bytes[17] << 8) | bytes[18];
               id(energy).publish_state(ener);

               int mt = (((bytes[19] << 8) | bytes[20]) - 40);
               id(mostemp).publish_state(mt);    
              }

              if (bytes.size() == 61) {
               ESP_LOGD("main", "MATCHED CELLS VOLTAGE");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);               

               int cv1 = (bytes[3] << 8) | bytes[4];
               id(cellv1).publish_state(cv1);
               int cv2 = (bytes[5] << 8) | bytes[6];
               id(cellv2).publish_state(cv2);
               int cv3 = (bytes[7] << 8) | bytes[8];
               id(cellv3).publish_state(cv3);
               int cv4 = (bytes[9] << 8) | bytes[10];
               id(cellv4).publish_state(cv4);
               int cv5 = (bytes[11] << 8) | bytes[12];
               id(cellv5).publish_state(cv5);
               int cv6 = (bytes[13] << 8) | bytes[14];
               id(cellv6).publish_state(cv6);
               int cv7 = (bytes[15] << 8) | bytes[16];
               id(cellv7).publish_state(cv7);
               int cv8 = (bytes[17] << 8) | bytes[18];
               id(cellv8).publish_state(cv8);
               int cv9 = (bytes[19] << 8) | bytes[20];
               id(cellv9).publish_state(cv9);
               int cv10 = (bytes[21] << 8) | bytes[22];
               id(cellv10).publish_state(cv10);
               int cv11 = (bytes[23] << 8) | bytes[24];
               id(cellv11).publish_state(cv11);
               int cv12 = (bytes[25] << 8) | bytes[26];
               id(cellv12).publish_state(cv12);
               int cv13 = (bytes[27] << 8) | bytes[28];
               id(cellv13).publish_state(cv13);
               int cv14 = (bytes[29] << 8) | bytes[30];
               id(cellv14).publish_state(cv14);
               int cv15 = (bytes[31] << 8) | bytes[32];
               id(cellv15).publish_state(cv15);
               int cv16 = (bytes[33] << 8) | bytes[34];
               id(cellv16).publish_state(cv16);
               int cv17 = (bytes[35] << 8) | bytes[36];
               id(cellv17).publish_state(cv17);
               int cv18 = (bytes[37] << 8) | bytes[38];
               id(cellv18).publish_state(cv18);
               int cv19 = (bytes[39] << 8) | bytes[40];
               id(cellv19).publish_state(cv19);
               int cv20 = (bytes[41] << 8) | bytes[42];
               id(cellv20).publish_state(cv20);
               int cv21 = (bytes[43] << 8) | bytes[44];
               id(cellv21).publish_state(cv21);
               int cv22 = (bytes[45] << 8) | bytes[46];
               id(cellv22).publish_state(cv22);
               int cv23 = (bytes[47] << 8) | bytes[48];
               id(cellv23).publish_state(cv23);
               int cv24 = (bytes[49] << 8) | bytes[50];
               id(cellv24).publish_state(cv24);
               
               int t1 = (((bytes[51] << 8) | bytes[52]) - 40);
               id(temp1).publish_state(t1);
               int t2 = (((bytes[53] << 8) | bytes[54]) - 40);
               id(temp2).publish_state(t2);
               int t3 = (((bytes[55] << 8) | bytes[56]) - 40);
               id(temp3).publish_state(t3);
               int t4 = (((bytes[57] << 8) | bytes[58]) - 40);
               id(temp4).publish_state(t4);
              } 

modbus:
  - id: modbus0
    uart_id: uart_0
    send_wait_time: 1000ms
    disable_crc: true
    #flow_control_pin: 4

              #  int at = (((bytes[73] << 8) | bytes[74]) - 40); 
              #  id(ambienttemp).publish_state(at);

modbus_controller:
  - id: smg0
    address: 1
    modbus_id: modbus0
    command_throttle: 400ms
    update_interval: 20s

  - id: bms
    address: 0x81
    modbus_id: modbus0
    command_throttle: 5000ms
    update_interval: 2s
    setup_priority: -20

Rest of the code are sensors.
The issue is it seems with this part:

if (bytes.size() == 13) { 
               ESP_LOGD("main", "MATCHED MISC INFO");
               ESP_LOGD("main", "Response data %d", bytes[0]);
               ESP_LOGD("main", "Response data %d", bytes[1]);           
               
               int brc = (((bytes[3] << 8) | bytes[4]) / 10);
               id(battremaincap).publish_state(brc);

               int bct = (bytes[5] << 8) | bytes[6];
               id(battcycletime).publish_state(bct);

               int bs = (bytes[7] << 8) | bytes[8];
               id(balancingstate).publish_state(bs);

               int bc = (bytes[9] << 8) | bytes[10];
               id(balancecurrent).publish_state(bc);
              }

Log output from my ESP is as follows:

[08:40:23][D][uart_debug:114]: <<< 51:03:08:01:98:00:18:00:00:75:30:4A:55
[08:40:23][D][main:051]: Response data only had 13 bytes!!
[08:40:23][D][main:087]: MATCHED MISC INFO
[08:40:23][D][main:088]: Response data 81
[08:40:23][D][main:089]: Response data 3
[08:40:23][D][sensor:094]: 'Battery Remain Capacity': Sending state 40.00000 Ah with 1 decimals of accuracy
[08:40:23][D][sensor:094]: 'Battery Num Cycles': Sending state 24.00000  with 0 decimals of accuracy
[08:40:23][D][sensor:094]: 'Balancing State [0:off,1:pas,2:act]': Sending state 0.00000  with 0 decimals of accuracy
[08:40:23][D][sensor:094]: 'Balance Current': Sending state 30.00000 mA with 0 decimals of accuracy

or on another run I get:

[08:40:27][D][uart_debug:114]: <<< 01:03:08:00:00:00:00:00:01:00:03:84:16
[08:40:27][D][main:051]: Response data only had 13 bytes!!
[08:40:27][D][main:087]: MATCHED MISC INFO
[08:40:27][D][main:088]: Response data 1
[08:40:27][D][main:089]: Response data 3
[08:40:27][D][sensor:094]: 'Battery Remain Capacity': Sending state 0.00000 Ah with 1 decimals of accuracy
[08:40:27][D][sensor:094]: 'Battery Num Cycles': Sending state 0.00000  with 0 decimals of accuracy
[08:40:27][D][sensor:094]: 'Balancing State [0:off,1:pas,2:act]': Sending state 1.00000  with 0 decimals of accuracy
[08:40:27][D][sensor:094]: 'Balance Current': Sending state 0.00300 mA with 0 decimals of accuracy

It seems the uart debug lambda is configured to wait for a particular byte size to get the info I need, but the byte size is present twice in the debug info (don’t know if that is caused by adding my inverter modbus config to bms config), and causes those HA entities to zero out for a minute or so, to show up again for some seconds, and to zero out again.
Question is: Is there a possibility to disregard info from 01:03:08:00:00:00:00:00:01:00:03:84:16, and receive only info from 51:03:08:01:98:00:18:00:00:75:30:4A:55 ?? I guess the condition shouldn’t be byte size oriented, but more address oriented?? Any ide how could I go about it?

It needs to be byte oriented. It was the easiest way to make 4 separate requests and identify the responses.
The easiest way to resolve your problem is to make one of those request (that gives 13 bytes) longer, adding register count by 1, so the response will be 15bytes.
Another option is to verify also the first byte value.