ESPHome 2026.3.0
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 bool update_address = to_run->command_type == EzoCommandType::EZO_I2C;
70 this->commands_.pop_front();
71 if (update_address)
72 this->address_ = this->new_address_;
73 return;
74 }
75
76 this->start_time_ = millis();
77 to_run->command_sent = true;
78 return;
79 }
80
81 if (millis() - this->start_time_ < to_run->delay_ms)
82 return;
83
84 uint8_t buf[32];
85
86 buf[0] = 0;
87
88 if (!this->read_bytes_raw(buf, 32)) {
89 ESP_LOGE(TAG, "read error");
90 this->commands_.pop_front();
91 return;
92 }
93
94 switch (buf[0]) {
95 case 1:
96 break;
97 case 2:
98 ESP_LOGE(TAG, "device returned a syntax error");
99 break;
100 case 254:
101 return; // keep waiting
102 case 255:
103 ESP_LOGE(TAG, "device returned no data");
104 break;
105 default:
106 ESP_LOGE(TAG, "device returned an unknown response: %d", buf[0]);
107 break;
108 }
109
110 ESP_LOGV(TAG, "Received buffer \"%s\" for command type %s", &buf[1], EZO_COMMAND_TYPE_STRINGS[to_run->command_type]);
111
112 if (buf[0] == 1) {
113 std::string payload = reinterpret_cast<char *>(&buf[1]);
114 if (!payload.empty()) {
115 auto start_location = payload.find(',');
116 switch (to_run->command_type) {
118 // some sensors return multiple comma-separated values, terminate string after first one
119 if (start_location != std::string::npos) {
120 payload.erase(start_location);
121 }
122 auto val = parse_number<float>(payload);
123 if (!val.has_value()) {
124 ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
125 } else {
126 this->publish_state(*val);
127 }
128 break;
129 }
131 this->led_callback_.call(payload.back() == '1');
132 break;
134 if (start_location != std::string::npos) {
135 this->device_infomation_callback_.call(payload.substr(start_location + 1));
136 }
137 break;
139 if (start_location != std::string::npos) {
140 this->slope_callback_.call(payload.substr(start_location + 1));
141 }
142 break;
144 if (start_location != std::string::npos) {
145 this->calibration_callback_.call(payload.substr(start_location + 1));
146 }
147 break;
149 if (start_location != std::string::npos) {
150 this->t_callback_.call(payload.substr(start_location + 1));
151 }
152 break;
154 this->custom_callback_.call(payload);
155 break;
156 default:
157 break;
158 }
159 }
160 }
161 this->commands_.pop_front();
162}
163
164void EZOSensor::add_command_(const char *command, EzoCommandType command_type, uint16_t delay_ms) {
165 std::unique_ptr<EzoCommand> ezo_command(new EzoCommand);
166 ezo_command->command = command;
167 ezo_command->command_type = command_type;
168 ezo_command->delay_ms = delay_ms;
169 this->commands_.push_back(std::move(ezo_command));
170}
171
173 // max 21: "Cal,"(4) + type(4) + ","(1) + float(11) + null; use 24 for safety
174 char payload[24];
175 snprintf(payload, sizeof(payload), "Cal,%s,%0.2f", EZO_CALIBRATION_TYPE_STRINGS[type], value);
177}
178
180 if (address > 0 && address < 128) {
181 // max 8: "I2C,"(4) + uint8(3) + null
182 char payload[8];
183 snprintf(payload, sizeof(payload), "I2C,%u", address);
184 this->new_address_ = address;
186 } else {
187 ESP_LOGE(TAG, "Invalid I2C address");
188 }
189}
190
192
194
196
198
200
201void EZOSensor::set_t(float value) {
202 // max 14 bytes: "T,"(2) + float with "%0.2f" (up to 11 chars) + null(1); use 16 for alignment
203 char payload[16];
204 snprintf(payload, sizeof(payload), "T,%0.2f", value);
205 this->add_command_(payload, EzoCommandType::EZO_T);
206}
207
208void EZOSensor::set_tempcomp_value(float temp) { this->set_t(temp); }
209
211
215
219
223
225 // exact 16 bytes: "Cal," (4) + float with "%0.2f" (up to 11 chars, e.g. "-9999999.99") + null (1) = 16
226 char payload[16];
227 snprintf(payload, sizeof(payload), "Cal,%0.2f", value);
229}
230
232
234
235void EZOSensor::set_led_state(bool on) { this->add_command_(on ? "L,1" : "L,0", EzoCommandType::EZO_LED); }
236
237void EZOSensor::send_custom(const std::string &to_send) {
238 this->add_command_(to_send.c_str(), EzoCommandType::EZO_CUSTOM);
239}
240
241} // namespace ezo
242} // namespace esphome
uint8_t address
Definition bl0906.h:4
bool is_failed() const
Definition component.h:233
void set_led_state(bool on)
Definition ezo.cpp:235
void set_address(uint8_t address)
Definition ezo.cpp:179
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:216
void set_calibration_point_high(float value)
Definition ezo.cpp:220
void set_calibration_point_low(float value)
Definition ezo.cpp:212
void set_t(float value)
Definition ezo.cpp:201
CallbackManager< void(bool)> led_callback_
Definition ezo.h:104
void set_calibration_generic(float value)
Definition ezo.cpp:224
void set_tempcomp_value(float temp)
Definition ezo.cpp:208
void update() override
Definition ezo.cpp:23
void get_device_information()
Definition ezo.cpp:191
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:172
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:237
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:164
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[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
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:1007
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:26