Multiple DS18B20 signalling reliability issues

Hi,

I’m trying to hook up a bunch of DS18B20s to an ESP8266 to monitor temperatures around my house.

I’ve had great success with up to appx. 6 sensors at around 2m max cable length, as I’m adding more and more sensors, I’ve started to get dropouts (sensors reading “-127C”).

I tried coding a loop to re-read sensors if an out-of-range value was received, though this ended up behaving very strangely, with some readings being applied to the wrong sensor (hopefully this is a simple coding problem - the loop can be seen in the code below, commented out). This persisted even when I reduced the number of sensors to a known-good configuration.

From research, it seems there’s a way to verify by CRC if the data is ok - though I think in my case it’s a straight up failure to read (gives -127C from the Dallas library).

The DS18B20s are the pre-wired waterproof type, hooked up with a 4.4k pull-up to 3v3, and Vcc connected to 5v (all on the ESP8266). I’ve got a single 1m “extension” (4-wire phone cable) out to a “hub”, which has a bunch of sensors (up to 8) hooked up, then I plan to also have another extension from there to another hub (this is where I started to see problems, even with only 1 sensor hooked into the furthest “hub”).

My theories are:

5V (Vcc) sagging - though it measures OK at the far end during use, as far as I can tell - could be sagging for a fraction of a second during communications. I was originally using 3v3 for Vcc, bumped up to 5v to test.
Signal reflections/noise - what can I do to mitigate this?
Not enough loop delay to read all sensors correctly (I beleive it’s roughly 750ms per sensor, though perhaps that was for parasite mode, which I’m not using). I’ve tried various delays, to no avail, though they may not have been in the right places.

Broader project info:
The readings are posted to an MQTT server as a float value, the topic is “TempSensor/” and the device address - this way I can manipulate the data elsewhere.

