ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
ezo.cpp
Go to the documentation of this file.
1#include "ezo.h"
2#include "esphome/core/log.h"
3#include "esphome/core/hal.h"
4
5namespace esphome::ezo {
6
7static const char *const EZO_COMMAND_TYPE_STRINGS[] = {"EZO_READ", "EZO_LED", "EZO_DEVICE_INFORMATION",
8 "EZO_SLOPE", "EZO_CALIBRATION", "EZO_SLEEP",
9 "EZO_I2C", "EZO_T", "EZO_CUSTOM"};
10
11static const char *const EZO_CALIBRATION_TYPE_STRINGS[] = {"LOW", "MID", "HIGH"};
12
14 LOG_SENSOR("", "EZO", this);
15 LOG_I2C_DEVICE(this);
16 LOG_UPDATE_INTERVAL(this);
17}
18
20 // Check if a read is in there already and if not insert on in the second position
21
22 if (!this->commands_.empty() && this->commands_.front()->command_type != EzoCommandType::EZO_READ &&
23 this->commands_.size() > 1) {
24 bool found = false;
25
26 for (auto &i : this->commands_) {
27 if (i->command_type == EzoCommandType::EZO_READ) {
28 found = true;
29 break;
30 }
31 }
32
33 if (!found) {
34 auto ezo_command = make_unique<EzoCommand>();
35 ezo_command->command = "R";
36 ezo_command->command_type = EzoCommandType::EZO_READ;
37 ezo_command->delay_ms = 900;
38
39 auto it = this->commands_.begin();
40 ++it;
41 this->commands_.insert(it, std::move(ezo_command));
42 }
43
44 return;
45 }
46
47 this->get_state();
48}
49
51 if (this->commands_.empty()) {
52 return;
53 }
54
55 EzoCommand *to_run = this->commands_.front().get();
56
57 if (!to_run->command_sent) {
58 const uint8_t *data = reinterpret_cast<const uint8_t *>(to_run->command.c_str());
59 ESP_LOGVV(TAG, "Sending command \"%s\"", data);
60
61 this->write(data, to_run->command.length());
62
64 to_run->command_type == EzoCommandType::EZO_I2C) { // Commands with no return data
65 bool update_address = to_run->command_type == EzoCommandType::EZO_I2C;
66 this->commands_.pop_front();
67 if (update_address)
68 this->address_ = this->new_address_;
69 return;
70 }
71
72 this->start_time_ = millis();
73 to_run->command_sent = true;
74 return;
75 }
76
77 if (millis() - this->start_time_ < to_run->delay_ms)
78 return;
79
80 uint8_t buf[32];
81
82 buf[0] = 0;
83
84 if (!this->read_bytes_raw(buf, 32)) {
85 ESP_LOGE(TAG, "read error");
86 this->commands_.pop_front();
87 return;
88 }
89
90 switch (buf[0]) {
91 case 1:
92 break;
93 case 2:
94 ESP_LOGE(TAG, "device returned a syntax error");
95 break;
96 case 254:
97 return; // keep waiting
98 case 255:
99 ESP_LOGE(TAG, "device returned no data");
100 break;
101 default:
102 ESP_LOGE(TAG, "device returned an unknown response: %d", buf[0]);
103 break;
104 }
105
106 ESP_LOGV(TAG, "Received buffer \"%s\" for command type %s", &buf[1], EZO_COMMAND_TYPE_STRINGS[to_run->command_type]);
107
108 if (buf[0] == 1) {
109 std::string payload = reinterpret_cast<char *>(&buf[1]);
110 if (!payload.empty()) {
111 auto start_location = payload.find(',');
112 switch (to_run->command_type) {
114 // some sensors return multiple comma-separated values, terminate string after first one
115 if (start_location != std::string::npos) {
116 payload.erase(start_location);
117 }
118 auto val = parse_number<float>(payload);
119 if (!val.has_value()) {
120 ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
121 } else {
122 this->publish_state(*val);
123 }
124 break;
125 }
127 this->led_callback_.call(payload.back() == '1');
128 break;
130 if (start_location != std::string::npos) {
131 this->device_infomation_callback_.call(payload.substr(start_location + 1));
132 }
133 break;
135 if (start_location != std::string::npos) {
136 this->slope_callback_.call(payload.substr(start_location + 1));
137 }
138 break;
140 if (start_location != std::string::npos) {
141 this->calibration_callback_.call(payload.substr(start_location + 1));
142 }
143 break;
145 if (start_location != std::string::npos) {
146 this->t_callback_.call(payload.substr(start_location + 1));
147 }
148 break;
150 this->custom_callback_.call(payload);
151 break;
152 default:
153 break;
154 }
155 }
156 }
157 this->commands_.pop_front();
158}
159
160void EZOSensor::add_command_(const char *command, EzoCommandType command_type, uint16_t delay_ms) {
161 auto ezo_command = make_unique<EzoCommand>();
162 ezo_command->command = command;
163 ezo_command->command_type = command_type;
164 ezo_command->delay_ms = delay_ms;
165 this->commands_.push_back(std::move(ezo_command));
166}
167
169 // max 21: "Cal,"(4) + type(4) + ","(1) + float(11) + null; use 24 for safety
170 char payload[24];
171 snprintf(payload, sizeof(payload), "Cal,%s,%0.2f", EZO_CALIBRATION_TYPE_STRINGS[type], value);
173}
174
176 if (address > 0 && address < 128) {
177 // max 8: "I2C,"(4) + uint8(3) + null
178 char payload[8];
179 snprintf(payload, sizeof(payload), "I2C,%u", address);
180 this->new_address_ = address;
182 } else {
183 ESP_LOGE(TAG, "Invalid I2C address");
184 }
185}
186
188
190
192
194
196
197void EZOSensor::set_t(float value) {
198 // max 14 bytes: "T,"(2) + float with "%0.2f" (up to 11 chars) + null(1); use 16 for alignment
199 char payload[16];
200 snprintf(payload, sizeof(payload), "T,%0.2f", value);
201 this->add_command_(payload, EzoCommandType::EZO_T);
202}
203
204void EZOSensor::set_tempcomp_value(float temp) { this->set_t(temp); }
205
207
211
215
219
221 // exact 16 bytes: "Cal," (4) + float with "%0.2f" (up to 11 chars, e.g. "-9999999.99") + null (1) = 16
222 char payload[16];
223 snprintf(payload, sizeof(payload), "Cal,%0.2f", value);
225}
226
228
230
231void EZOSensor::set_led_state(bool on) { this->add_command_(on ? "L,1" : "L,0", EzoCommandType::EZO_LED); }
232
233void EZOSensor::send_custom(const std::string &to_send) {
234 this->add_command_(to_send.c_str(), EzoCommandType::EZO_CUSTOM);
235}
236
237} // namespace esphome::ezo
uint8_t address
Definition bl0906.h:4
void set_led_state(bool on)
Definition ezo.cpp:231
void set_address(uint8_t address)
Definition ezo.cpp:175
CallbackManager< void(std::string)> calibration_callback_
Definition ezo.h:96
void loop() override
Definition ezo.cpp:50
void set_calibration_point_mid(float value)
Definition ezo.cpp:212
void set_calibration_point_high(float value)
Definition ezo.cpp:216
void set_calibration_point_low(float value)
Definition ezo.cpp:208
void set_t(float value)
Definition ezo.cpp:197
CallbackManager< void(bool)> led_callback_
Definition ezo.h:100
void set_calibration_generic(float value)
Definition ezo.cpp:220
void set_tempcomp_value(float temp)
Definition ezo.cpp:204
void update() override
Definition ezo.cpp:19
void get_device_information()
Definition ezo.cpp:187
CallbackManager< void(std::string)> device_infomation_callback_
Definition ezo.h:95
uint32_t start_time_
Definition ezo.h:102
CallbackManager< void(std::string)> t_callback_
Definition ezo.h:98
void set_calibration_point_(EzoCalibrationType type, float value)
Definition ezo.cpp:168
CallbackManager< void(std::string)> slope_callback_
Definition ezo.h:97
std::deque< std::unique_ptr< EzoCommand > > commands_
Definition ezo.h:88
void send_custom(const std::string &to_send)
Definition ezo.cpp:233
CallbackManager< void(std::string)> custom_callback_
Definition ezo.h:99
void add_command_(const char *command, EzoCommandType command_type, uint16_t delay_ms=300)
Definition ezo.cpp:160
void dump_config() override
Definition ezo.cpp:13
EzoCommandType command_type
Definition ezo.h:32
std::string command
Definition ezo.h:29
ErrorCode write(const uint8_t *data, size_t len) const
writes an array of bytes to a device using an I2CBus
Definition i2c.h:195
optional< std::array< uint8_t, N > > read_bytes_raw()
Definition i2c.h:262
uint8_t address_
store the address of the device on the bus
Definition i2c.h:327
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
uint8_t type
mopeka_std_values val[3]
EzoCalibrationType
Definition ezo.h:25
@ EZO_CAL_MID
Definition ezo.h:25
@ EZO_CAL_HIGH
Definition ezo.h:25
@ EZO_CAL_LOW
Definition ezo.h:25
EzoCommandType
Definition ezo.h:13
@ EZO_SLOPE
Definition ezo.h:17
@ EZO_READ
Definition ezo.h:14
@ EZO_LED
Definition ezo.h:15
@ EZO_CUSTOM
Definition ezo.h:22
@ EZO_DEVICE_INFORMATION
Definition ezo.h:16
@ EZO_SLEEP
Definition ezo.h:19
@ EZO_CALIBRATION
Definition ezo.h:18
@ EZO_T
Definition ezo.h:21
@ EZO_I2C
Definition ezo.h:20
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
Definition helpers.h:1352
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:25