-->
Page 1 of 1

WIFIclient, ArduinJSON and hardware serial stall

PostPosted: Sun Apr 23, 2023 12:26 pm
by dhajnes
Hi,

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
Code: Select allDeserializationError 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:
Code: Select all
#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.

Code: Select all
#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:
Code: Select allException 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

Re: WIFIclient, ArduinJSON and hardware serial stall

PostPosted: Fri May 12, 2023 10:14 am
by rooppoorali
It seems that your data transmission is working fine, and the JSON received on the NodeMCU is also being deserialized correctly.

The most likely issue is that the data struct is not being populated with the correct data after deserialization, which results in all values showing as zero. To fix this, you should change the doc2data function to use the as method instead of the bracket notation to access the values. Here is an updated version of the function:

Code: Select allstruct Data doc2data(struct Data data, StaticJsonDocument<256> doc){
  data.temp = doc["temp"].as<int>();
  data.hum = doc["hum"].as<int>();
  data.dist = doc["dist"].as<float>();
  data.wet = doc["wet"].as<int>();
  data.light = doc["light"].as<int>();
  data.co2 = doc["co2"].as<int>();
  data.pump = doc["pump"].as<bool>();

  return data;
}


Also, you could increase the size of the StaticJsonDocument to make sure that all the data fits into it. Try using a larger buffer, such as:

Code: Select all StaticJsonDocument<512> doc;


If these changes don't resolve the issue, you could try using a tool like Wireshark to capture the network traffic between the NodeMCU and your laptop to see if there are any issues with the data being sent over Wi-Fi.

I hope this helps! Let me know if you have any further questions.