image.png

本项目源于GitHub:

  1. syssi大佬的esphome-jk-bms
  2. 卡片美化UI代码来源自: (@dr3amr) shared some Home Assistant Lovelace UI cards for a beautiful dashboard here.
    感谢大佬们的辛苦付出!!

本文作者:云留月
本文地址:【ESP 32】20元让你的极空保护板连上HomeAssistant实现自动化管理 | 云留月的技术小站
转载须知:转载请与作者联系QQ:283980619,转载请注明来源,未经许可禁止转载。

一、项目前言

笔者由于喜欢折腾,且Nas盘位比较多,导致电耗一天能达到2-3度电,逛B站发现可以通过太阳能来发电,充进电池给Nas供电,达到省电的目的。

于是自己组装了一台太阳能发电系统,主要由太阳能板+MPPT控制器+电池组+逆变器组成。
image.png

然而让我头疼的是极空保护板官方app是通过蓝牙连接进行监控,无法通过wifi进行数据监控。

而我又给电池外接了一路市电输入,因此希望能实现电池电量过低时,自动开启市电输入为电池和Nas供电,当电池充满时自动断电,由电池和太阳能发电带动Nas工作,我在市电输入端加了一个涂鸦智能断路器,能够实现定时通断,在逆变器上也放置了一个涂鸦智能插座,两者都接入了NAS里的HomeAssistant(后文简称HA)中,能够实现定时切换,那么问题就是我该如何采集极空保护板的数据,让HA收集起来,根据电量自动进行充电管理,经过一番寻找和研究,终于实现了使用20元左右的ESP32 物联网模块实现了蓝牙采集数据,通过wifi发送给HA,下面主要介绍下如何实现。

二、准备工作

2.1 极空保护板+电池组

本项目主要针对极空保护板,其他保护板需要自己研究有没有对应的大神研究过相关的项目。
根据极空保护板的产品信息记好对应的型号。

2.2 安卓手机

2.1.1 下载安装BLT调试助手&极空APP

安装极空APP,并通过蓝牙连接到极空保护板,然后通过BLT调试助手查看保护板的MAC地址

  1. 注意必须要用安卓手机,因为苹果手机上显示的是蓝牙UUID,而后续esp项目需要使用到MAC地址,因此务必要获取到保护板蓝牙的MAC地址并记录好。
  2. 有可能连接了,BLT调试助手中还是没有显示对应的蓝牙信号,可以关闭蓝牙,退出调试助手,重新连接极空保护板进行尝试。

2.3 ESP32+ESPHome

  1. 需要用到ESP32模块,在taobao、jd、pdd上均可以20元左右的价格购买
  2. 一根typec数据线,能够将ESP32与您的电脑相连接
  3. 除此之外需要安装ESPHome,如果您使用的是HAOS,可以直接通过ESPHome官方的链接以插件形式进行安装。

2.3.1 安装ESPHome设备构建器

  1. 打开Home Assistant:在Home Assistant中,点击以下按钮以安装ESPHome设备构建器:
    点击此处也可以跳转安装
    安装按钮

    注意此处需要输入你HA服务端的地址

  2. 安装并启动:安装完成后,点击“Start”,然后点击“Open Web UI”。
  3. 手动添加:在Home Assistant集成页面,点击“Add Integration”,搜索“ESPHome”

2.3.2 Docker部署ESPHome

如果您跟我一样也是通过Docker安装的HA,那么上述安装会无法正常进行,需要通过安装ESPHome的docker进行ESP32的固件编译和烧录,详细dockercompose文件如下:

version: '3'
services:
  esphome:
    container_name: esphome
    image: ghcr.io/esphome/esphome
    volumes:
      - /自己的路径/Docker/esphome/config:/config
      - /etc/localtime:/etc/localtime:ro
    restart: always
    privileged: true
    network_mode: host
    environment:
      - USERNAME=admin
      - PASSWORD=自行设置密码

需要注意走的host网络模式,需要保证6052端口未被占用

安装好后,访问http://docker主机ip:6052 即可访问

三、项目配置文件及编译烧录

本项目使用的是GitHub开源项目syssi大佬的esphome-jk-bms

注意:后续拉库和编译均需要特定魔法网络,因此需要保证docker主机走的是魔法网络

3.1 保护板软件型号及连接方式

项目支持的极空保护板型号如下,请根据您采购的极空保护板型号选择对应的参数:

作者的官方说明:

All JK-BMS models with software version >=6.0 are using the implemented protocol and should be supported.

大意是:所有软件版本大于等于6.0的JK-BMS模块已经被本项目适配协议,应该都能支持。

连接方式主要分为以下两种:

  1. UART-TTL杜邦线相连
    连接示意图:
    image.png

    连接原理图:

                UART-TTL
┌──────────┐                ┌─────────┐
│          │<----- RX ----->│         │
│  JK-BMS  │<----- TX ----->│ ESP32/  │
│          │<----- GND ---->│ ESP8266 │<-- 3.3V
│          │                │         │<-- GND
└──────────┘                └─────────┘

# UART-TTL socket (4 Pin, JST 1.25mm pitch)
┌─── ─────── ────┐
│                │
│ O   O   O   O  │
│GND  RX  TX VBAT│
└────────────────┘
  │   │   │
  │   │   └─── GPIO17 (`rx_pin`)
  │   └─────── GPIO16 (`tx_pin`)
  └─────────── GND

BMS的UART-TTL(标记为RS485)插座可以连接到ESP的任何UART引脚。由于波特率较高(115200波特),应优先选择硬件UART。这个连接器被称为4针JST,间距为1.25mm。

  1. BLT蓝牙连接
    需要用到上面通过安卓手机BLT调试助手获取到的蓝牙MAC地址。

3.2 具体型号

下面会标注使用 JK02_32SJK02_24S或者是 JK04 ,后面括号内表示用户上报给项目作者反馈可以正常使用时所采用的连接方式
具体根据自己的型号进行适配。

  • JK-BD4A8S4P, hw 11.xw, sw 11.24, using JK02_32S (reported by @austin202220)
  • JK-BD6A17S6P, hw 7.2, sw 7.1.0H
  • JK-BD6A17S8P, hw 9.x, sw 9.01G (reported by @jonadis)
  • JK-BD6A20S10P, hw 10.XW, sw 10.07 (reported by @adadrag)
  • JK-BD6A20S12P, hw 11.XW, sw 11.281, using UART-TTL (reported by @asiridissa)
  • JK-BD6A20S6P, hw 11.XW, sw 11.42, using UART-TTL (reported by @parumsancto)
  • JK-BD6A24S6P, hw 6.x, sw 6.10S (reported by @ziporah)
  • JK-BD6A24S10P, hw 8.x, sw 8.0.6G (reported by @spoonwzd)
  • JK-BD6A24S10P, hw 10.xw, sw 10.09 (reported by @PMPoulsen)
  • JK-BD6A24S12P, hw v11.XW, sw 11.36, using JK02_32S (BLE) (reported by @hackmannbr)
  • JK-BD4A17S4P, hw 11.xw, sw 11.01 (reported by @Condor-XYZ)
  • JK-BD4A17S4P, hw 11.xw, sw 11.27, using JK02_32S and/or UART-TTL (reported by @hemskgren)
  • JK-B1A8S10P, hw 11.XW, sw 11.261, using JK02_32S (reported by @Chickenbreast0)
  • JK-B1A24S15P, hw 8.x, sw 8.1.0H (reported by @killee)
  • JK-B1A20S15P, hw 8.x, sw 8.14U (reported by @trippfam07)
  • JK-B1A20S15P, hw 10.xw, sw 10.07 (reported by @romeox44)
  • JK-B1A20S15P, hw 10.xw, sw 10.10, using JK02_24S (reported by @austin202220)
  • JK-B1A20S15P, hw 11.xw, sw 11.26, using UART-TTL (reported by @Tesla72PL)
  • JK-B2A24S15P, hw 6.x, sw 6.1.3S (reported by @miguel300477)
  • JK-B2A24S15P, hw 8.x, sw 8.21W (reported by @mariusvaida)
  • JK-B2A24S15P, hw 10.xw, sw 10.07, using JK02_24S (BLE) and UART-TTL
  • JK-B2A24S15P, hw 10.xw, sw 10.08 (reported by @meccip)
  • JK-B2A24S15P, hw 10.xw, sw 10.10, using UART-TTL (reported by @nayias)
  • JK-B2A24S20P, hw 8.x, sw 8.1.2H, using JK02_24S (reported by @KlausLi)
  • JK-B2A24S20P, hw 8.x, sw 8.20G, using JK02_24S (reported by @rob-oravec)
  • JK-B2A24S20P, hw 10.X-W, sw 10.02, using JK02_24S (reported by @SeByDocKy)
  • JK-B2A24S20P, hw 10.XG, sw 10.07D30, using JK02_24S (reported by @TheSmartGerman)
  • JK-B2A24S20P, hw 10.XW, sw 10.07, using JK02_24S (reported by @amagr0)
  • JK-B2A24S20P, hw 10.XW, sw 10.09, using JK02_24S (reported by @Ghilm1986)
  • JK-B2A8S20P, hw 9.x, sw 9.01M3, using JK02_24S (reported by @EasilyBoredEngineer)
  • JK-B2A8S20P, hw 9.x, sw 9.08W (reported by @vrabi-cv)
  • JK-B2A8S20P, hw 11.XW, sw 11.17, using JK02_32S (reported by @senfkorn)
  • JK-B2A8S20P, hw 11.XW, sw 11.26, using JK02_32S (reported by @riker65)
  • JK-B2A8S20P, hw 11.XA, sw 11.48, using UART-TTL (reported by @BytEvil)
  • JK-B2A20S20P, hw 10.XW, sw 10.09 (reported by @markusgg84)
  • JK-B2A20S20P, hw 10.XW, sw 10.10, using JK02_24S (reported by @cygeus)
  • JK-B2A20S20P, hw 10.XW, sw 11.21h, using JK02_32S (reported by @Salve87)
  • JK-B2A20S20P, hw 11.XW, sw 11.24H, using JK02_32S (reported by @austin202220)
  • JK-B2A20S20P, hw 11.XW, sw 11.25H, using JK02_32S (reported by @iovcharyk)
  • JK-B2A20S20P, hw 11.XW, sw 11.284, using JK02_32S (BLE) and UART-TTL (reported by @martinSezman)
  • JK-B5A24S, hw 8.x, sw 8.0.3M, using JK04 (reported by @JSladen)
  • JK-B2A16S, hw 3.0, sw 3.3.0, using JK04 (reported by @magnetus26)
  • GW-24S4EB (NEEY/Heltec 4A Smart Active Balancer), hw HW-2.8.0, sw ZH-1.2.3 (reported by @cristi2005)
  • GW-24S4EB (NEEY 4A Smart Active Balancer 4th generation), hw HW-3.2.0, sw ZH-1.2.4 (reported by @fabhund)

3.3 详细ESP-Home的Yaml配置文件

注意如果你的板子连接后无法正常联网或者连接蓝牙,可以尝试更改 esp:board:中的ESP板子型号。
image.png

取消勾选,再点击esp32,进去就能选择板子型号,烧录了看下能不能正常蓝牙和wifi连接,尝试到两者都能连上的话,把对应的板子型号填到下面yaml文件中。

substitutions:

  name: jk-bms

  device_description: "Monitor and control a JK-BMS via bluetooth"

  external_components_source: github://syssi/esphome-jk-bms@main

  mac_address: 此处填写前文中获得的极空保护板蓝牙mac地址
			  格式为:xx:xx:xx:xx:xx:xx

  # Please use "JK02_24S" if you own a old JK-BMS < hardware version 11.0 (hardware version >= 6.0 and < 11.0)

  # Please use "JK02_32S" if you own a new JK-BMS >= hardware version 11.0 (f.e. JK-B2A8S20P hw 11.XW, sw 11.26)

  # Please use "JK04" if you have some old JK-BMS <= hardware version 3.0 (f.e. JK-B2A16S hw 3.0, sw. 3.3.0)

  protocol_version: JK02_32S

  

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

  

wifi:

  ssid: !secret wifi_ssid

  password: !secret wifi_password

  

ota:

  platform: esphome

  on_begin:

    then:

      - switch.turn_off: ble_client_switch0

      - logger.log: "BLE connection suspended for OTA update"

  

logger:

  level: DEBUG

  logs:

    esp32_ble_tracker: INFO

    esp32_ble_client: INFO

  

# If you don't use Home Assistant please remove this `api` section and uncomment the `mqtt` component!

api:

  

# mqtt:

#   broker: !secret mqtt_host

#   username: !secret mqtt_username

#   password: !secret mqtt_password

#   id: mqtt_client

  

esp32_ble_tracker:

  scan_parameters:

    active: false

  

ble_client:

  - mac_address: ${mac_address}

    id: client0

  

jk_bms_ble:

  - ble_client_id: client0

    protocol_version: ${protocol_version}

    throttle: 5s

    id: bms0

  

binary_sensor:

  - platform: jk_bms_ble

    balancing:

      name: "${name} balancing"

    charging:

      name: "${name} charging"

    discharging:

      name: "${name} discharging"

    heating:

      name: "${name} heating"

    online_status:

      name: "${name} online status"

  

button:

  - platform: jk_bms_ble

    retrieve_settings:

      name: "${name} retrieve settings"

    retrieve_device_info:

      name: "${name} retrieve device info"

  

