From d8b8636a449f58d3bd37da1cf9857e3394a55892 Mon Sep 17 00:00:00 2001 From: Christopher Tremblay Date: Sun, 18 Oct 2020 05:10:12 -0700 Subject: [PATCH 1/6] EZOpH & EZOORP support This commits adds support for EZOpH and EZOORP to Tasmota --- BUILDS.md | 4 + I2CDEVICES.md | 2 + c | 1 + tasmota/.my_user_config.h.swp | Bin 0 -> 94208 bytes tasmota/ezo.ino | 120 ++++++++++++++++ tasmota/ezoManager.ino | 261 ++++++++++++++++++++++++++++++++++ tasmota/i18n.h | 4 + tasmota/language/en_GB.h | 3 + tasmota/my_user_config.h | 3 + tasmota/support_features.ino | 10 +- tasmota/xsns_78_ezoph.ino | 79 ++++++++++ tasmota/xsns_79_ezoorp.ino | 79 ++++++++++ 12 files changed, 562 insertions(+), 4 deletions(-) create mode 100644 c create mode 100644 tasmota/.my_user_config.h.swp create mode 100644 tasmota/ezo.ino create mode 100644 tasmota/ezoManager.ino create mode 100644 tasmota/xsns_78_ezoph.ino create mode 100644 tasmota/xsns_79_ezoorp.ino 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..70422148a 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,USE_EZO_PH | xsns_78 | EZOPH | 0x61 - 0x70 | pH Sensor + 55 | USE_EZO,USE_EZO_ORP | xsns_79 | EZOORP | 0x61 - 0x70 | ORP Sensor diff --git a/c b/c new file mode 100644 index 000000000..b1aec06d5 --- /dev/null +++ b/c @@ -0,0 +1 @@ +platformio run -e tasmota --target upload --upload-port /dev/ttyS4 diff --git a/tasmota/.my_user_config.h.swp b/tasmota/.my_user_config.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..06d47a4a7f506d569fd74b2a2ebc183976347655 GIT binary patch literal 94208 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

ZCYol@G}JZqUBwlhH@jgaEuL;_u$URag!u#s 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 OZ;jSTZJV81fcO{prI-x> literal 0 HcmV?d00001 diff --git a/tasmota/ezo.ino b/tasmota/ezo.ino new file mode 100644 index 000000000..a68a1981f --- /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]); + 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/en_GB.h b/tasmota/language/en_GB.h index 2ac306f8e..747f9a851 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -129,6 +129,7 @@ #define D_OK "Ok" #define D_ON "On" #define D_ONLINE "Online" +#define D_ORP "ORP" #define D_PASSWORD "Password" #define D_PORT "Port" #define D_POWER_FACTOR "Power Factor" @@ -136,6 +137,7 @@ #define D_POWERUSAGE_ACTIVE "Active Power" #define D_POWERUSAGE_APPARENT "Apparent Power" #define D_POWERUSAGE_REACTIVE "Reactive Power" +#define D_PH "pH" #define D_PRESSURE "Pressure" #define D_PRESSUREATSEALEVEL "SeaPressure" #define D_PROGRAM_FLASH_SIZE "Program Flash Size" @@ -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/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 From 8fda70643b47f5eaec555d2e5066ea3719ca942e Mon Sep 17 00:00:00 2001 From: Christopher Tremblay Date: Sun, 18 Oct 2020 05:19:04 -0700 Subject: [PATCH 2/6] Fix addressing & remove compile script - Fixed adderssing to start at 1 vs 0 - Removed my compile script --- c | 1 - tasmota/ezo.ino | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 c diff --git a/c b/c deleted file mode 100644 index b1aec06d5..000000000 --- a/c +++ /dev/null @@ -1 +0,0 @@ -platformio run -e tasmota --target upload --upload-port /dev/ttyS4 diff --git a/tasmota/ezo.ino b/tasmota/ezo.ino index a68a1981f..926fc334b 100644 --- a/tasmota/ezo.ino +++ b/tasmota/ezo.ino @@ -71,7 +71,7 @@ struct EZOStruct { // 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]); + uint32_t idx = atoi(&at[1]) - 1; at = strchr(at, ' '); if (!at++) { From f551817698febed2cd6c18c75c982747c8f9f7e7 Mon Sep 17 00:00:00 2001 From: Christopher Tremblay Date: Sun, 18 Oct 2020 05:19:48 -0700 Subject: [PATCH 3/6] Delete .my_user_config.h.swp Removed uselses file --- tasmota/.my_user_config.h.swp | Bin 94208 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tasmota/.my_user_config.h.swp diff --git a/tasmota/.my_user_config.h.swp b/tasmota/.my_user_config.h.swp deleted file mode 100644 index 06d47a4a7f506d569fd74b2a2ebc183976347655..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 94208 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

ZCYol@G}JZqUBwlhH@jgaEuL;_u$URag!u#s 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 OZ;jSTZJV81fcO{prI-x> From 5a910fd035e77f79a35dbd8be67e2a23ac6e3cd5 Mon Sep 17 00:00:00 2001 From: Christopher Tremblay Date: Sun, 18 Oct 2020 05:20:44 -0700 Subject: [PATCH 4/6] Update I2CDEVICES.md Removed requirement for USE_EZO --- I2CDEVICES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 70422148a..282381489 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -77,5 +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,USE_EZO_PH | xsns_78 | EZOPH | 0x61 - 0x70 | pH Sensor - 55 | USE_EZO,USE_EZO_ORP | xsns_79 | EZOORP | 0x61 - 0x70 | ORP Sensor + 55 | USE_EZO_PH | xsns_78 | EZOPH | 0x61 - 0x70 | pH Sensor + 55 | USE_EZO_ORP | xsns_79 | EZOORP | 0x61 - 0x70 | ORP Sensor From 46df6d5a52bd1c63daa938ac610a26903cf5228b Mon Sep 17 00:00:00 2001 From: Christopher Tremblay Date: Sun, 18 Oct 2020 05:43:40 -0700 Subject: [PATCH 5/6] Added deafult localized strings for pH & ORP Added default strings for pH & ORP to all languages --- tasmota/language/bg_BG.h | 2 ++ tasmota/language/cs_CZ.h | 2 ++ tasmota/language/de_DE.h | 2 ++ tasmota/language/el_GR.h | 2 ++ tasmota/language/en_GB.h | 2 +- tasmota/language/es_ES.h | 2 ++ tasmota/language/fr_FR.h | 2 ++ tasmota/language/he_HE.h | 2 ++ tasmota/language/hu_HU.h | 2 ++ tasmota/language/it_IT.h | 2 ++ tasmota/language/ko_KO.h | 2 ++ tasmota/language/nl_NL.h | 2 ++ tasmota/language/pl_PL.h | 2 ++ tasmota/language/pt_BR.h | 2 ++ tasmota/language/pt_PT.h | 2 ++ tasmota/language/ro_RO.h | 2 ++ tasmota/language/ru_RU.h | 2 ++ tasmota/language/sk_SK.h | 2 ++ tasmota/language/sv_SE.h | 2 ++ tasmota/language/tr_TR.h | 2 ++ tasmota/language/uk_UA.h | 2 ++ tasmota/language/vi_VN.h | 2 ++ tasmota/language/zh_CN.h | 2 ++ tasmota/language/zh_TW.h | 2 ++ 24 files changed, 47 insertions(+), 1 deletion(-) diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 9cc01de9a..00914920a 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 "Мощност" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index bf8f67a37..1800a7ec9 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" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 23db7da4f..161fdd8b8 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" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 95b640da8..37680c8bd 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 "Ισχύς" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 747f9a851..7e84ff75b 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -131,13 +131,13 @@ #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" #define D_POWERUSAGE_ACTIVE "Active Power" #define D_POWERUSAGE_APPARENT "Apparent Power" #define D_POWERUSAGE_REACTIVE "Reactive Power" -#define D_PH "pH" #define D_PRESSURE "Pressure" #define D_PRESSUREATSEALEVEL "SeaPressure" #define D_PROGRAM_FLASH_SIZE "Program Flash Size" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 1401c4fce..9f6264317 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" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 15dd090dc..c1ad2cc12 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" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index ae2e439be..d2b5075f6 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 "כוח" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 8a800383d..5989bb76a 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" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index d82c47aa3..bdf2b7b42 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" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 5a8522b72..dad0178b8 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 "전원" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index ec8116deb..87fdffa4e 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" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 8ebba663e..ab8d80e79 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" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 115704748..0b7328439 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" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 202564422..ca83bf51d 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" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 13c91f8e8..ff8dc817d 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" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index fe4de2043..f1b16d852 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 "Мощность" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 986bc95cd..0518ae56c 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" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 3178cbd30..f0ebb5ac6 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" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 5c6254f3b..001cfbb2e 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üç" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 8e3b01691..f8c2120dd 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 "Потужність" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 48a7b503c..b5a3957b9 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" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index a50acdb0e..25c925a66 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 "功率" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 65c865491..338c31a51 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 "用電量" From bb210bd33a50ba79509e2f63a94f17e8410a19bd Mon Sep 17 00:00:00 2001 From: Christopher Tremblay Date: Sun, 18 Oct 2020 05:51:21 -0700 Subject: [PATCH 6/6] Added mV for all languages I was missing the defines for mV for all languages :(. I added default placeholders --- tasmota/language/bg_BG.h | 1 + tasmota/language/cs_CZ.h | 1 + tasmota/language/de_DE.h | 1 + tasmota/language/el_GR.h | 1 + tasmota/language/es_ES.h | 1 + tasmota/language/fr_FR.h | 1 + tasmota/language/he_HE.h | 1 + tasmota/language/hu_HU.h | 1 + tasmota/language/it_IT.h | 1 + tasmota/language/ko_KO.h | 1 + tasmota/language/nl_NL.h | 1 + tasmota/language/pl_PL.h | 1 + tasmota/language/pt_BR.h | 1 + tasmota/language/pt_PT.h | 1 + tasmota/language/ro_RO.h | 1 + tasmota/language/ru_RU.h | 1 + tasmota/language/sk_SK.h | 1 + tasmota/language/sv_SE.h | 1 + tasmota/language/tr_TR.h | 1 + tasmota/language/uk_UA.h | 1 + tasmota/language/vi_VN.h | 1 + tasmota/language/zh_CN.h | 1 + tasmota/language/zh_TW.h | 1 + 23 files changed, 23 insertions(+) diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 00914920a..f0a869cf9 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -751,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 1800a7ec9..ec09983a7 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -751,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 161fdd8b8..4d3d9eecd 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -751,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 37680c8bd..1f20dd270 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -751,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 9f6264317..35f0ac6f5 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -751,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 c1ad2cc12..4c7775e49 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -747,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 d2b5075f6..4fb8cf5b6 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -751,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 5989bb76a..d0cddc994 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -751,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 bdf2b7b42..44c671fdb 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -751,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 dad0178b8..a0c162c17 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -751,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 87fdffa4e..5abc5852a 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -751,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 ab8d80e79..4d274f6c8 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -751,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 0b7328439..b81212785 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -751,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 ca83bf51d..684f87424 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -751,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 ff8dc817d..f61504c4e 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -751,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 f1b16d852..1bef3939e 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -751,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 0518ae56c..d090767a4 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -751,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 f0ebb5ac6..d186cf43b 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -751,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 001cfbb2e..244dad325 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -751,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 f8c2120dd..1f3448303 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -751,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 b5a3957b9..e0700ba32 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -751,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 25c925a66..a7d930ae4 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -751,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 338c31a51..4243f0b55 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -751,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 "每分升"