mirror of https://github.com/arendst/Tasmota.git
Merge pull request #9599 from tichris0/development
Refactor EZO drivers to only use one sns ID
This commit is contained in:
commit
dd3228c07f
|
@ -77,6 +77,7 @@ Index | Define | Driver | Device | Address(es) | Description
|
||||||
52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor
|
52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor
|
||||||
53 | USE_MLX90640 | xdrv_84 | MLX90640 | 0x33 | IR array temperature sensor
|
53 | USE_MLX90640 | xdrv_84 | MLX90640 | 0x33 | IR array temperature sensor
|
||||||
54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor
|
54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor
|
||||||
55 | USE_EZO_PH | xsns_78 | EZOPH | 0x61 - 0x70 | pH Sensor
|
55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH Sensor
|
||||||
55 | USE_EZO_ORP | xsns_79 | EZOORP | 0x61 - 0x70 | ORP Sensor
|
55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP Sensor
|
||||||
55 | USE_EZO_RTD | xsns_80 | EZORTD | 0x61 - 0x70 | Temperature Sensor
|
55 | USE_EZORTD | xsns_78 | EZORTD | 0x61 - 0x70 | Temperature Sensor
|
||||||
|
55 | USE_EZOHUM | xsns_78 | EZORTD | 0x61 - 0x70 | Humidity Sensor
|
||||||
|
|
|
@ -562,9 +562,10 @@
|
||||||
// #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code)
|
// #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code)
|
||||||
// #define USE_HP303B // [I2cDriver52] Enable HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
|
// #define USE_HP303B // [I2cDriver52] Enable HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
|
||||||
// #define USE_MLX90640 // [I2cDriver53] Enable MLX90640 IR array temperature sensor (I2C address 0x33) (+20k code)
|
// #define USE_MLX90640 // [I2cDriver53] Enable MLX90640 IR array temperature sensor (I2C address 0x33) (+20k code)
|
||||||
// #define USE_EZOPH // [I2cDriver55] Enable support for EZO's pH sensor (+0k6 code) - Shared EZO code required for any EZO device (+1k0 code)
|
// #define USE_EZOPH // [I2cDriver55] Enable support for EZO's pH sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code)
|
||||||
// #define USE_EZOORP // [I2cDriver55] Enable support for EZO's ORP sensor (+0k6 code) - Shared EZO code required for any EZO device (+1k0 code)
|
// #define USE_EZOORP // [I2cDriver55] Enable support for EZO's ORP sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code)
|
||||||
// #define USE_EZORTD // [I2cDriver55] Enable support for EZO's RTD sensor (+0k6 code) - Shared EZO code required for any EZO device (+1k0 code)
|
// #define USE_EZORTD // [I2cDriver55] Enable support for EZO's RTD sensor (+0k2 code) - Shared EZO code required for any EZO device (+1k2 code)
|
||||||
|
// #define USE_EZOHUM // [I2cDriver55] Enable support for EZO's HUM sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code)
|
||||||
|
|
||||||
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
||||||
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
ezo.ino - EZO modules base class
|
xsns_78_ezo.ino - EZO modules base class
|
||||||
|
|
||||||
Copyright (C) 2020 Christopher Tremblay
|
Copyright (C) 2020 Christopher Tremblay
|
||||||
|
|
||||||
|
@ -17,15 +17,19 @@
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef USE_I2C
|
#ifdef USE_I2C
|
||||||
#if defined(USE_EZOPH) || defined(USE_EZOORP) || defined(USE_EZORTD)
|
#if defined(USE_EZOPH) || defined(USE_EZOORP) || defined(USE_EZORTD) || defined(USE_EZOHUM)
|
||||||
|
|
||||||
#define D_EZO_DELAY 300 // Minimum delay for any instruction
|
#define D_EZO_DELAY 300 // Minimum delay for any instruction
|
||||||
#define D_EZO_MAX_BUF 40 // Maximum response
|
#define D_EZO_MAX_BUF 40 // Maximum response
|
||||||
|
|
||||||
|
const char D_EZO_NAME[] PROGMEM = "EZO";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This baseclass provides common functionality for all EZO devices
|
// This baseclass provides common functionality for all EZO devices
|
||||||
struct EZOStruct {
|
struct EZOStruct {
|
||||||
|
EZOStruct(uint32_t addr) : valid(0), addr(addr), lastRead(-2000) {}
|
||||||
|
|
||||||
void MeasureRequest(void)
|
void MeasureRequest(void)
|
||||||
{
|
{
|
||||||
const uint8_t EZOMeasureCmd[2] = {'R', 0};
|
const uint8_t EZOMeasureCmd[2] = {'R', 0};
|
||||||
|
@ -41,6 +45,38 @@ struct EZOStruct {
|
||||||
lastRead = millis();
|
lastRead = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandleCommand(char *cmd, uint32_t len) const
|
||||||
|
{
|
||||||
|
// Transmit our command verbatim
|
||||||
|
Wire.beginTransmission(addr);
|
||||||
|
Wire.write(cmd, len);
|
||||||
|
if (Wire.endTransmission() != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to read the results
|
||||||
|
char data[D_EZO_MAX_BUF];
|
||||||
|
for (uint32_t code = 254; code == 254; code = Wire.read()) {
|
||||||
|
delay(D_EZO_DELAY);
|
||||||
|
Wire.requestFrom(addr, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; Wire.available() > 0; i++) {
|
||||||
|
data[i] = Wire.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseCmndChar((char *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid(void)
|
||||||
|
{
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void ProcessMeasurement(void);
|
||||||
|
virtual void Show(bool json, const char *name);
|
||||||
|
|
||||||
|
protected:
|
||||||
void ProcessMeasurement(char *const data, const uint32_t len, const uint32_t latency)
|
void ProcessMeasurement(char *const data, const uint32_t len, const uint32_t latency)
|
||||||
{
|
{
|
||||||
// Wait for the data to arrive first
|
// Wait for the data to arrive first
|
||||||
|
@ -63,55 +99,9 @@ struct EZOStruct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleCommand(uint32_t index) const
|
uint8_t valid;
|
||||||
{
|
|
||||||
char *at = XdrvMailbox.data;
|
|
||||||
uint32_t len = XdrvMailbox.data_len;
|
|
||||||
|
|
||||||
// Figure out if we're trying to address a specific device
|
|
||||||
// PS: This should ideally be done through the Tasmota mailbox
|
|
||||||
if (at[0] == '-') {
|
|
||||||
uint32_t idx = atoi(&at[1]) - 1;
|
|
||||||
at = strchr(at, ' ');
|
|
||||||
|
|
||||||
if (!at++) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len -= (at - XdrvMailbox.data);
|
|
||||||
|
|
||||||
if (idx != index) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transmit our command verbatim
|
|
||||||
Wire.beginTransmission(addr);
|
|
||||||
Wire.write(at, len);
|
|
||||||
if (Wire.endTransmission() != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to read the results
|
|
||||||
char data[D_EZO_MAX_BUF];
|
|
||||||
for (uint32_t code = 254; code == 254; code = Wire.read()) {
|
|
||||||
delay(D_EZO_DELAY);
|
|
||||||
Wire.requestFrom(addr, sizeof(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; Wire.available() > 0; i++) {
|
|
||||||
data[i] = Wire.read();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResponseCmndChar((char *)data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint8_t valid = 0;
|
|
||||||
uint8_t addr;
|
uint8_t addr;
|
||||||
|
uint32_t lastRead;
|
||||||
private:
|
|
||||||
uint32_t lastRead = -2000;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
xsns_78_ezohum.ino - EZO HUM I2C HUM sensor support for Tasmota
|
||||||
|
|
||||||
|
Copyright (C) 2020 Christopher Tremblay
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_EZOHUM
|
||||||
|
|
||||||
|
#define EZO_HUM_READ_LATENCY 300
|
||||||
|
|
||||||
|
struct EZOHUM : public EZOStruct {
|
||||||
|
EZOHUM(uint32_t addr) : EZOStruct(addr), humidity(NAN), temperature(NAN) {}
|
||||||
|
|
||||||
|
virtual void ProcessMeasurement(void)
|
||||||
|
{
|
||||||
|
char data[D_EZO_MAX_BUF];
|
||||||
|
// Hum, Temp, Dew
|
||||||
|
|
||||||
|
EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_HUM_READ_LATENCY);
|
||||||
|
|
||||||
|
humidity = CharToFloat(data);
|
||||||
|
|
||||||
|
char *next = strchr(data, ',');
|
||||||
|
if (next) {
|
||||||
|
temperature = CharToFloat(next + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Show(bool json, const char *name)
|
||||||
|
{
|
||||||
|
if (isnan(temperature)) {
|
||||||
|
char parameter[FLOATSZ];
|
||||||
|
|
||||||
|
dtostrfd(humidity, Settings.flag2.humidity_resolution, parameter);
|
||||||
|
WSContentSend_PD(HTTP_SNS_HUM, name, parameter);
|
||||||
|
} else {
|
||||||
|
TempHumDewShow(json, (0 == tele_period), name, temperature, humidity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float humidity;
|
||||||
|
float temperature;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USE_EZOHUM
|
||||||
|
#endif // USE_I2C
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
xsns_78_ezoorp.ino - EZO ORP I2C ORP sensor support for Tasmota
|
||||||
|
|
||||||
|
Copyright (C) 2020 Christopher Tremblay
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_EZOORP
|
||||||
|
|
||||||
|
#define EZO_ORP_READ_LATENCY 900
|
||||||
|
|
||||||
|
struct EZOORP : public EZOStruct {
|
||||||
|
EZOORP(uint32_t addr) : EZOStruct(addr), ORP(NAN) {}
|
||||||
|
|
||||||
|
virtual void ProcessMeasurement(void)
|
||||||
|
{
|
||||||
|
char data[D_EZO_MAX_BUF];
|
||||||
|
|
||||||
|
EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_ORP_READ_LATENCY);
|
||||||
|
ORP = CharToFloat(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Show(bool json, const char *name)
|
||||||
|
{
|
||||||
|
char str[6];
|
||||||
|
dtostrfd(ORP, 0, str);
|
||||||
|
|
||||||
|
if (json) {
|
||||||
|
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ORP "\":%s}" ), name, str);
|
||||||
|
}
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
else {
|
||||||
|
WSContentSend_PD(HTTP_SNS_ORP, name, str);
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float ORP;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // USE_EZOORP
|
||||||
|
#endif // USE_I2C
|
|
@ -20,12 +20,12 @@
|
||||||
#ifdef USE_I2C
|
#ifdef USE_I2C
|
||||||
#ifdef USE_EZOPH
|
#ifdef USE_EZOPH
|
||||||
|
|
||||||
#define XSNS_78 78
|
|
||||||
|
|
||||||
#define EZO_PH_READ_LATENCY 900
|
#define EZO_PH_READ_LATENCY 900
|
||||||
|
|
||||||
struct EZOpH : public EZOStruct {
|
struct EZOpH : public EZOStruct {
|
||||||
void ProcessMeasurement(void)
|
EZOpH(uint32_t addr) : EZOStruct(addr), pH(NAN) {}
|
||||||
|
|
||||||
|
virtual void ProcessMeasurement(void)
|
||||||
{
|
{
|
||||||
char data[D_EZO_MAX_BUF];
|
char data[D_EZO_MAX_BUF];
|
||||||
|
|
||||||
|
@ -33,47 +33,24 @@ struct EZOpH : public EZOStruct {
|
||||||
pH = CharToFloat(data);
|
pH = CharToFloat(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Show(bool json, uint32_t index)
|
virtual void Show(bool json, const char *name)
|
||||||
{
|
{
|
||||||
if (valid) {
|
char str[6];
|
||||||
char str[6];
|
dtostrfd(pH, 2, str);
|
||||||
dtostrfd(pH, 2, str);
|
|
||||||
|
|
||||||
char name[10];
|
if (json) {
|
||||||
snprintf_P(name, sizeof(name), PSTR("%s%c%X"), EZOpH::name, IndexSeparator(), index + 1);
|
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_PH "\":%s}" ), name, str);
|
||||||
|
}
|
||||||
if (count == 1) {
|
|
||||||
name[sizeof("EZOpH") - 1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json) {
|
|
||||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_PH "\":%s}" ), name, str);
|
|
||||||
}
|
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
else {
|
else {
|
||||||
WSContentSend_PD(HTTP_SNS_PH, name, str);
|
WSContentSend_PD(HTTP_SNS_PH, name, str);
|
||||||
#endif // USE_WEBSERVER
|
#endif // USE_WEBSERVER
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int8_t count;
|
|
||||||
static EZOpH *list;
|
|
||||||
static const char name[];
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float pH = NAN;
|
float pH;
|
||||||
};
|
};
|
||||||
|
|
||||||
int8_t EZOpH::count = -1;
|
|
||||||
EZOpH *EZOpH::list = NULL;
|
|
||||||
const char EZOpH::name[] PROGMEM = "EZOpH";
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Interface
|
|
||||||
\*********************************************************************************************/
|
|
||||||
#define Xsns78 XsnsEZO<EZOpH, EZO_PH>
|
|
||||||
|
|
||||||
#endif // USE_EZOPH
|
#endif // USE_EZOPH
|
||||||
#endif // USE_I2C
|
#endif // USE_I2C
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
xsns_78_ezortd.ino - EZO RTD I2C RTD sensor support for Tasmota
|
||||||
|
|
||||||
|
Copyright (C) 2020 Christopher Tremblay
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_EZORTD
|
||||||
|
|
||||||
|
#define EZO_RTD_READ_LATENCY 600
|
||||||
|
|
||||||
|
struct EZORTD : public EZOStruct {
|
||||||
|
EZORTD(uint32_t addr) : EZOStruct(addr), temperature(NAN) {}
|
||||||
|
|
||||||
|
virtual void ProcessMeasurement(void)
|
||||||
|
{
|
||||||
|
char data[D_EZO_MAX_BUF];
|
||||||
|
|
||||||
|
EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_RTD_READ_LATENCY);
|
||||||
|
temperature = CharToFloat(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Show(bool json, const char *name)
|
||||||
|
{
|
||||||
|
char str[10];
|
||||||
|
dtostrfd(ConvertTemp(temperature), Settings.flag2.temperature_resolution, str);
|
||||||
|
|
||||||
|
if (json) {
|
||||||
|
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), name, str);
|
||||||
|
}
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
else {
|
||||||
|
WSContentSend_PD(HTTP_SNS_TEMP, name, str, TempUnit());
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
float temperature;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // USE_EZORTD
|
||||||
|
#endif // USE_I2C
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
ezoManager.ino - EZO device manager
|
xsns_78_xezo.ino - EZO family I2C driver support for Tasmota
|
||||||
|
|
||||||
Copyright (C) 2020 Christopher Tremblay
|
Copyright (C) 2020 Christopher Tremblay
|
||||||
|
|
||||||
|
@ -16,17 +16,20 @@
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#ifdef USE_I2C
|
|
||||||
#if defined(USE_EZOPH) || defined(USE_EZOORP) || defined(USE_EZORTD)
|
|
||||||
|
|
||||||
#define XI2C_55 55 // See I2CDEVICES.md
|
#ifdef USE_I2C
|
||||||
|
#if defined(USE_EZOPH) || defined(USE_EZOORP) || defined(USE_EZORTD) || defined(USE_EZOHUM)
|
||||||
|
|
||||||
|
#define XSNS_78 78
|
||||||
|
#define XI2C_55 55 // See I2CDEVICES.md
|
||||||
|
|
||||||
#define EZO_ADDR_0 0x61 // First EZO address
|
#define EZO_ADDR_0 0x61 // First EZO address
|
||||||
#define EZO_ADDR_n 16 // Number of ports for use with EZO devices
|
#define EZO_ADDR_n 16 // Number of ports for use with EZO devices
|
||||||
|
|
||||||
|
|
||||||
// List of known EZO devices and their default address
|
// List of known EZO devices and their default address
|
||||||
enum EZOType {
|
|
||||||
|
enum {
|
||||||
EZO_DO = 0x61, // D.O.
|
EZO_DO = 0x61, // D.O.
|
||||||
EZO_ORP = 0x62, // ORP
|
EZO_ORP = 0x62, // ORP
|
||||||
EZO_PH = 0x63, // pH
|
EZO_PH = 0x63, // pH
|
||||||
|
@ -45,6 +48,7 @@ enum EZOType {
|
||||||
EZO_RGB = 0x70, // RGB
|
EZO_RGB = 0x70, // RGB
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const char EZO_EMPTY[] PROGMEM = "";
|
const char EZO_EMPTY[] PROGMEM = "";
|
||||||
//const char EZO_DO_NAME[] PROGMEM = "DO";
|
//const char EZO_DO_NAME[] PROGMEM = "DO";
|
||||||
#ifdef USE_EZOORP
|
#ifdef USE_EZOORP
|
||||||
|
@ -62,7 +66,9 @@ const char EZO_RTD_NAME[] PROGMEM = "RTD";
|
||||||
//const char EZO_CO2_NAME[] PROGMEM = "CO2";
|
//const char EZO_CO2_NAME[] PROGMEM = "CO2";
|
||||||
//const char EZO_PRS_NAME[] PROGMEM = "PRS";
|
//const char EZO_PRS_NAME[] PROGMEM = "PRS";
|
||||||
//const char EZO_O2_NAME[] PROGMEM = "O2";
|
//const char EZO_O2_NAME[] PROGMEM = "O2";
|
||||||
//const char EZO_HUM_NAME[] PROGMEM = "HUM";
|
#ifdef USE_EZOHUM
|
||||||
|
const char EZO_HUM_NAME[] PROGMEM = "HUM";
|
||||||
|
#endif
|
||||||
//const char EZO_RGB_NAME[] PROGMEM = "RGB";
|
//const char EZO_RGB_NAME[] PROGMEM = "RGB";
|
||||||
|
|
||||||
const char *const EZOSupport[EZO_ADDR_n] PROGMEM = {
|
const char *const EZOSupport[EZO_ADDR_n] PROGMEM = {
|
||||||
|
@ -97,42 +103,85 @@ const char *const EZOSupport[EZO_ADDR_n] PROGMEM = {
|
||||||
EZO_EMPTY,
|
EZO_EMPTY,
|
||||||
EZO_EMPTY,
|
EZO_EMPTY,
|
||||||
EZO_EMPTY,
|
EZO_EMPTY,
|
||||||
|
|
||||||
|
#ifdef USE_EZOHUM
|
||||||
|
EZO_HUM_NAME,
|
||||||
|
#else
|
||||||
EZO_EMPTY,
|
EZO_EMPTY,
|
||||||
|
#endif
|
||||||
|
|
||||||
EZO_EMPTY,
|
EZO_EMPTY,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct EZOManager {
|
struct EZOManager {
|
||||||
// Returns the count of devices of the specified type or -1 if the driver isn't ready yet
|
void Command()
|
||||||
// list must be a client-allocated array of atleast 16 elements
|
|
||||||
int getDevice(const EZOType type, uint32_t *list)
|
|
||||||
{
|
{
|
||||||
// EZO devices take 2s to boot
|
char *at = XdrvMailbox.data;
|
||||||
if (uptime >= next) {
|
uint32_t len = XdrvMailbox.data_len;
|
||||||
if (stage == 0) {
|
|
||||||
DetectRequest();
|
// Figure out if we're trying to address a specific device
|
||||||
next = uptime + 1;
|
// PS: This should ideally be done through the Tasmota mailbox
|
||||||
} else if (stage == 1) {
|
if (at[0] == '-') {
|
||||||
ProcessDetection();
|
int32_t idx = atoi(&at[1]) - 1;
|
||||||
|
at = strchr(at, ' ');
|
||||||
|
|
||||||
|
if (!at++) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stage++;
|
len -= (at - XdrvMailbox.data);
|
||||||
|
|
||||||
|
if ((idx >= 0) && (idx < count)) {
|
||||||
|
sensor[idx]->ProcessMeasurement();
|
||||||
|
sensor[idx]->HandleCommand(at, len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
sensor[i]->ProcessMeasurement();
|
||||||
|
sensor[i]->HandleCommand(at, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (stage >= 2) {
|
void EverySecond()
|
||||||
int count = 0;
|
{
|
||||||
|
// Do we have to deal with the 2 stage booting process?
|
||||||
|
if (count < 0) {
|
||||||
|
// EZO devices take 2s to boot
|
||||||
|
if (uptime >= next) {
|
||||||
|
count++;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < EZO_ADDR_n; i++) {
|
if (count == -1) {
|
||||||
if ((alive & (1 << i)) && (((devices[i >> 3] >> ((i & 7) << 2)) & 0xF) == (type - EZO_ADDR_0))) {
|
DetectRequest();
|
||||||
list[count++] = i + EZO_ADDR_0;
|
next = uptime + 1;
|
||||||
|
} else if (count == 0) {
|
||||||
|
ProcessDetection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
for (int32_t i = 0; i < count; i++) {
|
||||||
|
sensor[i]->ProcessMeasurement();
|
||||||
|
sensor[i]->MeasureRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Show(bool json)
|
||||||
|
{
|
||||||
|
for (int32_t i = 0; i < count; i++) {
|
||||||
|
if (sensor[i]->isValid()) {
|
||||||
|
char name[7];
|
||||||
|
snprintf_P(name, sizeof(name), PSTR("%s%c%X"), D_EZO_NAME, IndexSeparator(), i + 1);
|
||||||
|
|
||||||
|
if (count == 1) {
|
||||||
|
name[sizeof(D_EZO_NAME) - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor[i]->Show(json, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -161,15 +210,11 @@ private:
|
||||||
|
|
||||||
void ProcessDetection(void)
|
void ProcessDetection(void)
|
||||||
{
|
{
|
||||||
uint32_t mask = alive;
|
|
||||||
|
|
||||||
devices[0] = devices[1] = 0;
|
|
||||||
|
|
||||||
// Check every address that we sent a request to
|
// Check every address that we sent a request to
|
||||||
for (uint8_t addr = 0; addr < EZO_ADDR_n; addr++) {
|
for (uint8_t addr = EZO_ADDR_0; addr < EZO_ADDR_0 + EZO_ADDR_n; addr++) {
|
||||||
if (mask & 1) {
|
if (alive & 1) {
|
||||||
char data[D_EZO_MAX_BUF];
|
char data[D_EZO_MAX_BUF];
|
||||||
Wire.requestFrom(addr + EZO_ADDR_0, sizeof(data));
|
Wire.requestFrom(addr, sizeof(data));
|
||||||
char code = Wire.read();
|
char code = Wire.read();
|
||||||
|
|
||||||
if (code == 1) {
|
if (code == 1) {
|
||||||
|
@ -189,77 +234,79 @@ private:
|
||||||
data[0] = 'E';
|
data[0] = 'E';
|
||||||
data[1] = 'Z';
|
data[1] = 'Z';
|
||||||
data[2] = 'O';
|
data[2] = 'O';
|
||||||
I2cSetActiveFound(addr + EZO_ADDR_0, data);
|
I2cSetActiveFound(addr, data);
|
||||||
devices[addr >> 3] |= j << ((addr & 7) * 4);
|
|
||||||
|
// We use switch intead of virtual function to save RAM
|
||||||
|
switch (j + EZO_ADDR_0) {
|
||||||
|
#ifdef USE_EZOORP
|
||||||
|
case EZO_ORP:
|
||||||
|
sensor[count] = new EZOORP(addr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EZOPH
|
||||||
|
case EZO_PH:
|
||||||
|
sensor[count] = new EZOpH(addr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EZORTD
|
||||||
|
case EZO_RTD:
|
||||||
|
sensor[count] = new EZORTD(addr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef USE_EZOHUM
|
||||||
|
case EZO_HUM:
|
||||||
|
sensor[count] = new EZOHUM(addr);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mask >>= 1;
|
alive >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t next = 2;
|
uint32_t next = 2;
|
||||||
uint8_t stage = 0;
|
int8_t count = -2;
|
||||||
|
|
||||||
// Following 2 members are harcoded to allow a maximum of 16 entries
|
// Following variables are harcoded to allow a maximum of 16 entries
|
||||||
uint16_t alive;
|
uint16_t alive;
|
||||||
uint32_t devices[2];
|
EZOStruct *sensor[EZO_ADDR_n];
|
||||||
} EZOManager;
|
} EZOManager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The main driver is the same for all devices.
|
// The main driver is the same for all devices.
|
||||||
// What changes is the implementation of the class itself
|
// What changes is the implementation of the class itself
|
||||||
template <class T, EZOType type> bool XsnsEZO(uint8_t function)
|
bool Xsns78(uint8_t function)
|
||||||
{
|
{
|
||||||
if (!I2cEnabled(XI2C_55)) {
|
if (!I2cEnabled(XI2C_55)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialization: Gather the list of devices for this class
|
switch (function) {
|
||||||
if ((T::count < 0) && (function == FUNC_EVERY_SECOND)) {
|
case FUNC_COMMAND_SENSOR:
|
||||||
uint32_t addr[EZO_ADDR_n];
|
EZOManager.Command();
|
||||||
T::count = EZOManager.getDevice(type, &addr[0]);
|
break;
|
||||||
|
|
||||||
if (T::count > 0) {
|
case FUNC_EVERY_SECOND:
|
||||||
T::list = new T[T::count];
|
EZOManager.EverySecond();
|
||||||
|
break;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < T::count; i++) {
|
case FUNC_JSON_APPEND:
|
||||||
T::list[i].addr = addr[i];
|
EZOManager.Show(1);
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process the function on each of them
|
|
||||||
T *cur = &T::list[0];
|
|
||||||
for (int32_t i = 0; i < T::count; i++) {
|
|
||||||
switch (function) {
|
|
||||||
case FUNC_COMMAND_SENSOR:
|
|
||||||
cur->ProcessMeasurement();
|
|
||||||
cur->HandleCommand(i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FUNC_EVERY_SECOND:
|
|
||||||
if (uptime & 1) {
|
|
||||||
cur->ProcessMeasurement();
|
|
||||||
cur->MeasureRequest();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FUNC_JSON_APPEND:
|
|
||||||
cur->Show(1, i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
case FUNC_WEB_SENSOR:
|
case FUNC_WEB_SENSOR:
|
||||||
cur->Show(0, i);
|
EZOManager.Show(0);
|
||||||
break;
|
break;
|
||||||
}
|
#endif
|
||||||
#endif // USE_WEBSERVER
|
|
||||||
cur++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
xsns_79_ezoorp.ino - EZO ORP I2C ORP sensor support for Tasmota
|
|
||||||
|
|
||||||
Copyright (C) 2020 Christopher Tremblay
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef USE_I2C
|
|
||||||
#ifdef USE_EZOORP
|
|
||||||
|
|
||||||
#define XSNS_79 79
|
|
||||||
|
|
||||||
#define EZO_ORP_READ_LATENCY 900
|
|
||||||
|
|
||||||
struct EZOORP : public EZOStruct {
|
|
||||||
void ProcessMeasurement(void)
|
|
||||||
{
|
|
||||||
char data[D_EZO_MAX_BUF];
|
|
||||||
|
|
||||||
EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_ORP_READ_LATENCY);
|
|
||||||
ORP = CharToFloat(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Show(bool json, uint32_t index)
|
|
||||||
{
|
|
||||||
if (valid) {
|
|
||||||
char str[6];
|
|
||||||
dtostrfd(ORP, 2, str);
|
|
||||||
|
|
||||||
char name[10];
|
|
||||||
snprintf_P(name, sizeof(name), PSTR("%s%c%X"), EZOORP::name, IndexSeparator(), index + 1);
|
|
||||||
|
|
||||||
if (count == 1) {
|
|
||||||
name[sizeof("EZOORP") - 1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json) {
|
|
||||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ORP "\":%s}" ), name, str);
|
|
||||||
}
|
|
||||||
#ifdef USE_WEBSERVER
|
|
||||||
else {
|
|
||||||
WSContentSend_PD(HTTP_SNS_ORP, name, str);
|
|
||||||
#endif // USE_WEBSERVER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int8_t count;
|
|
||||||
static EZOORP *list;
|
|
||||||
static const char name[];
|
|
||||||
|
|
||||||
private:
|
|
||||||
float ORP = NAN;
|
|
||||||
};
|
|
||||||
|
|
||||||
int8_t EZOORP::count = -1;
|
|
||||||
EZOORP *EZOORP::list = NULL;
|
|
||||||
const char EZOORP::name[] PROGMEM = "EZOORP";
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Interface
|
|
||||||
\*********************************************************************************************/
|
|
||||||
#define Xsns79 XsnsEZO<EZOORP, EZO_ORP>
|
|
||||||
|
|
||||||
#endif // USE_EZOORP
|
|
||||||
#endif // USE_I2C
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
xsns_80_ezortd.ino - EZO RTD I2C RTD sensor support for Tasmota
|
|
||||||
|
|
||||||
Copyright (C) 2020 Christopher Tremblay
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef USE_I2C
|
|
||||||
#ifdef USE_EZORTD
|
|
||||||
|
|
||||||
#define XSNS_80 80
|
|
||||||
|
|
||||||
#define EZO_RTD_READ_LATENCY 600
|
|
||||||
|
|
||||||
struct EZORTD : public EZOStruct {
|
|
||||||
void ProcessMeasurement(void)
|
|
||||||
{
|
|
||||||
char data[D_EZO_MAX_BUF];
|
|
||||||
|
|
||||||
EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_RTD_READ_LATENCY);
|
|
||||||
RTD = CharToFloat(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Show(bool json, uint32_t index)
|
|
||||||
{
|
|
||||||
if (valid) {
|
|
||||||
char str[10];
|
|
||||||
dtostrfd(ConvertTemp(RTD), 2, str);
|
|
||||||
|
|
||||||
char name[10];
|
|
||||||
snprintf_P(name, sizeof(name), PSTR("%s%c%X"), EZORTD::name, IndexSeparator(), index + 1);
|
|
||||||
|
|
||||||
if (count == 1) {
|
|
||||||
name[sizeof("EZORTD") - 1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json) {
|
|
||||||
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s}"), name, str);
|
|
||||||
}
|
|
||||||
#ifdef USE_WEBSERVER
|
|
||||||
else {
|
|
||||||
WSContentSend_PD(HTTP_SNS_TEMP, name, str, TempUnit());
|
|
||||||
#endif // USE_WEBSERVER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int8_t count;
|
|
||||||
static EZORTD *list;
|
|
||||||
static const char name[];
|
|
||||||
|
|
||||||
private:
|
|
||||||
float RTD = NAN;
|
|
||||||
};
|
|
||||||
|
|
||||||
int8_t EZORTD::count = -1;
|
|
||||||
EZORTD *EZORTD::list = NULL;
|
|
||||||
const char EZORTD::name[] PROGMEM = "EZORTD";
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
|
||||||
* Interface
|
|
||||||
\*********************************************************************************************/
|
|
||||||
#define Xsns80 XsnsEZO<EZORTD, EZO_RTD>
|
|
||||||
|
|
||||||
#endif // USE_EZORTD
|
|
||||||
#endif // USE_I2C
|
|
Loading…
Reference in New Issue