JKBMS s Pylontech simulací

Souhrn tématu

V diskusi je popsáno, jak připojit pět let starý JKBMS k měniči s Pylontech protokolem pomocí ESPHome a ESP32. Autor využívá UART GPS port JKBMS a RS485 optoizolátor pro simulaci Pylontech baterie, čímž umožňuje monitorování bez nutnosti kupovat nový BMS. Sdílený kód a nastavení pomáhají zájemcům integrovat starší JKBMS do moderních systémů s Pylontech protokolem.
proasnet
Příspěvky: 425
Registrován: čtv kvě 27, 2021 12:06 pm
Reputace: 43
Lokalita: Rajecké Teplice
Systémové napětí: 48V
Výkon panelů [Wp]: 5000
Kapacita baterie [kWh]: 14,5

JKBMS s Pylontech simulací

Nový příspěvek od proasnet »

Už tu je něco podobného nespočetněkrát, ale jestli to někomu pomůže, řešil jsem jak připojit svoji 5 letou JKBMS k měniči s pylontech protokolem, která už byla monitorovaná pomocí ESPHome.
Samotná BMS nemá RS485, jenom port GPS (UART) a tam jsem měl připojený ESP32. Kupovat novou s pylontech se mi nechtělo, tak jsem hledal řešení, jak to zkloubit do jednoho ESP.
K ESP kromě JKBMS je připojený také RS485 optoizolátor, který je následně připojený k měniči, a ten vidí Pylontech baterii

Kód: Vybrat vše

substitutions:
  name: "jk-bms"
  device_description: "Monitor a JK-BMS using the GPS port (UART-TTL)"
  external_components_source: github://syssi/esphome-jk-bms@main

esphome:
  name: ${name}
  comment: ${device_description}
  min_version: 2024.6.0
  project:
    name: "syssi.esphome-jk-bms"
    version: 2.1.0

esp32:
  board: wemos_d1_mini32
  framework:
    type: esp-idf

external_components:
  - source: ${external_components_source}
    refresh: 0s
  - source: github://fahmula/esphome-pylontech-rs485@main
    refresh: 0s

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "JKBMS"
    password: "Jirutka8011"

captive_portal:

web_server:
  port: 80
  auth:
    username: !secret web_server_username
    password: !secret web_server_password


ota:
  - platform: esphome
  - platform: web_server

logger:
  level: DEBUG

  
api:

globals:
  - id: g_heartbeat_enabled
    type: bool
    restore_value: yes
    initial_value: 'true'
  - id: g_force_charge_requested
    type: bool
    restore_value: yes
    initial_value: 'false'
  - id: g_max_v
    type: float
    restore_value: yes
    initial_value: '54.5'
  - id: g_min_v
    type: float
    restore_value: yes
    initial_value: '48.0'
  - id: g_max_charge_i
    type: float
    restore_value: yes
    initial_value: '80.0'
  - id: g_max_discharge_i
    type: float
    restore_value: yes
    initial_value: '120.0'

time:
  - platform: sntp
    id: sntp_time
    servers: "pool.ntp.org"

uart:
  - id: uart_0
    baud_rate: 115200
    rx_buffer_size: 384
    tx_pin: GPIO17
    rx_pin: GPIO16

  - id: pylontech
    tx_pin: GPIO22
    rx_pin: GPIO21
    baud_rate: 9600

jk_modbus:
  - id: modbus0
    uart_id: uart_0
    rx_timeout: 50ms

jk_bms:
  - id: bms0
    jk_modbus_id: modbus0
    update_interval: 5s 

