diff --git a/src/protocols/MeterW1therm.cpp b/src/protocols/MeterW1therm.cpp index d157a670..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,8 +132,11 @@ 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= if (fgets(buffer, 100, fp)) { // e.g. 07 01 55 00 7f ff 0c 10 18 t=16437 + if (!check_quirks(device, buffer)) + return false; + + // now parse t= char *pos = strstr(buffer, "t="); if (pos) { pos += 2;