syssi / esphome-pace-bms

ESPHome component to monitor and control a PACE Battery Management System (PACE-BMS) via RS485 (Modbus)
Apache License 2.0
23 stars 6 forks source link

Help installing #34

Open jacocilliers opened 2 days ago

jacocilliers commented 2 days ago

Hi I am a noob and not sure how to get your code into the esp32. Is there any documentation on how I can do the installation on the esp as well as what the pinout is for the esp to ttl please. I would like to integrate it into Home assistant.

syssi commented 2 days ago

Please start here: https://esphome.io/guides/getting_started_hassio

Try to create/flash your first basic ESPHome node. As soon this is working we will talk about adding this project/implementation to the node.

jacocilliers commented 2 days ago

Will do thank you

jacocilliers commented 2 days ago

I have done that part as per the link above. Not sure what to do next? I can see the esp in home assistant and I can edit it but I'm lost.

syssi commented 2 days ago

Okay. So the node is up and running as online node at the dashboard? Do you use a ESP32 or ESP8266?

jacocilliers commented 2 days ago

Yes that’s correct. ESP32

syssi commented 2 days ago

Please edit the node, don't remove the existing sections because the ota encryption key and/or api password is important and shouldn't be touched. Please extend YAML using this configuration example:

https://github.com/syssi/esphome-pace-bms/blob/main/esp32-example.yaml

If you provide your basic YAML (excluding the secrets) I can help you getting both files properly merged.

jacocilliers commented 2 days ago

Can I just copy the code within the home assistant / esphome / edit and paste it here or should it be uploaded for you to edit? I feel like a real idiot currently but this esp32 is winning me by far!

syssi commented 2 days ago

Please press the EDIT button on the ESPHome node tile of the dashboard. You should see here some lines already. Please don't overwrite these lines because they are already uploaded to your ESP and are required for the next over-the-air update. My config example must be added at the end of the existing entries but there a no section duplicates allowed.

If you have trouble to merge both YAMLs properly because it's your first time please provide the YAML code of your new node.

jacocilliers commented 2 days ago

Hi. I paste the YAML code below. Can you please help me merge the 2 I don't seem to get it working. I removed the encryption key and secret from wifi.

substitutions:
  name: esp-web-tools-example-0f7d6c
  friendly_name: ESP Web Tools Example 0f7d6c

packages:
  esphome.esp_web_tools_example: github://esphome/example-configs/esp-web-tools/esp32.yaml@main

esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}

api:
  encryption:
    key: 

wifi:
  ssid:
  password:
syssi commented 2 days ago

I've merged both files. You add the secrets to your setup or remove the statements again and add you secrets inline:

substitutions:
  name: esp-web-tools-example-0f7d6c
  friendly_name: ESP Web Tools Example 0f7d6c
  device_description: "Monitor and control a PACE BMS via RS485 (Modbus)"
  tx_pin: GPIO16
  rx_pin: GPIO17

packages:
  esphome.esp_web_tools_example: github://esphome/example-configs/esp-web-tools/esp32.yaml@main

esphome:
  name: ${name}
  name_add_mac_suffix: false
  friendly_name: ${friendly_name}
  comment: ${device_description}
  min_version: 2024.6.0
  project:
    name: "syssi.esphome-pace-bms"
    version: 1.0.0

api:
  encryption:
    key: 

wifi:
  ssid:
  password:

logger:
  level: DEBUG

uart:
  - id: uart_0
    baud_rate: 9600
    tx_pin: ${tx_pin}
    rx_pin: ${rx_pin}
    debug:
      direction: BOTH
      dummy_receiver: false

modbus:
  - id: modbus0
    uart_id: uart_0
    send_wait_time: 200ms

modbus_controller:
  - id: bms0
    # Slave address 0x01
    address: 0x01
    modbus_id: modbus0
    command_throttle: 200ms
    update_interval: 10s

# ...