number:

  - platform: jk_bms_ble

    jk_bms_ble_id: bms0

    balance_trigger_voltage:

      name: "${name} balance trigger voltage"

    cell_count:

      name: "${name} cell count"

    total_battery_capacity:

      name: "${name} total battery capacity"

    cell_voltage_overvoltage_protection:

      name: "${name} cell voltage overvoltage protection"

    cell_voltage_overvoltage_recovery:

      name: "${name} cell voltage overvoltage recovery"

    cell_voltage_undervoltage_protection:

      name: "${name} cell voltage undervoltage protection"

    cell_voltage_undervoltage_recovery:

      name: "${name} cell voltage undervoltage recovery"

    balance_starting_voltage:

      name: "${name} balance starting voltage"

    voltage_calibration:

      name: "${name} voltage calibration"

    current_calibration:

      name: "${name} current calibration"

    power_off_voltage:

      name: "${name} power off voltage"

    max_balance_current:

      name: "${name} max balance current"

    max_charge_current:

      name: "${name} max charge current"

    max_discharge_current:

      name: "${name} max discharge current"

    charge_overcurrent_protection_delay:

      name: "${name} charge overcurrent protection delay"

    charge_overcurrent_protection_recovery_time:

      name: "${name} charge overcurrent protection recovery time"

    discharge_overcurrent_protection_delay:

      name: "${name} discharge overcurrent protection delay"

    discharge_overcurrent_protection_recovery_time:

      name: "${name} discharge overcurrent protection recovery time"

    short_circuit_protection_delay:

      name: "${name} short circuit protection delay"

    short_circuit_protection_recovery_time:

      name: "${name} short circuit protection recovery time"

    charge_overtemperature_protection:

      name: "${name} charge overtemperature protection"

    charge_overtemperature_protection_recovery:

      name: "${name} charge overtemperature protection recovery"

    discharge_overtemperature_protection:

      name: "${name} discharge overtemperature protection"

    discharge_overtemperature_protection_recovery:

      name: "${name} discharge overtemperature protection recovery"

    charge_undertemperature_protection:

      name: "${name} charge undertemperature protection"

    charge_undertemperature_protection_recovery:

      name: "${name} charge undertemperature protection recovery"

    power_tube_overtemperature_protection:

      name: "${name} power tube overtemperature protection"

    power_tube_overtemperature_protection_recovery:

      name: "${name} power tube overtemperature protection recovery"

  

