ESPHome  2024.4.0
daly_bms.cpp
Go to the documentation of this file.
1 #include "daly_bms.h"
2 #include <vector>
3 #include "esphome/core/log.h"
4 
5 namespace esphome {
6 namespace daly_bms {
7 
8 static const char *const TAG = "daly_bms";
9 
10 static const uint8_t DALY_FRAME_SIZE = 13;
11 static const uint8_t DALY_TEMPERATURE_OFFSET = 40;
12 static const uint16_t DALY_CURRENT_OFFSET = 30000;
13 
14 static const uint8_t DALY_REQUEST_BATTERY_LEVEL = 0x90;
15 static const uint8_t DALY_REQUEST_MIN_MAX_VOLTAGE = 0x91;
16 static const uint8_t DALY_REQUEST_MIN_MAX_TEMPERATURE = 0x92;
17 static const uint8_t DALY_REQUEST_MOS = 0x93;
18 static const uint8_t DALY_REQUEST_STATUS = 0x94;
19 static const uint8_t DALY_REQUEST_CELL_VOLTAGE = 0x95;
20 static const uint8_t DALY_REQUEST_TEMPERATURE = 0x96;
21 
22 void DalyBmsComponent::setup() { this->next_request_ = 1; }
23 
25  ESP_LOGCONFIG(TAG, "Daly BMS:");
26  this->check_uart_settings(9600);
27 }
28 
30  this->trigger_next_ = true;
31  this->next_request_ = 0;
32 }
33 
35  const uint32_t now = millis();
36  if (this->receiving_ && (now - this->last_transmission_ >= 200)) {
37  // last transmission too long ago. Reset RX index.
38  ESP_LOGW(TAG, "Last transmission too long ago. Reset RX index.");
39  this->data_.clear();
40  this->receiving_ = false;
41  }
42  if ((now - this->last_transmission_ >= 250) && !this->trigger_next_) {
43  // last transmittion longer than 0.25s ago -> trigger next request
44  this->last_transmission_ = now;
45  this->trigger_next_ = true;
46  }
47  if (available())
48  this->last_transmission_ = now;
49  while (available()) {
50  uint8_t c;
51  read_byte(&c);
52  if (!this->receiving_) {
53  if (c != 0xa5)
54  continue;
55  this->receiving_ = true;
56  }
57  this->data_.push_back(c);
58  if (this->data_.size() == 4)
59  this->data_count_ = c;
60  if ((this->data_.size() > 4) and (data_.size() == this->data_count_ + 5)) {
61  this->decode_data_(this->data_);
62  this->data_.clear();
63  this->receiving_ = false;
64  }
65  }
66 
67  if (this->trigger_next_) {
68  this->trigger_next_ = false;
69  switch (this->next_request_) {
70  case 0:
71  this->request_data_(DALY_REQUEST_BATTERY_LEVEL);
72  this->next_request_ = 1;
73  break;
74  case 1:
75  this->request_data_(DALY_REQUEST_MIN_MAX_VOLTAGE);
76  this->next_request_ = 2;
77  break;
78  case 2:
79  this->request_data_(DALY_REQUEST_MIN_MAX_TEMPERATURE);
80  this->next_request_ = 3;
81  break;
82  case 3:
83  this->request_data_(DALY_REQUEST_MOS);
84  this->next_request_ = 4;
85  break;
86  case 4:
87  this->request_data_(DALY_REQUEST_STATUS);
88  this->next_request_ = 5;
89  break;
90  case 5:
91  this->request_data_(DALY_REQUEST_CELL_VOLTAGE);
92  this->next_request_ = 6;
93  break;
94  case 6:
95  this->request_data_(DALY_REQUEST_TEMPERATURE);
96  this->next_request_ = 7;
97  break;
98  case 7:
99  default:
100  break;
101  }
102  }
103 }
104 
106 
107 void DalyBmsComponent::request_data_(uint8_t data_id) {
108  uint8_t request_message[DALY_FRAME_SIZE];
109 
110  request_message[0] = 0xA5; // Start Flag
111  request_message[1] = this->addr_; // Communication Module Address
112  request_message[2] = data_id; // Data ID
113  request_message[3] = 0x08; // Data Length (Fixed)
114  request_message[4] = 0x00; // Empty Data
115  request_message[5] = 0x00; // |
116  request_message[6] = 0x00; // |
117  request_message[7] = 0x00; // |
118  request_message[8] = 0x00; // |
119  request_message[9] = 0x00; // |
120  request_message[10] = 0x00; // |
121  request_message[11] = 0x00; // Empty Data
122 
123  request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] +
124  request_message[3]); // Checksum (Lower byte of the other bytes sum)
125 
126  ESP_LOGV(TAG, "Request datapacket Nr %x", data_id);
127  this->write_array(request_message, sizeof(request_message));
128  this->flush();
129 }
130 
131 void DalyBmsComponent::decode_data_(std::vector<uint8_t> data) {
132  auto it = data.begin();
133 
134  while ((it = std::find(it, data.end(), 0xA5)) != data.end()) {
135  if (data.end() - it >= DALY_FRAME_SIZE && it[1] == 0x01) {
136  uint8_t checksum;
137  int sum = 0;
138  for (int i = 0; i < 12; i++) {
139  sum += it[i];
140  }
141  checksum = sum;
142 
143  if (checksum == it[12]) {
144  switch (it[2]) {
145 #ifdef USE_SENSOR
146  case DALY_REQUEST_BATTERY_LEVEL:
147  if (this->voltage_sensor_) {
148  this->voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 10);
149  }
150  if (this->current_sensor_) {
151  this->current_sensor_->publish_state(((float) (encode_uint16(it[8], it[9]) - DALY_CURRENT_OFFSET) / 10));
152  }
153  if (this->battery_level_sensor_) {
154  this->battery_level_sensor_->publish_state((float) encode_uint16(it[10], it[11]) / 10);
155  }
156  break;
157 
158  case DALY_REQUEST_MIN_MAX_VOLTAGE:
159  if (this->max_cell_voltage_sensor_) {
160  this->max_cell_voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 1000);
161  }
162  if (this->max_cell_voltage_number_sensor_) {
163  this->max_cell_voltage_number_sensor_->publish_state(it[6]);
164  }
165  if (this->min_cell_voltage_sensor_) {
166  this->min_cell_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
167  }
168  if (this->min_cell_voltage_number_sensor_) {
169  this->min_cell_voltage_number_sensor_->publish_state(it[9]);
170  }
171  break;
172 
173  case DALY_REQUEST_MIN_MAX_TEMPERATURE:
174  if (this->max_temperature_sensor_) {
175  this->max_temperature_sensor_->publish_state(it[4] - DALY_TEMPERATURE_OFFSET);
176  }
177  if (this->max_temperature_probe_number_sensor_) {
178  this->max_temperature_probe_number_sensor_->publish_state(it[5]);
179  }
180  if (this->min_temperature_sensor_) {
181  this->min_temperature_sensor_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET);
182  }
183  if (this->min_temperature_probe_number_sensor_) {
184  this->min_temperature_probe_number_sensor_->publish_state(it[7]);
185  }
186  break;
187 #endif
188  case DALY_REQUEST_MOS:
189 #ifdef USE_TEXT_SENSOR
190  if (this->status_text_sensor_ != nullptr) {
191  switch (it[4]) {
192  case 0:
193  this->status_text_sensor_->publish_state("Stationary");
194  break;
195  case 1:
196  this->status_text_sensor_->publish_state("Charging");
197  break;
198  case 2:
199  this->status_text_sensor_->publish_state("Discharging");
200  break;
201  default:
202  break;
203  }
204  }
205 #endif
206 #ifdef USE_BINARY_SENSOR
207  if (this->charging_mos_enabled_binary_sensor_) {
208  this->charging_mos_enabled_binary_sensor_->publish_state(it[5]);
209  }
210  if (this->discharging_mos_enabled_binary_sensor_) {
211  this->discharging_mos_enabled_binary_sensor_->publish_state(it[6]);
212  }
213 #endif
214 #ifdef USE_SENSOR
215  if (this->remaining_capacity_sensor_) {
216  this->remaining_capacity_sensor_->publish_state((float) encode_uint32(it[8], it[9], it[10], it[11]) /
217  1000);
218  }
219 #endif
220  break;
221 
222 #ifdef USE_SENSOR
223  case DALY_REQUEST_STATUS:
224  if (this->cells_number_sensor_) {
225  this->cells_number_sensor_->publish_state(it[4]);
226  }
227  break;
228 
229  case DALY_REQUEST_TEMPERATURE:
230  if (it[4] == 1) {
231  if (this->temperature_1_sensor_) {
232  this->temperature_1_sensor_->publish_state(it[5] - DALY_TEMPERATURE_OFFSET);
233  }
234  if (this->temperature_2_sensor_) {
235  this->temperature_2_sensor_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET);
236  }
237  }
238  break;
239 
240  case DALY_REQUEST_CELL_VOLTAGE:
241  switch (it[4]) {
242  case 1:
243  if (this->cell_1_voltage_sensor_) {
244  this->cell_1_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
245  }
246  if (this->cell_2_voltage_sensor_) {
247  this->cell_2_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
248  }
249  if (this->cell_3_voltage_sensor_) {
250  this->cell_3_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
251  }
252  break;
253  case 2:
254  if (this->cell_4_voltage_sensor_) {
255  this->cell_4_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
256  }
257  if (this->cell_5_voltage_sensor_) {
258  this->cell_5_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
259  }
260  if (this->cell_6_voltage_sensor_) {
261  this->cell_6_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
262  }
263  break;
264  case 3:
265  if (this->cell_7_voltage_sensor_) {
266  this->cell_7_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
267  }
268  if (this->cell_8_voltage_sensor_) {
269  this->cell_8_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
270  }
271  if (this->cell_9_voltage_sensor_) {
272  this->cell_9_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
273  }
274  break;
275  case 4:
276  if (this->cell_10_voltage_sensor_) {
277  this->cell_10_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
278  }
279  if (this->cell_11_voltage_sensor_) {
280  this->cell_11_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
281  }
282  if (this->cell_12_voltage_sensor_) {
283  this->cell_12_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
284  }
285  break;
286  case 5:
287  if (this->cell_13_voltage_sensor_) {
288  this->cell_13_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
289  }
290  if (this->cell_14_voltage_sensor_) {
291  this->cell_14_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
292  }
293  if (this->cell_15_voltage_sensor_) {
294  this->cell_15_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
295  }
296  break;
297  case 6:
298  if (this->cell_16_voltage_sensor_) {
299  this->cell_16_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
300  }
301  break;
302  }
303  break;
304 #endif
305  default:
306  break;
307  }
308  } else {
309  ESP_LOGW(TAG, "Checksum-Error on Packet %x", it[4]);
310  }
311  std::advance(it, DALY_FRAME_SIZE);
312  } else {
313  std::advance(it, 1);
314  }
315  }
316 }
317 
318 } // namespace daly_bms
319 } // namespace esphome
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
void write_array(const uint8_t *data, size_t len)
Definition: uart.h:21
constexpr uint32_t encode_uint32(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
Encode a 32-bit value given four bytes in most to least significant byte order.
Definition: helpers.h:186
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
void request_data_(uint8_t data_id)
Definition: daly_bms.cpp:107
void check_uart_settings(uint32_t baud_rate, uint8_t stop_bits=1, UARTParityOptions parity=UART_CONFIG_PARITY_NONE, uint8_t data_bits=8)
Check that the configuration of the UART bus matches the provided values and otherwise print a warnin...
Definition: uart.cpp:13
virtual void setup()
Where the component&#39;s initialization should happen.
Definition: component.cpp:48
void decode_data_(std::vector< uint8_t > data)
Definition: daly_bms.cpp:131
bool read_byte(uint8_t *data)
Definition: uart.h:29
std::vector< uint8_t > data_
Definition: daly_bms.h:82
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition: helpers.h:182
uint8_t checksum
Definition: bl0939.h:35
float get_setup_priority() const override
Definition: daly_bms.cpp:105
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7