DALY Modbus BMS: use loops for cell voltage configs

This commit is contained in:
patagona 2024-09-30 17:39:55 +02:00
parent 2f6d552589
commit b024e79687
3 changed files with 62 additions and 89 deletions

View file

@ -14,7 +14,6 @@ static const uint8_t DALY_MODBUS_REQUEST_ADDRESS_OFFSET = 0x80;
static const uint8_t DALY_MODBUS_RESPONSE_ADDRESS_OFFSET = 0x50; static const uint8_t DALY_MODBUS_RESPONSE_ADDRESS_OFFSET = 0x50;
static const uint8_t DALY_MODBUS_READ_CELL_VOLTAGES_ADDR = DALY_MODBUS_ADDR_CELL_VOLT_1; static const uint8_t DALY_MODBUS_READ_CELL_VOLTAGES_ADDR = DALY_MODBUS_ADDR_CELL_VOLT_1;
static const uint8_t DALY_MODBUS_READ_CELL_VOLTAGES_LENGTH = 16; // 16 cell voltages
static const uint8_t DALY_MODBUS_READ_DATA_ADDR = DALY_MODBUS_ADDR_CELL_TEMP_1; static const uint8_t DALY_MODBUS_READ_DATA_ADDR = DALY_MODBUS_ADDR_CELL_TEMP_1;
static const uint8_t DALY_MODBUS_READ_DATA_LENGTH = DALY_MODBUS_REGISTER_MAX - DALY_MODBUS_ADDR_CELL_TEMP_1 + 1; static const uint8_t DALY_MODBUS_READ_DATA_LENGTH = DALY_MODBUS_REGISTER_MAX - DALY_MODBUS_ADDR_CELL_TEMP_1 + 1;
@ -52,7 +51,8 @@ void DalyHkmsBmsComponent::loop() {
{ {
case ReadState::READ_CELL_VOLTAGES: case ReadState::READ_CELL_VOLTAGES:
start_address = DALY_MODBUS_READ_CELL_VOLTAGES_ADDR; start_address = DALY_MODBUS_READ_CELL_VOLTAGES_ADDR;
register_count = DALY_MODBUS_READ_CELL_VOLTAGES_LENGTH; // avoid reading all 48 cell voltages if we only want 16 or so
register_count = this->cell_voltage_sensors_max_;
break; break;
case ReadState::READ_DATA: case ReadState::READ_DATA:
start_address = DALY_MODBUS_READ_DATA_ADDR; start_address = DALY_MODBUS_READ_DATA_ADDR;
@ -76,7 +76,7 @@ void DalyHkmsBmsComponent::loop() {
void DalyHkmsBmsComponent::update() { void DalyHkmsBmsComponent::update() {
if(this->read_state_ == ReadState::IDLE){ if(this->read_state_ == ReadState::IDLE){
this->read_state_ = ReadState::READ_CELL_VOLTAGES; this->advance_read_state();
} }
} }
@ -98,7 +98,7 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector<uint8_t> &data) {
{ {
case ReadState::READ_CELL_VOLTAGES: case ReadState::READ_CELL_VOLTAGES:
register_offset = DALY_MODBUS_READ_CELL_VOLTAGES_ADDR; register_offset = DALY_MODBUS_READ_CELL_VOLTAGES_ADDR;
register_count = DALY_MODBUS_READ_CELL_VOLTAGES_LENGTH; register_count = this->cell_voltage_sensors_max_;
break; break;
case ReadState::READ_DATA: case ReadState::READ_DATA:
register_offset = DALY_MODBUS_READ_DATA_ADDR; register_offset = DALY_MODBUS_READ_DATA_ADDR;
@ -129,25 +129,11 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector<uint8_t> &data) {
if (this->read_state_ == ReadState::READ_CELL_VOLTAGES) { if (this->read_state_ == ReadState::READ_CELL_VOLTAGES) {
#ifdef USE_SENSOR #ifdef USE_SENSOR
publish_sensor_state(this->cell_1_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 , 0, 0.001); for (size_t i = 0; i < this->cell_voltage_sensors_max_; i++)
publish_sensor_state(this->cell_2_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 1 , 0, 0.001); {
publish_sensor_state(this->cell_3_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 2 , 0, 0.001); publish_sensor_state(this->cell_voltage_sensors_[i], register_offset, DALY_MODBUS_ADDR_CELL_VOLT_1 + i, 0, 0.001);
publish_sensor_state(this->cell_4_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 3 , 0, 0.001); }
publish_sensor_state(this->cell_5_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 4 , 0, 0.001);
publish_sensor_state(this->cell_6_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 5 , 0, 0.001);
publish_sensor_state(this->cell_7_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 6 , 0, 0.001);
publish_sensor_state(this->cell_8_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 7 , 0, 0.001);
publish_sensor_state(this->cell_9_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 + 8 , 0, 0.001);
publish_sensor_state(this->cell_10_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 9 , 0, 0.001);
publish_sensor_state(this->cell_11_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 10, 0, 0.001);
publish_sensor_state(this->cell_12_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 11, 0, 0.001);
publish_sensor_state(this->cell_13_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 12, 0, 0.001);
publish_sensor_state(this->cell_14_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 13, 0, 0.001);
publish_sensor_state(this->cell_15_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 14, 0, 0.001);
publish_sensor_state(this->cell_16_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_1 + 15, 0, 0.001);
#endif #endif
this->read_state_ = ReadState::READ_DATA;
} else if (this->read_state_ == ReadState::READ_DATA) { } else if (this->read_state_ == ReadState::READ_DATA) {
#ifdef USE_SENSOR #ifdef USE_SENSOR
publish_sensor_state(this->temperature_1_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 , -40, 1, 255); publish_sensor_state(this->temperature_1_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 , -40, 1, 255);
@ -217,8 +203,27 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector<uint8_t> &data) {
this->precharging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_PRECHG_MOS_ACTIVE) > 0); this->precharging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_PRECHG_MOS_ACTIVE) > 0);
} }
#endif #endif
}
this->advance_read_state();
}
void DalyHkmsBmsComponent::advance_read_state() {
switch (this->read_state_)
{
case ReadState::IDLE:
// skip reading cell voltages if there are no cell voltage sensors
if (this->cell_voltage_sensors_max_ == 0) {
this->read_state_ = ReadState::READ_DATA;
} else {
this->read_state_ = ReadState::READ_CELL_VOLTAGES;
}
break;
case ReadState::READ_CELL_VOLTAGES:
this->read_state_ = ReadState::READ_DATA;
break;
case ReadState::READ_DATA:
this->read_state_ = ReadState::IDLE; this->read_state_ = ReadState::IDLE;
break;
} }
} }

