-->
Page 1 of 1

Stability problems using OneWire & DallasTemperature libs

PostPosted: Wed Mar 28, 2018 11:58 am
by Arduolli
I am running an esp8266 (esp-01) as a simple home energy and temperature monitor.
(Reporting data to thingspeak as well as a local server).
This was running smooth and rock solid while I used a DHT11 module (and the related liberaries) for temperature tracking.
As these modules are not the most reliable and accurate, I changed to 18B20 devices and the related libs. Thats when the problems started: The systems reboots or hangs every couple of days.
With regard to tropubleshooting: I am tracking 'getResetReason' and 'getFreeHeap' Information and I see that the freeheap is around 40.000 when I start the esp, but it decreases constantly (by ~10 to 100) each time I check it (i.e. send data to the server). This happens until freeheap is down to ~2.800 - and then the 'Hardware watchdog' resets the device - or the system just hangs.

Does anybody has seen similar problems using the 18B20 devices & libs?
(I am on the newest program and lib versions)

Any ideas how to troubleshoot this problem?
(I want and need to stay on the 18B20 sensors, as these are great, accurate and I can read 3 sensors on 1 onewire)

Any help is greatly appreciated.

Re: Stability problems using OneWire & DallasTemperature lib

PostPosted: Wed Mar 28, 2018 12:02 pm
by Arduolli
Here is the code I am using, if that helps:

Code: Select all#include <TimeLib.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 9
#define REED_PIN 2
#define ARDU_PIN 0
#define loopmaxcount 10

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer, heatingThermometer, outsideThermometer;

const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxx";
const char* server = "api.thingspeak.com";
String apiKey = "xxxxxxx";     
const char* host = "xxxxxxx";     
const int timeZone = 1;                 // Central European Time
const int localPort = 8888;             // local port to listen for UDP packets
const int Port = 9999;
const int DHTInterval = 1000;           // defines interval between DHT readout in sec

volatile unsigned long GasCounter = 0; // counter; 1 equals 0,01 m3
volatile unsigned long StromCounter = 0; // counter; 1 equals 0,005 kWh
volatile int x = 0;                    // loopcounter gas
unsigned long xmax = 0;                          // actual loopmax for gas-meter (when DHT timer hits before loopmaxcount is reached)
volatile int z = 0;                    // loopcounter for electricity
unsigned long zmax = 0;                          // actual loopmax for e-meter (when DHT timer hits before loopmaxcount is reached)
volatile unsigned long timestamp[loopmaxcount]; // time stamp array for sending gasmeter batches of #[loopmaxcount] to local server
volatile unsigned long etimestamp[loopmaxcount]; // time stamp array for sending e-meter batches of #[loopmaxcount] to local server
unsigned long currentread = 0;
unsigned long previousread = 0;        // timestamp needed for DHT reading interval#
unsigned long lump = 5; // Powermeasuremetn: 5 cnts accumulated in Ardu for 1 ESP interrupt
unsigned long gduration = 0;           // duration of 1 reporting cycle to calc m3/h
unsigned long eduration = 0;           // duration of 1 reporting cycle to calc kW
float kW = 0;
float m3perh = 0;
float tin = 0;
float tout = 0;
float theat = 0;

// NTP Servers:
IPAddress timeServer(129, 6, 15, 29); // time-b-g.nist.gov
// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov
// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov
WiFiUDP Udp;
// Use WiFiClient class to create TCP connections
WiFiClient client;
time_t getNtpTime();

void sendNTPpacket(IPAddress &address);

// Initialize DHT sensor.
// DHT dht(DHT_PIN, DHTTYPE);

void setup() {
  // Serial.begin(115200);
  delay(10);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(50);
  }
  // Port defaults to 8266
  // ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  // ArduinoOTA.setHostname("myespEnMon");

  // No authentication by default
  // ArduinoOTA.setPassword((const char *)"123");

  ArduinoOTA.onStart([]() {
    // Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    // Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    // Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    // Serial.printf("Error[%u]: ", error);
    // if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    // else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    // else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    // else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    // else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  // Serial.println("Ready");
  // Serial.print("IP address: ");
  // Serial.println(WiFi.localIP());

  Udp.begin(localPort);                 // get time...
  setTime((time_t)getNtpTime());

  // prepare GPIO for Interrupt
  pinMode(REED_PIN, INPUT_PULLUP); //INPUT_PULLUP for Reed (Gas) input
  attachInterrupt(digitalPinToInterrupt(REED_PIN), interrupt_gas_reed, FALLING); //-> GPIO is high and interrupt will trigger when set to ground (via R to limit current)

  pinMode(ARDU_PIN, INPUT_PULLUP); //INPUT_PULLUP for Reed (Gas) input
  attachInterrupt(digitalPinToInterrupt(ARDU_PIN), interrupt_ardu, FALLING); //digitalPinToInterrupt()

  sensors.begin();

  // Search for devices on the bus and assign based on an index.
  sensors.getAddress(insideThermometer, 0);
  sensors.getAddress(heatingThermometer, 1);
  sensors.getAddress(outsideThermometer, 2);

  // set the resolution to 9 bit per device
  sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(heatingThermometer, TEMPERATURE_PRECISION);
  sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION);
}

