ESPHome  2022.12.8
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, EZO_COMMAND_TYPE_STRINGS[to_run->command_type]);
110 
111  if ((buf[0] == 1) || (to_run->command_type == EzoCommandType::EZO_CALIBRATION)) { // EZO_CALIBRATION returns 0-3
112  // some sensors return multiple comma-separated values, terminate string after first one
113  for (size_t i = 1; i < sizeof(buf) - 1; i++) {
114  if (buf[i] == ',') {
115  buf[i] = '\0';
116  break;
117  }
118  }
119  std::string payload = reinterpret_cast<char *>(&buf[1]);
120  if (!payload.empty()) {
121  switch (to_run->command_type) {
123  auto val = parse_number<float>(payload);
124  if (!val.has_value()) {
125  ESP_LOGW(TAG, "Can't convert '%s' to number!", payload.c_str());
126  } else {
127  this->publish_state(*val);
128  }
129  break;
130  }
132  this->led_callback_.call(payload.back() == '1');
133  break;
134  }
136  int start_location = 0;
137  if ((start_location = payload.find(',')) != std::string::npos) {
138  this->device_infomation_callback_.call(payload.substr(start_location + 1));
139  }
140  break;
141  }
143  int start_location = 0;
144  if ((start_location = payload.find(',')) != std::string::npos) {
145  this->slope_callback_.call(payload.substr(start_location + 1));
146  }
147  break;
148  }
150  int start_location = 0;
151  if ((start_location = payload.find(',')) != std::string::npos) {
152  this->calibration_callback_.call(payload.substr(start_location + 1));
153  }
154  break;
155  }
156  case EzoCommandType::EZO_T: {
157  this->t_callback_.call(payload);
158  break;
159  }
161  this->custom_callback_.call(payload);
162  break;
163  }
164  default: {
165  break;
166  }
167  }
168  }
169  }
170 
171  this->commands_.pop_front();
172 }
173 
174 void EZOSensor::add_command_(const std::string &command, EzoCommandType command_type, uint16_t delay_ms) {
175  std::unique_ptr<EzoCommand> ezo_command(new EzoCommand);
176  ezo_command->command = command;
177  ezo_command->command_type = command_type;
178  ezo_command->delay_ms = delay_ms;
179  this->commands_.push_back(std::move(ezo_command));
180 };
181 
183  std::string payload = str_sprintf("Cal,%s,%0.2f", EZO_CALIBRATION_TYPE_STRINGS[type], value);
184  this->add_command_(payload, EzoCommandType::EZO_CALIBRATION, 900);
185 }
186 
187 void EZOSensor::set_address(uint8_t address) {
188  if (address > 0 && address < 128) {
189  std::string payload = str_sprintf("I2C,%u", address);
190  this->new_address_ = address;
191  this->add_command_(payload, EzoCommandType::EZO_I2C);
192  } else {
193  ESP_LOGE(TAG, "Invalid I2C address");
194  }
195 }
196 
198 
200 
202 
204 
206 
207 void EZOSensor::set_t(float value) {
208  std::string payload = str_sprintf("T,%0.2f", value);
209  this->add_command_(payload, EzoCommandType::EZO_T);
210 }
211 
212 void EZOSensor::set_tempcomp_value(float temp) { this->set_t(temp); }
213 
215 
218 }
219 
222 }
223 
226 }
227 
229  std::string payload = str_sprintf("Cal,%0.2f", value);
230  this->add_command_(payload, EzoCommandType::EZO_CALIBRATION, 900);
231 }
232 
234 
236 
238  std::string to_send = "L,";
239  to_send += on ? "1" : "0";
240  this->add_command_(to_send, EzoCommandType::EZO_LED);
241 }
242 
243 void EZOSensor::send_custom(const std::string &to_send) { this->add_command_(to_send, EzoCommandType::EZO_CUSTOM); }
244 
245 } // namespace ezo
246 } // namespace esphome
void set_calibration_generic(float value)
Definition: ezo.cpp:228
void loop() override
Definition: ezo.cpp:54
void get_device_information()
Definition: ezo.cpp:197
void set_address(uint8_t address)
Definition: ezo.cpp:187
EzoCommandType command_type
Definition: ezo.h:32
void set_calibration_point_low(float value)
Definition: ezo.cpp:216
std::string command
Definition: ezo.h:29
optional< std::array< uint8_t, N > > read_bytes_raw()
Definition: i2c.h:80
void send_custom(const std::string &to_send)
Definition: ezo.cpp:243
void set_calibration_point_(EzoCalibrationType type, float value)
Definition: ezo.cpp:182
CallbackManager< void(std::string)> device_infomation_callback_
Definition: ezo.h:100
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
CallbackManager< void(std::string)> slope_callback_
Definition: ezo.h:102
void set_calibration_point_high(float value)
Definition: ezo.cpp:224
std::string str_sprintf(const char *fmt,...)
Definition: helpers.cpp:188
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:72
ErrorCode write(const uint8_t *data, uint8_t len, bool stop=true)
Definition: i2c.h:56
uint8_t type
uint32_t start_time_
Definition: ezo.h:107
void set_t(float value)
Definition: ezo.cpp:207
void set_calibration_point_mid(float value)
Definition: ezo.cpp:220
void set_tempcomp_value(float temp)
Definition: ezo.cpp:212
CallbackManager< void(std::string)> custom_callback_
Definition: ezo.h:104
uint8_t address_
Definition: i2c.h:130
void add_command_(const std::string &command, EzoCommandType command_type, uint16_t delay_ms=300)
Definition: ezo.cpp:174
CallbackManager< void(std::string)> calibration_callback_
Definition: ezo.h:101
void update() override
Definition: ezo.cpp:23
Definition: a4988.cpp:4
EzoCalibrationType
Definition: ezo.h:25
void get_calibration()
Definition: ezo.cpp:214
uint32_t val
Definition: datatypes.h:85
void dump_config() override
Definition: ezo.cpp:14
void clear_calibration()
Definition: ezo.cpp:233
void set_led_state(bool on)
Definition: ezo.cpp:237
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