View file

@ -18,6 +18,8 @@
namespace esphome { namespace esphome {
namespace daly_hkms_bms { namespace daly_hkms_bms {
static const uint8_t DALY_MODBUS_MAX_CELL_COUNT = 48;
class DalyHkmsBmsComponent : public PollingComponent, public modbus::ModbusDevice { class DalyHkmsBmsComponent : public PollingComponent, public modbus::ModbusDevice {
public: public:
void loop() override; void loop() override;
@ -28,6 +30,12 @@ class DalyHkmsBmsComponent : public PollingComponent, public modbus::ModbusDevic
void set_daly_address(uint8_t address); void set_daly_address(uint8_t address);
#ifdef USE_SENSOR #ifdef USE_SENSOR
void set_cell_voltage_sensor(size_t cell, sensor::Sensor *sensor) {
if(cell > this->cell_voltage_sensors_max_)
this->cell_voltage_sensors_max_ = cell;
this->cell_voltage_sensors_[cell-1] = sensor;
};
SUB_SENSOR(voltage) SUB_SENSOR(voltage)
SUB_SENSOR(current) SUB_SENSOR(current)
SUB_SENSOR(battery_level) SUB_SENSOR(battery_level)
@ -53,22 +61,6 @@ class DalyHkmsBmsComponent : public PollingComponent, public modbus::ModbusDevic
SUB_SENSOR(temperature_8) SUB_SENSOR(temperature_8)
SUB_SENSOR(temperature_mos) SUB_SENSOR(temperature_mos)
SUB_SENSOR(temperature_board) SUB_SENSOR(temperature_board)
SUB_SENSOR(cell_1_voltage)
SUB_SENSOR(cell_2_voltage)
SUB_SENSOR(cell_3_voltage)
SUB_SENSOR(cell_4_voltage)
SUB_SENSOR(cell_5_voltage)
SUB_SENSOR(cell_6_voltage)
SUB_SENSOR(cell_7_voltage)
SUB_SENSOR(cell_8_voltage)
SUB_SENSOR(cell_9_voltage)
SUB_SENSOR(cell_10_voltage)
SUB_SENSOR(cell_11_voltage)
SUB_SENSOR(cell_12_voltage)
SUB_SENSOR(cell_13_voltage)
SUB_SENSOR(cell_14_voltage)
SUB_SENSOR(cell_15_voltage)
SUB_SENSOR(cell_16_voltage)
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
@ -87,8 +79,12 @@ class DalyHkmsBmsComponent : public PollingComponent, public modbus::ModbusDevic
uint32_t last_send_; uint32_t last_send_;
uint8_t daly_address_; uint8_t daly_address_;
enum class ReadState{ READ_CELL_VOLTAGES, READ_DATA, IDLE } read_state_{ReadState::IDLE}; sensor::Sensor *cell_voltage_sensors_[DALY_MODBUS_MAX_CELL_COUNT]{};
size_t cell_voltage_sensors_max_{0};
void advance_read_state();
enum class ReadState{ READ_CELL_VOLTAGES, READ_DATA, IDLE } read_state_{ReadState::IDLE};
}; };
} // namespace daly_hkms_bms } // namespace daly_hkms_bms

View file

@ -48,23 +48,6 @@ CONF_TEMPERATURE_8 = "temperature_8"
CONF_TEMPERATURE_MOS = "temperature_mos" CONF_TEMPERATURE_MOS = "temperature_mos"
CONF_TEMPERATURE_BOARD = "temperature_board" CONF_TEMPERATURE_BOARD = "temperature_board"
CONF_CELL_1_VOLTAGE = "cell_1_voltage"
CONF_CELL_2_VOLTAGE = "cell_2_voltage"
CONF_CELL_3_VOLTAGE = "cell_3_voltage"
CONF_CELL_4_VOLTAGE = "cell_4_voltage"
CONF_CELL_5_VOLTAGE = "cell_5_voltage"
CONF_CELL_6_VOLTAGE = "cell_6_voltage"
CONF_CELL_7_VOLTAGE = "cell_7_voltage"
CONF_CELL_8_VOLTAGE = "cell_8_voltage"
CONF_CELL_9_VOLTAGE = "cell_9_voltage"
CONF_CELL_10_VOLTAGE = "cell_10_voltage"
CONF_CELL_11_VOLTAGE = "cell_11_voltage"
CONF_CELL_12_VOLTAGE = "cell_12_voltage"
CONF_CELL_13_VOLTAGE = "cell_13_voltage"
CONF_CELL_14_VOLTAGE = "cell_14_voltage"
CONF_CELL_15_VOLTAGE = "cell_15_voltage"
CONF_CELL_16_VOLTAGE = "cell_16_voltage"
ICON_CURRENT_DC = "mdi:current-dc" ICON_CURRENT_DC = "mdi:current-dc"
ICON_BATTERY_OUTLINE = "mdi:battery-outline" ICON_BATTERY_OUTLINE = "mdi:battery-outline"
ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up" ICON_THERMOMETER_CHEVRON_UP = "mdi:thermometer-chevron-up"
@ -73,6 +56,8 @@ ICON_CAR_BATTERY = "mdi:car-battery"
UNIT_AMPERE_HOUR = "Ah" UNIT_AMPERE_HOUR = "Ah"
MAX_CELL_NUMBER = 48
TYPES = [ TYPES = [
CONF_VOLTAGE, CONF_VOLTAGE,
CONF_CURRENT, CONF_CURRENT,
@ -99,22 +84,7 @@ TYPES = [
CONF_TEMPERATURE_8, CONF_TEMPERATURE_8,
CONF_TEMPERATURE_MOS, CONF_TEMPERATURE_MOS,
CONF_TEMPERATURE_BOARD, CONF_TEMPERATURE_BOARD,
CONF_CELL_1_VOLTAGE, # Cell voltages are handled by loops below
CONF_CELL_2_VOLTAGE,
CONF_CELL_3_VOLTAGE,
CONF_CELL_4_VOLTAGE,
CONF_CELL_5_VOLTAGE,
CONF_CELL_6_VOLTAGE,
CONF_CELL_7_VOLTAGE,
CONF_CELL_8_VOLTAGE,
CONF_CELL_9_VOLTAGE,
CONF_CELL_10_VOLTAGE,
CONF_CELL_11_VOLTAGE,
CONF_CELL_12_VOLTAGE,
CONF_CELL_13_VOLTAGE,
CONF_CELL_14_VOLTAGE,
CONF_CELL_15_VOLTAGE,
CONF_CELL_16_VOLTAGE,
] ]
TEMPERATURE_SENSOR_SCHEMA = sensor.sensor_schema( TEMPERATURE_SENSOR_SCHEMA = sensor.sensor_schema(
@ -133,6 +103,15 @@ CELL_VOLTAGE_SCHEMA = sensor.sensor_schema(
accuracy_decimals=3, accuracy_decimals=3,
) )
def get_cell_voltage_key(cell):
return f"cell_{cell}_voltage"
def get_cell_voltages_schema():
schema_obj = {}
for i in range(1, MAX_CELL_NUMBER+1):
schema_obj[cv.Optional(get_cell_voltage_key(i))] = CELL_VOLTAGE_SCHEMA
return cv.Schema(schema_obj)
CONFIG_SCHEMA = ( CONFIG_SCHEMA = (
cv.Schema( cv.Schema(
{ {
@ -241,24 +220,9 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_TEMPERATURE_8): TEMPERATURE_SENSOR_SCHEMA, cv.Optional(CONF_TEMPERATURE_8): TEMPERATURE_SENSOR_SCHEMA,
cv.Optional(CONF_TEMPERATURE_MOS): TEMPERATURE_SENSOR_SCHEMA, cv.Optional(CONF_TEMPERATURE_MOS): TEMPERATURE_SENSOR_SCHEMA,
cv.Optional(CONF_TEMPERATURE_BOARD): TEMPERATURE_SENSOR_SCHEMA, cv.Optional(CONF_TEMPERATURE_BOARD): TEMPERATURE_SENSOR_SCHEMA,
cv.Optional(CONF_CELL_1_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_2_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_3_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_4_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_5_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_6_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_7_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_8_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_9_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_10_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_11_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_12_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_13_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_14_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_15_VOLTAGE): CELL_VOLTAGE_SCHEMA,
cv.Optional(CONF_CELL_16_VOLTAGE): CELL_VOLTAGE_SCHEMA
} }
) )
.extend(get_cell_voltages_schema())
.extend(cv.COMPONENT_SCHEMA) .extend(cv.COMPONENT_SCHEMA)
) )
@ -267,7 +231,15 @@ async def setup_conf(config, key, hub):
sens = await sensor.new_sensor(sensor_config) sens = await sensor.new_sensor(sensor_config)
cg.add(getattr(hub, f"set_{key}_sensor")(sens)) cg.add(getattr(hub, f"set_{key}_sensor")(sens))
async def setup_cell_voltage_conf(config, cell, hub):
key = get_cell_voltage_key(cell)
if sensor_config := config.get(key):
sens = await sensor.new_sensor(sensor_config)
cg.add(hub.set_cell_voltage_sensor(cell, sens))
async def to_code(config): async def to_code(config):
hub = await cg.get_variable(config[CONF_DALY_HKMS_BMS_ID]) hub = await cg.get_variable(config[CONF_DALY_HKMS_BMS_ID])
for key in TYPES: for key in TYPES:
await setup_conf(config, key, hub) await setup_conf(config, key, hub)
for i in range(1, MAX_CELL_NUMBER+1):
await setup_cell_voltage_conf(config, i, hub)