Changed chlorine-pump to use the Ezo Orp module by AtlasScientific using I2C.
This module is by miles more accurate than any analog crap we could have come up with... Not that the last idea was anything to scoff at I guess
This commit is contained in:
176
external_components/ezo_orp_i2c/ezo_orp.cpp
Normal file
176
external_components/ezo_orp_i2c/ezo_orp.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "ezo_orp.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ezo_orp_i2c {
|
||||
|
||||
static const char *const TAG = "ezo_orp_i2c.sensor";
|
||||
|
||||
static const uint8_t COMMAND_READ[] = {0x52}; // R
|
||||
static const uint8_t COMMAND_PERFERM_CALIBRATION[] = {0x43, 0x61, 0x6C}; //Cal
|
||||
static const uint8_t COMMAND_IS_CALIBRATED[] = {0x43, 0x61, 0x6C, 0x2C, 0x3F}; //Cal
|
||||
static const uint8_t COMMAND_EXPORT_CALIBRATION[] = {0x45, 0x78, 0x70, 0x6F, 0x72, 0x74}; // Export
|
||||
static const uint8_t COMMAND_INFORMATION[] = {0x69}; // i (DON'T ASK ME WHY THAT IS ONLY A SMALL LETTER
|
||||
static const uint8_t COMMAND_STATUS[] = {0x53, 0x74, 0x61, 0x74, 0x75, 0x73}; // STATUS
|
||||
|
||||
static const uint8_t COMMAND_FACTORY_RESET[] = {0x46, 0x61, 0x63, 0x74, 0x6F, 0x72, 0x79}; // Factory
|
||||
|
||||
static const uint8_t COMMMAND_TO_ARGS_SEPERATOR = {0x2C};
|
||||
|
||||
static const int PROCESSING_DELAY_MS = 300; // FOR SOME OPERATIONS
|
||||
static const int READING_DELAY_MS = 900; // FOR BASICALLY EVERYTHING WHERE LARGE DATA IS READ/SENT
|
||||
|
||||
|
||||
void EzoOrpSensor::setup(){
|
||||
ESP_LOGCONFIG(TAG, "Setting up EzoOrpI2C '%s'...", this->get_name().c_str());
|
||||
ESP_LOGCONFIG(TAG, "EzoOrpI2C '%s' setup finished!", this->get_name().c_str());
|
||||
scheduleNextAction(SensorAction::IS_CALIBRATED, nullptr, 0, 450);
|
||||
}
|
||||
|
||||
void EzoOrpSensor::update() {
|
||||
scheduleNextAction(SensorAction::READ, nullptr, 0, 900);
|
||||
}
|
||||
|
||||
void EzoOrpSensor::read_response(int maxLength, SensorAction action) {
|
||||
uint8_t data[maxLength];
|
||||
|
||||
if(SensorAction::CALIBRATE == action){
|
||||
ESP_LOGD(TAG, "Device Calibrated");
|
||||
busy_ = false;
|
||||
runScheduledAction();
|
||||
return;
|
||||
}
|
||||
|
||||
if(i2c::ERROR_OK != this->read(data, maxLength)){
|
||||
ESP_LOGW(TAG, "Error Occured while reading respnse!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(data[0] != 1 && data[0] != 255){
|
||||
ESP_LOGW(TAG, "Read status code of %d, (Operation: %d)", data[0], action);
|
||||
return;
|
||||
}
|
||||
|
||||
if(SensorAction::READ == action){
|
||||
float value;
|
||||
sscanf((const char*) &data[1], "%f", &value);
|
||||
this->publish_state(value);
|
||||
}
|
||||
else if(SensorAction::IS_CALIBRATED == action){
|
||||
ESP_LOGD(TAG, "%s", data[6] == 0x31 ? "Device has been calibrated" : "Device has NOT been calibrated");
|
||||
}
|
||||
else if(SensorAction::INFORMATION == action){
|
||||
ESP_LOGD(TAG, "Device Printed the following information: %s", &data[1]);
|
||||
}
|
||||
|
||||
busy_ = false;
|
||||
|
||||
runScheduledAction();
|
||||
}
|
||||
|
||||
void EzoOrpSensor::calibrate_to_target(int target){
|
||||
char targetArray[3];
|
||||
sprintf(targetArray, "%d", target);
|
||||
ESP_LOGD(TAG, "Calibrating to: %3s", targetArray);
|
||||
scheduleNextAction(SensorAction::CALIBRATE, (uint8_t*) &targetArray, 3, 4000);
|
||||
|
||||
}
|
||||
|
||||
float EzoOrpSensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
void EzoOrpSensor::dump_config(){
|
||||
LOG_SENSOR("", "EzoOrpI2C Sensor", this);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
LOG_I2C_DEVICE(this);
|
||||
}
|
||||
|
||||
bool EzoOrpSensor::is_busy(){
|
||||
return this->busy_;
|
||||
}
|
||||
|
||||
void EzoOrpSensor::runScheduledAction(){
|
||||
if(scheduledAction_ == SensorAction::NOTHING) return;
|
||||
scheduleNextAction(scheduledAction_, scheduledActionData_, scheduledActionDataSize_, scheduledActionTime_);
|
||||
scheduledAction_ = SensorAction::NOTHING;
|
||||
scheduledActionDataSize_ = 0;
|
||||
}
|
||||
|
||||
void EzoOrpSensor::scheduleNextAction(SensorAction action, uint8_t* data, int size, int expected_response_time){
|
||||
if(busy_){
|
||||
if(scheduledAction_ == action) return; // Queued Action cannot has no need of being repeated;
|
||||
if(scheduledAction_ != SensorAction::NOTHING) return; // Ehh... Felt better lol
|
||||
|
||||
scheduledAction_ = action;
|
||||
if(data != nullptr){
|
||||
for(int i = 0;i < size; ++i){
|
||||
scheduledActionData_[i] = data[i];
|
||||
}
|
||||
}
|
||||
scheduledActionDataSize_ = size;
|
||||
scheduledActionTime_ = expected_response_time;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(action){
|
||||
case SensorAction::NOTHING:
|
||||
return;
|
||||
case SensorAction::READ:
|
||||
busy_ = true;
|
||||
send_command(COMMAND_READ, sizeof(COMMAND_READ));
|
||||
this->set_timeout(expected_response_time, [this](){ this->read_response(9, SensorAction::READ); });
|
||||
break;
|
||||
case SensorAction::CALIBRATE:
|
||||
busy_ = true;
|
||||
send_command(COMMAND_PERFERM_CALIBRATION, sizeof(COMMAND_PERFERM_CALIBRATION), scheduledActionData_, scheduledActionDataSize_);
|
||||
this->set_timeout(expected_response_time, [this](){ this->read_response(2, SensorAction::CALIBRATE); });
|
||||
break;
|
||||
case SensorAction::IS_CALIBRATED:
|
||||
busy_ = true;
|
||||
send_command(COMMAND_IS_CALIBRATED, sizeof(COMMAND_IS_CALIBRATED));
|
||||
this->set_timeout(expected_response_time, [this](){ this->read_response(8, SensorAction::IS_CALIBRATED); });
|
||||
break;
|
||||
case SensorAction::INFORMATION:
|
||||
busy_ = true;
|
||||
send_command(COMMAND_STATUS, sizeof(COMMAND_STATUS));
|
||||
this->set_timeout(expected_response_time, [this](){ this->read_response(18, SensorAction::INFORMATION); });
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool EzoOrpSensor::send_command(const uint8_t* data, size_t dataSize){
|
||||
return send_command(data, dataSize, nullptr, 0);
|
||||
}
|
||||
bool EzoOrpSensor::send_command(const uint8_t* data, size_t dataSize, const uint8_t* parameterData, size_t parameterSize){
|
||||
|
||||
if(parameterData == nullptr){
|
||||
if(i2c::ERROR_OK != this->write(data, dataSize)){
|
||||
ESP_LOGW(TAG, "send_command failed writing data!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t completeData[dataSize + 1 + parameterSize];
|
||||
for(int i = 0;i < dataSize; ++i){
|
||||
completeData[i] = data[i];
|
||||
}
|
||||
completeData[dataSize++] = COMMMAND_TO_ARGS_SEPERATOR;
|
||||
for(int i = 0; i < parameterSize; ++i){
|
||||
completeData[dataSize + i] = parameterData[i];
|
||||
}
|
||||
|
||||
if(i2c::ERROR_OK != this->write(completeData, sizeof(completeData))){
|
||||
ESP_LOGW(TAG, "send_command failed writing data!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void EzoOrpSensor::print_info(){
|
||||
scheduleNextAction(SensorAction::INFORMATION, nullptr, 0, 300);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user