From 86e2bc53beb429af057a09981fd567e62f56d243 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 8 Mar 2021 12:34:32 +0100 Subject: [PATCH 1/8] Fix CSE7761 default calibration --- tasmota/xnrg_19_cse7761.ino | 64 ++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/tasmota/xnrg_19_cse7761.ino b/tasmota/xnrg_19_cse7761.ino index d731bef89..571f50fc4 100644 --- a/tasmota/xnrg_19_cse7761.ino +++ b/tasmota/xnrg_19_cse7761.ino @@ -31,9 +31,9 @@ //#define CSE7761_SIMULATE -#define CSE7761_UREF 10000 // Gain 1 * 10000 in V -#define CSE7761_IREF 160000 // Gain 16 * 10000 in A -#define CSE7761_PREF 50000 // in W +#define CSE7761_UREF 42563 // RmsUc +#define CSE7761_IREF 52241 // RmsIAC +#define CSE7761_PREF 44513 // PowerPAC #define CSE7761_REG_SYSCON 0x00 // System Control Register #define CSE7761_REG_EMUCON 0x01 // Metering control register @@ -80,6 +80,7 @@ struct { uint32_t current_rms[2] = { 0 }; uint32_t energy[2] = { 0 }; uint32_t active_power[2] = { 0 }; + uint16_t coefficient[8] = { 0 }; uint8_t energy_update = 0; uint8_t init = 4; uint8_t ready = 0; @@ -162,16 +163,36 @@ uint32_t Cse7761ReadFallback(uint32_t reg, uint32_t prev) { return value; } +uint32_t Cse7761Ref(uint32_t unit) { + switch (unit) { + case 1: return 0x400000 * 100 / CSE7761Data.coefficient[RmsUC]; + case 2: return (0x800000 * 100 / CSE7761Data.coefficient[RmsIAC]) * 10; // Stay within 32 bits + case 3: return 0x80000000 / CSE7761Data.coefficient[PowerPAC]; + } + return 0; +} + bool Cse7761ChipInit(void) { uint16_t calc_chksum = 0xFFFF; for (uint32_t i = 0; i < 8; i++) { - calc_chksum = Cse7761Read(CSE7761_REG_RMSIAC + i); + CSE7761Data.coefficient[i] = Cse7761Read(CSE7761_REG_RMSIAC + i); + calc_chksum += CSE7761Data.coefficient[i]; } calc_chksum = ~calc_chksum; // uint16_t dummy = Cse7761Read(CSE7761_REG_COEFFOFFSET); uint16_t coeff_chksum = Cse7761Read(CSE7761_REG_COEFFCHKSUM); - if (calc_chksum != coeff_chksum) { - AddLog(LOG_LEVEL_DEBUG, PSTR("C61: Not calibrated")); + if ((calc_chksum != coeff_chksum) || (!calc_chksum)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("C61: Default calibration")); + CSE7761Data.coefficient[RmsIAC] = CSE7761_IREF; +// CSE7761Data.coefficient[RmsIBC] = 0xCC05; + CSE7761Data.coefficient[RmsUC] = CSE7761_UREF; + CSE7761Data.coefficient[PowerPAC] = CSE7761_PREF; +// CSE7761Data.coefficient[PowerPBC] = 0xADD7; + } + if (HLW_PREF_PULSE == Settings.energy_power_calibration) { + Settings.energy_voltage_calibration = Cse7761Ref(1); + Settings.energy_current_calibration = Cse7761Ref(2); + Settings.energy_power_calibration = Cse7761Ref(3); } Cse7761Write(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_ENABLE_WRITE); @@ -317,8 +338,7 @@ void Cse7761GetData(void) { // The active power parameter PowerA/B is in two’s complement format, 32-bit data, the highest bit is Sign bit. uint32_t value = Cse7761ReadFallback(CSE7761_REG_RMSU, CSE7761Data.voltage_rms); #ifdef CSE7761_SIMULATE -// value = 2342160; // 234.2V - value = 2000000; // 200V + value = 2342160; // 237.7V #endif CSE7761Data.voltage_rms = (value >= 0x800000) ? 0 : value; @@ -335,14 +355,12 @@ void Cse7761GetData(void) { value = Cse7761ReadFallback(CSE7761_REG_RMSIB, CSE7761Data.current_rms[1]); #ifdef CSE7761_SIMULATE -// value = 29760; // 0.186A - value = 800000; // 5A + value = 29760; // 0.185A #endif CSE7761Data.current_rms[1] = ((value >= 0x800000) || (value < 1600)) ? 0 : value; // No load threshold of 10mA value = Cse7761ReadFallback(CSE7761_REG_POWERPB, CSE7761Data.active_power[1]); #ifdef CSE7761_SIMULATE -// value = 2126641; // 42.5W - value = 50000000; // 1000W + value = 2126641; // 44.05W #endif CSE7761Data.active_power[1] = (0 == CSE7761Data.current_rms[1]) ? 0 : (value & 0x80000000) ? (~value) + 1 : value; @@ -352,24 +370,25 @@ void Cse7761GetData(void) { CSE7761Data.active_power[0], CSE7761Data.active_power[1]); if (Energy.power_on) { // Powered on + // Voltage = RmsU * RmsUC * 10 / 0x400000 + // Energy.voltage[0] = (float)(((uint64_t)CSE7761Data.voltage_rms * CSE7761Data.coefficient[RmsUC] * 10) >> 22) / 1000; // V Energy.voltage[0] = ((float)CSE7761Data.voltage_rms / Settings.energy_voltage_calibration); // V for (uint32_t channel = 0; channel < 2; channel++) { Energy.data_valid[channel] = 0; + // Active power = PowerPA * PowerPAC * 1000 / 0x80000000 + // Energy.active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / Settings.energy_power_calibration; // W if (0 == Energy.active_power[channel]) { Energy.current[channel] = 0; } else { + // Current = RmsIA * RmsIAC / 0x800000 + // Energy.current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / Settings.energy_current_calibration; // A CSE7761Data.energy[channel] += Energy.active_power[channel]; CSE7761Data.energy_update++; } } -/* - } else { // Powered off - Energy.data_valid[0] = ENERGY_WATCHDOG; - Energy.data_valid[1] = ENERGY_WATCHDOG; -*/ } } @@ -428,11 +447,6 @@ void Cse7761SnsInit(void) { SetSerial(38400, TS_SERIAL_8E1); ClaimSerial(); } - if (HLW_PREF_PULSE == Settings.energy_power_calibration) { - Settings.energy_voltage_calibration = CSE7761_UREF; - Settings.energy_current_calibration = CSE7761_IREF; - Settings.energy_power_calibration = CSE7761_PREF; - } } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } @@ -455,15 +469,15 @@ bool Cse7761Command(void) { uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 if (CMND_POWERCAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = CSE7761_PREF; } + if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(3); } // Service in xdrv_03_energy.ino } else if (CMND_VOLTAGECAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = CSE7761_UREF; } + if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(1); } // Service in xdrv_03_energy.ino } else if (CMND_CURRENTCAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = CSE7761_IREF; } + if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(2); } // Service in xdrv_03_energy.ino } else if (CMND_POWERSET == Energy.command_code) { From d231bb47314dabcfd074784bf330552be376d47b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 8 Mar 2021 16:56:33 +0100 Subject: [PATCH 2/8] Prep CSE7761 for final --- tasmota/xnrg_19_cse7761.ino | 46 +++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/tasmota/xnrg_19_cse7761.ino b/tasmota/xnrg_19_cse7761.ino index 571f50fc4..98ad863bb 100644 --- a/tasmota/xnrg_19_cse7761.ino +++ b/tasmota/xnrg_19_cse7761.ino @@ -114,7 +114,7 @@ void Cse7761Write(uint32_t reg, uint32_t data) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("C61: Tx %*_H"), len, buffer); } -uint32_t Cse7761Read(uint32_t reg) { +uint32_t Cse7761Read(uint32_t reg, uint32_t size) { while (Cse7761Serial->available()) { Cse7761Serial->read(); } Cse7761Write(reg, 0); @@ -122,6 +122,8 @@ uint32_t Cse7761Read(uint32_t reg) { uint8_t buffer[8] = { 0 }; uint32_t rcvd = 0; uint32_t timeout = millis() + 3; + +// while (!TimeReached(timeout) && (rcvd <= size)) { while (!TimeReached(timeout)) { int value = Cse7761Serial->read(); if ((value > -1) && (rcvd < sizeof(buffer) -1)) { @@ -155,8 +157,8 @@ uint32_t Cse7761Read(uint32_t reg) { return result; } -uint32_t Cse7761ReadFallback(uint32_t reg, uint32_t prev) { - uint32_t value = Cse7761Read(reg); +uint32_t Cse7761ReadFallback(uint32_t reg, uint32_t prev, uint32_t size) { + uint32_t value = Cse7761Read(reg, size); if (1 == value) { // CRC Error so use previous value read value = prev; } @@ -165,9 +167,9 @@ uint32_t Cse7761ReadFallback(uint32_t reg, uint32_t prev) { uint32_t Cse7761Ref(uint32_t unit) { switch (unit) { - case 1: return 0x400000 * 100 / CSE7761Data.coefficient[RmsUC]; - case 2: return (0x800000 * 100 / CSE7761Data.coefficient[RmsIAC]) * 10; // Stay within 32 bits - case 3: return 0x80000000 / CSE7761Data.coefficient[PowerPAC]; + case RmsUC: return 0x400000 * 100 / CSE7761Data.coefficient[RmsUC]; + case RmsIAC: return (0x800000 * 100 / CSE7761Data.coefficient[RmsIAC]) * 10; // Stay within 32 bits + case PowerPAC: return 0x80000000 / CSE7761Data.coefficient[PowerPAC]; } return 0; } @@ -175,12 +177,12 @@ uint32_t Cse7761Ref(uint32_t unit) { bool Cse7761ChipInit(void) { uint16_t calc_chksum = 0xFFFF; for (uint32_t i = 0; i < 8; i++) { - CSE7761Data.coefficient[i] = Cse7761Read(CSE7761_REG_RMSIAC + i); + CSE7761Data.coefficient[i] = Cse7761Read(CSE7761_REG_RMSIAC + i, 2); calc_chksum += CSE7761Data.coefficient[i]; } calc_chksum = ~calc_chksum; -// uint16_t dummy = Cse7761Read(CSE7761_REG_COEFFOFFSET); - uint16_t coeff_chksum = Cse7761Read(CSE7761_REG_COEFFCHKSUM); +// uint16_t dummy = Cse7761Read(CSE7761_REG_COEFFOFFSET, 2); + uint16_t coeff_chksum = Cse7761Read(CSE7761_REG_COEFFCHKSUM, 2); if ((calc_chksum != coeff_chksum) || (!calc_chksum)) { AddLog(LOG_LEVEL_DEBUG, PSTR("C61: Default calibration")); CSE7761Data.coefficient[RmsIAC] = CSE7761_IREF; @@ -190,9 +192,9 @@ bool Cse7761ChipInit(void) { // CSE7761Data.coefficient[PowerPBC] = 0xADD7; } if (HLW_PREF_PULSE == Settings.energy_power_calibration) { - Settings.energy_voltage_calibration = Cse7761Ref(1); - Settings.energy_current_calibration = Cse7761Ref(2); - Settings.energy_power_calibration = Cse7761Ref(3); + Settings.energy_voltage_calibration = Cse7761Ref(RmsUC); + Settings.energy_current_calibration = Cse7761Ref(RmsIAC); + Settings.energy_power_calibration = Cse7761Ref(PowerPAC); } Cse7761Write(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_ENABLE_WRITE); @@ -201,7 +203,7 @@ bool Cse7761ChipInit(void) { uint32_t timeout = millis() + 8; while (!TimeReached(timeout)) { } - uint8_t sys_status = Cse7761Read(CSE7761_REG_SYSSTATUS); + uint8_t sys_status = Cse7761Read(CSE7761_REG_SYSSTATUS, 1); #ifdef CSE7761_SIMULATE sys_status = 0x11; #endif @@ -336,29 +338,29 @@ void Cse7761GetData(void) { // The effective value of current and voltage Rms is a 24-bit signed number, the highest bit is 0 for valid data, // and when the highest bit is 1, the reading will be processed as zero // The active power parameter PowerA/B is in two’s complement format, 32-bit data, the highest bit is Sign bit. - uint32_t value = Cse7761ReadFallback(CSE7761_REG_RMSU, CSE7761Data.voltage_rms); + uint32_t value = Cse7761ReadFallback(CSE7761_REG_RMSU, CSE7761Data.voltage_rms, 3); #ifdef CSE7761_SIMULATE value = 2342160; // 237.7V #endif CSE7761Data.voltage_rms = (value >= 0x800000) ? 0 : value; - value = Cse7761ReadFallback(CSE7761_REG_RMSIA, CSE7761Data.current_rms[0]); + value = Cse7761ReadFallback(CSE7761_REG_RMSIA, CSE7761Data.current_rms[0], 3); #ifdef CSE7761_SIMULATE value = 455; #endif CSE7761Data.current_rms[0] = ((value >= 0x800000) || (value < 1600)) ? 0 : value; // No load threshold of 10mA - value = Cse7761ReadFallback(CSE7761_REG_POWERPA, CSE7761Data.active_power[0]); + value = Cse7761ReadFallback(CSE7761_REG_POWERPA, CSE7761Data.active_power[0], 4); #ifdef CSE7761_SIMULATE value = 217; #endif CSE7761Data.active_power[0] = (0 == CSE7761Data.current_rms[0]) ? 0 : (value & 0x80000000) ? (~value) + 1 : value; - value = Cse7761ReadFallback(CSE7761_REG_RMSIB, CSE7761Data.current_rms[1]); + value = Cse7761ReadFallback(CSE7761_REG_RMSIB, CSE7761Data.current_rms[1], 3); #ifdef CSE7761_SIMULATE value = 29760; // 0.185A #endif CSE7761Data.current_rms[1] = ((value >= 0x800000) || (value < 1600)) ? 0 : value; // No load threshold of 10mA - value = Cse7761ReadFallback(CSE7761_REG_POWERPB, CSE7761Data.active_power[1]); + value = Cse7761ReadFallback(CSE7761_REG_POWERPB, CSE7761Data.active_power[1], 4); #ifdef CSE7761_SIMULATE value = 2126641; // 44.05W #endif @@ -406,7 +408,7 @@ void Cse7761EverySecond(void) { Cse7761Write(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_RESET); } else if (2 == CSE7761Data.init) { - uint16_t syscon = Cse7761Read(0x00); // Default 0x0A04 + uint16_t syscon = Cse7761Read(0x00, 2); // Default 0x0A04 #ifdef CSE7761_SIMULATE syscon = 0x0A04; #endif @@ -469,15 +471,15 @@ bool Cse7761Command(void) { uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 if (CMND_POWERCAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(3); } + if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(PowerPAC); } // Service in xdrv_03_energy.ino } else if (CMND_VOLTAGECAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(1); } + if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(RmsUC); } // Service in xdrv_03_energy.ino } else if (CMND_CURRENTCAL == Energy.command_code) { - if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(2); } + if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(RmsIAC); } // Service in xdrv_03_energy.ino } else if (CMND_POWERSET == Energy.command_code) { From 84352706e97635605d7e090cd2578f1a01abfa25 Mon Sep 17 00:00:00 2001 From: David Friedland Date: Mon, 8 Mar 2021 22:35:38 -0800 Subject: [PATCH 3/8] support Dimmer < > and / for level move and stop --- tasmota/xdrv_04_light.ino | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 70390e67a..f6b58e491 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1844,6 +1844,16 @@ uint16_t fadeGammaReverse(uint32_t channel, uint16_t vg) { } } +uint8_t LightGetCurFadeBri(void) { + uint8_t max_bri = 0; + uint8_t bri_i = 0; + for (uint8_t i = 0; i < LST_MAX; i++) { + bri_i = changeUIntScale(fadeGammaReverse(i, Light.fade_cur_10[i]), 4, 1023, 1, 100); + if (bri_i > max_bri) max_bri = bri_i ; + } + return max_bri; +} + bool LightApplyFade(void) { // did the value chanegd and needs to be applied static uint32_t last_millis = 0; uint32_t now = millis(); @@ -2711,12 +2721,18 @@ void CmndDimmer(void) } else { dimmer = light_state.getDimmer(XdrvMailbox.index); } - // Handle +/- special command + // Handle +/-/!/ special commands if (1 == XdrvMailbox.data_len) { if ('+' == XdrvMailbox.data[0]) { XdrvMailbox.payload = (dimmer > (100 - Settings.dimmer_step - 1)) ? 100 : dimmer + Settings.dimmer_step; } else if ('-' == XdrvMailbox.data[0]) { XdrvMailbox.payload = (dimmer < (Settings.dimmer_step + 1)) ? 1 : dimmer - Settings.dimmer_step; + } else if ('!' == XdrvMailbox.data[0] && Light.fade_running) { + XdrvMailbox.payload = LightGetCurFadeBri(); + } else if ('<' == XdrvMailbox.data[0] ) { + XdrvMailbox.payload = 1; + } else if ('>' == XdrvMailbox.data[0] ) { + XdrvMailbox.payload = 100; } } // If value is ok, change it, otherwise report old value From 8e5a9c11b7cd3b88e1ea109d2c06ccaa0dd0f7a0 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Tue, 9 Mar 2021 12:10:37 +0100 Subject: [PATCH 4/8] fix sml 24 bit signed --- tasmota/xsns_53_sml.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tasmota/xsns_53_sml.ino b/tasmota/xsns_53_sml.ino index a84ad58de..4b9ccc1e8 100755 --- a/tasmota/xsns_53_sml.ino +++ b/tasmota/xsns_53_sml.ino @@ -1077,6 +1077,11 @@ double dval; #endif break; case 3: + // signed 24 bit + value=(int32_t)(uvalue<<8); + value/=256; + break; + case 4: // signed 32 bit value=(int32_t)uvalue; From ef39821b6d68f444f9b7dfa01f4c2faf225cb1a3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 9 Mar 2021 16:50:52 +0100 Subject: [PATCH 5/8] Fix OTA auto gz selection --- tasmota/support_tasmota.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 642b6afeb..9604be4ee 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1092,7 +1092,7 @@ void Every250mSeconds(void) } #endif // FIRMWARE_MINIMAL if (ota_retry_counter < OTA_ATTEMPTS / 2) { - if (!strcasecmp_P(TasmotaGlobal.mqtt_data, PSTR(".gz"))) { + if (strstr_P(TasmotaGlobal.mqtt_data, PSTR(".gz"))) { // Might be made case insensitive... ota_retry_counter = 1; } else { strcat_P(TasmotaGlobal.mqtt_data, PSTR(".gz")); From 31c238c1e95cdf85fab173d534e9e7676871a72f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 9 Mar 2021 16:52:14 +0100 Subject: [PATCH 6/8] Fix DS18x20 driver timing issue --- tasmota/xsns_05_ds18x20.ino | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tasmota/xsns_05_ds18x20.ino b/tasmota/xsns_05_ds18x20.ino index b95523cd9..8c5c2970d 100644 --- a/tasmota/xsns_05_ds18x20.ino +++ b/tasmota/xsns_05_ds18x20.ino @@ -56,6 +56,7 @@ struct DS18X20STRUCT { uint8_t ds18x20_sensors = 0; int8_t ds18x20_pin = 0; // Shelly GPIO3 input only int8_t ds18x20_pin_out = 0; // Shelly GPIO00 output only +uint8_t ds18x20_pin_mode = 0; // INPUT or INPUT_PULLUP (=2) bool ds18x20_dual_mode = false; // Single pin mode char ds18x20_types[17]; #ifdef W1_PARASITE_POWER @@ -82,7 +83,7 @@ uint8_t OneWireReset(void) uint8_t retries = 125; if (!ds18x20_dual_mode) { - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + pinMode(ds18x20_pin, ds18x20_pin_mode); do { if (--retries == 0) { return 0; @@ -92,7 +93,7 @@ uint8_t OneWireReset(void) pinMode(ds18x20_pin, OUTPUT); digitalWrite(ds18x20_pin, LOW); delayMicroseconds(480); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + pinMode(ds18x20_pin, ds18x20_pin_mode); delayMicroseconds(70); uint8_t r = !digitalRead(ds18x20_pin); delayMicroseconds(410); @@ -139,7 +140,7 @@ uint8_t OneWire1ReadBit(void) pinMode(ds18x20_pin, OUTPUT); digitalWrite(ds18x20_pin, LOW); delayMicroseconds(3); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + pinMode(ds18x20_pin, ds18x20_pin_mode); delayMicroseconds(10); uint8_t r = digitalRead(ds18x20_pin); delayMicroseconds(53); @@ -309,12 +310,13 @@ void Ds18x20Init(void) uint64_t ids[DS18X20_MAX_SENSORS]; ds18x20_pin = Pin(GPIO_DSB); + ds18x20_pin_mode = Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT; // SetOption74 - Enable internal pullup for single DS18x20 sensor if (PinUsed(GPIO_DSB_OUT)) { ds18x20_pin_out = Pin(GPIO_DSB_OUT); ds18x20_dual_mode = true; // Dual pins mode as used by Shelly pinMode(ds18x20_pin_out, OUTPUT); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + pinMode(ds18x20_pin, ds18x20_pin_mode); } OneWireResetSearch(); From b8a2d9a1611e000a4fdac0b9183865df4ec23a61 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 9 Mar 2021 18:01:29 +0100 Subject: [PATCH 7/8] Fix DS18x20 driver timing issue (#11270) Fix DS18x20 driver timing issue (#11270) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/xsns_05_ds18x20.ino | 228 ++++++++++++++++-------------------- 3 files changed, 101 insertions(+), 129 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4465d003b..ded922bad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ All notable changes to this project will be documented in this file. - Zigbee exception when bad frame is received (#11192) - ESP32 flash script for Odroid and Core2 (#11227) - ESP32 WS2812 bitbang support (#11248) +- DS18x20 driver timing issue (#11270) ## [Released] diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 960d14b18..c5ad1ba9e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,3 +109,4 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota - Zigbee exception when bad frame is received [#11192](https://github.com/arendst/Tasmota/issues/11192) - ESP32 flash script for Odroid and Core2 [#11227](https://github.com/arendst/Tasmota/issues/11227) - ESP32 WS2812 bitbang support [#11248](https://github.com/arendst/Tasmota/issues/11248) +- DS18x20 driver timing issue (#11270) diff --git a/tasmota/xsns_05_ds18x20.ino b/tasmota/xsns_05_ds18x20.ino index 8c5c2970d..ecb107e43 100644 --- a/tasmota/xsns_05_ds18x20.ino +++ b/tasmota/xsns_05_ds18x20.ino @@ -51,18 +51,21 @@ struct DS18X20STRUCT { uint8_t address[8]; uint8_t index; uint8_t valid; - float temperature; + float temperature; } ds18x20_sensor[DS18X20_MAX_SENSORS]; -uint8_t ds18x20_sensors = 0; -int8_t ds18x20_pin = 0; // Shelly GPIO3 input only -int8_t ds18x20_pin_out = 0; // Shelly GPIO00 output only -uint8_t ds18x20_pin_mode = 0; // INPUT or INPUT_PULLUP (=2) -bool ds18x20_dual_mode = false; // Single pin mode -char ds18x20_types[17]; + +struct { #ifdef W1_PARASITE_POWER -uint8_t ds18x20_sensor_curr = 0; -unsigned long w1_power_until = 0; + uint32_t w1_power_until = 0; + uint8_t current_sensor = 0; #endif + char name[17]; + uint8_t sensors = 0; + uint8_t input_mode = 0; // INPUT or INPUT_PULLUP (=2) + int8_t pin = 0; // Shelly GPIO3 input only + int8_t pin_out = 0; // Shelly GPIO00 output only + bool dual_mode = false; // Single pin mode +} DS18X20Data; /*********************************************************************************************\ * Embedded tuned OneWire library @@ -78,100 +81,94 @@ unsigned char onewire_rom_id[8] = { 0 }; /*------------------------------------------------------------------------------------------*/ -uint8_t OneWireReset(void) -{ +uint8_t OneWireReset(void) { uint8_t retries = 125; - if (!ds18x20_dual_mode) { - pinMode(ds18x20_pin, ds18x20_pin_mode); + if (!DS18X20Data.dual_mode) { + pinMode(DS18X20Data.pin, DS18X20Data.input_mode); do { if (--retries == 0) { return 0; } delayMicroseconds(2); - } while (!digitalRead(ds18x20_pin)); - pinMode(ds18x20_pin, OUTPUT); - digitalWrite(ds18x20_pin, LOW); + } while (!digitalRead(DS18X20Data.pin)); + pinMode(DS18X20Data.pin, OUTPUT); + digitalWrite(DS18X20Data.pin, LOW); delayMicroseconds(480); - pinMode(ds18x20_pin, ds18x20_pin_mode); + pinMode(DS18X20Data.pin, DS18X20Data.input_mode); delayMicroseconds(70); - uint8_t r = !digitalRead(ds18x20_pin); + uint8_t r = !digitalRead(DS18X20Data.pin); delayMicroseconds(410); return r; } else { - digitalWrite(ds18x20_pin_out, HIGH); + digitalWrite(DS18X20Data.pin_out, HIGH); do { if (--retries == 0) { return 0; } delayMicroseconds(2); - } while (!digitalRead(ds18x20_pin)); - digitalWrite(ds18x20_pin_out, LOW); + } while (!digitalRead(DS18X20Data.pin)); + digitalWrite(DS18X20Data.pin_out, LOW); delayMicroseconds(480); - digitalWrite(ds18x20_pin_out, HIGH); + digitalWrite(DS18X20Data.pin_out, HIGH); delayMicroseconds(70); - uint8_t r = !digitalRead(ds18x20_pin); + uint8_t r = !digitalRead(DS18X20Data.pin); delayMicroseconds(410); return r; } } -void OneWireWriteBit(uint8_t v) -{ +void OneWireWriteBit(uint8_t v) { static const uint8_t delay_low[2] = { 65, 10 }; static const uint8_t delay_high[2] = { 5, 55 }; v &= 1; - if (!ds18x20_dual_mode) { - digitalWrite(ds18x20_pin, LOW); - pinMode(ds18x20_pin, OUTPUT); + if (!DS18X20Data.dual_mode) { + digitalWrite(DS18X20Data.pin, LOW); + pinMode(DS18X20Data.pin, OUTPUT); delayMicroseconds(delay_low[v]); - digitalWrite(ds18x20_pin, HIGH); + digitalWrite(DS18X20Data.pin, HIGH); } else { - digitalWrite(ds18x20_pin_out, LOW); + digitalWrite(DS18X20Data.pin_out, LOW); delayMicroseconds(delay_low[v]); - digitalWrite(ds18x20_pin_out, HIGH); + digitalWrite(DS18X20Data.pin_out, HIGH); } delayMicroseconds(delay_high[v]); } -uint8_t OneWire1ReadBit(void) -{ - pinMode(ds18x20_pin, OUTPUT); - digitalWrite(ds18x20_pin, LOW); +uint8_t OneWire1ReadBit(void) { + pinMode(DS18X20Data.pin, OUTPUT); + digitalWrite(DS18X20Data.pin, LOW); delayMicroseconds(3); - pinMode(ds18x20_pin, ds18x20_pin_mode); + pinMode(DS18X20Data.pin, DS18X20Data.input_mode); delayMicroseconds(10); - uint8_t r = digitalRead(ds18x20_pin); + uint8_t r = digitalRead(DS18X20Data.pin); delayMicroseconds(53); return r; } -uint8_t OneWire2ReadBit(void) -{ - digitalWrite(ds18x20_pin_out, LOW); +uint8_t OneWire2ReadBit(void) { + digitalWrite(DS18X20Data.pin_out, LOW); delayMicroseconds(3); - digitalWrite(ds18x20_pin_out, HIGH); + digitalWrite(DS18X20Data.pin_out, HIGH); delayMicroseconds(10); - uint8_t r = digitalRead(ds18x20_pin); + uint8_t r = digitalRead(DS18X20Data.pin); delayMicroseconds(53); return r; } /*------------------------------------------------------------------------------------------*/ -void OneWireWrite(uint8_t v) -{ +void OneWireWrite(uint8_t v) { for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { OneWireWriteBit((bit_mask & v) ? 1 : 0); } } -uint8_t OneWireRead(void) -{ +uint8_t OneWireRead(void) { uint8_t r = 0; - if (!ds18x20_dual_mode) { + if (!DS18X20Data.dual_mode) { for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { if (OneWire1ReadBit()) { r |= bit_mask; @@ -187,26 +184,14 @@ uint8_t OneWireRead(void) return r; } -void OneWireSelect(const uint8_t rom[8]) -{ +void OneWireSelect(const uint8_t rom[8]) { OneWireWrite(W1_MATCH_ROM); for (uint32_t i = 0; i < 8; i++) { OneWireWrite(rom[i]); } } -void OneWireResetSearch(void) -{ - onewire_last_discrepancy = 0; - onewire_last_device_flag = false; - onewire_last_family_discrepancy = 0; - for (uint32_t i = 0; i < 8; i++) { - onewire_rom_id[i] = 0; - } -} - -uint8_t OneWireSearch(uint8_t *newAddr) -{ +uint8_t OneWireSearch(uint8_t *newAddr) { uint8_t id_bit_number = 1; uint8_t last_zero = 0; uint8_t rom_byte_number = 0; @@ -225,7 +210,7 @@ uint8_t OneWireSearch(uint8_t *newAddr) } OneWireWrite(W1_SEARCH_ROM); do { - if (!ds18x20_dual_mode) { + if (!DS18X20Data.dual_mode) { id_bit = OneWire1ReadBit(); cmp_id_bit = OneWire1ReadBit(); } else { @@ -284,8 +269,7 @@ uint8_t OneWireSearch(uint8_t *newAddr) return search_result; } -bool OneWireCrc8(uint8_t *addr) -{ +bool OneWireCrc8(uint8_t *addr) { uint8_t crc = 0; uint8_t len = 8; @@ -305,58 +289,60 @@ bool OneWireCrc8(uint8_t *addr) /********************************************************************************************/ -void Ds18x20Init(void) -{ - uint64_t ids[DS18X20_MAX_SENSORS]; - - ds18x20_pin = Pin(GPIO_DSB); - ds18x20_pin_mode = Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT; // SetOption74 - Enable internal pullup for single DS18x20 sensor +void Ds18x20Init(void) { + DS18X20Data.pin = Pin(GPIO_DSB); + DS18X20Data.input_mode = Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT; // SetOption74 - Enable internal pullup for single DS18x20 sensor if (PinUsed(GPIO_DSB_OUT)) { - ds18x20_pin_out = Pin(GPIO_DSB_OUT); - ds18x20_dual_mode = true; // Dual pins mode as used by Shelly - pinMode(ds18x20_pin_out, OUTPUT); - pinMode(ds18x20_pin, ds18x20_pin_mode); + DS18X20Data.pin_out = Pin(GPIO_DSB_OUT); + DS18X20Data.dual_mode = true; // Dual pins mode as used by Shelly + pinMode(DS18X20Data.pin_out, OUTPUT); + pinMode(DS18X20Data.pin, DS18X20Data.input_mode); } - OneWireResetSearch(); + onewire_last_discrepancy = 0; + onewire_last_device_flag = false; + onewire_last_family_discrepancy = 0; + for (uint32_t i = 0; i < 8; i++) { + onewire_rom_id[i] = 0; + } - ds18x20_sensors = 0; - while (ds18x20_sensors < DS18X20_MAX_SENSORS) { - if (!OneWireSearch(ds18x20_sensor[ds18x20_sensors].address)) { + uint64_t ids[DS18X20_MAX_SENSORS]; + DS18X20Data.sensors = 0; + while (DS18X20Data.sensors < DS18X20_MAX_SENSORS) { + if (!OneWireSearch(ds18x20_sensor[DS18X20Data.sensors].address)) { break; } - if (OneWireCrc8(ds18x20_sensor[ds18x20_sensors].address) && - ((ds18x20_sensor[ds18x20_sensors].address[0] == DS18S20_CHIPID) || - (ds18x20_sensor[ds18x20_sensors].address[0] == DS1822_CHIPID) || - (ds18x20_sensor[ds18x20_sensors].address[0] == DS18B20_CHIPID) || - (ds18x20_sensor[ds18x20_sensors].address[0] == MAX31850_CHIPID))) { - ds18x20_sensor[ds18x20_sensors].index = ds18x20_sensors; - ids[ds18x20_sensors] = ds18x20_sensor[ds18x20_sensors].address[0]; // Chip id + if (OneWireCrc8(ds18x20_sensor[DS18X20Data.sensors].address) && + ((ds18x20_sensor[DS18X20Data.sensors].address[0] == DS18S20_CHIPID) || + (ds18x20_sensor[DS18X20Data.sensors].address[0] == DS1822_CHIPID) || + (ds18x20_sensor[DS18X20Data.sensors].address[0] == DS18B20_CHIPID) || + (ds18x20_sensor[DS18X20Data.sensors].address[0] == MAX31850_CHIPID))) { + ds18x20_sensor[DS18X20Data.sensors].index = DS18X20Data.sensors; + ids[DS18X20Data.sensors] = ds18x20_sensor[DS18X20Data.sensors].address[0]; // Chip id for (uint32_t j = 6; j > 0; j--) { - ids[ds18x20_sensors] = ids[ds18x20_sensors] << 8 | ds18x20_sensor[ds18x20_sensors].address[j]; + ids[DS18X20Data.sensors] = ids[DS18X20Data.sensors] << 8 | ds18x20_sensor[DS18X20Data.sensors].address[j]; } - ds18x20_sensors++; + DS18X20Data.sensors++; } } - for (uint32_t i = 0; i < ds18x20_sensors; i++) { - for (uint32_t j = i + 1; j < ds18x20_sensors; j++) { + for (uint32_t i = 0; i < DS18X20Data.sensors; i++) { + for (uint32_t j = i + 1; j < DS18X20Data.sensors; j++) { if (ids[ds18x20_sensor[i].index] > ids[ds18x20_sensor[j].index]) { // Sort ascending std::swap(ds18x20_sensor[i].index, ds18x20_sensor[j].index); } } } - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), ds18x20_sensors); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), DS18X20Data.sensors); } -void Ds18x20Convert(void) -{ +void Ds18x20Convert(void) { OneWireReset(); #ifdef W1_PARASITE_POWER // With parasite power address one sensor at a time - if (++ds18x20_sensor_curr >= ds18x20_sensors) - ds18x20_sensor_curr = 0; - OneWireSelect(ds18x20_sensor[ds18x20_sensor_curr].address); + if (++DS18X20Data.current_sensor >= DS18X20Data.sensors) + DS18X20Data.current_sensor = 0; + OneWireSelect(ds18x20_sensor[DS18X20Data.current_sensor].address); #else OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus #endif @@ -364,8 +350,7 @@ void Ds18x20Convert(void) // delay(750); // 750ms should be enough for 12bit conv } -bool Ds18x20Read(uint8_t sensor) -{ +bool Ds18x20Read(uint8_t sensor) { uint8_t data[9]; int8_t sign = 1; @@ -381,16 +366,6 @@ bool Ds18x20Read(uint8_t sensor) if (OneWireCrc8(data)) { switch(ds18x20_sensor[index].address[0]) { case DS18S20_CHIPID: { -/* - if (data[1] > 0x80) { - data[0] = (~data[0]) +1; - sign = -1; // App-Note fix possible sign error - } - float temp9 = (float)(data[0] >> 1) * sign; - ds18x20_sensor[index].temperature = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); - - Replaced by below based on issue #8777 -*/ int16_t tempS = (((data[1] << 8) | (data[0] & 0xFE)) << 3) | ((0x10 - data[6]) & 0x0F); ds18x20_sensor[index].temperature = ConvertTemp(tempS * 0.0625 - 0.250); @@ -410,7 +385,7 @@ bool Ds18x20Read(uint8_t sensor) OneWireSelect(ds18x20_sensor[index].address); OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM #ifdef W1_PARASITE_POWER - w1_power_until = millis() + 10; // 10ms specified duration for EEPROM write + DS18X20Data.w1_power_until = millis() + 10; // 10ms specified duration for EEPROM write #endif } uint16_t temp12 = (data[1] << 8) + data[0]; @@ -435,8 +410,7 @@ bool Ds18x20Read(uint8_t sensor) return false; } -void Ds18x20Name(uint8_t sensor) -{ +void Ds18x20Name(uint8_t sensor) { uint8_t index = sizeof(ds18x20_chipids); while (index) { if (ds18x20_sensor[ds18x20_sensor[sensor].index].address[0] == ds18x20_chipids[index]) { @@ -444,46 +418,44 @@ void Ds18x20Name(uint8_t sensor) } index--; } - GetTextIndexed(ds18x20_types, sizeof(ds18x20_types), index, kDs18x20Types); - if (ds18x20_sensors > 1) { + GetTextIndexed(DS18X20Data.name, sizeof(DS18X20Data.name), index, kDs18x20Types); + if (DS18X20Data.sensors > 1) { #ifdef DS18x20_USE_ID_AS_NAME char address[17]; for (uint32_t j = 0; j < 3; j++) { sprintf(address+2*j, "%02X", ds18x20_sensor[ds18x20_sensor[sensor].index].address[3-j]); // Only last 3 bytes } - snprintf_P(ds18x20_types, sizeof(ds18x20_types), PSTR("%s%c%s"), ds18x20_types, IndexSeparator(), address); + snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%s"), DS18X20Data.name, IndexSeparator(), address); #else - snprintf_P(ds18x20_types, sizeof(ds18x20_types), PSTR("%s%c%d"), ds18x20_types, IndexSeparator(), sensor +1); + snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%d"), DS18X20Data.name, IndexSeparator(), sensor +1); #endif } } /********************************************************************************************/ -void Ds18x20EverySecond(void) -{ - if (!ds18x20_sensors) { return; } +void Ds18x20EverySecond(void) { + if (!DS18X20Data.sensors) { return; } #ifdef W1_PARASITE_POWER // skip access if there is still an eeprom write ongoing unsigned long now = millis(); - if (now < w1_power_until) - return; + if (now < DS18X20Data.w1_power_until) { return; } #endif if (TasmotaGlobal.uptime & 1 #ifdef W1_PARASITE_POWER // if more than 1 sensor and only parasite power: convert every cycle - || ds18x20_sensors >= 2 + || DS18X20Data.sensors >= 2 #endif ) { // 2mS Ds18x20Convert(); // Start conversion, takes up to one second } else { - for (uint32_t i = 0; i < ds18x20_sensors; i++) { + for (uint32_t i = 0; i < DS18X20Data.sensors; i++) { // 12mS per device if (!Ds18x20Read(i)) { // Read temperature Ds18x20Name(i); - AddLogMissed(ds18x20_types, ds18x20_sensor[ds18x20_sensor[i].index].valid); + AddLogMissed(DS18X20Data.name, ds18x20_sensor[ds18x20_sensor[i].index].valid); #ifdef USE_DS18x20_RECONFIGURE if (!ds18x20_sensor[ds18x20_sensor[i].index].valid) { memset(&ds18x20_sensor, 0, sizeof(ds18x20_sensor)); @@ -495,9 +467,8 @@ void Ds18x20EverySecond(void) } } -void Ds18x20Show(bool json) -{ - for (uint32_t i = 0; i < ds18x20_sensors; i++) { +void Ds18x20Show(bool json) { + for (uint32_t i = 0; i < DS18X20Data.sensors; i++) { uint8_t index = ds18x20_sensor[i].index; if (ds18x20_sensor[index].valid) { // Check for valid temperature @@ -509,7 +480,7 @@ void Ds18x20Show(bool json) sprintf(address+2*j, "%02X", ds18x20_sensor[index].address[6-j]); // Skip sensor type and crc } ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ID "\":\"%s\",\"" D_JSON_TEMPERATURE "\":%*_f}"), - ds18x20_types, address, Settings.flag2.temperature_resolution, &ds18x20_sensor[index].temperature); + DS18X20Data.name, address, Settings.flag2.temperature_resolution, &ds18x20_sensor[index].temperature); #ifdef USE_DOMOTICZ if ((0 == TasmotaGlobal.tele_period) && (0 == i)) { DomoticzFloatSensor(DZ_TEMP, ds18x20_sensor[index].temperature); @@ -522,7 +493,7 @@ void Ds18x20Show(bool json) #endif // USE_KNX #ifdef USE_WEBSERVER } else { - WSContentSend_Temp(ds18x20_types, ds18x20_sensor[index].temperature); + WSContentSend_Temp(DS18X20Data.name, ds18x20_sensor[index].temperature); #endif // USE_WEBSERVER } } @@ -533,8 +504,7 @@ void Ds18x20Show(bool json) * Interface \*********************************************************************************************/ -bool Xsns05(uint8_t function) -{ +bool Xsns05(uint8_t function) { bool result = false; if (PinUsed(GPIO_DSB)) { From d3015878c5797ba6a642bc44fdd1bb993a3d297d Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 9 Mar 2021 23:05:12 +0100 Subject: [PATCH 8/8] Fix ZbScan json output #11264 --- tasmota/xdrv_23_zigbee_8_parsers.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 083e6c966..0a5fe2e2d 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -190,7 +190,7 @@ int32_t EZSP_EnergyScanComplete(int32_t res, const SBuffer &buf) { // Dump energu scan results // void EnergyScanResults(void) { - Response_P(PSTR("{\"" D_JSON_ZIGBEE_SCAN "\":[")); + Response_P(PSTR("{\"" D_JSON_ZIGBEE_SCAN "\":{")); for (uint32_t i = 0; i < USE_ZIGBEE_CHANNEL_COUNT; i++) { int8_t energy = zigbee.energy[i]; @@ -210,7 +210,7 @@ void EnergyScanResults(void) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Channel %2d: %s"), i + USE_ZIGBEE_CHANNEL_MIN, bar_str); } - ResponseAppend_P(PSTR("]}")); + ResponseAppend_P(PSTR("}}")); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); }