From 2f6d5525896a300c9743610f813b405f59e8c628 Mon Sep 17 00:00:00 2001 From: patagona Date: Mon, 30 Sep 2024 00:08:13 +0200 Subject: [PATCH] DALY Modbus BMS: split data request into two requests --- .../daly_hkms_bms/daly_hkms_bms.cpp | 226 +++++++++++------- .../components/daly_hkms_bms/daly_hkms_bms.h | 2 + .../daly_hkms_bms/daly_hkms_bms_registers.h | 2 +- 3 files changed, 140 insertions(+), 90 deletions(-) diff --git a/esphome/components/daly_hkms_bms/daly_hkms_bms.cpp b/esphome/components/daly_hkms_bms/daly_hkms_bms.cpp index 38af977094..d32d1e5d74 100644 --- a/esphome/components/daly_hkms_bms/daly_hkms_bms.cpp +++ b/esphome/components/daly_hkms_bms/daly_hkms_bms.cpp @@ -13,6 +13,12 @@ static const char *const TAG = "daly_hkms_bms"; 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_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_LENGTH = DALY_MODBUS_REGISTER_MAX - DALY_MODBUS_ADDR_CELL_TEMP_1 + 1; + static const uint8_t MODBUS_CMD_READ_HOLDING_REGISTERS = 0x03; void DalyHkmsBmsComponent::set_daly_address(uint8_t daly_address) { @@ -25,13 +31,10 @@ void DalyHkmsBmsComponent::set_daly_address(uint8_t daly_address) { } void DalyHkmsBmsComponent::loop() { - // If update() was unable to send we retry until we can send. - if (!this->waiting_to_update_) + if (this->read_state_ == ReadState::IDLE) { return; - update(); -} + } -void DalyHkmsBmsComponent::update() { // If our last send has had no reply yet, and it wasn't that long ago, do nothing. uint32_t now = millis(); if (now - this->last_send_ < this->get_update_interval() / 2) { @@ -40,25 +43,43 @@ void DalyHkmsBmsComponent::update() { // The bus might be slow, or there might be other devices, or other components might be talking to our device. if (this->waiting_for_response()) { - this->waiting_to_update_ = true; return; } - this->waiting_to_update_ = false; + uint8_t start_address; + uint8_t register_count; + switch (this->read_state_) + { + case ReadState::READ_CELL_VOLTAGES: + start_address = DALY_MODBUS_READ_CELL_VOLTAGES_ADDR; + register_count = DALY_MODBUS_READ_CELL_VOLTAGES_LENGTH; + break; + case ReadState::READ_DATA: + start_address = DALY_MODBUS_READ_DATA_ADDR; + register_count = DALY_MODBUS_READ_DATA_LENGTH; + break; + default: + return; + } + + ESP_LOGD(TAG, "Sending modbus read request to %d: start register %d, register count %d", + this->daly_address_, start_address, register_count); // send the request using Modbus directly instead of ModbusDevice so we can send the data with the request address - uint8_t modbus_request_address = this->daly_address_ + DALY_MODBUS_REQUEST_ADDRESS_OFFSET; - this->parent_->send( - modbus_request_address, - MODBUS_CMD_READ_HOLDING_REGISTERS, - 0x00, - DALY_MODBUS_REGISTER_COUNT, - 0, - nullptr); + uint8_t modbus_device_request_address = this->daly_address_ + DALY_MODBUS_REQUEST_ADDRESS_OFFSET; + + this->parent_->send(modbus_device_request_address, MODBUS_CMD_READ_HOLDING_REGISTERS, start_address, register_count, + 0, nullptr); this->last_send_ = millis(); } +void DalyHkmsBmsComponent::update() { + if(this->read_state_ == ReadState::IDLE){ + this->read_state_ = ReadState::READ_CELL_VOLTAGES; + } +} + void DalyHkmsBmsComponent::on_modbus_data(const std::vector &data) { // Other components might be sending commands to our device. But we don't get called with enough // context to know what is what. So if we didn't do a send, we ignore the data. @@ -68,18 +89,37 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector &data) { } this->last_send_ = 0; - // Also ignore the data if the message is too short. Otherwise we will publish invalid values. - if (data.size() < DALY_MODBUS_REGISTER_COUNT * 2) { + ESP_LOGD(TAG, "Got modbus response: %d bytes", data.size()); + + size_t register_count; + size_t register_offset; + + switch (this->read_state_) + { + case ReadState::READ_CELL_VOLTAGES: + register_offset = DALY_MODBUS_READ_CELL_VOLTAGES_ADDR; + register_count = DALY_MODBUS_READ_CELL_VOLTAGES_LENGTH; + break; + case ReadState::READ_DATA: + register_offset = DALY_MODBUS_READ_DATA_ADDR; + register_count = DALY_MODBUS_READ_DATA_LENGTH; + break; + default: + ESP_LOGE(TAG, "Invalid read state"); + return; + } + + if (data.size() < register_count * 2) { ESP_LOGD(TAG, "Not enough data in modbus response"); return; } auto get_register = [&](size_t i) -> uint16_t { - return encode_uint16(data[i * 2], data[i * 2 + 1]); + return encode_uint16(data[(i - register_offset) * 2], data[(i - register_offset) * 2 + 1]); }; - auto publish_sensor_state = [&](sensor::Sensor *sensor, size_t i, int16_t offset, float factor, - int32_t unavailable_value = -1) -> void { + auto publish_sensor_state = [&](sensor::Sensor *sensor, size_t i, + int16_t offset, float factor, int32_t unavailable_value = -1) -> void { if (sensor == nullptr) return; uint16_t register_value = get_register(i); @@ -87,91 +127,99 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector &data) { sensor->publish_state(value); }; + if (this->read_state_ == ReadState::READ_CELL_VOLTAGES) { #ifdef USE_SENSOR - publish_sensor_state(this->cell_1_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 , 0, 0.001); - 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_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); + publish_sensor_state(this->cell_1_voltage_sensor_ , DALY_MODBUS_ADDR_CELL_VOLT_1 , 0, 0.001); + 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_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 - publish_sensor_state(this->temperature_1_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 , -40, 1, 255); - publish_sensor_state(this->temperature_2_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 1, -40, 1, 255); - publish_sensor_state(this->temperature_3_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 2, -40, 1, 255); - publish_sensor_state(this->temperature_4_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 3, -40, 1, 255); - publish_sensor_state(this->temperature_5_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 4, -40, 1, 255); - publish_sensor_state(this->temperature_6_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 5, -40, 1, 255); - publish_sensor_state(this->temperature_7_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 6, -40, 1, 255); - publish_sensor_state(this->temperature_8_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 7, -40, 1, 255); + this->read_state_ = ReadState::READ_DATA; + } else if (this->read_state_ == ReadState::READ_DATA) { +#ifdef USE_SENSOR + publish_sensor_state(this->temperature_1_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 , -40, 1, 255); + publish_sensor_state(this->temperature_2_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 1, -40, 1, 255); + publish_sensor_state(this->temperature_3_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 2, -40, 1, 255); + publish_sensor_state(this->temperature_4_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 3, -40, 1, 255); + publish_sensor_state(this->temperature_5_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 4, -40, 1, 255); + publish_sensor_state(this->temperature_6_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 5, -40, 1, 255); + publish_sensor_state(this->temperature_7_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 6, -40, 1, 255); + publish_sensor_state(this->temperature_8_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_1 + 7, -40, 1, 255); - publish_sensor_state(this->voltage_sensor_, DALY_MODBUS_ADDR_VOLT, 0, 0.1); - publish_sensor_state(this->current_sensor_, DALY_MODBUS_ADDR_CURR, -30000, 0.1); - publish_sensor_state(this->battery_level_sensor_, DALY_MODBUS_ADDR_SOC, 0, 0.1); + publish_sensor_state(this->voltage_sensor_, DALY_MODBUS_ADDR_VOLT, 0, 0.1); + publish_sensor_state(this->current_sensor_, DALY_MODBUS_ADDR_CURR, -30000, 0.1); + publish_sensor_state(this->battery_level_sensor_, DALY_MODBUS_ADDR_SOC, 0, 0.1); - publish_sensor_state(this->cells_number_sensor_, DALY_MODBUS_ADDR_CELL_COUNT, 0, 1); - publish_sensor_state(this->temps_number_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_COUNT, 0, 1); + publish_sensor_state(this->cells_number_sensor_, DALY_MODBUS_ADDR_CELL_COUNT, 0, 1); + publish_sensor_state(this->temps_number_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_COUNT, 0, 1); - publish_sensor_state(this->max_cell_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MAX, 0, 0.001); - publish_sensor_state(this->max_cell_voltage_number_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MAX_NUM, 0, 1); - - publish_sensor_state(this->min_cell_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MIN, 0, 0.001); - publish_sensor_state(this->min_cell_voltage_number_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MIN_NUM, 0, 1); + publish_sensor_state(this->max_cell_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MAX, 0, 0.001); + publish_sensor_state(this->max_cell_voltage_number_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MAX_NUM, 0, 1); + + publish_sensor_state(this->min_cell_voltage_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MIN, 0, 0.001); + publish_sensor_state(this->min_cell_voltage_number_sensor_, DALY_MODBUS_ADDR_CELL_VOLT_MIN_NUM, 0, 1); - publish_sensor_state(this->max_temperature_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MAX, -40, 1, 255); - publish_sensor_state(this->max_temperature_probe_number_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MAX_NUM, 0, 1); - - publish_sensor_state(this->min_temperature_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MIN, -40, 1, 255); - publish_sensor_state(this->min_temperature_probe_number_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MIN_NUM, 0, 1); + publish_sensor_state(this->max_temperature_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MAX, -40, 1, 255); + publish_sensor_state(this->max_temperature_probe_number_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MAX_NUM, 0, 1); + + publish_sensor_state(this->min_temperature_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MIN, -40, 1, 255); + publish_sensor_state(this->min_temperature_probe_number_sensor_, DALY_MODBUS_ADDR_CELL_TEMP_MIN_NUM, 0, 1); - publish_sensor_state(this->remaining_capacity_sensor_, DALY_MODBUS_ADDR_REMAINING_CAPACITY, 0, 0.1); - publish_sensor_state(this->cycles_sensor_, DALY_MODBUS_ADDR_CYCLES, 0, 1); + publish_sensor_state(this->remaining_capacity_sensor_, DALY_MODBUS_ADDR_REMAINING_CAPACITY, 0, 0.1); + publish_sensor_state(this->cycles_sensor_, DALY_MODBUS_ADDR_CYCLES, 0, 1); - publish_sensor_state(this->temperature_mos_sensor_, DALY_MODBUS_ADDR_MOS_TEMP, -40, 1, 255); - publish_sensor_state(this->temperature_board_sensor_, DALY_MODBUS_ADDR_BOARD_TEMP, -40, 1, 255); + publish_sensor_state(this->temperature_mos_sensor_, DALY_MODBUS_ADDR_MOS_TEMP, -40, 1, 255); + publish_sensor_state(this->temperature_board_sensor_, DALY_MODBUS_ADDR_BOARD_TEMP, -40, 1, 255); #endif #ifdef USE_TEXT_SENSOR - if (this->status_text_sensor_ != nullptr) { - switch (get_register(DALY_MODBUS_ADDR_CHG_DSCHG_STATUS)) { - 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->status_text_sensor_ != nullptr) { + switch (get_register(DALY_MODBUS_ADDR_CHG_DSCHG_STATUS)) { + 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; + } } - } #endif #ifdef USE_BINARY_SENSOR - if (this->balancing_active_binary_sensor_) { - this->balancing_active_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_BALANCE_STATUS) > 0); - } - if (this->charging_mos_enabled_binary_sensor_) { - this->charging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_CHG_MOS_ACTIVE) > 0); - } - if (this->discharging_mos_enabled_binary_sensor_) { - this->discharging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_DSCHG_MOS_ACTIVE) > 0); - } - if (this->precharging_mos_enabled_binary_sensor_) { - this->precharging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_PRECHG_MOS_ACTIVE) > 0); - } + if (this->balancing_active_binary_sensor_) { + this->balancing_active_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_BALANCE_STATUS) > 0); + } + if (this->charging_mos_enabled_binary_sensor_) { + this->charging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_CHG_MOS_ACTIVE) > 0); + } + if (this->discharging_mos_enabled_binary_sensor_) { + this->discharging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_DSCHG_MOS_ACTIVE) > 0); + } + if (this->precharging_mos_enabled_binary_sensor_) { + this->precharging_mos_enabled_binary_sensor_->publish_state(get_register(DALY_MODBUS_ADDR_PRECHG_MOS_ACTIVE) > 0); + } #endif + + this->read_state_ = ReadState::IDLE; + } } void DalyHkmsBmsComponent::dump_config() { diff --git a/esphome/components/daly_hkms_bms/daly_hkms_bms.h b/esphome/components/daly_hkms_bms/daly_hkms_bms.h index 7fecbed1c7..1cb68580dd 100644 --- a/esphome/components/daly_hkms_bms/daly_hkms_bms.h +++ b/esphome/components/daly_hkms_bms/daly_hkms_bms.h @@ -87,6 +87,8 @@ class DalyHkmsBmsComponent : public PollingComponent, public modbus::ModbusDevic uint32_t last_send_; uint8_t daly_address_; + enum class ReadState{ READ_CELL_VOLTAGES, READ_DATA, IDLE } read_state_{ReadState::IDLE}; + }; } // namespace daly_hkms_bms diff --git a/esphome/components/daly_hkms_bms/daly_hkms_bms_registers.h b/esphome/components/daly_hkms_bms/daly_hkms_bms_registers.h index ae0402deea..ecfb071a74 100644 --- a/esphome/components/daly_hkms_bms/daly_hkms_bms_registers.h +++ b/esphome/components/daly_hkms_bms/daly_hkms_bms_registers.h @@ -47,7 +47,7 @@ static const uint16_t DALY_MODBUS_ADDR_MOS_TEMP = 0x5A; static const uint16_t DALY_MODBUS_ADDR_BOARD_TEMP = 0x5B; static const uint16_t DALY_MODBUS_ADDR_HEATING_TEMP = 0x5C; -static const uint16_t DALY_MODBUS_REGISTER_COUNT = 0x5D; +static const uint16_t DALY_MODBUS_REGISTER_MAX = 0x5C; } // namespace daly_hkms_bms } // namespace esphome