I’m also curious as to why my “loop” for re-reads introduced the overlap bug (i.e., 2 or more “addresses” getting one sensor’s actual “reading” - is this a memory issure? I’m not particularly well versed in deeper C++ memory allocation, and had all manner of strange behaviour in my previous iterations of this project due to (I’m assuming) memory overlapping/being re-used because of accidental pointer/variable/reference/dereferece misunderstandings.

Here’s the full code - mostly irrelevant I expect, but perhaps the issue stems from something outside the main guts!

Thanks in advance,

Moley

#include <Arduino.h>
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged TO GPIO 4
#define ONE_WIRE_BUS 4

// Setup a oneWire instance to communicate with OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass the oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

// Number of temperature devices found
int numberOfDevices;

// Use this variable to store a found device address
DeviceAddress tempDeviceAddress;

char ssid[] = "My_SSID";
char pass[] = "My_Password";

const char* mqtt_server = "192.168.1.177";

// Initializes the espClient. You should change the espClient name if you have multiple ESPs running in your home automation system
WiFiClient myTempMeasuringEsp;
PubSubClient client(myTempMeasuringEsp);

const char *ID = "My_Device_ID";  // Name of our device, must be unique

char tempC_char[8];
float tempC;

// Connect to WiFi network
void setup_wifi() {
  Serial.print("\nConnecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, pass); // Connect to network

  while (WiFi.status() != WL_CONNECTED) { // Wait for connection
    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

// Reconnect to client
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(ID, "scott", "thisismylongMQTTpassword")) {
      Serial.println("connected");
      Serial.print("Publishing to server");
      Serial.println('\n');

    } else {
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress) {
  for (uint8_t i = 0; i < 8; i++){
    if (deviceAddress[i] < 16) Serial.print("0");
      Serial.print(deviceAddress[i], HEX);
  }
}


// funtion to convert deviceAdress to hex char array
void charAddress(DeviceAddress deviceAddress, char* hexAddress) {
  char hexString[17];
  for (uint8_t i = 0; i < 8; i++){
    sprintf(hexString+i*2, "%02X", deviceAddress[i]);
  }
  for (uint8_t i = 0; i < 17; i++){
    hexAddress[i] = hexString[i];  //possibly not needed, could be wrapped in the sprintf
  }
}




void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);

  // Start up the library
  sensors.begin();
  
  // Grab a count of devices on the wire
  numberOfDevices = sensors.getDeviceCount();
  
  // locate devices on the bus
  Serial.print("Locating devices...");
  Serial.print("Found ");
  Serial.print(numberOfDevices, DEC);
  Serial.println(" devices.");

  // Loop through each device, print out address
  for(int i=0;i<numberOfDevices; i++){
    // Search the wire for address
    if(sensors.getAddress(tempDeviceAddress, i)){
      Serial.print("Found device ");
      Serial.print(i, DEC);
      Serial.print(" with address: ");
      printAddress(tempDeviceAddress);
      Serial.println();
    } else {
      Serial.print("Found ghost device at ");
      Serial.print(i, DEC);
      Serial.print(" but could not detect address. Check power and cabling");
    }
  }
}

void loop() {
  
  if (!client.connected())  // Reconnect if connection is lost
  {
    reconnect();
  }
  client.loop();
  
  sensors.requestTemperatures(); // Send the command to get temperatures
  delay(1000); //delay to see if waiting after requestT aids stability
  
  char tempDeviceAddressHex[17];
  // Loop through each device, print out temperature data
  for(int i=0;i<numberOfDevices; i++){
    // Search the wire for address
    if(sensors.getAddress(tempDeviceAddress, i)){
      char topic[28] = "TempSensors/";  //note this behaved unexpectedly when no size was defined
      charAddress(tempDeviceAddress, tempDeviceAddressHex);
      strcat(topic, (char*) tempDeviceAddressHex);
      tempC = sensors.getTempC(tempDeviceAddress);
      /*  Tried this to filter bad responses - ended up with overlaps (tempC getting reported against the wrong device address)
      for(int retries=0; i<5; retries++){
        tempC = sensors.getTempC(tempDeviceAddress);
        if(tempC > 3){
          break;
        // delay(751);  // also tried this to stop overlap
        }
      }
      tempC = (tempC > 3) ? tempC : -2; //force a bad (consistent) number if no good after the retries
      */

      sprintf(tempC_char, "%.3f", tempC); //print to string, 3 decimal places, float input/format
      client.publish(topic, tempC_char);
    }
  }
  delay(4000); //decreased this delay while testing the 1000ms delay after requestT
  //delay(5000);  //standard loop delay for normal operation purposes
}

Hello,

I see a problem here

char topic[28] = "TempSensors/";  //note this behaved unexpectedly when no size was defined
charAddress(tempDeviceAddress, tempDeviceAddressHex);
strcat(topic, (char*) tempDeviceAddressHex);

"TempSensors/" is 12 characters, tempDeviceAddressHex is 16 characters, that is 28 characters total, so strcat will write the null terminator outside of topic

  • Waiting @drmpf's reply about evil c-strings :slight_smile: *

Have you read this? Guidelines for Reliable Long Line 1-Wire Networks (maximintegrated.com)

Thanks for the responses,

@guix - well spotted - I’ve updated this to [29]! It hadn’t caused any stability issues/unexpected behaviour running 8 sensors on the near “hub” for a few days, but is has fixed my “retry loop” as far as I can tell - it is now behaving as expected, and reporting “-2C” when if fails even after a few retries.

To be completely honest, I’m only using a string there as I was really struggling wrangling the DeviceAddress data into a submit-able sequence of characters - if you’ve got any suggestions on how to improve that function I’m all ears (happy to go to a proper char array if that’s easy). I essentially banged together functions/methods till I got something which “worked”. C-Strings truly are evil :o :o


@countrypaul - yes, I have read that, it’s somewhat helpful, though given the sizes they’re discussing, I feel like my tiny little network shouldn’t put up too much of an issue. In the terms they use there, my radius is max. 4m, and my weight, if we say the sensor wires are 1m and the sensor “weight” is 1m equivalent (the larger of the suggestions), is max well under 30m.

As far as topology, it does mention that stars are the hardest, and in the strictest sense, mine could be considered two "star"s attached to a linear backbone. With that said, in the linear topology description, they describe each “stub” as having “insignificant (< 3m) branches”, which mine certainly are - so perhaps mine still fits in a “linear” topology by their definition, it just happens that the short stubs are grouped together at certain points on the line.


Deploying @guix’s fix, my retry loop now works, and I’m able to better control the output when an outright read failure happens, but I’m still getting failures. Perhaps with more retries, I could lower misreads/failures to the point of insignificance, though I’d rather fix the network/wiring than work around it.

From the paper @countrypaul linked, possibilities to try would be adding 100-150R resistors at each “hub” connection point, to reduce the reflections of that “stub”, though the same paper said <3m should be negligible, and isn’t really a “stub”. The other possibility is the driver circuit in Appendix A, though at that point, since ESP8266s are so cheap, I may as well simply deploy one at each “hub” point and forget wiring altogether (not to mention have extra flexibility with placement, less wires, etc.).

Thanks for the help so far, let me know if there’s anything else which jumps out for me to try.

You should also be able to have 2 or more One-Wire networks, each only requires a single digital pin and the esp8266 has many of those unless yo are using them for something else. Beware that someone has recently reported problems using multiple One-Wire networks on an Arduino - not sure of the cause or details of the problem though.