void loop() {
  ArduinoOTA.handle();
  //  once every DHTInterval sec: read DHT and store DHT to thingspeak and local file;
  currentread = now();
  //  either when hitting loopmaxcount array entries for gasmetering / strommetering or at least once every DHTIntervals in sec:
  // read & store DHT data and array of gasvalues to local file; to thingspeak upload DHT values and GasCounter
  if ((x >= loopmaxcount) || (z >= loopmaxcount) || (currentread - previousread >= DHTInterval)) { // accumulate batch of timestamps
    previousread = currentread; // save the last time DHT was read
    xmax = x; // save max amount of gas-measurements (array)
    zmax = z; // save max amount of e-measurements (array)
    x = 0; // set array pointer to 0
    z = 0; // set array pointer to 0

    yield;
    sensors.requestTemperatures();
    yield;
    tin = sensors.getTempC(insideThermometer);
    yield;
    theat = sensors.getTempC(heatingThermometer);
    yield;
    tout = sensors.getTempC(outsideThermometer);
    yield;
    if (zmax <= 1) {
      eduration = 0;
      kW = 0;
    }
    else {
      eduration = (etimestamp[zmax - 1] - etimestamp[0]); //duration for kW - if else to cover zmax-1=0 case
      kW = ((zmax * lump * 3600) / float(eduration)); // 3600 = 1000(msec)*60(sec)*60(min)/1000cnts_per_kW
    }

    if (xmax <= 1) {
      gduration = 0;
      m3perh = 0;
    }
    else {
      gduration = (timestamp[xmax - 1] - timestamp[0]); //duration for gas m3/h - if else see above
      m3perh = ((xmax  * 36000) / float(gduration)); // 36000 = 1000(msec)*60(sec)*60(min)/100cnts_per_m3/h
    }

    if (client.connect(host, Port)) {     // This will send the data to the local server
      String s = "";
      s = String(day(now())) + "." + String(month(now())) + "." + String(year(now())) + "," +
          String(hour(now())) + ":" + String(minute(now())) + ":" + String(second(now())) +  "," +
          String(GasCounter) +  "," + String(m3perh) +  "," + String(gduration) +  "," + String(xmax - 1) + "," +
          String(timestamp[xmax - 1]) +  "," + String(timestamp[0]) +  "," +
          String(StromCounter) +  "," + String(kW) +  "," + String(eduration) +  "," + String(zmax - 1) + "," +
          String(etimestamp[zmax - 1]) +  "," + String(etimestamp[0]) +  "," +
          String(tin) + "," + String(theat) + "," + String(tout) + "," +
          String(ESP.getResetReason()) + "," + String(ESP.getFreeHeap()) + "\n"; //
      client.print(s);
      yield;
      client.stop();    // stop upload to local server
    }

    if (client.connect(server, 80)) { // "184.106.153.149" or api.thingspeak.com -- start upload to thingspeak
      String postStr = "&field1=";
      postStr += String(tin); // m3 = GasCounter*100 due to every 1st trigger of ardu, falling trigger only & 100 reeds  per m3
      postStr += "&field2=";
      postStr += String(theat);
      postStr += "&field3=";
      postStr += String(tout);
      postStr += "&field4=";
      postStr += String(float(GasCounter) / 100);
      postStr += "&field5=";
      postStr += String(float(StromCounter) * lump / 1000); // kWh = StromCounter*5/1000 due to every 5th trigger of ardu, falling trigger only & 1000 blinks per kWh
      postStr += "&field6=";
      postStr += String(float(kW)); // this calcualtes kW from intervals kWh / interval duration
      postStr += "&field7=";
      postStr += String(float(m3perh));
      postStr += "\r\n\r\n";

      client.print("POST /update HTTP/1.1\n");
      client.print("Host: api.thingspeak.com\n");
      client.print("Connection: close\n");
      client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
      client.print("Content-Type: application/x-www-form-urlencoded\n");
      client.print("Content-Length: ");
      client.print(postStr.length());
      client.print("\n\n");
      client.print(postStr);
      yield;
      client.stop();    // stop upload to thingspeak
    }
    delay(10);
    return;
  }
}

/*-------- NTP code ----------*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  // Serial.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      // Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  // Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress & address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}
/*-------- NTP code END ----------*/

void interrupt_gas_reed() {
  timestamp[x] = millis();
  GasCounter++;
  x++;
}

void interrupt_ardu() {
  etimestamp[z] = millis();
  StromCounter++;
  z++;
}

Solved Stability problems using OneWire & DallasTemperature

PostPosted: Fri Mar 30, 2018 4:59 am
by Arduolli
Update:
The issue seems not to be driven by the quoted libraries, but the newest ESP8266 Arduino Core Version 2.4.1.

I now went back to 2.4.0rc2 (which I used before) and the heap size stays constant again!

I'll move this information to the bug report section, so hopefully igor & company will get aware of it and can address it at some point.