From 7c33d0fc9a606c2f975e6190cb82b16440d4ee73 Mon Sep 17 00:00:00 2001 From: h-eff <150251193+h-eff@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:19:30 +0100 Subject: [PATCH 1/2] Update MeterW1therm.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added some code to catch 1) the erroneous 0°C temperature reading, 2) the 85°C error reading and 3) the 127.9375°C error reading before they end up in the database. This is based upon work from Chris Petrich: https://github.com/cpetrich/counterfeit_DS18B20 A similar check for conversion success was added to w1_therm kernel module in 2020: https://github.com/torvalds/linux/blame/305230142ae0637213bf6e04f6d9f10bbcb74af8/drivers/w1/slaves/w1_therm.c#L1186-L1197 I did not test this code on a RasPi yet. --- src/protocols/MeterW1therm.cpp | 44 +++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/protocols/MeterW1therm.cpp b/src/protocols/MeterW1therm.cpp index d157a670..c807510a 100644 --- a/src/protocols/MeterW1therm.cpp +++ b/src/protocols/MeterW1therm.cpp @@ -83,8 +83,50 @@ bool MeterW1therm::W1sysHWif::readTemp(const std::string &device, double &value) print(log_debug, "CRC not ok from %s (%s)", "w1t", dev.c_str(), buffer); } else { // crc ok - // now parse t= + // now check for other errors: if (fgets(buffer, 100, fp)) { // e.g. 07 01 55 00 7f ff 0c 10 18 t=16437 + + ///// Start of new code: Catch DS18B20-specific errors. ///// + /// For reference: https://github.com/cpetrich/counterfeit_DS18B20 + /// Check byte 6 of scratchpad to recognize error readings. + /// Genuine DS18B20 compute byte 6 as the difference from + /// 00001111 & to 00010000; most clones always use 0x0c. + /// Genuine DS18B20 are still in the 00000xxxxxxx address range + /// as of 2023; clones are not. + + // Check for sensor family DS18B20 via device == "28*": + if (device[0]=='2' && device[1]=='8') { + if (!strncmp(buffer,"00 00 00 00 00 00 00 00 00",26)) { + // According to DS18B20 datasheet, this scratchpad-reading MUST be wrong. + print(log_debug, "only zeroes from %s (%s), " + "the 1wire-bus is probably unstable", "w1t", dev.c_str(), buffer); + return false; + } + // if (buffer == "?? ?? ?? ?? ?? ?? 0c*"), maybe an error has happened: + if (buffer[18]=='0' && buffer[19]=='c') { + // only do this handling for genuine DS18B20, e.g. device="28-0000*": + if (device[3]=='0' && buffer[4]=='0' && buffer[5]=='0' && buffer[6]=='0') { + // if (buffer == "50 05*"), 0x0550/16 = 85 degrees Celsius + if (!strncmp(buffer,"50 05",5)) { + // Sensor returned default boot-up value; did not complete temperature conversion. + print(log_debug, "85 degree error from %s (%s), " + "the 1wire-bus is probably unstable", "w1t", dev.c_str(), buffer); + return false; + } + // (if buffer == "ff 07*"), 0x07ff/16 = 127.9375 degrees Celsius + if (!strncmp(buffer,"ff 07",5)) { + // Sensor returned code for insufficient power during temperature conversion. + // This can happen in parasitic 2-wire circuits with floating Vcc pins. + print(log_debug, "insufficient power error from %s (%s), " + "maybe Vcc was left floating", "w1t", dev.c_str(), buffer); + return false; + } + } + } + } + ///// End of new code. ///// + + // now parse t= char *pos = strstr(buffer, "t="); if (pos) { pos += 2; From 160df1323ca15d6197d3b1cdd28081c6709bbc88 Mon Sep 17 00:00:00 2001 From: r00t Date: Fri, 5 Jan 2024 23:35:32 +0100 Subject: [PATCH 2/2] MeterW1therm: move quirks checking code into check_quirks() --- src/protocols/MeterW1therm.cpp | 94 +++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/src/protocols/MeterW1therm.cpp b/src/protocols/MeterW1therm.cpp index c807510a..ed275a51 100644 --- a/src/protocols/MeterW1therm.cpp +++ b/src/protocols/MeterW1therm.cpp @@ -63,6 +63,55 @@ bool MeterW1therm::W1sysHWif::scanW1devices() { return false; } +// check for DS18B20-specific errors +// For reference: https://github.com/cpetrich/counterfeit_DS18B20 +// Check byte 6 of scratchpad to recognize error readings. +// Genuine DS18B20 compute byte 6 as the difference from +// 00001111 & to 00010000; most clones always use 0x0c. +// Genuine DS18B20 are still in the 00000xxxxxxx address range +// as of 2023; clones are not. +bool MeterW1therm::check_quirks(const std::string &device, char buffer[100]) { + // Check for sensor family DS18B20 via device == "28*": + if (device[0] != '2' || device[1] != '8') + return true; + + if (!strncmp(buffer, "00 00 00 00 00 00 00 00 00", 26)) { + // According to DS18B20 datasheet, this scratchpad-reading MUST be wrong. + print(log_debug, + "only zeroes from %s (%s), " + "the 1wire-bus is probably unstable", + "w1t", dev.c_str(), buffer); + return false; + } + // if (buffer == "?? ?? ?? ?? ?? ?? 0c*"), maybe an error has happened: + if (buffer[18] == '0' && buffer[19] == 'c') { + // only do this handling for genuine DS18B20, e.g. device="28-0000*": + if (device[3] == '0' && buffer[4] == '0' && buffer[5] == '0' && buffer[6] == '0') { + // if (buffer == "50 05*"), 0x0550/16 = 85 degrees Celsius + if (!strncmp(buffer, "50 05", 5)) { + // Sensor returned default boot-up value; did not complete temperature + // conversion. + print(log_debug, + "85 degree error from %s (%s), " + "the 1wire-bus is probably unstable", + "w1t", dev.c_str(), buffer); + return false; + } + // (if buffer == "ff 07*"), 0x07ff/16 = 127.9375 degrees Celsius + if (!strncmp(buffer, "ff 07", 5)) { + // Sensor returned code for insufficient power during temperature conversion. + // This can happen in parasitic 2-wire circuits with floating Vcc pins. + print(log_debug, + "insufficient power error from %s (%s), " + "maybe Vcc was left floating", + "w1t", dev.c_str(), buffer); + return false; + } + } + } + return true; +} + bool MeterW1therm::W1sysHWif::readTemp(const std::string &device, double &value) { bool toret = false; // read from /sys/bus/w1/devices//w1_slave @@ -83,49 +132,10 @@ bool MeterW1therm::W1sysHWif::readTemp(const std::string &device, double &value) print(log_debug, "CRC not ok from %s (%s)", "w1t", dev.c_str(), buffer); } else { // crc ok - // now check for other errors: if (fgets(buffer, 100, fp)) { // e.g. 07 01 55 00 7f ff 0c 10 18 t=16437 - - ///// Start of new code: Catch DS18B20-specific errors. ///// - /// For reference: https://github.com/cpetrich/counterfeit_DS18B20 - /// Check byte 6 of scratchpad to recognize error readings. - /// Genuine DS18B20 compute byte 6 as the difference from - /// 00001111 & to 00010000; most clones always use 0x0c. - /// Genuine DS18B20 are still in the 00000xxxxxxx address range - /// as of 2023; clones are not. - - // Check for sensor family DS18B20 via device == "28*": - if (device[0]=='2' && device[1]=='8') { - if (!strncmp(buffer,"00 00 00 00 00 00 00 00 00",26)) { - // According to DS18B20 datasheet, this scratchpad-reading MUST be wrong. - print(log_debug, "only zeroes from %s (%s), " - "the 1wire-bus is probably unstable", "w1t", dev.c_str(), buffer); - return false; - } - // if (buffer == "?? ?? ?? ?? ?? ?? 0c*"), maybe an error has happened: - if (buffer[18]=='0' && buffer[19]=='c') { - // only do this handling for genuine DS18B20, e.g. device="28-0000*": - if (device[3]=='0' && buffer[4]=='0' && buffer[5]=='0' && buffer[6]=='0') { - // if (buffer == "50 05*"), 0x0550/16 = 85 degrees Celsius - if (!strncmp(buffer,"50 05",5)) { - // Sensor returned default boot-up value; did not complete temperature conversion. - print(log_debug, "85 degree error from %s (%s), " - "the 1wire-bus is probably unstable", "w1t", dev.c_str(), buffer); - return false; - } - // (if buffer == "ff 07*"), 0x07ff/16 = 127.9375 degrees Celsius - if (!strncmp(buffer,"ff 07",5)) { - // Sensor returned code for insufficient power during temperature conversion. - // This can happen in parasitic 2-wire circuits with floating Vcc pins. - print(log_debug, "insufficient power error from %s (%s), " - "maybe Vcc was left floating", "w1t", dev.c_str(), buffer); - return false; - } - } - } - } - ///// End of new code. ///// - + if (!check_quirks(device, buffer)) + return false; + // now parse t= char *pos = strstr(buffer, "t="); if (pos) {