sensor:

  - platform: jk_bms_ble

    jk_bms_ble_id: bms0

    min_cell_voltage:

      name: "${name} min cell voltage"

    max_cell_voltage:

      name: "${name} max cell voltage"

    min_voltage_cell:

      name: "${name} min voltage cell"

    max_voltage_cell:

      name: "${name} max voltage cell"

    delta_cell_voltage:

      name: "${name} delta cell voltage"

    average_cell_voltage:

      name: "${name} average cell voltage"

    cell_voltage_1:

      name: "${name} cell voltage 1"

    cell_voltage_2:

      name: "${name} cell voltage 2"

    cell_voltage_3:

      name: "${name} cell voltage 3"

    cell_voltage_4:

      name: "${name} cell voltage 4"

    cell_voltage_5:

      name: "${name} cell voltage 5"

    cell_voltage_6:

      name: "${name} cell voltage 6"

    cell_voltage_7:

      name: "${name} cell voltage 7"

    cell_voltage_8:

      name: "${name} cell voltage 8"

    cell_voltage_9:

      name: "${name} cell voltage 9"

    cell_voltage_10:

      name: "${name} cell voltage 10"

    cell_voltage_11:

      name: "${name} cell voltage 11"

    cell_voltage_12:

      name: "${name} cell voltage 12"

    cell_voltage_13:

      name: "${name} cell voltage 13"

    cell_voltage_14:

      name: "${name} cell voltage 14"

    cell_voltage_15:

      name: "${name} cell voltage 15"

    cell_voltage_16:

      name: "${name} cell voltage 16"

    cell_voltage_17:

      name: "${name} cell voltage 17"

    cell_voltage_18:

      name: "${name} cell voltage 18"

    cell_voltage_19:

      name: "${name} cell voltage 19"

    cell_voltage_20:

      name: "${name} cell voltage 20"

    cell_voltage_21:

      name: "${name} cell voltage 21"

    cell_voltage_22:

      name: "${name} cell voltage 22"

    cell_voltage_23:

      name: "${name} cell voltage 23"

    cell_voltage_24:

      name: "${name} cell voltage 24"

    cell_resistance_1:

      name: "${name} cell resistance 1"

    cell_resistance_2:

      name: "${name} cell resistance 2"

    cell_resistance_3:

      name: "${name} cell resistance 3"

    cell_resistance_4:

      name: "${name} cell resistance 4"

    cell_resistance_5:

      name: "${name} cell resistance 5"

    cell_resistance_6:

      name: "${name} cell resistance 6"

    cell_resistance_7:

      name: "${name} cell resistance 7"

    cell_resistance_8:

      name: "${name} cell resistance 8"

    cell_resistance_9:

      name: "${name} cell resistance 9"

    cell_resistance_10:

      name: "${name} cell resistance 10"

    cell_resistance_11:

      name: "${name} cell resistance 11"

    cell_resistance_12:

      name: "${name} cell resistance 12"

    cell_resistance_13:

      name: "${name} cell resistance 13"

    cell_resistance_14:

      name: "${name} cell resistance 14"

    cell_resistance_15:

      name: "${name} cell resistance 15"

    cell_resistance_16:

      name: "${name} cell resistance 16"

    cell_resistance_17:

      name: "${name} cell resistance 17"

    cell_resistance_18:

      name: "${name} cell resistance 18"

    cell_resistance_19:

      name: "${name} cell resistance 19"

    cell_resistance_20:

      name: "${name} cell resistance 20"

    cell_resistance_21:

      name: "${name} cell resistance 21"

    cell_resistance_22:

      name: "${name} cell resistance 22"

    cell_resistance_23:

      name: "${name} cell resistance 23"

    cell_resistance_24:

      name: "${name} cell resistance 24"

    total_voltage:

      name: "${name} total voltage"

    current:

      name: "${name} current"

    heating_current:

      name: "${name} heating current"

    power:

      name: "${name} power"

    charging_power:

      name: "${name} charging power"

    discharging_power:

      name: "${name} discharging power"

    temperature_sensor_1:

      name: "${name} temperature sensor 1"

    temperature_sensor_2:

      name: "${name} temperature sensor 2"

    # temperature_sensor_3:

    #   name: "${name} temperature sensor 3"

    # temperature_sensor_4:

    #   name: "${name} temperature sensor 4"

    power_tube_temperature:

      name: "${name} power tube temperature"

    balancing:

      name: "${name} balancing"

    state_of_charge:

      name: "${name} state of charge"

    capacity_remaining:

      name: "${name} capacity remaining"

    total_battery_capacity_setting:

      name: "${name} total battery capacity setting"

    charging_cycles:

      name: "${name} charging cycles"

    total_charging_cycle_capacity:

      name: "${name} total charging cycle capacity"

    total_runtime:

      name: "${name} total runtime"

    balancing_current:

      name: "${name} balancing current"

    errors_bitmask:

      name: "${name} errors bitmask"

  

switch:

  - platform: jk_bms_ble

    charging:

      name: "${name} charging"

    discharging:

      name: "${name} discharging"

    balancer:

      name: "${name} balancer"

  

  - platform: ble_client

    ble_client_id: client0

    id: ble_client_switch0

    name: "${name} enable bluetooth connection"

  

text_sensor:

  - platform: jk_bms_ble

    errors:

      name: "${name} errors"

    total_runtime_formatted:

      name: "${name} total runtime formatted"

然后点 三个点 - install
image.png

根据自己熟悉的烧录方式
我推荐用manmual download - factory文件
image.png

下载固件后,再点击Manual download 选Open ESPHome Web 进行固件烧录,此时将esp32 用typec 数据线接到电脑。

image.png
进入web烧录页面,点击connect,然后选择
image.png

注意电脑需要安装esp32的驱动
没有安装的话,会提示
image.png
选择对应芯片的驱动,不知道的话找卖家问。
此处也提供两个常用下载,来自于合宙文档。

然后选择对应com串口,点击连接
image.png

然后选择install,再选择文件,再上传文件,选择install,然后等待烧录完毕。
image.png

然后回ESPHome,点击对应yaml文件的LOGS,就能看到当前ESP32的日志。

如果连到了极空保护板,就会开始上传数据,如下所示:

[sensor:127]: 'jk-bms cell voltage 1': Sending state 4.12500 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 2': Sending state 4.12500 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 3': Sending state 4.12800 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 4': Sending state 4.12400 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 5': Sending state 4.12500 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 6': Sending state 4.12800 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 7': Sending state 4.12400 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 8': Sending state 4.12300 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 9': Sending state 4.12800 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 10': Sending state 4.12800 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 11': Sending state 4.12800 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 12': Sending state 4.13100 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage 13': Sending state 4.12400 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms power tube temperature': Sending state 24.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms temperature sensor 1': Sending state 22.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms temperature sensor 2': Sending state 22.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms total voltage': Sending state 53.64000 V with 2 decimals of accuracy
[sensor:127]: 'jk-bms current': Sending state -0.00000 A with 2 decimals of accuracy
[sensor:127]: 'jk-bms capacity remaining': Sending state 99.00000 % with 0 decimals of accuracy
[sensor:127]: 'jk-bms temperature sensors': Sending state 2.00000  with 0 decimals of accuracy
[sensor:127]: 'jk-bms charging cycles': Sending state 0.00000  with 0 decimals of accuracy
[sensor:127]: 'jk-bms total charging cycle capacity': Sending state 0.00000  with 0 decimals of accuracy
[sensor:127]: 'jk-bms battery strings': Sending state 13.00000  with 0 decimals of accuracy
[sensor:127]: 'jk-bms errors bitmask': Sending state 0.00000  with 0 decimals of accuracy
[text_sensor:015]: 'jk-bms errors': Sending state ''
[sensor:127]: 'jk-bms operation mode bitmask': Sending state 0.00000  with 0 decimals of accuracy
[text_sensor:015]: 'jk-bms operation mode': Sending state ''
[sensor:127]: 'jk-bms total voltage overvoltage protection': Sending state 5.46000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms total voltage undervoltage protection': Sending state 3.77000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage overvoltage protection': Sending state 4.20000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage overvoltage recovery': Sending state 4.10000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage overvoltage delay': Sending state 5.00000 s with 0 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage undervoltage protection': Sending state 2.90000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage undervoltage recovery': Sending state 3.20000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms cell voltage undervoltage delay': Sending state 5.00000 s with 0 decimals of accuracy
[sensor:127]: 'jk-bms cell pressure difference protection': Sending state 0.30000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms discharging overcurrent protection': Sending state 60.00000 A with 0 decimals of accuracy
[sensor:127]: 'jk-bms discharging overcurrent delay': Sending state 300.00000 s with 0 decimals of accuracy
[sensor:127]: 'jk-bms charging overcurrent protection': Sending state 25.00000 A with 0 decimals of accuracy
[sensor:127]: 'jk-bms charging overcurrent delay': Sending state 30.00000 s with 0 decimals of accuracy
[sensor:127]: 'jk-bms balance starting voltage': Sending state 3.30000 V with 3 decimals of accuracy
[sensor:127]: 'jk-bms balance opening pressure difference': Sending state 0.01000 V with 3 decimals of accuracy
[switch:045]: 'jk-bms balancing': Sending state ON
[sensor:127]: 'jk-bms power tube temperature protection': Sending state 90.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms power tube temperature recovery': Sending state 70.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms temperature sensor temperature protection': Sending state 100.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms temperature sensor temperature recovery': Sending state 100.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms temperature sensor temperature difference protection': Sending state 20.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms charging high temperature protection': Sending state 70.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms discharging high temperature protection': Sending state 70.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms charging low temperature protection': Sending state -20.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms charging low temperature recovery': Sending state -10.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms discharging low temperature protection': Sending state -20.00000 °C with 0 decimals of accuracy
[sensor:127]: 'jk-bms discharging low temperature recovery': Sending state -10.00000 °C with 0 decimals of accuracy
[switch:045]: 'jk-bms charging': Sending state OFF
[switch:045]: 'jk-bms discharging': Sending state OFF
[sensor:127]: 'jk-bms current calibration': Sending state 0.72500 A with 3 decimals of accuracy
[sensor:127]: 'jk-bms device address': Sending state 1.00000  with 0 decimals of accuracy
[text_sensor:015]: 'jk-bms battery type': Sending state 'Ternary Lithium'
[sensor:127]: 'jk-bms sleep wait time': Sending state 10.00000 s with 0 decimals of accuracy
[sensor:127]: 'jk-bms alarm low volume': Sending state 20.00000  with 0 decimals of accuracy
[text_sensor:015]: 'jk-bms password': Sending state '123456'
[switch:045]: 'jk-bms dedicated charger': Sending state OFF
[text_sensor:015]: 'jk-bms device type': Sending state 'Input Us'
[sensor:127]: 'jk-bms total runtime': Sending state 0.00000 h with 0 decimals of accuracy
[text_sensor:015]: 'jk-bms software version': Sending state 'H7.X__S7.1.0H__'
[sensor:127]: 'jk-bms actual_battery_capacity': Sending state 186.00000 Ah with 0 decimals of accuracy
[text_sensor:015]: 'jk-bms manufacturer': Sending state 'BT3072020120000200521001'
[sensor:127]: 'jk-bms protocol version': Sending state 1.00000  with 0 decimals of accuracy

四、接入HA并美化卡片UI

