mirror of
https://github.com/esphome/esphome.git
synced 2024-12-03 20:24:14 +01:00
DALY Modbus BMS: split data request into two requests
This commit is contained in:
parent
206562bebf
commit
2f6d552589
3 changed files with 140 additions and 90 deletions
|
@ -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<uint8_t> &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<uint8_t> &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,6 +127,7 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector<uint8_t> &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);
|
||||
|
@ -104,7 +145,11 @@ void DalyHkmsBmsComponent::on_modbus_data(const std::vector<uint8_t> &data) {
|
|||
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
|
||||
|
||||
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);
|
||||
|
@ -172,6 +217,9 @@ 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
this->read_state_ = ReadState::IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void DalyHkmsBmsComponent::dump_config() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue