ESPHome 2025.6.3
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
108
109void DalyBmsComponent::request_data_(uint8_t data_id) {
110 uint8_t request_message[DALY_FRAME_SIZE];
111
112 request_message[0] = 0xA5; // Start Flag
113 request_message[1] = this->addr_; // Communication Module Address
114 request_message[2] = data_id; // Data ID
115 request_message[3] = 0x08; // Data Length (Fixed)
116 request_message[4] = 0x00; // Empty Data
117 request_message[5] = 0x00; // |
118 request_message[6] = 0x00; // |
119 request_message[7] = 0x00; // |
120 request_message[8] = 0x00; // |
121 request_message[9] = 0x00; // |
122 request_message[10] = 0x00; // |
123 request_message[11] = 0x00; // Empty Data
124
125 request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] +
126 request_message[3]); // Checksum (Lower byte of the other bytes sum)
127
128 ESP_LOGV(TAG, "Request datapacket Nr %x", data_id);
129 this->write_array(request_message, sizeof(request_message));
130 this->flush();
131}
132
133void DalyBmsComponent::decode_data_(std::vector<uint8_t> data) {
134 auto it = data.begin();
135
136 while ((it = std::find(it, data.end(), 0xA5)) != data.end()) {
137 if (data.end() - it >= DALY_FRAME_SIZE && it[1] == 0x01) {
138 uint8_t checksum;
139 int sum = 0;
140 for (int i = 0; i < 12; i++) {
141 sum += it[i];
142 }
143 checksum = sum;
144
145 if (checksum == it[12]) {
146 switch (it[2]) {
147#ifdef USE_SENSOR
148 case DALY_REQUEST_BATTERY_LEVEL:
149 if (this->voltage_sensor_) {
150 this->voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 10);
151 }
152 if (this->current_sensor_) {
153 this->current_sensor_->publish_state(((float) (encode_uint16(it[8], it[9]) - DALY_CURRENT_OFFSET) / 10));
154 }
155 if (this->battery_level_sensor_) {
156 this->battery_level_sensor_->publish_state((float) encode_uint16(it[10], it[11]) / 10);
157 }
158 break;
159
160 case DALY_REQUEST_MIN_MAX_VOLTAGE:
161 if (this->max_cell_voltage_sensor_) {
162 this->max_cell_voltage_sensor_->publish_state((float) encode_uint16(it[4], it[5]) / 1000);
163 }
164 if (this->max_cell_voltage_number_sensor_) {
165 this->max_cell_voltage_number_sensor_->publish_state(it[6]);
166 }
167 if (this->min_cell_voltage_sensor_) {
168 this->min_cell_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
169 }
170 if (this->min_cell_voltage_number_sensor_) {
171 this->min_cell_voltage_number_sensor_->publish_state(it[9]);
172 }
173 break;
174
175 case DALY_REQUEST_MIN_MAX_TEMPERATURE:
176 if (this->max_temperature_sensor_) {
177 this->max_temperature_sensor_->publish_state(it[4] - DALY_TEMPERATURE_OFFSET);
178 }
179 if (this->max_temperature_probe_number_sensor_) {
180 this->max_temperature_probe_number_sensor_->publish_state(it[5]);
181 }
182 if (this->min_temperature_sensor_) {
183 this->min_temperature_sensor_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET);
184 }
185 if (this->min_temperature_probe_number_sensor_) {
186 this->min_temperature_probe_number_sensor_->publish_state(it[7]);
187 }
188 break;
189#endif
190 case DALY_REQUEST_MOS:
191#ifdef USE_TEXT_SENSOR
192 if (this->status_text_sensor_ != nullptr) {
193 switch (it[4]) {
194 case 0:
195 this->status_text_sensor_->publish_state("Stationary");
196 break;
197 case 1:
198 this->status_text_sensor_->publish_state("Charging");
199 break;
200 case 2:
201 this->status_text_sensor_->publish_state("Discharging");
202 break;
203 default:
204 break;
205 }
206 }
207#endif
208#ifdef USE_BINARY_SENSOR
209 if (this->charging_mos_enabled_binary_sensor_) {
210 this->charging_mos_enabled_binary_sensor_->publish_state(it[5]);
211 }
212 if (this->discharging_mos_enabled_binary_sensor_) {
213 this->discharging_mos_enabled_binary_sensor_->publish_state(it[6]);
214 }
215#endif
216#ifdef USE_SENSOR
217 if (this->remaining_capacity_sensor_) {
218 this->remaining_capacity_sensor_->publish_state((float) encode_uint32(it[8], it[9], it[10], it[11]) /
219 1000);
220 }
221#endif
222 break;
223
224#ifdef USE_SENSOR
225 case DALY_REQUEST_STATUS:
226 if (this->cells_number_sensor_) {
227 this->cells_number_sensor_->publish_state(it[4]);
228 }
229 break;
230
231 case DALY_REQUEST_TEMPERATURE:
232 if (it[4] == 1) {
233 if (this->temperature_1_sensor_) {
234 this->temperature_1_sensor_->publish_state(it[5] - DALY_TEMPERATURE_OFFSET);
235 }
236 if (this->temperature_2_sensor_) {
237 this->temperature_2_sensor_->publish_state(it[6] - DALY_TEMPERATURE_OFFSET);
238 }
239 }
240 break;
241
242 case DALY_REQUEST_CELL_VOLTAGE:
243 switch (it[4]) {
244 case 1:
245 if (this->cell_1_voltage_sensor_) {
246 this->cell_1_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
247 }
248 if (this->cell_2_voltage_sensor_) {
249 this->cell_2_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
250 }
251 if (this->cell_3_voltage_sensor_) {
252 this->cell_3_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
253 }
254 break;
255 case 2:
256 if (this->cell_4_voltage_sensor_) {
257 this->cell_4_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
258 }
259 if (this->cell_5_voltage_sensor_) {
260 this->cell_5_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
261 }
262 if (this->cell_6_voltage_sensor_) {
263 this->cell_6_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
264 }
265 break;
266 case 3:
267 if (this->cell_7_voltage_sensor_) {
268 this->cell_7_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
269 }
270 if (this->cell_8_voltage_sensor_) {
271 this->cell_8_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
272 }
273 if (this->cell_9_voltage_sensor_) {
274 this->cell_9_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
275 }
276 break;
277 case 4:
278 if (this->cell_10_voltage_sensor_) {
279 this->cell_10_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
280 }
281 if (this->cell_11_voltage_sensor_) {
282 this->cell_11_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
283 }
284 if (this->cell_12_voltage_sensor_) {
285 this->cell_12_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
286 }
287 break;
288 case 5:
289 if (this->cell_13_voltage_sensor_) {
290 this->cell_13_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
291 }
292 if (this->cell_14_voltage_sensor_) {
293 this->cell_14_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
294 }
295 if (this->cell_15_voltage_sensor_) {
296 this->cell_15_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
297 }
298 break;
299 case 6:
300 if (this->cell_16_voltage_sensor_) {
301 this->cell_16_voltage_sensor_->publish_state((float) encode_uint16(it[5], it[6]) / 1000);
302 }
303 if (this->cell_17_voltage_sensor_) {
304 this->cell_17_voltage_sensor_->publish_state((float) encode_uint16(it[7], it[8]) / 1000);
305 }
306 if (this->cell_18_voltage_sensor_) {
307 this->cell_18_voltage_sensor_->publish_state((float) encode_uint16(it[9], it[10]) / 1000);
308 }
309 break;
310 }
311 break;
312#endif
313 default:
314 break;
315 }
316 } else {
317 ESP_LOGW(TAG, "Checksum-Error on Packet %x", it[4]);
318 }
319 std::advance(it, DALY_FRAME_SIZE);
320 } else {
321 std::advance(it, 1);
322 }
323 }
324}
325
326} // namespace daly_bms
327} // 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.
Definition component.cpp:54
std::vector< uint8_t > data_
Definition daly_bms.h:84
float get_setup_priority() const override
Definition daly_bms.cpp:107
void decode_data_(std::vector< uint8_t > data)
Definition daly_bms.cpp:133
void request_data_(uint8_t data_id)
Definition daly_bms.cpp:109
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
bool read_byte(uint8_t *data)
Definition uart.h:29
void write_array(const uint8_t *data, size_t len)
Definition uart.h:21
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:20
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:200
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:192
Application App
Global storage of Application pointer - only one Application can exist.