I have Arduino UNO as a sensor base that collects data and sends them in JSON files over serial communication to ESP8266 NodeMCU (a spinoff called HW-628 V1.1). NodeMCU shows it on display and sends it to a server on my laptop over WIFI.
I first tried sending the data from Arduino to NodeMCU over SoftwareSerial, but I read on the internet that it's not the best practice, and it may cause issues with interrupts and whatnot.
My problem:
The data seems to reach NodeMCU from Arduino at first, but then something happens. The JSON is allegedly deserialized correctly
(I use
DeserializationError error = deserializeJson(doc, Serial);
but then the json seems to contain all zeros. I thought, it may just fall down to the default values in the struct I use, but that's not the fact, the default struct values are set to 999's etc. Any idea, what this might mean? How do I fix this? Are there any interrupt clashes between Serial and
What I already tried:
- - Using Hardware serial instead of the software one, because NodeMCU often restarted because of Fault(0), invalid instruction
- Using a less memory-demanding library for a display called `U8x8lib.h`
- lowering baud rate to 9600 on both sides
- Adding external voltage input for NodeMCU
- hooking Arduino's and NodeMCU 's ground together
- trying out the serial communication without the WIFI - it works - WIFI seems to do something with memory
- removing any `millis()` functions, since they might cause problems (? i read it somewhere)
- I had some stack dupms from NodeMCU which didn't seem to occur anymore after removing software serial, the translated dump is at the end of this post
I would be thankful for any help, getting desperate here...
The NodeMCU code:
#include <U8x8lib.h>
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
const char* ssid = "hotspot";
const char* password = "password";
// The IP address and port number of the remote server
const char* serverIP = "10.42.0.1";
const int serverPort = 1880;
const char* urlPath = "/url";
volatile bool START_WATERING = false;
WiFiClient client;
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* reset=*/ U8X8_PIN_NONE);
StaticJsonDocument<256> doc;
struct Data{
int temp = 99;
int hum = 99;
float dist = 999.9;
int wet = 9999;
int light = 9999;
int co2 = 9999;
bool pump = false;
} data;
struct Data doc2data(struct Data data, StaticJsonDocument<256> doc){
data.temp = doc["temp"];
data.hum = doc["hum"];
data.dist = doc["dist"];
data.wet = doc["wet"];
data.light = doc["light"];
data.co2 = doc["co2"];
data.pump = doc["pump"];
return data;
}
void setup() {
// minimal display setup
u8x8.begin();
u8x8.setFont(u8x8_font_chroma48medium8_r);
Serial.begin(9600);
WiFi.begin(ssid, password);
// setup the WIFI client
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
void loop() {
data = Data();
DeserializationError error = deserializeJson(doc, Serial);
if (error){
u8x8.clearDisplay();
u8x8.setCursor(4,0);
u8x8.print("| Incorrect Json |");
u8x8.refreshDisplay();
return;
}
else {
data = doc2data(data, doc);
String jsonString;
serializeJson(doc, jsonString);
sendPostRequest(jsonString);
}
drawData(data);
}
void sendPostRequest(String jsonPayload) {
// check for connection
if (!client.connect(serverIP, serverPort)) {
client.stop();
return;
}
// Send the HTTP POST request
client.print(String("POST ") + urlPath + " HTTP/1.1\r\n" +
"Host: " + serverIP + "\r\n" +
"Content-Type: application/json\r\n" +
"Content-Length: " + jsonPayload.length() + "\r\n" +
"Connection: close\r\n\r\n" +
jsonPayload + "\r\n");
// Listen for the server's response
int n_of_trials = 5;
int k = 0;
while (client.connected() && k <= n_of_trials){
if (client.available()) {
String response = client.readStringUntil('\r');
k ++;
// delay(100);
if (response.indexOf("water") >= 0) {
START_WATERING = true;
}
}
}
// Close the connection
client.stop();
}
// below continues function `drawData()` for showing on display, I left it out for conciseness
I also attach the Arduino part, but I don't think the problem is there.
#include "DHT.h"
#include <SPI.h>
#include <stdio.h>
#include <Wire.h>
#include <ArduinoJson.h>
// constants
#define DHTPIN 10
#define DHTTYPE DHT11
#define CO2_INTERRUPT 2
#define ADRESS_CDM_7160 0x69
#define ADRESS_REGISTER 0x03
#define wetPin0 A0
#define lightPin A1
#define echoPin 8
#define trigPin 9
#define pumpPin 3
// DHT 11 sensor variables
DHT dht(DHTPIN, DHTTYPE);
int hum = 0;
int temp = 0;
// CO2 sensor variables
byte co2_lower_bits = 0;
byte co2_upper_bits = 0;
int co2_ppm = 0;
volatile bool sensor_free = true;
const int AVG_BUFFER_SIZE = 5;
float running_average_wet = 0;
int bufferIndex = 0;
float run_avg_arr[AVG_BUFFER_SIZE] = {0};
// Moisture sensor variables
int wetVal0 = 0;
// Light sensor variables
int lightVal = 0;
// Pump variables
bool pump_on = false;
float get_run_avg(float new_meas){
run_avg_arr[bufferIndex] = new_meas;
bufferIndex = (bufferIndex + 1) % AVG_BUFFER_SIZE;
float sum = 0;
for (int i = 0; i < AVG_BUFFER_SIZE; i++){
sum += run_avg_arr[i];
}
float avg = sum / AVG_BUFFER_SIZE;
return avg;
}
void sensor_interrupt() {
sensor_free = true;
}
float echo_distance(){
// Clears the trigPin condition
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin HIGH (ACTIVE) for 10 microseconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
float duration = pulseIn(echoPin, HIGH);
// Calculating the distance
float distance = (duration * 0.034) / 2; // Speed of sound wave divided by 2 (go and back)
return distance;
}
StaticJsonDocument<256> doc;
StaticJsonDocument<256> get_doc;
void setup() {
// pinmodes
pinMode(CO2_INTERRUPT, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CO2_INTERRUPT), sensor_interrupt, FALLING );
Wire.begin();
pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
pinMode(echoPin, INPUT); // Sets the echoPin as an
pinMode(pumpPin, OUTPUT);
Serial.begin(9600);
dht.begin();
}
void loop() {
delay(100);
DeserializationError error = deserializeJson(get_doc, Serial);
hum = dht.readHumidity();
temp = dht.readTemperature();
wetVal0 = analogRead(wetPin0);
lightVal = analogRead(lightPin);
float distance = echo_distance();
if (isnan(hum) || isnan(temp)) {
return;
}
running_average_wet = get_run_avg(float(wetVal0));
if (running_average_wet > 850.0){
pump_on = true;
digitalWrite(pumpPin, HIGH);
}
else {
pump_on = false;
digitalWrite(pumpPin, LOW);
}
// CO2 sensor
if (sensor_free) {
Wire.beginTransmission(ADRESS_CDM_7160); // verified with I2C scanner
Wire.write(ADRESS_REGISTER);
Wire.endTransmission();
Wire.requestFrom(ADRESS_CDM_7160, 2); // request 2 bytes
co2_lower_bits = Wire.read();
co2_upper_bits = Wire.read();
co2_ppm = (co2_upper_bits << 8) | co2_lower_bits; //lower + upper shifted by 8 = resulting ppm
co2_ppm += 200; // offeset
}
doc["hum"] = hum;
doc["temp"] = temp;
doc["wet"] = int(running_average_wet);
doc["light"] = lightVal;
doc["dist"] = distance;
doc["co2"] = co2_ppm;
doc["pump"] = pump_on;
serializeJson(doc, Serial);
}
An older NodeMCU dump that does not happen anymore (It seems, nodemcu does not restart), might maybe help:
Exception 0: Illegal instruction
PC: 0x4020a288: read_encoded_value_with_base at /workdir/repo/gcc-gnu/libgcc/unwind-pe.h line 251
EXCVADDR: 0x00000000
Decoding stack results
0x40100b3c: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 809
0x40100a78: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 746
0x40100600: puts(char const*) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/libc_replacements.cpp line 113
0x40100a78: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 746
0x402167a1: autoip_arp_reply at core/ipv4/autoip.c line 472
0x401000ab: app_entry_redefinable() at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_main.cpp line 386
0x40100b3c: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 809
0x40100a78: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 746
0x402114e7: dns_setserver at core/dns.c line 364
0x40100600: puts(char const*) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/libc_replacements.cpp line 113
0x40100600: puts(char const*) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/libc_replacements.cpp line 113
0x402112b9: dns_recv at core/dns.c line 1235
0x402114e7: dns_setserver at core/dns.c line 364
0x40211946: netif_add_LWIP2 at core/netif.c line 340
0x40218c74: ip_napt_new_port at core/ipv4/ip4.c line 500
0x40218d48: ip_napt_add at core/ipv4/ip4.c line 583
0x4021a6b8: sntp_send_request at apps/sntp/sntp.c line 558
0x4021a720: sntp_request at apps/sntp/sntp.c line 617
0x402121fd: raw_input at core/raw.c line 178
0x4021a746: sntp_request at apps/sntp/sntp.c line 627
0x40206a84: __stack_chk_fail() at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_postmortem.cpp line 321
0x40206bd9: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 201
0x40206c4e: Twi::write_start() at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 280
0x4020478c: ClientContext::wait_until_acked(int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/libraries/ESP8266WiFi/src/include/ClientContext.h line 352
0x4020487f: ClientContext::_write_from_source(char const*, unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/libraries/ESP8266WiFi/src/include/ClientContext.h line 529
0x40206b32: Twi::eventTask(ETSEventTag*) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 699
0x4020478c: ClientContext::wait_until_acked(int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/libraries/ESP8266WiFi/src/include/ClientContext.h line 352
0x40203f1c: std::swap (std::_Any_data&, std::_Any_data&) at /home/andrej/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/3.1.0-gcc10.3-e5f9fec/xtensa-lx106-elf/include/c++/10.3.0/bits/move.h line 189
0x4020a860: search_object at /workdir/repo/gcc-gnu/libgcc/unwind-dw2-fde.c line 999
0x4020a860: search_object at /workdir/repo/gcc-gnu/libgcc/unwind-dw2-fde.c line 999
0x40205c04: String::copy(char const*, unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/WString.cpp line 258
0x402031f7: ArduinoJson::V6210PB::detail::TextFormatter >::writeFloat (double) at /home/andrej/Arduino/libraries/ArduinoJson/src/ArduinoJson/Json/TextFormatter.hpp line 165
0x40202a82: ArduinoJson::V6210PB::detail::JsonDeserializer , ArduinoJson::V6210PB::detail::StringCopier>::parseVariant (ArduinoJson::V6210PB::detail::VariantData&, ArduinoJson::V6210PB::detail::AllowAllFilter, ArduinoJson::V6210PB::DeserializationOption::NestingLimit) at /home/andrej/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/VariantData.hpp line 321
0x402066bc: ets_printf_P(char const*, ...) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_postmortem.cpp line 97
0x40202ab2: ArduinoJson::V6210PB::detail::JsonDeserializer , ArduinoJson::V6210PB::detail::StringCopier>::parseVariant (ArduinoJson::V6210PB::detail::VariantData&, ArduinoJson::V6210PB::detail::AllowAllFilter, ArduinoJson::V6210PB::DeserializationOption::NestingLimit) at /home/andrej/Arduino/libraries/ArduinoJson/src/ArduinoJson/Variant/SlotFunctions.hpp line 43
0x40206505: dtostrf(double, signed char, unsigned char, char*) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_noniso.cpp line 76
0x4020352d: sendPostRequest(String) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/libraries/ESP8266WiFi/src/WiFiClient.h line 88
0x40100b3c: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 809
0x40206bd9: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 201
0x40100a78: umm_malloc_core(umm_heap_context_t*, size_t) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/umm_malloc/umm_malloc.cpp line 746
0x40208ab7: DhcpServer::parse_options(unsigned char*, short) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/LwipDhcpServer.cpp line 644
0x40206bd9: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 201
0x40206c15: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 215
0x40206c15: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 215
0x40206c15: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 215
0x40206c15: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 215
0x40206c15: Twi::setClock(unsigned int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/core_esp8266_si2c.cpp line 215
0x40207a38: uart_set_baudrate(uart_t*, int) at /home/andrej/.arduino15/packages/esp8266/hardware/esp8266/3.1.1/cores/esp8266/uart.cpp line 606