8 static const char *
const TAG =
"ezo-pmp";
10 static const uint16_t EZO_PMP_COMMAND_NONE = 0;
11 static const uint16_t EZO_PMP_COMMAND_TYPE_READ = 1;
13 static const uint16_t EZO_PMP_COMMAND_FIND = 2;
14 static const uint16_t EZO_PMP_COMMAND_DOSE_CONTINUOUSLY = 4;
15 static const uint16_t EZO_PMP_COMMAND_DOSE_VOLUME = 8;
16 static const uint16_t EZO_PMP_COMMAND_DOSE_VOLUME_OVER_TIME = 16;
17 static const uint16_t EZO_PMP_COMMAND_DOSE_WITH_CONSTANT_FLOW_RATE = 32;
18 static const uint16_t EZO_PMP_COMMAND_SET_CALIBRATION_VOLUME = 64;
19 static const uint16_t EZO_PMP_COMMAND_CLEAR_TOTAL_VOLUME_DOSED = 128;
20 static const uint16_t EZO_PMP_COMMAND_CLEAR_CALIBRATION = 256;
21 static const uint16_t EZO_PMP_COMMAND_PAUSE_DOSING = 512;
22 static const uint16_t EZO_PMP_COMMAND_STOP_DOSING = 1024;
23 static const uint16_t EZO_PMP_COMMAND_CHANGE_I2C_ADDRESS = 2048;
24 static const uint16_t EZO_PMP_COMMAND_EXEC_ARBITRARY_COMMAND_ADDRESS = 4096;
26 static const uint16_t EZO_PMP_COMMAND_READ_DOSING = 3;
27 static const uint16_t EZO_PMP_COMMAND_READ_SINGLE_REPORT = 5;
28 static const uint16_t EZO_PMP_COMMAND_READ_MAX_FLOW_RATE = 9;
29 static const uint16_t EZO_PMP_COMMAND_READ_PAUSE_STATUS = 17;
30 static const uint16_t EZO_PMP_COMMAND_READ_TOTAL_VOLUME_DOSED = 33;
31 static const uint16_t EZO_PMP_COMMAND_READ_ABSOLUTE_TOTAL_VOLUME_DOSED = 65;
32 static const uint16_t EZO_PMP_COMMAND_READ_CALIBRATION_STATUS = 129;
33 static const uint16_t EZO_PMP_COMMAND_READ_PUMP_VOLTAGE = 257;
35 static const std::string DOSING_MODE_NONE =
"None";
36 static const std::string DOSING_MODE_VOLUME =
"Volume";
37 static const std::string DOSING_MODE_VOLUME_OVER_TIME =
"Volume/Time";
38 static const std::string DOSING_MODE_CONSTANT_FLOW_RATE =
"Constant Flow Rate";
39 static const std::string DOSING_MODE_CONTINUOUS =
"Continuous";
44 ESP_LOGE(TAG,
"Communication with EZO-PMP circuit failed!");
46 LOG_UPDATE_INTERVAL(
this);
59 this->
queue_command_(EZO_PMP_COMMAND_READ_ABSOLUTE_TOTAL_VOLUME_DOSED, 0, 0,
61 this->
queue_command_(EZO_PMP_COMMAND_READ_PAUSE_STATUS, 0, 0,
true);
71 this->
queue_command_(EZO_PMP_COMMAND_READ_ABSOLUTE_TOTAL_VOLUME_DOSED, 0, 0,
77 ESP_LOGV(TAG,
"Not Scheduling new Command during update()");
107 uint8_t response_buffer[21] = {
'\0'};
109 response_buffer[0] = 0;
111 ESP_LOGE(TAG,
"read error");
116 switch (response_buffer[0]) {
122 ESP_LOGE(TAG,
"device returned a syntax error");
126 ESP_LOGE(TAG,
"device returned no data");
130 ESP_LOGE(TAG,
"device returned an unknown response: %d", response_buffer[0]);
135 char first_parameter_buffer[10] = {
'\0'};
136 char second_parameter_buffer[10] = {
'\0'};
137 char third_parameter_buffer[10] = {
'\0'};
139 first_parameter_buffer[0] =
'\0';
140 second_parameter_buffer[0] =
'\0';
141 third_parameter_buffer[0] =
'\0';
143 int current_parameter = 1;
145 size_t position_in_parameter_buffer = 0;
147 for (
size_t i = 1; i <
sizeof(response_buffer) - 1; i++) {
148 char current_char = response_buffer[i];
150 if (current_char ==
'\0') {
151 ESP_LOGV(TAG,
"Read Response from device: %s", (
char *) response_buffer);
152 ESP_LOGV(TAG,
"First Component: %s", (
char *) first_parameter_buffer);
153 ESP_LOGV(TAG,
"Second Component: %s", (
char *) second_parameter_buffer);
154 ESP_LOGV(TAG,
"Third Component: %s", (
char *) third_parameter_buffer);
159 if (current_char ==
',') {
161 position_in_parameter_buffer = 0;
165 switch (current_parameter) {
167 first_parameter_buffer[position_in_parameter_buffer] = current_char;
168 first_parameter_buffer[position_in_parameter_buffer + 1] =
'\0';
171 second_parameter_buffer[position_in_parameter_buffer] = current_char;
172 second_parameter_buffer[position_in_parameter_buffer + 1] =
'\0';
175 third_parameter_buffer[position_in_parameter_buffer] = current_char;
176 third_parameter_buffer[position_in_parameter_buffer + 1] =
'\0';
180 position_in_parameter_buffer++;
183 auto parsed_first_parameter = parse_number<float>(first_parameter_buffer);
184 auto parsed_second_parameter = parse_number<float>(second_parameter_buffer);
185 auto parsed_third_parameter = parse_number<float>(third_parameter_buffer);
189 case EZO_PMP_COMMAND_READ_DOSING:
190 if (parsed_third_parameter.has_value())
208 case EZO_PMP_COMMAND_READ_SINGLE_REPORT:
214 case EZO_PMP_COMMAND_READ_MAX_FLOW_RATE:
219 case EZO_PMP_COMMAND_READ_PAUSE_STATUS:
220 if (parsed_second_parameter.has_value())
227 case EZO_PMP_COMMAND_READ_TOTAL_VOLUME_DOSED:
232 case EZO_PMP_COMMAND_READ_ABSOLUTE_TOTAL_VOLUME_DOSED:
237 case EZO_PMP_COMMAND_READ_CALIBRATION_STATUS:
239 if (parsed_second_parameter.value_or(0) == 1) {
241 }
else if (parsed_second_parameter.value_or(0) == 2) {
243 }
else if (parsed_second_parameter.value_or(0) == 3) {
251 case EZO_PMP_COMMAND_READ_PUMP_VOLTAGE:
252 if (parsed_second_parameter.has_value() && this->
pump_voltage_)
258 case EZO_PMP_COMMAND_DOSE_VOLUME:
263 case EZO_PMP_COMMAND_DOSE_VOLUME_OVER_TIME:
268 case EZO_PMP_COMMAND_DOSE_WITH_CONSTANT_FLOW_RATE:
273 case EZO_PMP_COMMAND_DOSE_CONTINUOUSLY:
278 case EZO_PMP_COMMAND_STOP_DOSING:
286 case EZO_PMP_COMMAND_EXEC_ARBITRARY_COMMAND_ADDRESS:
287 ESP_LOGI(TAG,
"Arbitrary Command Response: %s", (
char *) response_buffer);
290 case EZO_PMP_COMMAND_CLEAR_CALIBRATION:
291 case EZO_PMP_COMMAND_PAUSE_DOSING:
292 case EZO_PMP_COMMAND_SET_CALIBRATION_VOLUME:
293 case EZO_PMP_COMMAND_CLEAR_TOTAL_VOLUME_DOSED:
294 case EZO_PMP_COMMAND_FIND:
298 case EZO_PMP_COMMAND_TYPE_READ:
299 case EZO_PMP_COMMAND_NONE:
309 int wait_time_for_command = 400;
310 uint8_t command_buffer[21];
311 int command_buffer_length = 0;
317 case EZO_PMP_COMMAND_READ_DOSING:
318 command_buffer_length = sprintf((
char *) command_buffer,
"D,?");
321 case EZO_PMP_COMMAND_READ_SINGLE_REPORT:
322 command_buffer_length = sprintf((
char *) command_buffer,
"R");
325 case EZO_PMP_COMMAND_READ_MAX_FLOW_RATE:
326 command_buffer_length = sprintf((
char *) command_buffer,
"DC,?");
329 case EZO_PMP_COMMAND_READ_PAUSE_STATUS:
330 command_buffer_length = sprintf((
char *) command_buffer,
"P,?");
333 case EZO_PMP_COMMAND_READ_TOTAL_VOLUME_DOSED:
334 command_buffer_length = sprintf((
char *) command_buffer,
"TV,?");
337 case EZO_PMP_COMMAND_READ_ABSOLUTE_TOTAL_VOLUME_DOSED:
338 command_buffer_length = sprintf((
char *) command_buffer,
"ATV,?");
341 case EZO_PMP_COMMAND_READ_CALIBRATION_STATUS:
342 command_buffer_length = sprintf((
char *) command_buffer,
"Cal,?");
345 case EZO_PMP_COMMAND_READ_PUMP_VOLTAGE:
346 command_buffer_length = sprintf((
char *) command_buffer,
"PV,?");
351 case EZO_PMP_COMMAND_FIND:
352 command_buffer_length = sprintf((
char *) command_buffer,
"Find");
353 wait_time_for_command = 60000;
356 case EZO_PMP_COMMAND_DOSE_CONTINUOUSLY:
357 command_buffer_length = sprintf((
char *) command_buffer,
"D,*");
360 case EZO_PMP_COMMAND_CLEAR_TOTAL_VOLUME_DOSED:
361 command_buffer_length = sprintf((
char *) command_buffer,
"Clear");
364 case EZO_PMP_COMMAND_CLEAR_CALIBRATION:
365 command_buffer_length = sprintf((
char *) command_buffer,
"Cal,clear");
368 case EZO_PMP_COMMAND_PAUSE_DOSING:
369 command_buffer_length = sprintf((
char *) command_buffer,
"P");
372 case EZO_PMP_COMMAND_STOP_DOSING:
373 command_buffer_length = sprintf((
char *) command_buffer,
"X");
378 case EZO_PMP_COMMAND_DOSE_VOLUME:
379 command_buffer_length = sprintf((
char *) command_buffer,
"D,%0.1f", this->
next_command_volume_);
382 case EZO_PMP_COMMAND_DOSE_VOLUME_OVER_TIME:
383 command_buffer_length =
387 case EZO_PMP_COMMAND_DOSE_WITH_CONSTANT_FLOW_RATE:
388 command_buffer_length =
392 case EZO_PMP_COMMAND_SET_CALIBRATION_VOLUME:
393 command_buffer_length = sprintf((
char *) command_buffer,
"Cal,%0.2f", this->
next_command_volume_);
396 case EZO_PMP_COMMAND_CHANGE_I2C_ADDRESS:
400 case EZO_PMP_COMMAND_EXEC_ARBITRARY_COMMAND_ADDRESS:
402 ESP_LOGI(TAG,
"Sending arbitrary command: %s", (
char *) command_buffer);
405 case EZO_PMP_COMMAND_TYPE_READ:
406 case EZO_PMP_COMMAND_NONE:
408 ESP_LOGE(TAG,
"Unsupported command received: %d", this->
next_command_);
413 ESP_LOGV(TAG,
"Sending command to device: %s", (
char *) command_buffer);
414 this->
write(command_buffer, command_buffer_length);
425 ESP_LOGE(TAG,
"Tried to dequeue command from empty queue");
448 return EZO_PMP_COMMAND_NONE;
455 if (!should_schedule) {
460 ESP_LOGE(TAG,
"Tried to queue command '%d' but queue is full", command);
484 this->
queue_command_(EZO_PMP_COMMAND_DOSE_CONTINUOUSLY, 0, 0,
true);
490 this->
queue_command_(EZO_PMP_COMMAND_DOSE_VOLUME, volume, 0,
true);
496 this->
queue_command_(EZO_PMP_COMMAND_DOSE_VOLUME_OVER_TIME, volume, duration,
true);
502 this->
queue_command_(EZO_PMP_COMMAND_DOSE_WITH_CONSTANT_FLOW_RATE, volume, duration,
true);
508 this->
queue_command_(EZO_PMP_COMMAND_SET_CALIBRATION_VOLUME, volume, 0,
true);
509 this->
queue_command_(EZO_PMP_COMMAND_READ_CALIBRATION_STATUS, 0, 0,
true);
510 this->
queue_command_(EZO_PMP_COMMAND_READ_MAX_FLOW_RATE, 0, 0,
true);
514 this->
queue_command_(EZO_PMP_COMMAND_CLEAR_TOTAL_VOLUME_DOSED, 0, 0,
true);
515 this->
queue_command_(EZO_PMP_COMMAND_READ_SINGLE_REPORT, 0, 0,
true);
516 this->
queue_command_(EZO_PMP_COMMAND_READ_TOTAL_VOLUME_DOSED, 0, 0,
true);
517 this->
queue_command_(EZO_PMP_COMMAND_READ_ABSOLUTE_TOTAL_VOLUME_DOSED, 0, 0,
true);
521 this->
queue_command_(EZO_PMP_COMMAND_CLEAR_CALIBRATION, 0, 0,
true);
522 this->
queue_command_(EZO_PMP_COMMAND_READ_CALIBRATION_STATUS, 0, 0,
true);
523 this->
queue_command_(EZO_PMP_COMMAND_READ_MAX_FLOW_RATE, 0, 0,
true);
528 this->
queue_command_(EZO_PMP_COMMAND_READ_PAUSE_STATUS, 0, 0,
true);
534 this->
queue_command_(EZO_PMP_COMMAND_CHANGE_I2C_ADDRESS, 0, address,
true);
539 this->
queue_command_(EZO_PMP_COMMAND_EXEC_ARBITRARY_COMMAND_ADDRESS, 0, 0,
true);
uint16_t peek_next_command_()
double next_command_volume_queue_[10]
int next_command_queue_head_
sensor::Sensor * absolute_total_volume_dosed_
int next_command_duration_queue_[10]
uint16_t current_command_
optional< std::array< uint8_t, N > > read_bytes_raw()
sensor::Sensor * last_volume_requested_
void clear_total_volume_dosed()
void change_i2c_address(int address)
void clear_current_command_()
text_sensor::TextSensor * dosing_mode_
binary_sensor::BinarySensor * is_paused_
void publish_state(const std::string &state)
sensor::Sensor * total_volume_dosed_
int next_command_duration_
const char * arbitrary_command_
void exec_arbitrary_command(const std::basic_string< char > &command)
uint32_t IRAM_ATTR HOT millis()
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
text_sensor::TextSensor * calibration_status_
void queue_command_(uint16_t command, double volume, int duration, bool should_schedule)
void publish_state(float state)
Publish a new state to the front-end.
void publish_state(bool state)
Publish a new state to the front-end.
void dose_volume_over_time(double volume, int duration)
void dose_volume(double volume)
void dose_with_constant_flow_rate(double volume, int duration)
sensor::Sensor * pump_voltage_
void set_calibration_volume(double volume)
void read_command_result_()
int next_command_queue_last_
uint16_t next_command_queue_[10]
Implementation of SPI Controller mode.
sensor::Sensor * current_volume_dosed_
binary_sensor::BinarySensor * is_dosing_
void send_next_command_()
void dump_config() override
int next_command_queue_length_
sensor::Sensor * max_flow_rate_
double next_command_volume_