sensor:
  #   0  Current                               2 byte   R   int16  10mA (Positive: chargingm Negative: discharging)
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} current"
    address: 0
    register_type: holding
    value_type: S_WORD
    unit_of_measurement: "A"
    device_class: current
    state_class: measurement
    accuracy_decimals: 2
    filters:
      - multiply: 0.01

  #   1  Voltage of pack                       2 byte   R  uint16  10mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} total voltage"
    address: 1
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 2
    filters:
      - multiply: 0.01

  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} power"
    address: 0
    register_type: holding
    value_type: U_WORD
    register_count: 2
    response_size: 4
    unit_of_measurement: "W"
    device_class: power
    state_class: measurement
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 4) {
        return NAN;
      }
      float current = (int16_t)(data[0] << 8 | data[1] << 0);
      float total_voltage = (uint16_t)(data[2] << 8 | data[3] << 0);
      return current * total_voltage * 0.0001f;

  #   2  State of charge                       2 byte   R   uint8  % (0-100%)
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} state of charge"
    address: 2
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "%"
    device_class: battery
    state_class: measurement
    accuracy_decimals: 0

  #   3  SOH                                   2 byte   R   uint8  % (0-100%)
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} state of health"
    address: 3
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "%"
    state_class: measurement
    accuracy_decimals: 0

  #  15  Cell voltage 1                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 1"
    address: 15
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  16  Cell voltage 2                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 2"
    address: 16
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  17  Cell voltage 3                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 3"
    address: 17
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  18  Cell voltage 4                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 4"
    address: 18
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  19  Cell voltage 5                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 5"
    address: 19
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  20  Cell voltage 6                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 6"
    address: 20
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  21  Cell voltage 7                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 7"
    address: 21
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  22  Cell voltage 8                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 8"
    address: 22
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  23  Cell voltage 9                        2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 9"
    address: 23
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  24  Cell voltage 10                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 10"
    address: 24
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  25  Cell voltage 11                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 11"
    address: 25
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  26  Cell voltage 12                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 12"
    address: 26
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  27  Cell voltage 13                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 13"
    address: 27
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  28  Cell voltage 14                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 14"
    address: 28
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  29  Cell voltage 15                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 15"
    address: 29
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  #  30  Cell voltage 16                       2 byte   R  uint16  mV
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} cell voltage 16"
    address: 30
    register_type: holding
    value_type: U_WORD
    unit_of_measurement: "V"
    state_class: measurement
    accuracy_decimals: 3
    filters:
      - multiply: 0.001

  ### Calculated sensors

  # Delta cell voltage
  - platform: modbus_controller
    modbus_controller_id: bms0
    name: "${name} delta cell voltage"
    address: 15
    register_type: holding
    value_type: U_WORD
    register_count: 16
    response_size: 32
    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 3
    lambda: |-
      uint8_t cells = 16;
      if (data.size() < cells * 2) {
        return NAN;
      }

      float min_cell_voltage = 100.0f;
      float max_cell_voltage = -100.0f;
      float average_cell_voltage = 0.0f;
      uint8_t min_voltage_cell = 0;
      uint8_t max_voltage_cell = 0;
      for (uint8_t i = 0; i < cells; i++) {
        float cell_voltage = (uint16_t)(data[item->offset + (i * 2)] << 8 | data[item->offset + (i * 2) + 1] << 0) * 0.001f;
        average_cell_voltage = average_cell_voltage + cell_voltage;
        if (cell_voltage < min_cell_voltage) {
            min_cell_voltage = cell_voltage;
            min_voltage_cell = i + 1;
        }
        if (cell_voltage > max_cell_voltage) {
          max_cell_voltage = cell_voltage;
          max_voltage_cell = i + 1;
        }
      }
      average_cell_voltage = average_cell_voltage / cells;

      id(bms0_average_cell_voltage).publish_state(average_cell_voltage);
      id(bms0_min_cell_voltage).publish_state(min_cell_voltage);
      id(bms0_max_cell_voltage).publish_state(max_cell_voltage);
      id(bms0_min_voltage_cell).publish_state(min_voltage_cell);
      id(bms0_max_voltage_cell).publish_state(max_voltage_cell);

      return max_cell_voltage - min_cell_voltage;

  - platform: template
    id: bms0_average_cell_voltage
    name: "${name} average cell voltage"
    update_interval: never
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 3

  - platform: template
    id: bms0_min_cell_voltage
    name: "${name} min cell voltage"
    update_interval: never
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 3

  - platform: template
    id: bms0_max_cell_voltage
    name: "${name} max cell voltage"
    update_interval: never
    unit_of_measurement: V
    device_class: voltage
    state_class: measurement
    accuracy_decimals: 3

  - platform: template
    id: bms0_min_voltage_cell
    name: "${name} min voltage cell"
    update_interval: never
    unit_of_measurement: ""
    state_class: measurement
    accuracy_decimals: 0

  - platform: template
    id: bms0_max_voltage_cell
    name: "${name} max voltage cell"
    update_interval: never
    unit_of_measurement: ""
    state_class: measurement
    accuracy_decimals: 0
jacocilliers commented 2 days ago

You are the best thank you. Im still learning and will go through both to teach myself how you did it. Thank you again.

syssi commented 2 days ago

You have to use these GPIOs:

  tx_pin: GPIO16
  rx_pin: GPIO17

Feel free to ask additional questions if it doesn't work out of the box.

jacocilliers commented 2 days ago

Hi. Thank you once again for the help. If my pace bms does not want to work via rs485 can I change it to rs232? I usually use the rs232 to connect to my pc software so at least I know it is working. The pc software gives me an sending failed when trying to change the protocol.

syssi commented 2 days ago

Which protocols are available via RS232?

jacocilliers commented 2 days ago

Connecting to Pbms tools gives me options for CAN & rs485 however I am not able to send it and Pace confirmed that the BMS I have cannot be changed ( protocols ) If I connect to solar assistant via rs232 it will connect and show in home assistant however then I cannot see my other 2 battery banks with JK BMS in them, Wanted to see all 3x my batteries in home assistant.

syssi commented 2 days ago

I don't know which protocols is used on the RS232 port in your case. Just give it a try but don't forget to replace the RS485 converter module with a RS232 (MAX3232) one.

jacocilliers commented 2 days ago

Will do thank you

syssi commented 2 days ago

Please take a look at this issue. May be it applies to your setup too: https://github.com/syssi/esphome-pace-bms/issues/32