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