ESPHome 2026.2.1
Loading...
Searching...
No Matches
daly_bms.cpp
Go to the documentation of this file.
1#include "daly_bms.h"
2#include <vector>
5#include "esphome/core/log.h"
6
7namespace esphome {
8namespace daly_bms {
9
10static const char *const TAG = "daly_bms";
11
12static const uint8_t DALY_FRAME_SIZE = 13;
13static const uint8_t DALY_TEMPERATURE_OFFSET = 40;
14static const uint16_t DALY_CURRENT_OFFSET = 30000;
15
16static const uint8_t DALY_REQUEST_BATTERY_LEVEL = 0x90;
17static const uint8_t DALY_REQUEST_MIN_MAX_VOLTAGE = 0x91;
18static const uint8_t DALY_REQUEST_MIN_MAX_TEMPERATURE = 0x92;
19static const uint8_t DALY_REQUEST_MOS = 0x93;
20static const uint8_t DALY_REQUEST_STATUS = 0x94;
21static const uint8_t DALY_REQUEST_CELL_VOLTAGE = 0x95;
22static const uint8_t DALY_REQUEST_TEMPERATURE = 0x96;
23
24void DalyBmsComponent::setup() { this->next_request_ = 1; }
25
27 ESP_LOGCONFIG(TAG, "Daly BMS:");
28 this->check_uart_settings(9600);
29}
30
32 this->trigger_next_ = true;
33 this->next_request_ = 0;
34}
35
37 const uint32_t now = App.get_loop_component_start_time();
38 if (this->receiving_ && (now - this->last_transmission_ >= 200)) {
39 // last transmission too long ago. Reset RX index.
40 ESP_LOGW(TAG, "Last transmission too long ago. Reset RX index.");
41 this->data_.clear();
42 this->receiving_ = false;
43 }
44 if ((now - this->last_transmission_ >= 250) && !this->trigger_next_) {
45 // last transmittion longer than 0.25s ago -> trigger next request
46 this->last_transmission_ = now;
47 this->trigger_next_ = true;
48 }
49 if (available())
50 this->last_transmission_ = now;
51 while (available()) {
52 uint8_t c;
53 read_byte(&c);
54 if (!this->receiving_) {
55 if (c != 0xa5)
56 continue;
57 this->receiving_ = true;
58 }
59 this->data_.push_back(c);
60 if (this->data_.size() == 4)
61 this->data_count_ = c;
62 if ((this->data_.size() > 4) and (data_.size() == this->data_count_ + 5)) {
63 this->decode_data_(this->data_);
64 this->data_.clear();
65 this->receiving_ = false;
66 }
67 }
68
69 if (this->trigger_next_) {
70 this->trigger_next_ = false;
71 switch (this->next_request_) {
72 case 0:
73 this->request_data_(DALY_REQUEST_BATTERY_LEVEL);
74 this->next_request_ = 1;
75 break;
76 case 1:
77 this->request_data_(DALY_REQUEST_MIN_MAX_VOLTAGE);
78 this->next_request_ = 2;
79 break;
80 case 2:
81 this->request_data_(DALY_REQUEST_MIN_MAX_TEMPERATURE);
82 this->next_request_ = 3;
83 break;
84 case 3:
85 this->request_data_(DALY_REQUEST_MOS);
86 this->next_request_ = 4;
87 break;
88 case 4:
89 this->request_data_(DALY_REQUEST_STATUS);
90 this->next_request_ = 5;
91 break;
92 case 5:
93 this->request_data_(DALY_REQUEST_CELL_VOLTAGE);
94 this->next_request_ = 6;
95 break;
96 case 6:
97 this->request_data_(DALY_REQUEST_TEMPERATURE);
98 this->next_request_ = 7;
99 break;
100 case 7:
101 default:
102 break;
103 }
104 }
105}
106
107void 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
131void 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 if (this->cell_17_voltage_sensor_) {
302 this->cell_17_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
303 }
304 if (this->cell_18_voltage_sensor_) {
305 this->cell_18_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
306 }
307 break;
308 }
309 break;
310#endif
311 default:
312 break;
313 }
314 } else {
315 ESP_LOGW(TAG, "Checksum-Error on Packet %x", it[4]);
316 }
317 std::advance(it, DALY_FRAME_SIZE);
318 } else {
319 std::advance(it, 1);
320 }
321 }
322}
323
324} // namespace daly_bms
325} // namespace esphome
uint8_t checksum
Definition bl0906.h:3
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
virtual void setup()
Where the component's initialization should happen.
std::vector< uint8_t > data_
Definition daly_bms.h:83
void decode_data_(std::vector< uint8_t > data)
Definition daly_bms.cpp:131
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:16
bool read_byte(uint8_t *data)
Definition uart.h:34
void write_array(const uint8_t *data, size_t len)
Definition uart.h:26
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
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:536
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:528
Application App
Global storage of Application pointer - only one Application can exist.