Stability problems using OneWire & DallasTemperature libs
Posted:
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
Posted:
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
Posted:
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.