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