sensor:
  # JKBMS
  - platform: jk_bms
    total_voltage:
      name: "bms0 total voltage"
      id: bms_total_voltage
    min_cell_voltage:
      name: "${name} min cell voltage"
      id: bms_min_cell_voltage
      internal: true
    max_cell_voltage:
      name: "${name} max cell voltage"
      id: bms_max_cell_voltage
      internal: true
    current:
      name: "bms0 current"
      id: bms_current
    power:
      name: "bms0 power"
      id: bms0_power
    temperature_sensor_1:
      name: "bms0 temperature sensor 1"
      id: bms_temperature_1
    temperature_sensor_2:
      name: "bms0 temperature sensor 2"
      id: bms_temperature_2
    power_tube_temperature:
      name: "bms0 power tube temperature"
      id: bms_mosfet_temp
    capacity_remaining:
      name: "bms0 capacity remaining"
      id: bms_capacity
    charging_cycles:
      name: "bms0 charging cycles"
      id: bms_cycles
    errors_bitmask:
      name: "bms0 errors bitmask"
      id: bms_errors_bitmask
    cell_voltage_1:
      name: "bms0 cell voltage 1"
      id: bms_cell_voltage_1
    cell_voltage_2:
      name: "bms0 cell voltage 2"
      id: bms_cell_voltage_2
    cell_voltage_3:
      name: "bms0 cell voltage 3"
      id: bms_cell_voltage_3
    cell_voltage_4:
      name: "bms0 cell voltage 4"
      id: bms_cell_voltage_4
    cell_voltage_5:
      name: "bms0 cell voltage 5"
      id: bms_cell_voltage_5
    cell_voltage_6:
      name: "bms0 cell voltage 6"
      id: bms_cell_voltage_6
    cell_voltage_7:
      name: "bms0 cell voltage 7"
      id: bms_cell_voltage_7
    cell_voltage_8:
      name: "bms0 cell voltage 8"
      id: bms_cell_voltage_8
    cell_voltage_9:
      name: "bms0 cell voltage 9"
      id: bms_cell_voltage_9
    cell_voltage_10:
      name: "bms0 cell voltage 10"
      id: bms_cell_voltage_10
    cell_voltage_11:
      name: "bms0 cell voltage 11"
      id: bms_cell_voltage_11
    cell_voltage_12:
      name: "bms0 cell voltage 12"
      id: bms_cell_voltage_12
    cell_voltage_13:
      name: "bms0 cell voltage 13"
      id: bms_cell_voltage_13
    cell_voltage_14:
      name: "bms0 cell voltage 14"
      id: bms_cell_voltage_14
    cell_voltage_15:
      name: "bms0 cell voltage 15"
      id: bms_cell_voltage_15
    cell_voltage_16:
      name: "bms0 cell voltage 16"
      id: bms_cell_voltage_16

  - platform: template
    name: "BMS Charging current"
    id: "bms_charging_current"
    unit_of_measurement: W
    lambda: |-
      if(id(bms0_power).state > 0 ) {
      return id(bms0_power).state;
      } else return 0;

  - platform: template
    name: "BMS Discharging current"
    id: "bms_discharging_current"
    unit_of_measurement: W
    lambda: |-
      if(id(bms0_power).state < 0 ) {
      return (id(bms0_power).state * -1);
      } else return 0;    

  # Energie
  - platform: total_daily_energy
    name: BMS Charging Energy
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    accuracy_decimals: 2
    power_id: bms_charging_current
    restore: True
    filters:
      - multiply: 0.001

  - platform: total_daily_energy
    name: BMS Discharging Energy
    state_class: total_increasing
    device_class: energy
    unit_of_measurement: kWh
    accuracy_decimals: 2
    power_id: bms_discharging_current
    restore: True
    filters:
      - multiply: 0.001

  - platform: template
    id: link_heartbeat
    name: "Inverter Heartbeat"
    unit_of_measurement: "ms"
    icon: "mdi:heart-pulse"

  - platform: template
    id: live_max_v
    lambda: return id(input_max_v).state;
    unit_of_measurement: "V"
    update_interval: 3s

  - platform: template
    id: live_min_v
    lambda: return id(input_min_v).state;
    unit_of_measurement: "V"
    update_interval: 3s

  - platform: template
    id: live_max_charge_i
    lambda: return id(input_max_charge_i).state;
    unit_of_measurement: "A"
    update_interval: 3s

  - platform: template
    id: live_max_discharge_i
    lambda: return id(input_max_discharge_i).state;
    unit_of_measurement: "A"
    update_interval: 3s

number:
  - platform: template
    id: input_max_v
    name: "BMS Max Voltage"
    unit_of_measurement: "V"
    update_interval: 3s
    min_value: 50.0
    max_value: 58.6
    mode: BOX
    step: 0.1
    lambda: return id(g_max_v);
    set_action:
      - globals.set:
          id: g_max_v
          value: !lambda 'return x;'

  - platform: template
    id: input_min_v
    name: "BMS Min Voltage"
    unit_of_measurement: "V"
    update_interval: 3s
    min_value: 44.0
    max_value: 48.0
    mode: BOX
    step: 0.1
    lambda: return id(g_min_v);
    set_action:
      - globals.set:
          id: g_min_v
          value: !lambda 'return x;'

  - platform: template
    id: input_max_charge_i
    name: "BMS Max Charge Current"
    unit_of_measurement: "A"
    update_interval: 3s
    min_value: 0.0
    max_value: 120.0
    mode: BOX
    step: 0.5
    lambda: return id(g_max_charge_i);
    set_action:
      - globals.set:
          id: g_max_charge_i
          value: !lambda 'return x;'

  - platform: template
    id: input_max_discharge_i
    name: "BMS Max Discharge Current"
    unit_of_measurement: "A"
    update_interval: 3s
    min_value: 0.0
    max_value: 120.0
    mode: BOX
    step: 0.5
    lambda: return id(g_max_discharge_i);
    set_action:
      - globals.set:
          id: g_max_discharge_i
          value: !lambda 'return x;'  

