diff --git a/BUILDS.md b/BUILDS.md index 254c84be8..686798083 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -186,6 +186,10 @@ | USE_DISPLAY_ILI9488 | - | - | - | - | - | - | - | | USE_DISPLAY_SSD1351 | - | - | - | - | - | - | - | | USE_DISPLAY_RA8876 | - | - | - | - | - | - | - | +| | | | | | | | | +| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks +| USE_EZOPH | - | - | - | - | - | - | - | +| USE_EZOORP | - | - | - | - | - | - | - | ## Additional Features and Sensors on ESP32 diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 71ceba8ac..282381489 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -77,3 +77,5 @@ Index | Define | Driver | Device | Address(es) | Description 52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and 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 + 55 | USE_EZO_PH | xsns_78 | EZOPH | 0x61 - 0x70 | pH Sensor + 55 | USE_EZO_ORP | xsns_79 | EZOORP | 0x61 - 0x70 | ORP Sensor diff --git a/tasmota/ezo.ino b/tasmota/ezo.ino new file mode 100644 index 000000000..926fc334b --- /dev/null +++ b/tasmota/ezo.ino @@ -0,0 +1,120 @@ +/* + ezo.ino - EZO modules base class + + 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 . +*/ +#ifdef USE_I2C +#if defined(USE_EZOPH) || defined(USE_EZOORP) + +#define D_EZO_DELAY 300 // Minimum delay for any instruction +#define D_EZO_MAX_BUF 40 // Maximum response + + + +// This baseclass provides common functionality for all EZO devices +struct EZOStruct { + void MeasureRequest(void) + { + const uint8_t EZOMeasureCmd[2] = {'R', 0}; + + if (valid) { + valid--; + } + + Wire.beginTransmission(addr); + Wire.write(EZOMeasureCmd, sizeof(EZOMeasureCmd)); + Wire.endTransmission(); + + lastRead = millis(); + } + + void ProcessMeasurement(char *const data, const uint32_t len, const uint32_t latency) + { + // Wait for the data to arrive first + const int32_t dur = lastRead + latency - millis(); + + // Wait for the last readout to complete (only when commands are issued) + if (dur > 0) { + delay(dur); + } + + Wire.requestFrom(addr, len); + const char code = Wire.read(); + + if (code == 1) { + for (uint32_t i = 0; (Wire.available() > 0) && (i < len); i++) { + data[i] = Wire.read(); + } + + valid = SENSOR_MAX_MISS; + } + } + + void HandleCommand(uint32_t index) const + { + 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; + +private: + uint32_t lastRead = -2000; +}; + + + +#endif // USE_EZO* +#endif // USE_I2C diff --git a/tasmota/ezoManager.ino b/tasmota/ezoManager.ino new file mode 100644 index 000000000..5e2bf4485 --- /dev/null +++ b/tasmota/ezoManager.ino @@ -0,0 +1,261 @@ +/* + ezoManager.ino - EZO device manager + + 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 . +*/ +#ifdef USE_I2C +#if defined(USE_EZOPH) || defined(USE_EZOORP) + +#define XI2C_55 55 // See I2CDEVICES.md + +#define EZO_ADDR_0 0x61 // First EZO address +#define EZO_ADDR_n 16 // Number of ports for use with EZO devices + + +// List of known EZO devices and their default address +enum EZOType { + EZO_DO = 0x61, // D.O. + EZO_ORP = 0x62, // ORP + EZO_PH = 0x63, // pH + EZO_EC = 0x64, // EC + + EZO_RTD = 0x66, // RTD + EZO_PMP = 0x67, // PMP + EZO_FLO = 0x68, // FLO + EZO_CO2 = 0x69, // CO2 + EZO_PRS = 0x6A, // PRS + + EZO_O2 = 0x6C, // O2 + + + EZO_HUM = 0x6F, // HUM + EZO_RGB = 0x70, // RGB +}; + +const char EZO_EMPTY[] PROGMEM = ""; +//const char EZO_DO_NAME[] PROGMEM = "DO"; +#ifdef USE_EZOORP +const char EZO_ORP_NAME[] PROGMEM = "ORP"; +#endif +#ifdef USE_EZOPH +const char EZO_PH_NAME[] PROGMEM = "pH"; +#endif +//const char EZO_EC_NAME[] PROGMEM = "EC"; +//const char EZO_RTD_NAME[] PROGMEM = "RTD"; +//const char EZO_PMP_NAME[] PROGMEM = "PMP"; +//const char EZO_FLO_NAME[] PROGMEM = "FLO"; +//const char EZO_CO2_NAME[] PROGMEM = "CO2"; +//const char EZO_PRS_NAME[] PROGMEM = "PRS"; +//const char EZO_O2_NAME[] PROGMEM = "O2"; +//const char EZO_HUM_NAME[] PROGMEM = "HUM"; +//const char EZO_RGB_NAME[] PROGMEM = "RGB"; + +const char *const EZOSupport[EZO_ADDR_n] PROGMEM = { + EZO_EMPTY, + +#ifdef USE_EZOORP + EZO_ORP_NAME, +#else + EZO_EMPTY, +#endif + +#ifdef USE_EZOPH + EZO_PH_NAME, +#else + EZO_EMPTY, +#endif + + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, + EZO_EMPTY, +}; + + + +struct EZOManager { + // Returns the count of devices of the specified type or -1 if the driver isn't ready yet + // 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 + if (uptime >= next) { + if (stage == 0) { + DetectRequest(); + next = uptime + 1; + } else if (stage == 1) { + ProcessDetection(); + } + + stage++; + } + + if (stage >= 2) { + int count = 0; + + for (uint32_t i = 0; i < EZO_ADDR_n; i++) { + if ((alive & (1 << i)) && (((devices[i >> 3] >> ((i & 7) << 2)) & 0xF) == (type - EZO_ADDR_0))) { + list[count++] = i + EZO_ADDR_0; + } + } + + return count; + } + + return -1; + } + +private: + void DetectRequest(void) + { + const uint8_t EZOInfoCmd[2] = {'i', 0}; + alive = 0; + + // Scan the address range + uint16_t shift = 1; + for (uint8_t i = EZO_ADDR_0; shift; i++) { + if (!I2cActive(i)) { + // Request the device to identify itself + Wire.beginTransmission(i); + Wire.write(EZOInfoCmd, sizeof(EZOInfoCmd)); + + int c = Wire.endTransmission(); + + if (c == 0) { + alive |= shift; + } + } + shift <<= 1; + } + } + + void ProcessDetection(void) + { + uint32_t mask = alive; + + devices[0] = devices[1] = 0; + + // Check every address that we sent a request to + for (uint8_t addr = 0; addr < EZO_ADDR_n; addr++) { + if (mask & 1) { + char data[D_EZO_MAX_BUF]; + Wire.requestFrom(addr + EZO_ADDR_0, sizeof(data)); + char code = Wire.read(); + + if (code == 1) { + uint32_t i; + + for (i = 0; Wire.available() > 0; i++) { + char c = Wire.read(); + + // Helps us strcmp + data[i] = (c == ',') ? 0 : c; + } + + // Technically the response starts with "?I," but we'll skip testing it to save space + if (i >= 3) { + for (uint32_t j = 0; j < EZO_ADDR_n; j++) { + if (strcasecmp_P(&data[3], EZOSupport[j]) == 0) { + data[0] = 'E'; + data[1] = 'Z'; + data[2] = 'O'; + I2cSetActiveFound(addr, data); + devices[addr >> 3] |= j << ((addr & 7) * 4); + } + } + } + } + } + + mask >>= 1; + } + } + + uint32_t next = 2; + uint8_t stage = 0; + +// Following 2 members are harcoded to allow a maximum of 16 entries + uint16_t alive; + uint32_t devices[2]; +} EZOManager; + + + +// The main driver is the same for all devices. +// What changes is the implementation of the class itself +template bool XsnsEZO(uint8_t function) +{ + if (!I2cEnabled(XI2C_55)) { + return false; + } + + // Initialization: Gather the list of devices for this class + if ((T::count < 0) && (function == FUNC_EVERY_SECOND)) { + uint32_t addr[EZO_ADDR_n]; + T::count = EZOManager.getDevice(type, &addr[0]); + + if (T::count > 0) { + T::list = new T[T::count]; + + for (uint32_t i = 0; i < T::count; i++) { + T::list[i].addr = addr[i]; + } + } + } + + // 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 + case FUNC_WEB_SENSOR: + cur->Show(0, i); + break; + } +#endif // USE_WEBSERVER + cur++; + } + + return false; +} + +#endif // USE_EZO* +#endif // USE_I2C diff --git a/tasmota/i18n.h b/tasmota/i18n.h index d6ee87038..b41a2505d 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -111,7 +111,9 @@ #define D_JSON_NOISE "Noise" #define D_JSON_NONE "None" #define D_JSON_OR "or" +#define D_JSON_ORP "ORP" #define D_JSON_PERIOD "Period" +#define D_JSON_PH "pH" #define D_JSON_PHASE_ANGLE "PhaseAngle" #define D_JSON_POWERFACTOR "Factor" #define D_JSON_POWERUSAGE "Power" @@ -768,6 +770,8 @@ const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{ const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"; const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE "{m}%s " D_UNIT_WATT "{e}"; const char HTTP_SNS_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_PH[] PROGMEM = "{s}%s " D_PH "{m}%s " "{e}"; +const char HTTP_SNS_ORP[] PROGMEM = "{s}%s " D_ORP "{m}%s " D_UNIT_MILLIVOLT "{e}"; const char S_MAIN_MENU[] PROGMEM = D_MAIN_MENU; const char S_CONFIGURATION[] PROGMEM = D_CONFIGURATION; diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 9cc01de9a..f0a869cf9 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -129,7 +129,9 @@ #define D_OK "Ок" #define D_ON "Вкл." #define D_ONLINE "Онлайн" +#define D_ORP "ORP" #define D_PASSWORD "Парола" +#define D_PH "pH" #define D_PORT "Порт" #define D_POWER_FACTOR "Фактор на мощността" #define D_POWERUSAGE "Мощност" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index bf8f67a37..ec09983a7 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -129,7 +129,9 @@ #define D_OK "OK" #define D_ON "Zap." #define D_ONLINE "Online" // Don't translate, LWT message! Nepředkládat, LWT zpráva! +#define D_ORP "ORP" #define D_PASSWORD "Heslo" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Účiník" #define D_POWERUSAGE "Příkon" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 23db7da4f..4d3d9eecd 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -129,7 +129,9 @@ #define D_OK "OK" #define D_ON "an" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Passwort" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Leistungsfaktor" #define D_POWERUSAGE "Leistung" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 95b640da8..1f20dd270 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "On" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Κωδικός" +#define D_PH "pH" #define D_PORT "Θύρα" #define D_POWER_FACTOR "Συντελεστής Ισχύος" #define D_POWERUSAGE "Ισχύς" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 2ac306f8e..7e84ff75b 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "On" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Password" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Power Factor" #define D_POWERUSAGE "Power" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 1401c4fce..35f0ac6f5 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "Encendido" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Clave" +#define D_PH "pH" #define D_PORT "Puerto" #define D_POWER_FACTOR "Factor de Potencia" #define D_POWERUSAGE "Potencia" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 15dd090dc..4c7775e49 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -125,7 +125,9 @@ #define D_OK "Ok" #define D_ON "Marche" #define D_ONLINE "Connecté" +#define D_ORP "ORP" #define D_PASSWORD "Mot de passe" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Fact de puiss" #define D_POWERUSAGE "Puissance" @@ -745,6 +747,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "min" // https://fr.wikipedia.org/wiki/Minute_(temps)#Symbole%20et%20d%C3%A9finition #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index ae2e439be..4fb8cf5b6 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -129,7 +129,9 @@ #define D_OK "אוקיי" #define D_ON "פועל" #define D_ONLINE "מחובר" +#define D_ORP "ORP" #define D_PASSWORD "סיסמא" +#define D_PH "pH" #define D_PORT "פורט" #define D_POWER_FACTOR "גורם כוח" #define D_POWERUSAGE "כוח" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 8a800383d..d0cddc994 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -129,7 +129,9 @@ #define D_OK "OK" #define D_ON "Be" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Jelszó" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Teljesítménytényező" #define D_POWERUSAGE "Energiafelhasználás" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index d82c47aa3..44c671fdb 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -129,7 +129,9 @@ #define D_OK "OK" #define D_ON "ON" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Password" +#define D_PH "pH" #define D_PORT "Porta" #define D_POWER_FACTOR "Fattore di potenza" #define D_POWERUSAGE "Potenza" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 5a8522b72..a0c162c17 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "켜짐" #define D_ONLINE "온라인" +#define D_ORP "ORP" #define D_PASSWORD "비밀번호" +#define D_PH "pH" #define D_PORT "포트" #define D_POWER_FACTOR "Power Factor" #define D_POWERUSAGE "전원" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "밀리초" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "분" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index ec8116deb..5abc5852a 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "Aan" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Wachtwoord" +#define D_PH "pH" #define D_PORT "Poort" #define D_POWER_FACTOR "Arbeidsfactor" #define D_POWERUSAGE "Vermogen" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 8ebba663e..4d274f6c8 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "Załączony" #define D_ONLINE "Aktywny" +#define D_ORP "ORP" #define D_PASSWORD "Hasło" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Cosinus fi" #define D_POWERUSAGE "Moc" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 115704748..b81212785 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "Ligado" #define D_ONLINE "Conectado" +#define D_ORP "ORP" #define D_PASSWORD "Senha" +#define D_PH "pH" #define D_PORT "Porta" #define D_POWER_FACTOR "Fator de potência" #define D_POWERUSAGE "Potência" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "M" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 202564422..684f87424 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "On" #define D_ONLINE "Conetado" +#define D_ORP "ORP" #define D_PASSWORD "Palavra Chave" +#define D_PH "pH" #define D_PORT "Porta" #define D_POWER_FACTOR "Factor de Potência" #define D_POWERUSAGE "Potência" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 13c91f8e8..f61504c4e 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "Aprins" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Parolă" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Factor de Putere" #define D_POWERUSAGE "Putere" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index fe4de2043..1bef3939e 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -129,7 +129,9 @@ #define D_OK "Ок" #define D_ON "Вкл" #define D_ONLINE "Он-лайн" +#define D_ORP "ORP" #define D_PASSWORD "Пароль" +#define D_PH "pH" #define D_PORT "Порт" #define D_POWER_FACTOR "Коэффициент Мощности" #define D_POWERUSAGE "Мощность" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "мм рт.ст." #define D_UNIT_MILLISECOND "мс" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "мин" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 986bc95cd..d090767a4 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -129,7 +129,9 @@ #define D_OK "OK" #define D_ON "Zap." #define D_ONLINE "Aktívny" +#define D_ORP "ORP" #define D_PASSWORD "Heslo" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Účinník" #define D_POWERUSAGE "Príkon" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 3178cbd30..d186cf43b 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "På" #define D_ONLINE "Ansluten" +#define D_ORP "ORP" #define D_PASSWORD "Lösenord" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Spänningsfaktor" #define D_POWERUSAGE "Spänning" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 5c6254f3b..244dad325 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -129,7 +129,9 @@ #define D_OK "Tamam" #define D_ON "On" #define D_ONLINE "Çevirimiçi" +#define D_ORP "ORP" #define D_PASSWORD "Şifre" +#define D_PH "pH" #define D_PORT "Port" #define D_POWER_FACTOR "Güç Faktörü" #define D_POWERUSAGE "Güç" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 8e3b01691..1f3448303 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -129,7 +129,9 @@ #define D_OK "Ок" #define D_ON "Увімкнено" #define D_ONLINE "Активний" +#define D_ORP "ORP" #define D_PASSWORD "Гасло" +#define D_PH "pH" #define D_PORT "Порт" #define D_POWER_FACTOR "Коефіцієнт потужності" #define D_POWERUSAGE "Потужність" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "мм" #define D_UNIT_MILLIMETER_MERCURY "ммHg" #define D_UNIT_MILLISECOND "мС" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "хв" #define D_UNIT_PARTS_PER_BILLION "млрд⁻¹" #define D_UNIT_PARTS_PER_DECILITER "децилітр⁻¹" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 48a7b503c..e0700ba32 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -129,7 +129,9 @@ #define D_OK "Ok" #define D_ON "Bật" #define D_ONLINE "Trực tuyến" +#define D_ORP "ORP" #define D_PASSWORD "Mật khẩu" +#define D_PH "pH" #define D_PORT "Cổng" #define D_POWER_FACTOR "Hệ số công suất" #define D_POWERUSAGE "Công suất" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "ms" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "Min" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index a50acdb0e..a7d930ae4 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -129,7 +129,9 @@ #define D_OK "好" #define D_ON "开" #define D_ONLINE "在线" +#define D_ORP "ORP" #define D_PASSWORD "密码" +#define D_PH "pH" #define D_PORT "端口" #define D_POWER_FACTOR "功率因数" #define D_POWERUSAGE "功率" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "毫米" #define D_UNIT_MILLIMETER_MERCURY "毫米汞柱" #define D_UNIT_MILLISECOND "毫秒" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "分" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "每分升" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 65c865491..4243f0b55 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -129,7 +129,9 @@ #define D_OK "好" #define D_ON "開啟" #define D_ONLINE "線上" +#define D_ORP "ORP" #define D_PASSWORD "密碼" +#define D_PH "pH" #define D_PORT "通訊埠" #define D_POWER_FACTOR "功率因數" #define D_POWERUSAGE "用電量" @@ -749,6 +751,7 @@ #define D_UNIT_MILLIMETER "mm" #define D_UNIT_MILLIMETER_MERCURY "mmHg" #define D_UNIT_MILLISECOND "毫秒" +#define D_UNIT_MILLIVOLT "mV" #define D_UNIT_MINUTE "分" #define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "每分升" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 883d3ca46..0c0cd6cda 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -796,6 +796,9 @@ //#define USE_WEBCAM // Add support for webcam #endif + // Shared EZO code required for any EZO device (+1k0 code) +// #define USE_EZOPH // Add support for EZO's pH sensor (+0k6 code) +// #define USE_EZOORP // Add support for EZO's ORP sensor (+0k6 code) /*********************************************************************************************\ * Debug features diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 0a71d86ed..d3e66eb35 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -613,9 +613,9 @@ void GetFeatures(void) #if defined(USE_ENERGY_SENSOR) && defined(USE_WE517) feature6 |= 0x08000000; // xnrg_17_ornowe517.ino #endif - -// feature6 |= 0x10000000; - +#if defined(USE_I2C) && defined(USE_EZOPH) + feature6 |= 0x10000000; // xsns_78_ezoph.ino +#endif #if defined(ESP32) && defined(USE_TTGO_WATCH) feature6 |= 0x20000000; // xdrv_83_esp32watch.ino #endif @@ -630,7 +630,9 @@ void GetFeatures(void) feature7 = 0x00000000; -// feature7 |= 0x00000001; +#if defined(USE_I2C) && defined(USE_EZOORP) + feature7 |= 0x00000001; // xsns_79_ezoorp.ino +#endif // feature7 |= 0x00000002; // feature7 |= 0x00000004; // feature7 |= 0x00000008; diff --git a/tasmota/xsns_78_ezoph.ino b/tasmota/xsns_78_ezoph.ino new file mode 100644 index 000000000..fd5f0c667 --- /dev/null +++ b/tasmota/xsns_78_ezoph.ino @@ -0,0 +1,79 @@ +/* + xsns_78_ezoph.ino - EZO pH I2C pH 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_EZOPH + +#define XSNS_78 78 + +#define EZO_PH_READ_LATENCY 900 + +struct EZOpH : public EZOStruct { + void ProcessMeasurement(void) + { + char data[D_EZO_MAX_BUF]; + + EZOStruct::ProcessMeasurement(data, sizeof(data), EZO_PH_READ_LATENCY); + pH = CharToFloat(data); + } + + void Show(bool json, uint32_t index) + { + if (valid) { + char str[6]; + dtostrfd(pH, 2, str); + + char name[10]; + snprintf_P(name, sizeof(name), PSTR("%s%c%X"), EZOpH::name, IndexSeparator(), index + 1); + + if (count == 1) { + name[sizeof("EZOpH") - 1] = 0; + } + + if (json) { + ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_PH "\":%s}" ), name, str); + } +#ifdef USE_WEBSERVER + else { + WSContentSend_PD(HTTP_SNS_PH, name, str); +#endif // USE_WEBSERVER + } + } + } + + static int8_t count; + static EZOpH *list; + static const char name[]; + +private: + float pH = NAN; +}; + +int8_t EZOpH::count = -1; +EZOpH *EZOpH::list = NULL; +const char EZOpH::name[] PROGMEM = "EZOpH"; + + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ +#define Xsns78 XsnsEZO + +#endif // USE_EZOPH +#endif // USE_I2C diff --git a/tasmota/xsns_79_ezoorp.ino b/tasmota/xsns_79_ezoorp.ino new file mode 100644 index 000000000..4599bfecd --- /dev/null +++ b/tasmota/xsns_79_ezoorp.ino @@ -0,0 +1,79 @@ +/* + 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 . +*/ + +#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 + +#endif // USE_EZOORP +#endif // USE_I2C