ESPHome  2024.12.2
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 
5 namespace esphome {
6 namespace ezo {
7 
8 static 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 
12 static 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, "Communication with EZO circuit failed!");
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 
67  if (to_run->command_type == EzoCommandType::EZO_SLEEP ||
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 
163 void EZOSensor::add_command_(const std::string &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  std::string payload = str_sprintf("Cal,%s,%0.2f", EZO_CALIBRATION_TYPE_STRINGS[type], value);
173  this->add_command_(payload, EzoCommandType::EZO_CALIBRATION, 900);
174 }
175 
177  if (address > 0 && address < 128) {
178  std::string payload = str_sprintf("I2C,%u", address);
179  this->new_address_ = address;
180  this->add_command_(payload, EzoCommandType::EZO_I2C);
181  } else {
182  ESP_LOGE(TAG, "Invalid I2C address");
183  }
184 }
185 
187 
189 
191 
193 
195 
196 void EZOSensor::set_t(float value) {
197  std::string payload = str_sprintf("T,%0.2f", value);
198  this->add_command_(payload, EzoCommandType::EZO_T);
199 }
200 
201 void EZOSensor::set_tempcomp_value(float temp) { this->set_t(temp); }
202 
204 
207 }
208 
211 }
212 
215 }
216 
218  std::string payload = str_sprintf("Cal,%0.2f", value);
219  this->add_command_(payload, EzoCommandType::EZO_CALIBRATION, 900);
220 }
221 
223 
225 
227  std::string to_send = "L,";
228  to_send += on ? "1" : "0";
229  this->add_command_(to_send, EzoCommandType::EZO_LED);
230 }
231 
232 void EZOSensor::send_custom(const std::string &to_send) { this->add_command_(to_send, EzoCommandType::EZO_CUSTOM); }
233 
234 } // namespace ezo
235 } // namespace esphome
void set_calibration_generic(float value)
Definition: ezo.cpp:217
void loop() override
Definition: ezo.cpp:54
void get_device_information()
Definition: ezo.cpp:186
void set_address(uint8_t address)
Definition: ezo.cpp:176
EzoCommandType command_type
Definition: ezo.h:32
void set_calibration_point_low(float value)
Definition: ezo.cpp:205
std::string command
Definition: ezo.h:29
bool is_failed() const
Definition: component.cpp:143
optional< std::array< uint8_t, N > > read_bytes_raw()
Definition: i2c.h:225
mopeka_std_values val[4]
void send_custom(const std::string &to_send)
Definition: ezo.cpp:232
void set_calibration_point_(EzoCalibrationType type, float value)
Definition: ezo.cpp:171
CallbackManager< void(std::string)> device_infomation_callback_
Definition: ezo.h:100
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
Definition: i2c.h:186
CallbackManager< void(std::string)> slope_callback_
Definition: ezo.h:102
void set_calibration_point_high(float value)
Definition: ezo.cpp:213
std::string str_sprintf(const char *fmt,...)
Definition: helpers.cpp:320
CallbackManager< void(std::string)> t_callback_
Definition: ezo.h:103
void publish_state(float state)
Publish a new state to the front-end.
Definition: sensor.cpp:39
uint8_t type
uint32_t start_time_
Definition: ezo.h:107
void set_t(float value)
Definition: ezo.cpp:196
void set_calibration_point_mid(float value)
Definition: ezo.cpp:209
void set_tempcomp_value(float temp)
Definition: ezo.cpp:201
CallbackManager< void(std::string)> custom_callback_
Definition: ezo.h:104
uint8_t address_
store the address of the device on the bus
Definition: i2c.h:269
void add_command_(const std::string &command, EzoCommandType command_type, uint16_t delay_ms=300)
Definition: ezo.cpp:163
CallbackManager< void(std::string)> calibration_callback_
Definition: ezo.h:101
void update() override
Definition: ezo.cpp:23
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
EzoCalibrationType
Definition: ezo.h:25
uint8_t address
Definition: bl0906.h:211
void get_calibration()
Definition: ezo.cpp:203
void dump_config() override
Definition: ezo.cpp:14
void clear_calibration()
Definition: ezo.cpp:222
void set_led_state(bool on)
Definition: ezo.cpp:226
std::deque< std::unique_ptr< EzoCommand > > commands_
Definition: ezo.h:93
CallbackManager< void(bool)> led_callback_
Definition: ezo.h:105
EzoCommandType
Definition: ezo.h:13