From ed593544d896df1a830cd7320432ddcde9ddcbec Mon Sep 17 00:00:00 2001 From: Silvio <4004968+s1lvi0@users.noreply.github.com> Date: Wed, 22 Sep 2021 12:03:42 +0200 Subject: [PATCH] Add support for Daly Smart BMS (#2156) * Add support for Daly Smart BMS * Fix clang-format and python lint * Fix const declaration * Add code owner * Fix malloc with std::vector * Fix with suggestions * Revert "Fix with suggestions" This reverts commit bc618f20cf83e3df903fdbbca8d2529d946264b0. * Fix last commit * Fix Python Lint * Fix typo * Use std::vector instead pointer and fix loop * Fix typo * Add test configuration to test3.yaml * Fix test3.yaml * Fix uart in test3.yaml --- CODEOWNERS | 1 + esphome/components/daly_bms/__init__.py | 27 +++ esphome/components/daly_bms/binary_sensor.py | 49 +++++ esphome/components/daly_bms/daly_bms.cpp | 181 +++++++++++++++++ esphome/components/daly_bms/daly_bms.h | 83 ++++++++ esphome/components/daly_bms/sensor.py | 192 +++++++++++++++++++ esphome/components/daly_bms/text_sensor.py | 39 ++++ tests/test3.yaml | 44 +++++ 8 files changed, 616 insertions(+) create mode 100644 esphome/components/daly_bms/__init__.py create mode 100644 esphome/components/daly_bms/binary_sensor.py create mode 100644 esphome/components/daly_bms/daly_bms.cpp create mode 100644 esphome/components/daly_bms/daly_bms.h create mode 100644 esphome/components/daly_bms/sensor.py create mode 100644 esphome/components/daly_bms/text_sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index adf96b7382..2577e0d706 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -39,6 +39,7 @@ esphome/components/coolix/* @glmnet esphome/components/cover/* @esphome/core esphome/components/cs5460a/* @balrog-kun esphome/components/ct_clamp/* @jesserockz +esphome/components/daly_bms/* @s1lvi0 esphome/components/debug/* @OttoWinter esphome/components/dfplayer/* @glmnet esphome/components/dht/* @OttoWinter diff --git a/esphome/components/daly_bms/__init__.py b/esphome/components/daly_bms/__init__.py new file mode 100644 index 0000000000..45b8f98f0c --- /dev/null +++ b/esphome/components/daly_bms/__init__.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import uart +from esphome.const import CONF_ID + +CODEOWNERS = ["@s1lvi0"] +DEPENDENCIES = ["uart"] +AUTO_LOAD = ["sensor", "text_sensor", "binary_sensor"] + +CONF_BMS_DALY_ID = "bms_daly_id" + +daly_bms = cg.esphome_ns.namespace("daly_bms") +DalyBmsComponent = daly_bms.class_( + "DalyBmsComponent", cg.PollingComponent, uart.UARTDevice +) + +CONFIG_SCHEMA = ( + cv.Schema({cv.GenerateID(): cv.declare_id(DalyBmsComponent)}) + .extend(uart.UART_DEVICE_SCHEMA) + .extend(cv.polling_component_schema("30s")) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) diff --git a/esphome/components/daly_bms/binary_sensor.py b/esphome/components/daly_bms/binary_sensor.py new file mode 100644 index 0000000000..23330cd945 --- /dev/null +++ b/esphome/components/daly_bms/binary_sensor.py @@ -0,0 +1,49 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import binary_sensor +from esphome.const import CONF_ID +from . import DalyBmsComponent, CONF_BMS_DALY_ID + +CONF_CHARGING_MOS_ENABLED = "charging_mos_enabled" +CONF_DISCHARGING_MOS_ENABLED = "discharging_mos_enabled" + +TYPES = [ + CONF_CHARGING_MOS_ENABLED, + CONF_DISCHARGING_MOS_ENABLED, +] + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent), + cv.Optional( + CONF_CHARGING_MOS_ENABLED + ): binary_sensor.BINARY_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor), + } + ), + cv.Optional( + CONF_DISCHARGING_MOS_ENABLED + ): binary_sensor.BINARY_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(binary_sensor.BinarySensor), + } + ), + } + ).extend(cv.COMPONENT_SCHEMA) +) + + +async def setup_conf(config, key, hub): + if key in config: + conf = config[key] + sens = cg.new_Pvariable(conf[CONF_ID]) + await binary_sensor.register_binary_sensor(sens, conf) + cg.add(getattr(hub, f"set_{key}_binary_sensor")(sens)) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_BMS_DALY_ID]) + for key in TYPES: + await setup_conf(config, key, hub) diff --git a/esphome/components/daly_bms/daly_bms.cpp b/esphome/components/daly_bms/daly_bms.cpp new file mode 100644 index 0000000000..19e8f12e1c --- /dev/null +++ b/esphome/components/daly_bms/daly_bms.cpp @@ -0,0 +1,181 @@ +#include "daly_bms.h" +#include "esphome/core/log.h" +#include + +namespace esphome { +namespace daly_bms { + +static const char *const TAG = "daly_bms"; + +static const uint8_t DALY_FRAME_SIZE = 13; +static const uint8_t DALY_TEMPERATURE_OFFSET = 40; +static const uint16_t DALY_CURRENT_OFFSET = 30000; + +static const uint8_t DALY_REQUEST_BATTERY_LEVEL = 0x90; +static const uint8_t DALY_REQUEST_MIN_MAX_VOLTAGE = 0x91; +static const uint8_t DALY_REQUEST_MIN_MAX_TEMPERATURE = 0x92; +static const uint8_t DALY_REQUEST_MOS = 0x93; +static const uint8_t DALY_REQUEST_STATUS = 0x94; +static const uint8_t DALY_REQUEST_TEMPERATURE = 0x96; + +void DalyBmsComponent::setup() {} + +void DalyBmsComponent::dump_config() { + ESP_LOGCONFIG(TAG, "Daly BMS:"); + this->check_uart_settings(9600); +} + +void DalyBmsComponent::update() { + this->request_data(DALY_REQUEST_BATTERY_LEVEL); + this->request_data(DALY_REQUEST_MIN_MAX_VOLTAGE); + this->request_data(DALY_REQUEST_MIN_MAX_TEMPERATURE); + this->request_data(DALY_REQUEST_MOS); + this->request_data(DALY_REQUEST_STATUS); + this->request_data(DALY_REQUEST_TEMPERATURE); + + std::vector get_battery_level_data; + int available_data = this->available(); + if (available_data >= DALY_FRAME_SIZE) { + get_battery_level_data.resize(available_data); + this->read_array(get_battery_level_data.data(), available_data); + this->decode_data(get_battery_level_data); + } +} + +float DalyBmsComponent::get_setup_priority() const { return setup_priority::DATA; } + +void DalyBmsComponent::request_data(uint8_t data_id) { + uint8_t request_message[DALY_FRAME_SIZE]; + + request_message[0] = 0xA5; // Start Flag + request_message[1] = 0x80; // Communication Module Address + request_message[2] = data_id; // Data ID + request_message[3] = 0x08; // Data Length (Fixed) + request_message[4] = 0x00; // Empty Data + request_message[5] = 0x00; // | + request_message[6] = 0x00; // | + request_message[7] = 0x00; // | + request_message[8] = 0x00; // | + request_message[9] = 0x00; // | + request_message[10] = 0x00; // | + request_message[11] = 0x00; // Empty Data + request_message[12] = (uint8_t)(request_message[0] + request_message[1] + request_message[2] + + request_message[3]); // Checksum (Lower byte of the other bytes sum) + + this->write_array(request_message, sizeof(request_message)); + this->flush(); +} + +void DalyBmsComponent::decode_data(std::vector data) { + auto it = data.begin(); + + while ((it = std::find(it, data.end(), 0xA5)) != data.end()) { + if (data.end() - it >= DALY_FRAME_SIZE && it[1] == 0x01) { + uint8_t checksum; + int sum = 0; + for (int i = 0; i < 12; i++) { + sum += it[i]; + } + checksum = sum; + + if (checksum == it[12]) { + switch (it[2]) { + case DALY_REQUEST_BATTERY_LEVEL: + if (this->voltage_sensor_) { + this->voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 10); + } + if (this->current_sensor_) { + this->current_sensor_->publish_state(((float) (encode_uint16(it[8], it[9]) - DALY_CURRENT_OFFSET) / 10)); + } + if (this->battery_level_sensor_) { + this->battery_level_sensor_->publish_state((float) encode_uint16(it[10], it[11]) / 10); + } + break; + + case DALY_REQUEST_MIN_MAX_VOLTAGE: + if (this->max_cell_voltage_) { + this->max_cell_voltage_->publish_state((float) encode_uint16(it[4], it[5]) / 1000); + } + if (this->max_cell_voltage_number_) { + this->max_cell_voltage_number_->publish_state(it[6]); + } + if (this->min_cell_voltage_) { + this->min_cell_voltage_->publish_state((float) encode_uint16(it[7], it[8]) / 1000); + } + if (this->min_cell_voltage_number_) { + this->min_cell_voltage_number_->publish_state(it[9]); + } + break; + + case DALY_REQUEST_MIN_MAX_TEMPERATURE: + if (this->max_temperature_) { + this->max_temperature_->publish_state(it[4] - DALY_TEMPERATURE_OFFSET); + } + if (this->max_temperature_probe_number_) { + this->max_temperature_probe_number_->publish_state(it[5]); + } + if (this->min_temperature_) { + this->min_temperature_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET); + } + if (this->min_temperature_probe_number_) { + this->min_temperature_probe_number_->publish_state(it[7]); + } + break; + + case DALY_REQUEST_MOS: + if (this->status_text_sensor_ != nullptr) { + switch (it[4]) { + case 0: + this->status_text_sensor_->publish_state("Stationary"); + break; + case 1: + this->status_text_sensor_->publish_state("Charging"); + break; + case 2: + this->status_text_sensor_->publish_state("Discharging"); + break; + default: + break; + } + } + if (this->charging_mos_enabled_) { + this->charging_mos_enabled_->publish_state(it[5]); + } + if (this->discharging_mos_enabled_) { + this->discharging_mos_enabled_->publish_state(it[6]); + } + if (this->remaining_capacity_) { + this->remaining_capacity_->publish_state((float) encode_uint32(it[8], it[9], it[10], it[11]) / 1000); + } + break; + + case DALY_REQUEST_STATUS: + if (this->cells_number_) { + this->cells_number_->publish_state(it[4]); + } + break; + + case DALY_REQUEST_TEMPERATURE: + if (it[4] == 1) { + if (this->temperature_1_sensor_) { + this->temperature_1_sensor_->publish_state(it[5] - DALY_TEMPERATURE_OFFSET); + } + if (this->temperature_2_sensor_) { + this->temperature_2_sensor_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET); + } + } + break; + + default: + break; + } + } + std::advance(it, DALY_FRAME_SIZE); + } else { + std::advance(it, 1); + } + } +} + +} // namespace daly_bms +} // namespace esphome diff --git a/esphome/components/daly_bms/daly_bms.h b/esphome/components/daly_bms/daly_bms.h new file mode 100644 index 0000000000..e4f48776dd --- /dev/null +++ b/esphome/components/daly_bms/daly_bms.h @@ -0,0 +1,83 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/text_sensor/text_sensor.h" +#include "esphome/components/binary_sensor/binary_sensor.h" +#include "esphome/components/uart/uart.h" + +namespace esphome { +namespace daly_bms { + +class DalyBmsComponent : public PollingComponent, public uart::UARTDevice { + public: + DalyBmsComponent() = default; + + // SENSORS + void set_voltage_sensor(sensor::Sensor *voltage_sensor) { voltage_sensor_ = voltage_sensor; } + void set_current_sensor(sensor::Sensor *current_sensor) { current_sensor_ = current_sensor; } + void set_battery_level_sensor(sensor::Sensor *battery_level_sensor) { battery_level_sensor_ = battery_level_sensor; } + void set_max_cell_voltage_sensor(sensor::Sensor *max_cell_voltage) { max_cell_voltage_ = max_cell_voltage; } + void set_max_cell_voltage_number_sensor(sensor::Sensor *max_cell_voltage_number) { + max_cell_voltage_number_ = max_cell_voltage_number; + } + void set_min_cell_voltage_sensor(sensor::Sensor *min_cell_voltage) { min_cell_voltage_ = min_cell_voltage; } + void set_min_cell_voltage_number_sensor(sensor::Sensor *min_cell_voltage_number) { + min_cell_voltage_number_ = min_cell_voltage_number; + } + void set_max_temperature_sensor(sensor::Sensor *max_temperature) { max_temperature_ = max_temperature; } + void set_max_temperature_probe_number_sensor(sensor::Sensor *max_temperature_probe_number) { + max_temperature_probe_number_ = max_temperature_probe_number; + } + void set_min_temperature_sensor(sensor::Sensor *min_temperature) { min_temperature_ = min_temperature; } + void set_min_temperature_probe_number_sensor(sensor::Sensor *min_temperature_probe_number) { + min_temperature_probe_number_ = min_temperature_probe_number; + } + void set_remaining_capacity_sensor(sensor::Sensor *remaining_capacity) { remaining_capacity_ = remaining_capacity; } + void set_cells_number_sensor(sensor::Sensor *cells_number) { cells_number_ = cells_number; } + void set_temperature_1_sensor(sensor::Sensor *temperature_1_sensor) { temperature_1_sensor_ = temperature_1_sensor; } + void set_temperature_2_sensor(sensor::Sensor *temperature_2_sensor) { temperature_2_sensor_ = temperature_2_sensor; } + // TEXT_SENSORS + void set_status_text_sensor(text_sensor::TextSensor *status_text_sensor) { status_text_sensor_ = status_text_sensor; } + // BINARY_SENSORS + void set_charging_mos_enabled_binary_sensor(binary_sensor::BinarySensor *charging_mos_enabled) { + charging_mos_enabled_ = charging_mos_enabled; + } + void set_discharging_mos_enabled_binary_sensor(binary_sensor::BinarySensor *discharging_mos_enabled) { + discharging_mos_enabled_ = discharging_mos_enabled; + } + + void setup() override; + void dump_config() override; + void update() override; + + float get_setup_priority() const override; + + protected: + void request_data(uint8_t data_id); + void decode_data(std::vector data); + + sensor::Sensor *voltage_sensor_{nullptr}; + sensor::Sensor *current_sensor_{nullptr}; + sensor::Sensor *battery_level_sensor_{nullptr}; + sensor::Sensor *max_cell_voltage_{nullptr}; + sensor::Sensor *max_cell_voltage_number_{nullptr}; + sensor::Sensor *min_cell_voltage_{nullptr}; + sensor::Sensor *min_cell_voltage_number_{nullptr}; + sensor::Sensor *max_temperature_{nullptr}; + sensor::Sensor *max_temperature_probe_number_{nullptr}; + sensor::Sensor *min_temperature_{nullptr}; + sensor::Sensor *min_temperature_probe_number_{nullptr}; + sensor::Sensor *remaining_capacity_{nullptr}; + sensor::Sensor *cells_number_{nullptr}; + sensor::Sensor *temperature_1_sensor_{nullptr}; + sensor::Sensor *temperature_2_sensor_{nullptr}; + + text_sensor::TextSensor *status_text_sensor_{nullptr}; + + binary_sensor::BinarySensor *charging_mos_enabled_{nullptr}; + binary_sensor::BinarySensor *discharging_mos_enabled_{nullptr}; +}; + +} // namespace daly_bms +} // namespace esphome diff --git a/esphome/components/daly_bms/sensor.py b/esphome/components/daly_bms/sensor.py new file mode 100644 index 0000000000..1d0ee89914 --- /dev/null +++ b/esphome/components/daly_bms/sensor.py @@ -0,0 +1,192 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_VOLTAGE, + CONF_CURRENT, + CONF_BATTERY_LEVEL, + CONF_MAX_TEMPERATURE, + CONF_MIN_TEMPERATURE, + DEVICE_CLASS_VOLTAGE, + DEVICE_CLASS_CURRENT, + DEVICE_CLASS_BATTERY, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_EMPTY, + STATE_CLASS_MEASUREMENT, + STATE_CLASS_NONE, + UNIT_VOLT, + UNIT_AMPERE, + UNIT_PERCENT, + UNIT_CELSIUS, + UNIT_EMPTY, + ICON_FLASH, + ICON_PERCENT, + ICON_COUNTER, + ICON_THERMOMETER, + ICON_GAUGE, +) +from . import DalyBmsComponent, CONF_BMS_DALY_ID + +CONF_MAX_CELL_VOLTAGE = "max_cell_voltage" +CONF_MAX_CELL_VOLTAGE_NUMBER = "max_cell_voltage_number" +CONF_MIN_CELL_VOLTAGE = "min_cell_voltage" +CONF_MIN_CELL_VOLTAGE_NUMBER = "min_cell_voltage_number" +CONF_MAX_TEMPERATURE_PROBE_NUMBER = "max_temperature_probe_number" +CONF_MIN_TEMPERATURE_PROBE_NUMBER = "min_temperature_probe_number" +CONF_CELLS_NUMBER = "cells_number" + +CONF_REMAINING_CAPACITY = "remaining_capacity" +CONF_TEMPERATURE_1 = "temperature_1" +CONF_TEMPERATURE_2 = "temperature_2" + +ICON_CURRENT_DC = "mdi:current-dc" +ICON_BATTERY_OUTLINE = "mdi:battery-outline" +ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up" +ICON_THERMOMETER_CHEVRON_DOWN = "mdi:thermometer-chevron-down" +ICON_CAR_BATTERY = "mdi:car-battery" + +UNIT_AMPERE_HOUR = "Ah" + +TYPES = [ + CONF_VOLTAGE, + CONF_CURRENT, + CONF_BATTERY_LEVEL, + CONF_MAX_CELL_VOLTAGE, + CONF_MAX_CELL_VOLTAGE_NUMBER, + CONF_MIN_CELL_VOLTAGE, + CONF_MIN_CELL_VOLTAGE_NUMBER, + CONF_MAX_TEMPERATURE, + CONF_MAX_TEMPERATURE_PROBE_NUMBER, + CONF_MIN_TEMPERATURE, + CONF_MIN_TEMPERATURE_PROBE_NUMBER, + CONF_CELLS_NUMBER, + CONF_REMAINING_CAPACITY, + CONF_TEMPERATURE_1, + CONF_TEMPERATURE_2, +] + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent), + cv.Optional(CONF_VOLTAGE): sensor.sensor_schema( + UNIT_VOLT, + ICON_FLASH, + 1, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CURRENT): sensor.sensor_schema( + UNIT_AMPERE, + ICON_CURRENT_DC, + 1, + DEVICE_CLASS_CURRENT, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema( + UNIT_PERCENT, + ICON_PERCENT, + 1, + DEVICE_CLASS_BATTERY, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_MAX_CELL_VOLTAGE): sensor.sensor_schema( + UNIT_VOLT, + ICON_FLASH, + 2, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_MAX_CELL_VOLTAGE_NUMBER): sensor.sensor_schema( + UNIT_EMPTY, + ICON_COUNTER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + ), + cv.Optional(CONF_MIN_CELL_VOLTAGE): sensor.sensor_schema( + UNIT_VOLT, + ICON_FLASH, + 2, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_MIN_CELL_VOLTAGE_NUMBER): sensor.sensor_schema( + UNIT_EMPTY, + ICON_COUNTER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + ), + cv.Optional(CONF_MAX_TEMPERATURE): sensor.sensor_schema( + UNIT_CELSIUS, + ICON_THERMOMETER_CHEVRON_UP, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_MAX_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema( + UNIT_EMPTY, + ICON_COUNTER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + ), + cv.Optional(CONF_MIN_TEMPERATURE): sensor.sensor_schema( + UNIT_CELSIUS, + ICON_THERMOMETER_CHEVRON_DOWN, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_MIN_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema( + UNIT_EMPTY, + ICON_COUNTER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + ), + cv.Optional(CONF_REMAINING_CAPACITY): sensor.sensor_schema( + UNIT_AMPERE_HOUR, + ICON_GAUGE, + 2, + DEVICE_CLASS_VOLTAGE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_CELLS_NUMBER): sensor.sensor_schema( + UNIT_EMPTY, + ICON_COUNTER, + 0, + DEVICE_CLASS_EMPTY, + STATE_CLASS_NONE, + ), + cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema( + UNIT_CELSIUS, + ICON_THERMOMETER, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema( + UNIT_CELSIUS, + ICON_THERMOMETER, + 0, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + ), + } + ).extend(cv.COMPONENT_SCHEMA) +) + + +async def setup_conf(config, key, hub): + if key in config: + conf = config[key] + sens = await sensor.new_sensor(conf) + cg.add(getattr(hub, f"set_{key}_sensor")(sens)) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_BMS_DALY_ID]) + for key in TYPES: + await setup_conf(config, key, hub) diff --git a/esphome/components/daly_bms/text_sensor.py b/esphome/components/daly_bms/text_sensor.py new file mode 100644 index 0000000000..de49a0b4b9 --- /dev/null +++ b/esphome/components/daly_bms/text_sensor.py @@ -0,0 +1,39 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import text_sensor +from esphome.const import CONF_ICON, CONF_ID, CONF_STATUS +from . import DalyBmsComponent, CONF_BMS_DALY_ID + +ICON_CAR_BATTERY = "mdi:car-battery" + +TYPES = [ + CONF_STATUS, +] + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent), + cv.Optional(CONF_STATUS): text_sensor.TEXT_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), + cv.Optional(CONF_ICON, default=ICON_CAR_BATTERY): cv.icon, + } + ), + } + ).extend(cv.COMPONENT_SCHEMA) +) + + +async def setup_conf(config, key, hub): + if key in config: + conf = config[key] + sens = cg.new_Pvariable(conf[CONF_ID]) + await text_sensor.register_text_sensor(sens, conf) + cg.add(getattr(hub, f"set_{key}_text_sensor")(sens)) + + +async def to_code(config): + hub = await cg.get_variable(config[CONF_BMS_DALY_ID]) + for key in TYPES: + await setup_conf(config, key, hub) diff --git a/tests/test3.yaml b/tests/test3.yaml index de46cec99c..386775749d 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -273,6 +273,37 @@ adalight: sensor: + - platform: daly_bms + voltage: + name: "Battery Voltage" + current: + name: "Battery Current" + battery_level: + name: "Battery Level" + max_cell_voltage: + name: "Max Cell Voltage" + max_cell_voltage_number: + name: "Max Cell Voltage Number" + min_cell_voltage: + name: "Min Cell Voltage" + min_cell_voltage_number: + name: "Min Cell Voltage Number" + max_temperature: + name: "Max Temperature" + max_temperature_probe_number: + name: "Max Temperature Probe Number" + min_temperature: + name: "Min Temperature" + min_temperature_probe_number: + name: "Min Temperature Probe Number" + remaining_capacity: + name: "Remaining Capacity" + cells_number: + name: "Cells Number" + temperature_1: + name: "Temperature 1" + temperature_2: + name: "Temperature 2" - platform: apds9960 type: proximity name: APDS9960 Proximity @@ -621,6 +652,11 @@ mpr121: address: 0x5A binary_sensor: + - platform: daly_bms + charging_mos_enabled: + name: "Charging MOS" + discharging_mos_enabled: + name: "Discharging MOS" - platform: apds9960 direction: up name: APDS9960 Up @@ -701,6 +737,9 @@ status_led: pin: GPIO2 text_sensor: + - platform: daly_bms + status: + name: "BMS Status" - platform: version name: 'ESPHome Version' icon: mdi:icon @@ -1219,3 +1258,8 @@ fingerprint_grow: dsmr: decryption_key: 00112233445566778899aabbccddeeff uart_id: uart6 + +daly_bms: + update_interval: 20s + uart_id: uart1 +