首先进入设置-设备与服务中去添加自动发现的设备image.png
没有的话,可以先添加ESPHome的集成
image.png
然后就会自动发现。
配置好后,就会是这样的。
image.png
然后配置卡片UI

4.1 安装HACS

HA有一个插件市场叫做HACS,具体安装比较简单,这里简单说一下,如果还不会的请自行百度。

4.1.1 HAOS

对于 Home Assistant Operating System 和 Supervised,有一个用于下载 HACS 的附加组件。要添加允许您获取此附加组件的自定义附加组件存储库,请执行以下步骤。

  1. 要将 HACS 附加组件存储库添加到您的 Home Assistant,请选择此 链接
    1. 当系统提示您确认是否要在 Home Assistant 中打开页面时,请检查 URL 是否正确。然后,选择 Open link (打开链接)。
    2. 在 Missing add-on repository 对话框中,选择 Add
    3. 您现在已经添加了允许您将 HACS 下载到 Home Assistant 的存储库。
  2. 在 Get HACS 附加组件中,选择 Install 。
  3. 启动附加组件。
  4. 导航到附加组件日志并按照那里给出的说明进行作。
  5. 重新启动 Home Assistant。
  6. 按照设置 HACS 集成中的步骤进行作。

4.1.2 HA docker容器

要设置 HACS,您可以使用 HACS 下载脚本。

  1. 打开Docker主机的SSH终端
  2. 使用 docker exec -it <name of the container running homeassistant> bash . 进入容器 .
  3. 运行 HACS 下载脚本。
  4. wget -O - https://get.hacs.xyz | bash -
  5. 重新启动 Home Assistant。
  6. 按照设置 HACS 集成中的步骤进行作。

4.2 安装 stack in card 堆叠卡片

image.png
输入stack in card 然后 安装

image.png

4.3 到自己的仪表盘添加垂直堆叠卡牌

  1. 添加卡片

    image.png

  2. 在堆叠卡片中添加4个按钮卡片
    image.png

  3. 然后依次点击每个卡片进入代码编辑模式
    image.png

  4. 下面为每个卡片对应的代码,卡片美化UI代码来源自: (@dr3amr) shared some Home Assistant Lovelace UI cards for a beautiful dashboard here.

4.3.1 CARD 1 运行时长及开关状态

用文本编辑器,把下面的代码中的 bms_bt_monitor替换为你自己的ESP32名称

type: custom:stack-in-card
keep:
  margin: false
  box_shadow: false
  background: false
cards:
  - type: grid
    square: false
    columns: 1
    cards:
      - type: markdown
        content: content: >-
          <center>运行时长: <b><font color=#3090C7>{{
          states('sensor.bms_bt_monitor_total_runtime_formatted') | upper |
          regex_replace('D', '天') | regex_replace('H', '小时') }}</font>
  - type: grid
    square: false
    columns: 3
    cards:
      - type: markdown
        content: >-
          <center>充电开关: <b>{% if states('switch.bms_bt_monitor_charging')
          == 'on' %} <font color=#41CD52>{{
          states('switch.bms_bt_monitor_charging') | upper }}</font> {% else %}
          <font color=red>{{ states('switch.bms_bt_monitor_charging') | upper
          }}</font> {% endif %} 
      - type: markdown
        content: >-
          <center>放电开关: <b> {% if
          states('switch.bms_bt_monitor_discharging') == 'on' %} <font
          color=#41CD52>{{ states('switch.bms_bt_monitor_discharging') | upper
          }}</font> {% else %} <font color=red>{{
          states('switch.bms_bt_monitor_discharging') | upper }}</font> {% endif
          %} 
      - type: markdown
        content: >-
          <center>均衡开关: <b> {% if
          states('switch.bms_bt_monitor_balancer') == 'on' %} <font
          color=#41CD52>{{ states('switch.bms_bt_monitor_balancer') | upper
          }}</font> {% else %} <font color=red>{{
          states('switch.bms_bt_monitor_balancer') | upper }}</font> {% endif
          %} 

4.3.2 CARD 2 电池组状态

用文本编辑器,把下面的代码中的 jk_bms替换为你自己的ESP32名称

type: custom:stack-in-card
keep:
  margin: false
  box_shadow: false
  background: false
