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