binary_sensor:
  - platform: jk_bms
    balancing:
      name: "bms0 balancing"
    balancing_switch:
      name: "bms0 balancing switch"
    charging:
      name: "bms0 charging"
    discharging:
      name: "bms0 discharging"
    dedicated_charger_switch:
      name: "bms0 dedicated charger switch"
    online_status:
      name: "bms0 online status"

  - platform: template
    id: rs485_link_status
    name: "RS485 Link Status"
    device_class: connectivity


  - platform: template
    id: bms_cell_ov
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x01;"
    internal: true
  - platform: template
    id: bms_cell_uv
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x02; "
    internal: true
  - platform: template
    id: bms_total_ov
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x04;"
    internal: true
  - platform: template
    id: bms_total_uv
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x08;"
    internal: true
  - platform: template
    id: bms_chg_oc
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x10;"
    internal: true
  - platform: template
    id: bms_dischg_oc
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x20;"
    internal: true
  - platform: template
    id: bms_temp_high
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x140;" # Bity 6 (chg) a 8 (dischg)
    internal: true
  - platform: template
    id: bms_temp_low
    lambda: "return (uint32_t)id(bms_errors_bitmask).state & 0x280;" # Bity 7 (chg) a 9 (dischg)
    internal: true



switch:
  - platform: jk_bms
    charging:
      name: "${name} charging"
    discharging:
      name: "${name} discharging"
#    balancer:
#      name: "bms0 balancer"

  - platform: template
    name: "Enable Inverter Heartbeat Sensor"
    id: link_heartbeat_enable
    lambda: return id(g_heartbeat_enabled);
    turn_on_action:
      - globals.set: { id: g_heartbeat_enabled, value: 'true' }
    turn_off_action:
      - globals.set: { id: g_heartbeat_enabled, value: 'false' }

text_sensor:
  # JKBMS
  - platform: jk_bms
    errors:
      name: "bms0 errors"
    total_runtime_formatted:
      name: "bms0 total runtime formatted"

button:
  # JKBMS
  - platform: restart
    name: "ESP_Restart"



pylontech_rs485:
  uart_id: pylontech
  update_timeout: 60s

  # --- RS485 Link Monitoring ---
  rs485_status: rs485_link_status
  inverter_heartbeat: link_heartbeat
  heartbeat_switch: link_heartbeat_enable

  # --- Link ALL sensors to the component ---
  # Core data
  state_of_charge: bms_capacity
  voltage: bms_total_voltage
  current: bms_current
  temperature: bms_temperature_1
 
  # Health data
  cycle_count: bms_cycles

  # Cell voltage data
  max_cell_voltage: bms_max_cell_voltage
  min_cell_voltage: bms_min_cell_voltage

 

  # MOSFET temperature data
  mosfet_temperature: bms_mosfet_temp

  # BMS temperature data
  bms_temperature: bms_temperature_1

  # Alarms and warnings

  # Alarm Status 1
  total_voltage_high_alarm: bms_total_ov
  total_voltage_low_alarm: bms_total_uv
  cell_voltage_high_alarm: bms_cell_ov
  cell_voltage_low_alarm: bms_cell_uv
  #cell_temp_high_alarm: alarm_cell_temp_high
  #cell_temp_low_alarm: alarm_cell_temp_low
  #mosfet_temp_high_alarm: alarm_mosfet_temp_high
  #cell_imbalance_alarm: alarm_cell_imbalance
  charge_overcurrent_alarm: bms_chg_oc
  discharge_overcurrent_alarm: bms_dischg_oc

  # Alarm Status 2
  #cell_temp_imbalance_alarm: alarm_cell_temp_imbalance
  #charge_overcurrent_alarm: alarm_charge_over_current
  #discharge_overcurrent_alarm: alarm_discharge_over_current

  # Protection Status 1
  #module_overvoltage_protection: protection_module_overvoltage
  #module_undervoltage_protection: protection_module_undervoltage
  #cell_overvoltage_protection: protection_cell_overvoltage
  #cell_undervoltage_protection: protection_cell_undervoltage
  #cell_overtemp_protection: protection_cell_over_temperature
  #cell_undertemp_protection: protection_cell_under_temperature
  #mosfet_overtemp_protection: protection_mosfet_over_temperature

  # Protection Status 2
  #charge_overcurrent_protection: protection_charge_over_current
  #discharge_overcurrent_protection: protection_discharge_over_current
  #system_fault_protection: protection_system_fault

  # Dynamic battery limits (for command 63)
  max_voltage: live_max_v
  min_voltage: live_min_v
  max_charge_current: live_max_charge_i
  max_discharge_current: live_max_discharge_i
  #requested_force_charge: my_force_charge_sensor
Offgrid 11kW, Lifepo4

Kdo je online

Uživatelé prohlížející si toto fórum: Claudebot [Bot] a 0 hostů