Open TinajaLabs opened 5 years ago
Just happened again, and this is the lead up to the crash:
mqtt pub - PIR state: 1
mqtt pub - RSSI level: -56
mqtt pub - temperature: 71.96 *F
mqtt pub - rel humidity: 59.40 %
mqtt pub - lux value: 0
mqtt pub - lux broaband: 17
mqtt pub - lux infrared: 3
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqtt pub - PIR state: 1
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqtt pub - PIR state: 1
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
mqttClient not connected...
Soft WDT reset
>>>stack>>>
ctx: sys
sp: 3fffed40 end: 3fffffb0 offset: 01b0
.
.
.
see if you have time to decode the stack trace, it will tell you exactly where its crashing
Just learned how to decode the stack trace. Please see below. This is a more recent crash, not from the prior post.
It is revealing. I added a check with Serial.println(ESP.getFreeHeap());
and it shows a slow reduction in free memory.
Is there a trick to tell where the memory leak is happening?
Thank you, Chris.
Memory allocation of 116 bytes failed at 0x4022ad8c: mem_malloc at core/mem.c line 210
Decoding stack results
0x40222086: memp_free at core/memp.c line 447
0x402149ef: loop_task(ETSEvent*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 133
0x40213159: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x402158ec: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x40213159: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x402158ec: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x40213159: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x40215871: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 127
0x40214a34: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40100119: __wrap_spi_flash_read at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_phy.c line 267
0x40215788: spiffs_hal_read(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 67
0x4021fd36: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x4021fc70: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 180
0x4021b830: _printf_i at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 194
0x4021fd36: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x4021fc70: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 180
0x4021b930: _printf_i at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 244
0x4021fd36: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x40220147: _svfprintf_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 660
0x4021fc70: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 180
0x40101564: free at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/umm_malloc/umm_malloc.c line 1760
0x40202291: uart_do_write_char at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/uart.c line 450
0x40202652: uart_write at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/uart.c line 496
0x40101564: free at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/umm_malloc/umm_malloc.c line 1760
0x4020b2a4: ClientContext::_s_connected(void*, tcp_pcb*, long) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/include/ClientContext.h line 635
0x402217ad: operator delete(void*) at ../../../../../dl/gcc-xtensa/libstdc++-v3/libsupc++/del_op.cc line 48
0x4020b4ab: ClientContext::unref() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/include/ClientContext.h line 123
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x4020b004: WiFiClient::connect(char const*, unsigned short) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/WiFiClient.cpp line 133
0x402081e3: publishLuxValues() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 844
0x40219150: PubSubClient::connected() at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 606
0x4021337c: HardwareSerial::write(unsigned char const*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/HardwareSerial.h line 174
0x40213681: Print::write(char const*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Print.h line 60
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x40214a34: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40201d6f: delay at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 51
0x4020a1e2: loop() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 289
0x40214ae0: loop_wrapper() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 125
Happened again when It was Attempting connection to MQTT server: 192.168.1.138...
Heapfree starts at 39344
and is 33344
just before the crash. It took less than 5 minutes to happen and
Decoding stack results
0x40214a7f: loop_task(ETSEvent*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 133
0x40213211: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x4021597c: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x40213211: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x4021597c: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x40213211: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x40215901: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 127
0x40214ac4: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40100119: __wrap_spi_flash_read at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_phy.c line 267
0x40213235: EspClass::flashRead(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 639
0x40215818: spiffs_hal_read(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 67
0x4020699d: spiffs_phys_rd at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs/spiffs_cache.c line 153
0x402219e9: glue2esp_linkoutput at glue-esp/lwip-esp.c line 299
0x402219e9: glue2esp_linkoutput at glue-esp/lwip-esp.c line 299
0x4021fdc6: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x40221c7a: new_linkoutput at glue-lwip/lwip-git.c line 238
0x4022205c: ethernet_output at netif/ethernet.c line 312
0x40229734: etharp_output_to_arp_index at core/ipv4/etharp.c line 770
0x40229938: etharp_output_LWIP2 at core/ipv4/etharp.c line 885
0x402201d7: _svfprintf_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 660
0x4022a350: ip4_output_if_opt_src at core/ipv4/ip4.c line 1007
0x4021fdc6: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x4021fd00: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 180
0x4022a398: ip4_output_if_opt at core/ipv4/ip4.c line 820
0x4022ae1c: mem_malloc at core/mem.c line 210
0x4022ae1c: mem_malloc at core/mem.c line 210
0x4022a3be: ip4_output_if at core/ipv4/ip4.c line 793
0x4022af2f: ip_chksum_pseudo at core/inet_chksum.c line 395
0x4022731e: tcp_output at core/tcp_out.c line 1361
0x40226609: tcp_create_segment at core/tcp_out.c line 190
0x40214ac4: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40201d6f: delay at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 51
0x4020bb6d: WiFiClient::connect(IPAddress const&, unsigned short) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/include/ClientContext.h line 136
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x4020b0bc: WiFiClient::connect(char const*, unsigned short) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/WiFiClient.cpp line 133
0x402191e0: PubSubClient::connected() at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 606
0x4020c02b: PubSubClient::connect(char const*, char const*, char const*, char const*, unsigned char, unsigned char, char const*, unsigned char) at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 129
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x40213434: HardwareSerial::write(unsigned char const*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/HardwareSerial.h line 174
0x4020c214: PubSubClient::connect(char const*) at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 106
0x4021374c: Print::print(char const*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Print.cpp line 122
0x40207d6f: mqttReconnected() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 447
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x40100b31: __digitalWrite at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring_digital.c line 82
0x4020a262: loop() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 263
0x40214b70: loop_wrapper() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 125
And another after about an hour and 10 minutes of running OK:
Memory went from 40668 to 35408. It happened right after it's attempt to connect:
TL: Attempting connection to MQTT server: 192.168.1.138... Not connected, error code: -2
... then
TL: Attempting connection to MQTT server: 192.168.1.138...
Soft WDT reset
>>>stack>>>
ctx: sys
sp: 3fffed40 end: 3fffffb0 offset: 01b0
3fffeef0: 3ffe9be8 35e33b83 60000600 40222106
etc.
Decoding stack results
0x40222106: memp_free at core/memp.c line 447
0x402131fd: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x40215968: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x402131fd: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x40215968: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x402131fd: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x402158ed: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 127
0x40213221: EspClass::flashRead(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 639
0x402219d9: glue2esp_linkoutput at glue-esp/lwip-esp.c line 299
0x402219d9: glue2esp_linkoutput at glue-esp/lwip-esp.c line 299
0x40221c6a: new_linkoutput at glue-lwip/lwip-git.c line 238
0x4022204c: ethernet_output at netif/ethernet.c line 312
0x4021fdb6: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x40229724: etharp_output_to_arp_index at core/ipv4/etharp.c line 770
0x4021b9b0: _printf_i at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 244
0x40229928: etharp_output_LWIP2 at core/ipv4/etharp.c line 885
0x4022a340: ip4_output_if_opt_src at core/ipv4/ip4.c line 1007
0x4021fdb6: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x4021fcf0: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 180
0x4022a388: ip4_output_if_opt at core/ipv4/ip4.c line 820
0x4022ae0c: mem_malloc at core/mem.c line 210
0x4022a3ae: ip4_output_if at core/ipv4/ip4.c line 793
0x4022af1f: ip_chksum_pseudo at core/inet_chksum.c line 395
0x4022730e: tcp_output at core/tcp_out.c line 1361
0x402238d9: sys_timeout_abs at core/timeouts.c line 189
0x40214ab0: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40201d6f: delay at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 51
0x4020bb59: WiFiClient::connect(IPAddress const&, unsigned short) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/include/ClientContext.h line 136
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x4020b0a8: WiFiClient::connect(char const*, unsigned short) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/libraries/ESP8266WiFi/src/WiFiClient.cpp line 133
0x40208237: publishLuxValues() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 855
0x402191cc: PubSubClient::connected() at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 606
0x4020c017: PubSubClient::connect(char const*, char const*, char const*, char const*, unsigned char, unsigned char, char const*, unsigned char) at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 129
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x40213420: HardwareSerial::write(unsigned char const*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/HardwareSerial.h line 174
0x4020c200: PubSubClient::connect(char const*) at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 106
0x40213738: Print::print(char const*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Print.cpp line 122
0x40207d6f: mqttReconnected() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 447
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x40100b31: __digitalWrite at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring_digital.c line 82
0x4020a24e: loop() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 263
0x40214b5c: loop_wrapper() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 125
are you writing to spiffs over and over ? What are you using spiffs for?
is there a loop that updates some variables than then get saved ?
I do write to the file system with spiffs library to save 2 parameters (as json), the MQTT server, and the location part of the topic string (e.g., ) for the calls being made when published. These are accessed in setup and during a reset when running wifimanager.
My code for my room sensor - PIR, TSL2561 (lux/light), DHT22 (temp, humidity), RSSI + MQTT and wifimanager.
It's a tedious bit of code, but I've broken out much of the bits into separate methods.
The key parts:
Variables:
I don't expect anyone to go through this code in any detail, but I appreciate any insights into where I'm going wrong here.
BTW, I'm hoping to show how this can work at Maker Faire next week.
Thank you, Chris.
/*
TinajaLabs.com, Chris Jefferies, May 2019
---------------------------------------------------------------
roomSensor-wfm-lux-temp-hum-01
Attributes:
- WifiManager
- FS
- MQTT
- RSSI: dbm, wifi signal strength
- TSL2561: light level in lux
- DHT22: temperature & humidity
- pir: motion sensor
- // bme280: temperature, humidity, barometric pressure
- // tmp36: temperature
Arduino IDE settings:
Board: Feather HUZZAH ESP8266
Flash Size: 1M (64k SPIFFS)
lwIPVariant: v2 Lower Memory
VTables: Flash
CPU Frequency: 80MHz
Upload Speed: 230400
Port: dev/ttyUSB0, dev/ttyUSB1
Board: LOLIN (WEMOS) D1, R2 & Mini
Flash Size: 4M (64k SPIFFS)
lwIPVariant: v2 Lower Memory
VTables: Flash
CPU Frequency: 80MHz
Upload Speed: 921600
Port: dev/ttyUSB0, dev/ttyUSB1
---------------------------------------------------------------
*/
#include <FS.h> // this needs to be first, or it all crashes and burns...
#include <Wire.h>
#include <ESP8266WiFi.h> // https://github.com/esp8266/Arduino
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
#include <PubSubClient.h>
// #include <DNSServer.h> // this conflicts with other libraries
#include <ESP8266WebServer.h> // Local WebServer used to serve the configuration portal
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include <Adafruit_Sensor.h> // Adafruit Unified Sensor Driver - https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_TSL2561_U.h> // https://adafruit.github.io/Adafruit_TSL2561/html/index.html
#include <DHT.h>
// #include <SPI.h> // for BME280, Serial Peripheral Interface (SPI)
// #include <Adafruit_BME280.h>
#ifdef ESP32
#include <SPIFFS.h>
#endif
// ========================== for this system device
// -------------------------- pin definitions
#define DHT_PIN 2 // D4, GPIO2 on wemos d1 mini
#define PIR_PIN 12 // D6, GPIO12, on wemos d1 mini, motion detection
#define WIFI_MNGR_PIN 0 // D3, GPIO0, on wemos d1 mini, reset button for wifiManager
#define MQTT_LED 16 // D0, GPIO16, on wemos d1 mini, mqtt functions
#define PIR_LED 14 // D5, GPIO14, on wemos d1 mini, pir led
// define SCL 5 // D1, GPIO5, on wemos d1 mini
// define SDA 4 // D2, GPIO4, on wemos d1 mini
// defines specific microcontroller device
// char topic_device[20] = "WemosD1Mini/";
char topic_device[20] = "feather-esp/";
// ========================== specific sensor configs
// -------------------------- RSSI sensor value
long pubLastRssi = 0;
long pubIntervalRssi = 5000; // every 5 seconds
char chipID[10];
char rssi_base[60] = "rssi/state/room";
char rssi_topic[100];
char heap_base[60] = "heap/state/room";
char heap_topic[100];
// -------------------------- for TSL2561 light sensor
long pubLastLux = 0;
long pubIntervalLux = 5000;
char lux[20];
char lux_base[60] = "lux/state/room";
char lux_bb_base[60] = "lux_bb/state/room";
char lux_ir_base[60] = "lux_ir/state/room";
char lux_topic[100];
char lux_bb_topic[100];
char lux_ir_topic[100];
uint16_t broadband = 0;
uint16_t infrared = 0;
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 72921);
// -------------------------- DHT22 sensor values
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHT_PIN, DHTTYPE);
long pubLastDHT22 = 0;
long pubIntervalDHT22 = 5000;
char temperature[20];
char temp_base[60] = "temperature/state/room";
char humi_base[60] = "humidity/state/room";
char temp_topic[100];
char humi_topic[100];
// -------------------------- for PIR sensor
// hook up to +5V, Gnd, output = 0V - 3.3V
int pirState = 0;
long pubLastPir = 0;
long pubIntervalPir = 1000;
char pir[20];
char pir_base[60] = "pir/state/room";
char pir_topic[100];
// -------------------------- for mqtt
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
String mqttClientId = "";
long lastMqttReconnectAttempt = 0;
char mqtt_server[40] = "192.168.0.254"; // configurable in wifiManager
// -------------------------- for wifiManager
// to save settings, SPIFFS
// for SPIFFS, keep to less than 31 characters
bool shouldSaveConfig = true;
const char *CONFIG_FILE = "/config.json";
// -------------------------- generic topic strings
// topic_loc is for the location prefix for all of the topics - it is configurable
// the middle is injected with the chipid
// the rest are suffixes for the various pub/sub entities
char topic_loc[30] = "maker/house/livingroom/"; // configurable in wifiManager
char publ_base[60] = "publish/state/room";
char subs_base[60] = "subscribe/state/room";
char publ_topic[100];
char subs_topic[100];
// Function Prototypes
bool loadConfigFile();
bool saveConfigFile();
// ###############################################################################
// SETUP & LOOP: #################################################################
// ==========================================================
// SETUP ====================================================
void setup()
{
Serial.begin(57600);
while (!Serial)
; // wait for serial monitor to open
Serial.println("\n\nTL: === Starting Tinaja Device ===");
Serial.print("TL: === ");
Serial.println(topic_loc);
Serial.print("TL: === ");
Serial.println(topic_device);
// set the pins to be used for buttons, LEDs, etc.
pinMode(PIR_PIN, INPUT); // set the pin to trigger pir detection
pinMode(PIR_LED, OUTPUT); // set the pin to trigger pir detection
pinMode(WIFI_MNGR_PIN, INPUT_PULLUP); // set the pin to trigger wifiManager
pinMode(MQTT_LED, OUTPUT); // Initialize the MQTT_LED pin as an output
digitalWrite(MQTT_LED, LOW); // turn on LED during setup
digitalWrite(PIR_LED, LOW); // turn on LED during setup
// Create a random client ID
mqttClientId = "tinajaMQTTClient-";
mqttClientId += String(random(0xffff), HEX);
setChipId();
runWifiManager("auto");
// setupBme280();
dht.begin();
if (!tsl.begin())
{
/* There was a problem detecting the TSL2561 ... check your connections */
Serial.print("TL: Ooops, no TSL2561 detected... Check your wiring or I2C ADDR!");
while (1)
;
}
/* Setup the sensor gain and integration time */
printLuxSensorDetails();
configureLuxSensor();
// ----------------------------- set mqtt topics
Serial.println("TL: final mqtt topics list: ");
setTopicsDevices();
setTopicsDht22();
setTopicsLux();
setTopicsPir();
// setBme280Topics();
// setTmp36Topics();
// ----------------------------- for mqtt client
mqttClient.setServer(mqtt_server, 1883);
mqttClient.setCallback(mqttCallback); // listening for subscriptions
Serial.println("TL: === Finished setup ===");
Serial.println("");
digitalWrite(MQTT_LED, HIGH); // turn off LED after setup
digitalWrite(PIR_LED, HIGH); // turn off LED after setup
}
// ==========================================================
// LOOP =====================================================
void loop()
{
checkWifiManagerButton();
if (!mqttClient.connected())
{
Serial.println("TL: mqttClient not connected...");
digitalWrite(MQTT_LED, LOW); // turn on LED to indicate disconnected
long now = millis();
if (now - lastMqttReconnectAttempt > 10000)
{
lastMqttReconnectAttempt = now;
// Attempt to reconnect
if (mqttReconnected())
{
digitalWrite(MQTT_LED, HIGH);
lastMqttReconnectAttempt = 0;
}
}
mqttClient.loop();
}
else
{
// Client connected
mqttClient.loop();
digitalWrite(MQTT_LED, HIGH); // turn off LED
}
// ----------------------------------------------------------
// put the main code below, to run repeatedly:
// publish msgs about the sensor stats
publishPirValues();
publishRssiValues();
publishDHT22Values();
publishLuxValues();
delay(250); // longer than 50 if mqttClient is often not connected...
}
// ###############################################################################
// Special Methods: ##############################################################
// ========================== wifi manager methods
// ----------------------------------------------------------
void checkWifiManagerButton()
{
// if config reset pin has been pushed down
if (digitalRead(WIFI_MNGR_PIN) == LOW)
{
Serial.println("TL: ========> Wifi Manager trigger pin detected...");
delay(50); // poor mans debounce, not recommended for production code
if (digitalRead(WIFI_MNGR_PIN) == LOW)
{
delay(3000);
// if config reset pin has been pushed down for more than 3 seconds, reset/restart
if (digitalRead(WIFI_MNGR_PIN) == LOW)
{
Serial.println("TL: Trigger pin low for 3+ seconds. Resetting device...");
runWifiManager("reset"); // < <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< RESET CAN HAPPEN
}
else
{
Serial.println("TL: Starting config portal, auto ...");
runWifiManager("auto");
}
}
}
}
// ----------------------------------------------------------
void saveConfigCallback()
{
//callback notifying us of the need to save config
Serial.println("TL: --- Should save config");
shouldSaveConfig = true;
}
// ----------------------------------------------------------
void runWifiManager(String mode)
{
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
wifiManager.setSaveConfigCallback(saveConfigCallback);
if (mode == "reset")
{
Serial.println("TL: Resetting/restarting the current configuration...");
wifiManager.resetSettings(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< RESET CAN HAPPEN
ESP.restart();
}
// load the settings from the file system (FS), from setupSpiffs
loadConfigFile();
Serial.println("TL: starting wifiManager");
// set up some additional parameters
WiFiManagerParameter custom_mqtt_server("mqtt_server", "MQTT server addr", mqtt_server, 40);
WiFiManagerParameter custom_topic_loc("topic_loc", "Topic Location", topic_loc, 30);
wifiManager.addParameter(&custom_mqtt_server);
wifiManager.addParameter(&custom_topic_loc);
wifiManager.setConfigPortalTimeout(60); // sets timeout until configuration portal gets turned off
wifiManager.setConnectTimeout(5); // how long to try to connect for before continuing
// TODO: add password to wifimanager login
if (mode == "auto")
{
Serial.println("TL: Attempting automatic connection");
if (!wifiManager.autoConnect("TinajaAutoAP"))
{
Serial.println("TL: failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
}
else
{
Serial.println("TL: Attempting on demand connection");
if (!wifiManager.startConfigPortal("TinajaOnDemandAP"))
{
Serial.println("TL: Failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
}
strcpy(mqtt_server, custom_mqtt_server.getValue());
strcpy(topic_loc, custom_topic_loc.getValue());
// ----------------------------- save the custom parameters to FS
if (shouldSaveConfig)
{
saveConfigFile();
shouldSaveConfig = false;
}
//if you get here you have connected to the WiFi
Serial.print("TL: == OK == Device is running with IP address: ");
Serial.println(WiFi.localIP());
// Serial.println(WiFi.SSID());
// Serial.println(WiFi.psk());
}
// ----------------------------------------------------------
// mqtt subscription callback listener
void mqttCallback(char *topic, byte *payload, unsigned int length)
{
Serial.print("TL: Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1')
{
digitalWrite(MQTT_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is acive low on the ESP-01)
}
else
{
digitalWrite(MQTT_LED, HIGH); // Turn the LED off by making the voltage HIGH
}
}
// ----------------------------------------------------------
bool mqttReconnected()
{
// Loop until we're reconnected
Serial.print("TL: Attempting connection to MQTT server: ");
Serial.print(mqtt_server);
Serial.print("...");
// // Create a random client ID
// String clientId = "tinajaMQTTClient-";
// clientId += String(random(0xffff), HEX);
// Attempt to connect
if (mqttClient.connect(mqttClientId.c_str()))
{
Serial.println(" Connected.");
// Once connected, publish an announcement...
char publVal[50];
snprintf(publVal, 75, "%ld", 0);
mqttClient.publish(publ_topic, publVal);
Serial.print("TL: published to topic: ");
Serial.println(publ_topic);
// ... and resubscribe
mqttClient.subscribe(subs_topic);
Serial.print("TL: subscribed to topic: ");
Serial.println(subs_topic);
}
else
{
Serial.print(" Not connected, error code: ");
Serial.println(mqttClient.state());
}
Serial.println();
Serial.println("=========================================================");
Serial.println();
return mqttClient.connected();
}
// ----------------------------------------------------------
bool loadConfigFile()
{
// clean FS, for testing
// SPIFFS.format(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//read configuration from FS json
Serial.println("");
Serial.print("TL: mounting FS...");
if (SPIFFS.begin())
{
Serial.println(" mounted.");
if (SPIFFS.exists(CONFIG_FILE))
{
//file exists, reading and loading
Serial.print("TL: reading config file, ");
Serial.println(CONFIG_FILE);
File cfgFile = SPIFFS.open(CONFIG_FILE, "r");
if (cfgFile)
{
Serial.println("TL: opened and retrieved data:");
size_t size = cfgFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
cfgFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer;
JsonObject &json = jsonBuffer.parseObject(buf.get());
// this prints the json that was loaded
json.printTo(Serial);
if (json.success())
{
// set up the extra parameters
if (json.containsKey("mqtt_server"))
{
strcpy(mqtt_server, json["mqtt_server"]);
}
if (json.containsKey("topic_loc"))
{
strcpy(topic_loc, json["topic_loc"]);
}
Serial.println("\nTL: successfully loaded json config");
}
else
{
Serial.println("\n\nTL: >>> failed to load json config <<<");
}
}
}
}
else
{
Serial.println("\n\nTL: >>> failed to mount FS <<<\n\n");
}
//end read
}
// ----------------------------------------------------------
bool saveConfigFile()
{
// write configs to local file store
Serial.println("TL: Saving config...");
DynamicJsonBuffer jsonBuffer;
JsonObject &json = jsonBuffer.createObject();
// JSONify local configuration parameters
// json["ssid"] = ssid;
// json["password"] = password;
json["mqtt_server"] = mqtt_server;
json["topic_loc"] = topic_loc;
// Open file for writing
File cfgFile = SPIFFS.open(CONFIG_FILE, "w");
if (!cfgFile)
{
Serial.println("TL: Failed to open config file for saving");
return false;
}
json.prettyPrintTo(Serial);
// Write data to file and close it
json.printTo(cfgFile);
cfgFile.close();
Serial.println("\nTL: Config file was successfully saved");
return true;
}
// ----------------------------------------------------------
void configureLuxSensor(void)
{
// Configures the gain and integration time for the TSL2561
/* You can also manually set the gain or enable auto-gain support */
// tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */
// tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */
tsl.enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */
/* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */
/* Update these values depending on what you've set above! */
Serial.println("TL: ------------------------------------");
Serial.print("TL: Gain:\t");
Serial.println("1x");
Serial.print("TL: Timing:\t");
Serial.println("101 ms");
Serial.println("TL: ------------------------------------");
}
void printLuxSensorDetails(void)
{
/* Populate broadband and infrared with the latest values */
tsl.getLuminosity(&broadband, &infrared);
sensor_t sensor;
tsl.getSensor(&sensor);
Serial.println("\nTL: Lux Sensor Details ------------------------");
Serial.print("TL: Sensor:\t");
Serial.println(sensor.name);
Serial.print("TL: Driver Ver:\t");
Serial.println(sensor.version);
Serial.print("TL: Unique ID:\t");
Serial.println(sensor.sensor_id);
Serial.print("TL: Max Value:\t");
Serial.print(sensor.max_value);
Serial.println(" lux");
Serial.print("TL: Min Value:\t");
Serial.print(sensor.min_value);
Serial.println(" lux");
Serial.print("TL: Resolution:\t");
Serial.print(sensor.resolution);
Serial.println(" lux");
Serial.print("TL: Broadband:\t");
Serial.println(broadband);
Serial.print("TL: Infrared:\t");
Serial.println(infrared);
}
// ========================== sensor checks ==
// ----------------------------------------------------------
void publishRssiValues()
{
if (millis() - pubLastRssi <= pubIntervalRssi)
{
return;
}
int32_t heapValue = ESP.getFreeHeap();
char heapMsg[50];
snprintf(heapMsg, 75, "%ld", heapValue);
Serial.print("TL: mqtt pub - FreeHeap: \t");
Serial.println(heapMsg);
mqttClient.publish(heap_topic, heapMsg);
int32_t rssiValue = WiFi.RSSI();
char rssiMsg[50];
// snprintf(rssiMsg, 75, "%ld", WiFi.RSSI());
snprintf(rssiMsg, 75, "%ld", rssiValue);
Serial.print("TL: mqtt pub - RSSI level: \t");
Serial.println(rssiValue);
mqttClient.publish(rssi_topic, rssiMsg);
pubLastRssi = millis();
}
// ----------------------------------------------------------
void publishDHT22Values()
{
if (millis() - pubLastDHT22 <= pubIntervalDHT22)
{
return;
}
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
// delay(2000);
float h = dht.readHumidity();
// // Read temperature as Celsius (the default)
// delay(1000);
// float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
// delay(2000);
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
// if (isnan(h) || isnan(t) || isnan(f)) {
if (isnan(h))
{
Serial.println("TL: Failed to read from DHT humidity sensor!");
Serial.println(h);
Serial.println(f);
return;
}
if (isnan(f))
{
Serial.println("TL: Failed to read from DHT temperature sensor!");
// Serial.println(h);
// Serial.println(f);
return;
}
Serial.print("TL: mqtt pub - temperature:\t");
Serial.print(f);
Serial.println(" *F");
mqttClient.publish(temp_topic, String(f).c_str());
Serial.print("TL: mqtt pub - rel humidity:\t");
Serial.print(h);
Serial.println(" %");
mqttClient.publish(humi_topic, String(h).c_str());
pubLastDHT22 = millis();
}
// ----------------------------------------------------------
void publishLuxValues()
{
if (millis() - pubLastLux <= pubIntervalLux)
{
return;
}
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
tsl.getLuminosity(&broadband, &infrared);
/* Display the results (light is measured in lux) */
uint16_t lux = event.light;
if (lux)
{
char luxMsg[50];
snprintf(luxMsg, 75, "%ld", lux);
char luxbbMsg[50];
snprintf(luxbbMsg, 75, "%ld", broadband);
char luxirMsg[50];
snprintf(luxirMsg, 75, "%ld", infrared);
// these are the raw values
Serial.print("\tlux level:\t");
Serial.println(event.light);
Serial.print("\tbroadband:\t");
Serial.println(broadband);
Serial.print("\tinfrared:\t");
Serial.println(infrared);
// these are for publishing to mqtt
Serial.print("TL: mqtt pub - lux:\t\t");
Serial.println(luxMsg);
mqttClient.publish(lux_topic, luxMsg);
Serial.print("TL: mqtt pub - lux broaband:\t");
Serial.println(luxbbMsg);
mqttClient.publish(lux_bb_topic, luxbbMsg);
Serial.print("TL: mqtt pub - lux infrared:\t");
Serial.println(luxirMsg);
mqttClient.publish(lux_ir_topic, luxirMsg);
}
else
{
/* If event.light = 0 lux the sensor is probably saturated
and no reliable data could be generated! */
Serial.println("TL: Sensor overload");
}
// delay(250);
pubLastLux = millis();
}
// ----------------------------------------------------------
void publishPirValues()
{
if (millis() - pubLastPir <= pubIntervalPir)
{
return;
}
pirState = digitalRead(PIR_PIN);
if (pirState == LOW) // low means no action
{
// pirState = 0;
digitalWrite(PIR_LED, LOW); // turns ON the LED
}
else
{
// pirState = 1;
digitalWrite(PIR_LED, HIGH); // turns OFF the LED
}
char pirMsg[50];
snprintf(pirMsg, 75, "%ld", pirState);
Serial.print("TL: mqtt pub - PIR state:\t");
Serial.println(pirMsg);
mqttClient.publish(pir_topic, pirMsg);
pubLastPir = millis();
}
void setTopicsDevices()
{
strcat(rssi_topic, topic_loc);
strcat(rssi_topic, topic_device);
strcat(rssi_topic, chipID);
strcat(rssi_topic, "/");
strcat(rssi_topic, "device/");
strcat(rssi_topic, rssi_base);
strcat(heap_topic, topic_loc);
strcat(heap_topic, topic_device);
strcat(heap_topic, chipID);
strcat(heap_topic, "/");
strcat(heap_topic, "device/");
strcat(heap_topic, heap_base);
strcat(publ_topic, topic_loc);
strcat(publ_topic, topic_device);
strcat(publ_topic, chipID);
strcat(publ_topic, "/");
strcat(publ_topic, "device/");
strcat(publ_topic, publ_base);
strcat(subs_topic, topic_loc);
strcat(subs_topic, topic_device);
strcat(subs_topic, chipID);
strcat(subs_topic, "/");
strcat(subs_topic, "device/");
strcat(subs_topic, subs_base);
Serial.println(rssi_topic);
Serial.println(publ_topic);
Serial.println(subs_topic);
}
// ----------------------------------------------------------
void setTopicsDht22()
{
strcat(temp_topic, topic_loc);
strcat(temp_topic, topic_device);
strcat(temp_topic, chipID);
strcat(temp_topic, "/");
strcat(temp_topic, "dht22/");
strcat(temp_topic, temp_base);
strcat(humi_topic, topic_loc);
strcat(humi_topic, topic_device);
strcat(humi_topic, chipID);
strcat(humi_topic, "/");
strcat(humi_topic, "dht22/");
strcat(humi_topic, humi_base);
Serial.println(temp_topic);
Serial.println(humi_topic);
}
// ----------------------------------------------------------
void setTopicsLux()
{
strcat(lux_topic, topic_loc);
strcat(lux_topic, topic_device);
strcat(lux_topic, chipID);
strcat(lux_topic, "/");
strcat(lux_topic, "tsl2561/");
strcat(lux_topic, lux_base);
strcat(lux_bb_topic, topic_loc);
strcat(lux_bb_topic, topic_device);
strcat(lux_bb_topic, chipID);
strcat(lux_bb_topic, "/");
strcat(lux_bb_topic, "tsl2561/");
strcat(lux_bb_topic, lux_bb_base);
strcat(lux_ir_topic, topic_loc);
strcat(lux_ir_topic, topic_device);
strcat(lux_ir_topic, chipID);
strcat(lux_ir_topic, "/");
strcat(lux_ir_topic, "tsl2561/");
strcat(lux_ir_topic, lux_ir_base);
Serial.println(lux_topic);
Serial.println(lux_bb_topic);
Serial.println(lux_ir_topic);
}
// ----------------------------------------------------------
void setTopicsPir()
{
strcat(pir_topic, topic_loc);
strcat(pir_topic, topic_device);
strcat(pir_topic, chipID);
strcat(pir_topic, "/");
strcat(pir_topic, "pir/");
strcat(pir_topic, pir_base);
Serial.println(pir_topic);
}
// ========================== specilized methods
// ----------------------------------------------------------
void setChipId()
{
snprintf(chipID, 10, "%ld", ESP.getChipId());
Serial.print("TL: === Device id: ");
Serial.println(chipID);
// return chipID;
}
Things I've done to try and fix the problem...
Aligned the variables associated with the payload value when publishing to MQTT. Changed code like this:
char luxMsg[50];
snprintf(luxMsg, 75, "%ld", lux);
to this:
char luxMsg[50];
snprintf(luxMsg, 50, "%ld", lux);
Changed timer variables that change within the loop from long
to unsigned long
.
unsigned long now = millis();
unsigned long pubLastPir = 0;
Lots of code lol
Are you closing spiffs when done with it? Are you passing any of those large char to a async pub func as refs
Are you creating any objects on loops say wifimanager?
I would reduce the complexity, bug could be any one of those sensor libraries, make your code so you can disable large pieces maybe use includes or defines also add a debugging wrapper.
Put a debug log call at every benchmark function say debug func name then in debuglog you can output memory logging and try to narrow it down.
The above is an image of the free heap over the afternoon. The code reboots after the crash. Once the leak starts it cascades out over about 15 minutes and eventually chokes.
The room sensor sends mqtt data (the publish routines) to node-red and node-red forwards to grafana.
Obviously I don't know where the leak is happening, but I'll look at your advice and see where I can inject a peek at the memory status. The tedious part is that, as you can see in the chart, it takes about an hour to an hour and a half to start the memory leak cascade... ugh.
Thank you.
Yeah that is hard to debug, at least its not 24 hours.. maybe you can log what it was doing when the memory starts to change beyond a nominal value, and catch it that way, maybe you get a different response from something, maybe you hit a rate limit threshold
I would also remove all string operations for testing, those strcat for example, and use dummy messages
I would also suspect anything that you are doing repeatedly like getting something from a class or library, in case the leak in inside one of those, could even be in side esp lib.
ALSO never use loops in esp while (!Serial) ; // wait for serial monitor to open
these are all bad for the watch dog, make sure there is a yield in every loop
@TinajaLabs a use MQTT with WiFiManager without problems. It can be a bug in char arrays operations... This is a code in my project: https://github.com/dontsovcmc/waterius/blob/master/ESP8266/src/sender_mqtt.h
I don't use SPIFFS, maybe some heap problems...
I also had a bugs with arrays and dangerous functions that don't check null terminators.
And my favourite bug is unsigned/signed arithmetic... Every operations with millis() should be unsigned..
Refactor idea: You needn't call setTopicsDevices You can build topic realtime.
int32_t rssiValue = WiFi.RSSI();
char rssiMsg[50];
// snprintf(rssiMsg, 75, "%ld", WiFi.RSSI());
snprintf(rssiMsg, 75, "%ld", rssiValue);
Serial.print("TL: mqtt pub - RSSI level: \t");
Serial.println(rssiValue);
mqttClient.publish(rssi_topic, rssiMsg);
Example:
String topic = topic_loc + topic_device + chipID + "/device/" + rssi_base;
String msg = String((uint16_t)WiFi.RSSI());
mqttClient.publish(topic, msg);
Example 2:
String root = topic_loc + topic_device + chipID;
bool mqtt_publish(const String §ion, const String &title, const String &msg) {
LOG_DEBUG() << section << title << ": " << msg;
mqttClient.publish(root + section + title, msg);
}
mqtt_publish("/device", "/rssi/state/room", String((uint16_t)WiFi.RSSI());
Evgeny,
You have advised a refactoring similar to what I have just done. I refactored all the parts where I used snprintf
and it has been running for a few hours now without any change to the HeapFree value. We'll see if it holds.
Instead of using the approach where I use something like this:
int16_t rssiValue = WiFi.RSSI();
char rssiMsg[50];
snprintf(rssiMsg, 50, "%ld", rssiValue);
Serial.print("TL: mqtt pub - RSSI level: \t");
Serial.println(rssiMsg);
mqttPublish(rssi_topic, rssiMsg, false);
I am using this:
int16_t rssiValue = WiFi.RSSI();
mqttPublish(rssi_topic, String(rssiValue).c_str(), true);
Also, your approach to create the concatenated topic string, real-time, with String(type) cast looks very efficient. My thought was to create all the topic strings within the setup and thereafter when I need them, they already exist.
As you can probably see all of the topic string manipulation is so I can use wifimanager to update the location part in the field. The rest of the topic is embedded and is associated with the set of sensors and values built into the device.
Thank you for your help, Chris.
Ach...
How does one read the stack? Top to bottom, bottom to top? Is this an exact trace through to the actual lines where the error occurred?
I see references to spiffs which I executed early on when launching the application. Perhaps that should be removed per Evgeny's suggestion. What is the alternative to persisting data on esp8266?
Thanks.
0x40214adb: loop_task(ETSEvent*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 133
0x4021326d: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x402159d8: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x4021326d: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x402159d8: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 161
0x4021326d: EspClass::flashWrite(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 634
0x4021595d: spiffs_hal_write(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 127
0x40214b20: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40100119: __wrap_spi_flash_read at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_phy.c line 267
0x40213291: EspClass::flashRead(unsigned int, unsigned int*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Esp.cpp line 639
0x40215874: spiffs_hal_read(unsigned int, unsigned int, unsigned char*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/spiffs_hal.cpp line 67
0x40221a41: glue2esp_linkoutput at glue-esp/lwip-esp.c line 299
0x40221cd2: new_linkoutput at glue-lwip/lwip-git.c line 238
0x402220b4: ethernet_output at netif/ethernet.c line 312
0x4021b581: _printf_common at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 94
0x40221a41: glue2esp_linkoutput at glue-esp/lwip-esp.c line 299
0x4022978c: etharp_output_to_arp_index at core/ipv4/etharp.c line 770
0x40229990: etharp_output_LWIP2 at core/ipv4/etharp.c line 885
0x4021fe1e: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x4021b918: _printf_i at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 194
0x4021fe1e: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 233
0x4021b918: _printf_i at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 194
0x4021fd58: __ssputs_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 180
0x4021ba18: _printf_i at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf_i.c line 244
0x4022022f: _svfprintf_r at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/nano-vfprintf.c line 660
0x40212c9a: DHT::read(bool) at /home/chrisj/Documents/code/arduino/libraries/DHT_sensor_library/DHT.cpp line 221
0x40202291: uart_do_write_char at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/uart.c line 450
0x4021c264: sprintf at ../../../../../../dl/newlib-xtensa/newlib/libc/stdio/sprintf.c line 646
0x40101401: realloc at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/umm_malloc/umm_malloc.c line 1504
0x40213edf: String::changeBuffer(unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/WString.cpp line 156
0x40213490: HardwareSerial::write(unsigned char const*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/HardwareSerial.h line 174
0x40213795: Print::write(char const*) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/Print.h line 60
0x40213edf: String::changeBuffer(unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/WString.cpp line 156
0x40213f2b: String::reserve(unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/WString.cpp line 146
0x40219238: PubSubClient::connected() at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 606
0x4020c294: PubSubClient::publish(char const*, unsigned char const*, unsigned int, unsigned char) at /home/chrisj/Documents/code/arduino/libraries/PubSubClient/src/PubSubClient.cpp line 399
0x40213490: HardwareSerial::write(unsigned char const*, unsigned int) at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/HardwareSerial.h line 174
0x40100a9e: millis at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 183
0x40208277: publishLuxValues() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 869
0x40214b20: esp_yield() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 91
0x40201d6f: delay at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_wiring.c line 51
0x4020a2f9: loop() at /home/chrisj/Documents/code/arduino/tinaja/roomSensor-wfm-lux-temp-hum-01/roomSensor-wfm-lux-temp-hum-01.ino line 295
0x40214bcc: loop_wrapper() at /home/chrisj/.arduino15/packages/esp8266/hardware/esp8266/2.5.0/cores/esp8266/core_esp8266_main.cpp line 125
Hi @TinajaLabs , The best MQTT client i used till date is https://github.com/256dpi/arduino-mqtt It does not have much features, but its light weight and has TLS support. Im using it with my mosquito broker in cloud..!
I also get these issues with Latest release of Arduino Esp8266 core and wifimanager not working together but everytime there was some or other issue i resolved by using some best practices.
Knowing the flow of code and laying things as per it.!
For example once I was having crashing issue with it, I figured it out was due to mDns. If i do mdns before mqtt begin, it used to crash. I resolved it by putting latter.
Next i did not understood but it was unable to connect if i use string for client id and topic. So made sure to convert those string with .c_str(), which resolved issue. I dont undesrstood the exact reson behind this or might be it was related to something else but it worked.
Recently everything was ok. But my server was refusing to connect. Now my code is similar to yours. Complex and long, im using for my IoT hardware... nothing was changed from previous code, but still it was refusing to subscribe or sometime wont connect.
After lot of tries i decide to put a scheduler delay to start mqtt connection after everything finishes on boot. using library https://github.com/Toshik/TickerScheduler
And everything started working fine.
Hope this might help you!
Don't know if you fixed this, but I just had the same issue.
In these lines:
WiFiClient myWifiClient;
PubSubClient mqttClient(myWifiClient);
myWifiClient must be unique within your LAN. If you have another device connecting to PubSubClient, it's client name has to also be unique.
Getting a crash on a wemos d1 mini (and also on the Feather Huzzah ESP8266 ) after a few minutes of the device trying to reconnect to the wifi router. The router's running openwrt and is about 8 feet away, so I doubt it's a problem with OTA connectivity.
I'm trying to make a room sensor with a collection of sensors (temp, humidity, pir, light level) and associated libraries -
WifiManager
("version": "1.0.0" - from library.json),MQTT
(pupsub),DHT22
(temp/humidity),TSL2561 (lux)
, and aPIR
sensor.Below is the list of libraries I use to accomplish this. I'm trying to understand any interaction between these libs. I've read that the FS library needs to always be first one defined. Are there any others that need to be sequenced in the order?
The code compiles fine and doesn't seem to be related to a memory problem:
Thanks for any tips,
Chris.
The error stack... in case it's meaningful to anyone. First some normal output, then a few dozen attempts to reconnect then - boom.