cards:
  - type: grid
    square: false
    columns: 2
    cards:
      - type: markdown
        content: >-
          <b><font color=#41CD52 size=6>
          {{states('sensor.jk_bms_total_voltage')}} V</font></b><br>
          电池功耗:  <font color=#41CD52>{{ states('sensor.jk_bms_power')
          }} W</font><br> 电池总容量:  <font color=#41CD52>{{
          states('sensor.jk_bms_total_battery_capacity_setting') }}
          Ah</font><br> 循环容量:  <font color=#41CD52>{{
          states('sensor.jk_bms_total_charging_cycle_capacity') }} Ah</font><br>
          平均单元电压:  <font color=#41CD52>{{
          states('sensor.jk_bms_average_cell_voltage') }} V</font><br>
          均衡电流:  <font color=#41CD52>{{
          states('sensor.jk_bms_balancing_current') }} A</font><br>
          电池测温点1:  <font color=#41CD52>{{
          states('sensor.jk_bms_temperature_sensor_1') }} °C</font>
      - type: markdown
        content: >-
          <b><font color=#41CD52 size=6>{{ states('sensor.jk_bms_current') }}
          A</font></b><br> 剩余电量:  <font color=#41CD52>{{
          states('sensor.jk_bms_state_of_charge') }} %</font><br>
          剩余容量:  <font color=#41CD52>{{
          states('sensor.jk_bms_capacity_remaining') }} Ah</font><br>
          循环次数:  <font color=#41CD52>{{
          states('sensor.jk_bms_charging_cycles') }}</font><br>
          单元压差:  <font color=#41CD52>{{
          states('sensor.jk_bms_delta_cell_voltage') }} V</font><br>
          MOS测温点:  <font color=#41CD52>{{
          states('sensor.jk_bms_power_tube_temperature') }} °C</font><br>
          电池测温点2:  <font color=#41CD52>{{
          states('sensor.jk_bms_temperature_sensor_2') }} °C</font>

4.3.3 CARD 3 电池单元状态(根据自己的电池单元数量进行保留)

用文本编辑器,把下面的代码中的 bms_bt_monitor替换为你自己的ESP32名称

type: custom:stack-in-card
keep:
  margin: false
  box_shadow: false
  background: false
cards:
  - type: grid
    square: false
    columns: 1
    cards:
      - type: markdown
        content: <center><b>Cells
  - type: grid
    square: false
    columns: 2
    cards:
      - type: markdown
        content: >-
          <center>01.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '1' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_1') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '1' %}  <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_1') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_1') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_1') }} Ω <br>
          02.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '2' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_2') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '2' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_2') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_2') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_2') }} Ω <br>
          03.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '3' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_3') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '3' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_3') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_3') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_3') }} Ω <br>
          04.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '4' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_4') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '4' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_4') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_4') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_4') }} Ω <br>
          05.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '5' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_5') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '5' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_5') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_5') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_5') }} Ω <br>
          06.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '6' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_6') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '6' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_6') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_6') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_6') }} Ω <br>
          07.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '7' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_7') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '7' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_7') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_7') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_7') }} Ω <br>
          08.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '8' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_8') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '8' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_8') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_8') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_8') }} Ω <br></center>
      - type: markdown
        content: >-
          <center>09.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '9' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_9') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '9' %}  <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_9') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_9') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_9') }} Ω <br>
          10.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '10' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_10') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '10' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_10') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_10') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_10') }} Ω <br>
          11.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '11' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_11') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '11' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_11') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_11') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_11') }} Ω <br>
          12.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '12' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_12') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '12' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_12') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_12') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_12') }} Ω <br>
          13.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '13' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_13') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '13' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_13') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_13') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_13') }} Ω <br>
          14.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '14' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_14') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '14' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_14') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_14') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_14') }} Ω <br>
          15.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '15' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_15') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '15' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_15') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_15') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_15') }} Ω <br>
          16.    {% if
          states('sensor.bms_bt_monitor_max_voltage_cell') == '16' %}  <font
          color="#3090C7">{{ states('sensor.bms_bt_monitor_cell_voltage_16') }}
          V</font> {% elif states('sensor.bms_bt_monitor_min_voltage_cell') ==
          '16' %} <font color="red">{{
          states('sensor.bms_bt_monitor_cell_voltage_16') }} V</font> {% else %}
          {{ states('sensor.bms_bt_monitor_cell_voltage_16') }} V {% endif %}
             /    {{
          states('sensor.bms_bt_monitor_cell_resistance_16') }} Ω <br></center>

4.3.4 控制卡片

用文本编辑器,把下面的代码中的 bms_bt_monitor替换为你自己的ESP32名称

type: entities
entities:
  - entity: switch.bms_bt_monitor_balancer
    name: Balancer
  - entity: switch.bms_bt_monitor_charging
    name: Charging
  - entity: switch.bms_bt_monitor_discharging
    name: Discharging
show_header_toggle: false

4.3.5 最终效果(有些卡片,笔者进行了简单翻译,可根据需求自定义):

image.png

4.3.6 笔者的实际效果

image.png