Hello all,
This is my first post, it is nice to interact with this community
My application is a MKR Wifi 1010 with an RT transmitter module. I get temp and humidity data connecting to OpenWeatherMap API and transmit it via RF to my Oregon devices at home.
This is working, except that I have to send the data via RF with a fixed frequency each 39s. The problem is that not all the functions that run in the time in-between two transmissions can be stopped or get a timeout that completely ensures that the transmission will not be delayed. For instance, the connection to wifi sometimes can hang and delays the transmission. Do you have any recommendation on a way to interrupt anything and ensure the transmission every 39 seconds?
#include <ArduinoTrace.h>
#include <ArduinoJson.h>
#include <Oregon_TM.h>
#include <SPI.h>
#include <WiFiNINA.h>
#include "config.h"
float tempOut = 24.2;
int humiOut = 30;
bool MakeApiReqFlag = false;
char result[1024];
Oregon_TM transmitter(6, 19);
unsigned long lastApiRequestTime = 0;
const unsigned long apiRequestInterval = 195000; // 195 seconds between API calls
enum ApiRequestState {
IDLE,
CONNECTING_WIFI,
SENDING_REQUEST,
WAITING_FOR_RESPONSE,
PROCESSING_RESPONSE,
DONE
};
ApiRequestState apiState = IDLE;
unsigned long stateStartTime = 0;
const unsigned long stateTimeout = 20000; // 20 seconds max for API request
WiFiClient client;
const char* webserver = "api.openweathermap.org";
struct ClientData {
char temp[8];
char humidity[8];
};
ClientData clientData;
void setup() {
Serial.begin(115200);
transmitter.setType(THGN132);
transmitter.setChannel(1);
transmitter.setBatteryFlag(1);
transmitter.setTemperature(tempOut);
transmitter.setHumidity(humiOut);
transmitter.setComfort(tempOut, humiOut);
transmitter.buffer_size = 19;
TRACE();
}
void loop() {
unsigned long currentTime = millis();
// Transmit temp and humidity data via RF transmitter
if (transmitter.transmit()) {
PrintSentData(transmitter.SendBuffer, transmitter.buffer_size);
// Trigger API request if the interval has passed
if (currentTime - lastApiRequestTime >= apiRequestInterval && apiState == IDLE) {
apiState = CONNECTING_WIFI;
stateStartTime = currentTime;
}
}
// Handle API request state machine
handleApiRequest(currentTime);
}
void handleApiRequest(unsigned long currentTime) {
switch (apiState) {
case IDLE:
// Do nothing
break;
case CONNECTING_WIFI:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("WiFi connection timed out.");
apiState = DONE;
break;
}
if (connectWiFi()) {
Serial.println("\nWiFi connected! IP: " + WiFi.localIP().toString());
apiState = SENDING_REQUEST;
stateStartTime = currentTime;
} else {
apiState = IDLE;
}
break;
case SENDING_REQUEST:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("API request timed out.");
disconnectWiFi();
apiState = DONE;
break;
}
if (sendRequest(webserver, resource)) {
apiState = WAITING_FOR_RESPONSE;
stateStartTime = currentTime;
}
break;
case WAITING_FOR_RESPONSE:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("Response waiting timed out.");
disconnectWiFi();
apiState = DONE;
break;
}
if (client.available()) {
apiState = PROCESSING_RESPONSE;
stateStartTime = currentTime;
}
break;
case PROCESSING_RESPONSE:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("Response processing timed out.");
disconnectWiFi();
apiState = DONE;
break;
}
if (readResponseContent()) {
tempOut = String(clientData.temp).toFloat();
humiOut = String(clientData.humidity).toInt();
transmitter.setTemperature(tempOut);
transmitter.setHumidity(humiOut);
lastApiRequestTime = currentTime;
apiState = DONE;
}
break;
case DONE:
disconnectWiFi();
apiState = IDLE;
break;
}
}
bool connectWiFi() {
Serial.println("Connecting to WiFi...");
unsigned long startTime = millis();
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
if (millis() - startTime > 10000) { // Timeout after 10 seconds
Serial.println("WiFi connection timeout!");
return false; // Exit immediately if it takes too long
}
delay(500); // Shorter delay to check status more often
}
Serial.println("Connected to WiFi!");
return true;
}
bool sendRequest(const char* host, const char* resource) {
if (client.connect(host, 80)) {
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close");
client.println();
return true;
} else {
Serial.println("Connection to OpenWeatherMap failed");
return false;
}
}
bool readResponseContent() {
resetResultBuffer(); // Clear result buffer before use
int index = 0;
bool jsonFound = false;
while (client.available() && index < 1024 - 1) {
char c = client.read();
result[index++] = c;
}
result[index] = '\0'; // Null-terminate the string
client.stop();
Serial.println("Full HTTP Response:");
Serial.println(result); // Debug: Print the raw response
char* jsonStart = strchr(result, '{'); // Locate JSON start
if (jsonStart) {
Serial.println("Extracted JSON:");
Serial.println(jsonStart);
parseWeatherJson(jsonStart);
} else {
Serial.println("Invalid JSON response (No '{' found)");
}
}
void disconnectWiFi() {
WiFi.disconnect();
Serial.println("Disconnected from WiFi.");
}
void PrintSentData(byte* buf, int buf_size) {
Serial.print(millis() / 1000);
Serial.print("s \t\t");
for (byte i = 0; i < buf_size; i++) {
byte trmbuf = *buf;
Serial.print(trmbuf >> 4, HEX);
i++;
if (i >= buf_size) break;
Serial.print(trmbuf & 0x0F, HEX);
buf++;
}
Serial.println();
delay(1000);
}
void parseWeatherJson(String json) {
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, json);
if (error) {
Serial.print("JSON deserialization failed: ");
Serial.println(error.c_str());
return;
}
JsonVariant tempVar = doc["main"]["temp"];
JsonVariant humidityVar = doc["main"]["humidity"];
Serial.println(tempVar.isNull());
if (tempVar.isNull() || humidityVar.isNull()) {
Serial.println("Required fields not present in JSON response.");
}
// Convert the values to strings and store in the clientData struct
String tempString = tempVar.as<String>();
String humidityString = humidityVar.as<String>();
tempString.toCharArray(clientData.temp, sizeof(clientData.temp));
humidityString.toCharArray(clientData.humidity, sizeof(clientData.humidity));
float temperature = doc["main"]["temp"];
int humidity = doc["main"]["humidity"];
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
}
void resetResultBuffer() {
memset(result, 0, 1024); // Clear buffer
}
Thanks for the advice. I think I did the disconnect and connect because keeping the WiFi connection indefinitely was causing some issue after some time, but I can try to revert back to keeping the connection.
Unless there a compelling reason that a new temperature or humidity reading has to be transmitted every 39 seconds, just re-send the most recent value obtained.
Radio is inherently unreliable, so people plan for missed or corrupted transmissions.
I resend the same temp and humidity every 39 seconds because this is required by the Oregon sensor protocol, else the receiver will not show the data. I query new weather data every 195 seconds and that could be even longer, but I still think the timing problem could occur.
I have an update. I modified the sketch to avoid wifi disconnection and reconnection for each API call.
It all works perfectly for some hour, but then it seems the wifi connection is lost, and then it is not possible to reconnect anymore. Maybe there is something going wrong in handling the reconnection with my wifi router?
Here is the serial information and the current sketch.
#include <ArduinoTrace.h>
#include <ArduinoJson.h>
#include <Oregon_TM.h>
#include <SPI.h>
#include <WiFiNINA.h>
#include "config.h"
float tempOut = 24.2;
int humiOut = 30;
bool MakeApiReqFlag = false;
char result[1024];
int status = WL_IDLE_STATUS; // the Wifi radio's status
Oregon_TM transmitter(6, 19);
unsigned long lastApiRequestTime = 0;
const unsigned long apiRequestInterval = 195500; // 195.5 seconds (3 minutes)
enum ApiRequestState {
IDLE,
CONNECTING_WIFI,
SENDING_REQUEST,
WAITING_FOR_RESPONSE,
PROCESSING_RESPONSE,
DISCONNECT
};
ApiRequestState apiState = IDLE;
unsigned long stateStartTime = 0;
const unsigned long stateTimeout = 20000; // 20 seconds max for API request
WiFiClient client;
const char* webserver = "api.openweathermap.org";
struct ClientData {
char temp[8];
char humidity[8];
};
ClientData clientData;
void setup() {
Serial1.begin(115200);
transmitter.setType(THGN132);
transmitter.setChannel(1);
transmitter.setBatteryFlag(1);
transmitter.setTemperature(tempOut);
transmitter.setHumidity(humiOut);
transmitter.setComfort(tempOut, humiOut);
transmitter.buffer_size = 19;
TRACE();
// connectWiFi();
}
void loop() {
unsigned long currentTime = millis();
// Transmit temp and humidity data via RF transmitter
if (transmitter.transmit()) {
PrintSentData(transmitter.SendBuffer, transmitter.buffer_size);
// Trigger API request if the interval has passed
if (currentTime - lastApiRequestTime >= apiRequestInterval && apiState == IDLE) {
apiState = SENDING_REQUEST;
stateStartTime = currentTime;
}
}
//Reconnect to WiFi if connection is lost
if (WiFi.status() != WL_CONNECTED) {
delay(8000);
connectWiFi();
}
// Handle API request state machine
handleApiRequest(currentTime);
}
void handleApiRequest(unsigned long currentTime) {
switch (apiState) {
case IDLE:
// Do nothing
break;
case CONNECTING_WIFI:
if (connectWiFi()) {
Serial1.println("\nWiFi connected! IP: " + WiFi.localIP().toString());
apiState = SENDING_REQUEST;
stateStartTime = currentTime;
}
apiState = IDLE;
break;
case SENDING_REQUEST:
if (currentTime - stateStartTime > stateTimeout) {
Serial1.println("API request timed out.");
disconnectWiFi();
apiState = IDLE;
break;
}
if (sendRequest(webserver, resource)) {
apiState = WAITING_FOR_RESPONSE;
stateStartTime = currentTime;
}
break;
case WAITING_FOR_RESPONSE:
if (currentTime - stateStartTime > stateTimeout) {
Serial1.println("Response waiting timed out.");
disconnectWiFi();
apiState = IDLE;
break;
}
if (client.available()) {
apiState = PROCESSING_RESPONSE;
stateStartTime = currentTime;
}
break;
case PROCESSING_RESPONSE:
if (currentTime - stateStartTime > stateTimeout) {
Serial1.println("Response processing timed out.");
disconnectWiFi();
apiState = IDLE;
break;
}
if (readResponseContent()) {
tempOut = String(clientData.temp).toFloat();
humiOut = String(clientData.humidity).toInt();
transmitter.setTemperature(tempOut);
transmitter.setHumidity(humiOut);
lastApiRequestTime = currentTime;
apiState = IDLE;
}
break;
case DISCONNECT:
disconnectWiFi();
apiState = IDLE;
break;
}
}
bool connectWiFi() {
Serial1.println("Connecting to WiFi...");
while (status != WL_CONNECTED) {
Serial1.print("Attempting to connect to WEP network, SSID: ");
Serial1.println(ssid);
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// once you are connected :
Serial1.print("You're connected to the network");
printCurrentNet();
printWifiData();
// WiFi.begin(ssid, pass);
// while (WiFi.status() != WL_CONNECTED) {
// if (millis() - startTime > 10000) { // Timeout after 10 seconds
// Serial1.println("WiFi connection timeout!");
// return false; // Exit immediately if it takes too long
// }
// delay(500); // Shorter delay to check status more often
// }
// Serial1.println("Connected to WiFi!");
// return true;
}
bool sendRequest(const char* host, const char* resource) {
if (client.connect(host, 80)) {
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close");
client.println();
return true;
} else {
Serial1.println("Connection to OpenWeatherMap failed");
return false;
}
}
bool readResponseContent() {
resetResultBuffer(); // Clear result buffer before use
int index = 0;
bool jsonFound = false;
while (client.available() && index < 1024 - 1) {
char c = client.read();
result[index++] = c;
}
result[index] = '\0'; // Null-terminate the string
client.stop();
Serial1.println("Full HTTP Response:");
Serial1.println(result); // Debug: Print the raw response
char* jsonStart = strchr(result, '{'); // Locate JSON start
if (jsonStart) {
Serial1.println("Extracted JSON:");
Serial1.println(jsonStart);
parseWeatherJson(jsonStart);
} else {
Serial1.println("Invalid JSON response (No '{' found)");
}
}
void disconnectWiFi() {
WiFi.disconnect();
Serial1.println("Disconnected from WiFi.");
}
void PrintSentData(byte* buf, int buf_size) {
Serial1.print(millis() / 1000);
Serial1.print("s \t\t");
for (byte i = 0; i < buf_size; i++) {
byte trmbuf = *buf;
Serial1.print(trmbuf >> 4, HEX);
i++;
if (i >= buf_size) break;
Serial1.print(trmbuf & 0x0F, HEX);
buf++;
}
Serial1.println();
delay(1000);
}
void parseWeatherJson(String json) {
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, json);
if (error) {
Serial1.print("JSON deserialization failed: ");
Serial1.println(error.c_str());
return;
}
JsonVariant tempVar = doc["main"]["temp"];
JsonVariant humidityVar = doc["main"]["humidity"];
Serial1.println(tempVar.isNull());
if (tempVar.isNull() || humidityVar.isNull()) {
Serial1.println("Required fields not present in JSON response.");
}
// Convert the values to strings and store in the clientData struct
String tempString = tempVar.as<String>();
String humidityString = humidityVar.as<String>();
tempString.toCharArray(clientData.temp, sizeof(clientData.temp));
humidityString.toCharArray(clientData.humidity, sizeof(clientData.humidity));
float temperature = doc["main"]["temp"];
int humidity = doc["main"]["humidity"];
Serial1.print("Temperature: ");
Serial1.print(temperature);
Serial1.println(" °C");
Serial1.print("Humidity: ");
Serial1.print(humidity);
Serial1.println(" %");
}
void resetResultBuffer() {
memset(result, 0, 1024); // Clear buffer
}
void printCurrentNet() {
// print the SSID of the network you're attached to:
Serial1.print("SSID: ");
Serial1.println(WiFi.SSID());
// print the MAC address of the router you're attached to:
byte bssid[6];
WiFi.BSSID(bssid);
Serial1.print("BSSID: ");
printMacAddress(bssid);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial1.print("signal strength (RSSI):");
Serial1.println(rssi);
// print the encryption type:
byte encryption = WiFi.encryptionType();
Serial1.print("Encryption Type:");
Serial1.println(encryption, HEX);
Serial1.println();
}
void printMacAddress(byte mac[]) {
for (int i = 5; i >= 0; i--) {
if (mac[i] < 16) {
Serial1.print("0");
}
Serial1.print(mac[i], HEX);
if (i > 0) {
Serial1.print(":");
}
}
Serial1.println();
}
void printWifiData() {
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial1.print("IP Address: ");
Serial1.println(ip);
Serial1.println(ip);
// print your MAC address:
byte mac[6];
WiFi.macAddress(mac);
Serial1.print("MAC address: ");
printMacAddress(mac);
}
Connecting to WiFi...
You're connected to the networkSSID:
BSSID: 00:00:00:00:00:00
signal strength (RSSI):0
Encryption Type:7
IP Address: 0.0.0.0```
Not very helpful for you perhaps but I use ESP8266s which connect once to WiFi and remain connected. In the event of disconnection, for example because my router is restarted, they reconnect without any intervention by me.
if your local WiFi is unreliable during periods when it is down you could save data in an array for transmission when the WiFi is restored
if all else fails use the preferences library
Hello, I come here with even more questions after some testing.
I tried the wifinina test sketch with my MKR 1010. It is stable as rock and so far did not disconnect after days. So, I would expect that the WiFi router and the MKR 1010 are working good, and there is something in my sketch that causes the issue. For reference I attach both the wifinina test sketch and my application.
What could be wrong in my sketch? The state machine? The interruption due to the transmitter.transmit that happen every 39 seconds may disturb wifi communication?
wifi test:
#include <WiFiNINA.h>
#include "config.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
int status = WL_IDLE_STATUS; // the Wifi radio's status
void setup() {
//Initialize Serial1 and wait for port to open:
Serial1.begin(9600);
while (!Serial1)
;
// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
Serial1.print("Attempting to connect to network: ");
Serial1.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial1.println("You're connected to the network");
Serial1.println("----------------------------------------");
printData();
Serial1.println("----------------------------------------");
}
void loop() {
// check the network connection once every 10 seconds:
delay(10000);
printData();
Serial1.println("----------------------------------------");
}
void printData() {
Serial1.println("Board Information:");
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial1.print("IP Address: ");
Serial1.println(ip);
Serial1.println();
Serial1.println("Network Information:");
Serial1.print("SSID: ");
Serial1.println(WiFi.SSID());
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial1.print("signal strength (RSSI):");
Serial1.println(rssi);
byte encryption = WiFi.encryptionType();
Serial1.print("Encryption Type:");
Serial1.println(encryption, HEX);
Serial1.println();
}
Additional idea: I have also an Arduino Uno Ethernet R3 and I thought I could do the same application (Oregon Scientific sensor emulation) using that connected to my LAN instead of the MKR 1010 on wifi. Unfortunately I am not able to stay within the limited memory available, especially with the json buffer that must be +800 characters according to the arduinojson6 wizard and when I build it on the card I get garbage from serial monitor which I guess is from memory issues. Do you think it is doable at all?
#include <ArduinoTrace.h>
#include <ArduinoJson.h>
#include <Oregon_TM.h>
#include <Ethernet.h>
#include "config.h"
float tempOut = 24.2;
int humiOut = 30;
bool MakeApiReqFlag = false;
char result[843];
// int status = WL_IDLE_STATUS; // the Wifi radio's status
EthernetClient client;
Oregon_TM transmitter(6, 19);
unsigned long lastApiRequestTime = 0;
const unsigned long apiRequestInterval = 195500; // 195.5 seconds (3 minutes)
enum ApiRequestState {
IDLE,
RECONNECT_LAN,
SENDING_REQUEST,
WAITING_FOR_RESPONSE,
PROCESSING_RESPONSE,
DISCONNECT
};
ApiRequestState apiState = IDLE;
unsigned int stateStartTime = 0;
const unsigned int stateTimeout = 20000; // 20 seconds max for API request
const char webserver[] PROGMEM = { "api.openweathermap.org" };
struct ClientData {
char temp[8];
char humidity[8];
};
ClientData clientData;
void setup() {
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to initialize
}
Serial.println("Serial ready");
if (!Ethernet.begin(mac)) {
Serial.println("Failed to configure Ethernet");
return;
}
Serial.println("Ethernet ready");
transmitter.setType(THGN132);
transmitter.setChannel(1);
transmitter.setBatteryFlag(1);
transmitter.setTemperature(tempOut);
transmitter.setHumidity(humiOut);
transmitter.setComfort(tempOut, humiOut);
transmitter.buffer_size = 19;
}
void loop() {
unsigned long currentTime = millis();
// Transmit temp and humidity data via RF transmitter
if (transmitter.transmit()) {
PrintSentData(transmitter.SendBuffer, transmitter.buffer_size);
// Trigger API request if the interval has passed
if (currentTime - lastApiRequestTime >= apiRequestInterval && apiState == IDLE) {
apiState = SENDING_REQUEST;
stateStartTime = currentTime;
}
}
// Handle API request state machine
handleApiRequest(currentTime);
}
void handleApiRequest(unsigned long currentTime) {
switch (apiState) {
case IDLE:
// Do nothing
break;
case RECONNECT_LAN:
if (client.connected()) {
Serial.println("Ethernet is connected");
apiState = IDLE;
stateStartTime = currentTime;
} else {
Serial.println("Ethernet is disconnected");
}
apiState = IDLE;
break;
case SENDING_REQUEST:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("API request timed out.");
apiState = IDLE;
break;
}
if (sendRequest(webserver, resource)) {
apiState = WAITING_FOR_RESPONSE;
stateStartTime = currentTime;
}
break;
case WAITING_FOR_RESPONSE:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("Response waiting timed out.");
apiState = IDLE;
break;
}
if (client.available()) {
apiState = PROCESSING_RESPONSE;
stateStartTime = currentTime;
}
break;
case PROCESSING_RESPONSE:
if (currentTime - stateStartTime > stateTimeout) {
Serial.println("Response processing timed out.");
apiState = IDLE;
break;
}
if (readResponseContent()) {
tempOut = String(clientData.temp).toFloat();
humiOut = String(clientData.humidity).toInt();
transmitter.setTemperature(tempOut);
transmitter.setHumidity(humiOut);
lastApiRequestTime = currentTime;
apiState = IDLE;
}
break;
case DISCONNECT:
apiState = IDLE;
break;
}
}
bool sendRequest(const char* host, const char* resource) {
if (client.connect(host, 80)) {
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close");
client.println();
return true;
} else {
Serial.println("Connection to OpenWeatherMap failed");
return false;
}
}
bool readResponseContent() {
resetResultBuffer(); // Clear result buffer before use
int index = 0;
bool jsonFound = false;
while (client.available() && index < 1024 - 1) {
char c = client.read();
result[index++] = c;
}
result[index] = '\0'; // Null-terminate the string
client.stop();
Serial.println("Full HTTP Response:");
Serial.println(result); // Debug: Print the raw response
char* jsonStart = strchr(result, '{'); // Locate JSON start
if (jsonStart) {
Serial.println("Extracted JSON:");
Serial.println(jsonStart);
parseWeatherJson(jsonStart);
} else {
Serial.println("Invalid JSON response (No '{' found)");
}
}
void PrintSentData(byte* buf, int buf_size) {
Serial.print(millis() / 1000);
Serial.print("s \t\t");
for (byte i = 0; i < buf_size; i++) {
byte trmbuf = *buf;
Serial.print(trmbuf >> 4, HEX);
i++;
if (i >= buf_size) break;
Serial.print(trmbuf & 0x0F, HEX);
buf++;
}
Serial.println();
delay(1000);
}
void parseWeatherJson(String json) {
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, json);
if (error) {
Serial.print("JSON deserialization failed: ");
Serial.println(error.c_str());
return;
}
JsonVariant tempVar = doc["main"]["temp"];
JsonVariant humidityVar = doc["main"]["humidity"];
Serial.println(tempVar.isNull());
if (tempVar.isNull() || humidityVar.isNull()) {
Serial.println("Required fields not present in JSON response.");
}
// Convert the values to strings and store in the clientData struct
String tempString = tempVar.as<String>();
String humidityString = humidityVar.as<String>();
tempString.toCharArray(clientData.temp, sizeof(clientData.temp));
humidityString.toCharArray(clientData.humidity, sizeof(clientData.humidity));
float temperature = doc["main"]["temp"];
int humidity = doc["main"]["humidity"];
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
}
void resetResultBuffer() {
memset(result, 0, 1024); // Clear buffer
}
Hello, I have an update. I added the Oregon_TM library with the transmitter.transmit() function to the loop() function and this caused again the wifi to disconnect. So, I would assume that the transmit function may interrupt some task that is requested to keep wifi connection. Can this be the cause? I will now test by adding a reconnect function to the loop() but I would prefer to avoid disconnections.
Hello, finally it seems that I identified the problem, and I got a working fix from ChatGPT.
Understanding the Root Problem
You're dealing with a hardware resource conflict or timing issue. Here’s what’s happening:
The Oregon_TM library likely depends on timing-critical routines (maybe micros() or a hardware timer).
A globally instantiated WiFiClient object might be occupying resources or causing blocking behavior that disrupts this timing (especially during socket allocation or timeout waits).
Declaring WiFiClient client;locally inside loop()works, probably because the object is destroyed after each loop iteration, freeing up whatever resource was causing the problem.
But, if you declare the client in each helper function like connect(), sendRequest(), etc., the client object becomes function-local, and hence a different instance per function — meaning socket state and connection persistence is broken across functions.
Working Solution Strategy
To resolve both constraints — no interference with the transmitter, and working API calls — you need a middle ground:
Pass a single local WiFiClient instance into each function that needs it, rather than relying on a global or creating separate instances in every function.
Implementation Steps
Declare WiFiClient client; locally in loop() or makeApiRequest().
In case anyone ever will be interested in a Oregon sensor emulator, here is the final working sketch that can run on a Arduino MKR WiFi 1010 or adapted on other cards:
#include <WiFiNINA.h>
#include <Oregon_TM.h>
#include "config.h"
#include <ArduinoJson.h>
float tempOut = 24.2;
float humiOut = 30;
bool MakeApiReqFlag = false;
unsigned long lastApiRequestTime = 50000;
const unsigned long apiRequestInterval = 180000; // 180 seconds (3 minutes)
const unsigned long HTTP_TIMEOUT = 10000; // max response time from server
//WiFiClient client; // Declare WiFi client globally !!! This is causing an error in transmitting the temperature, no idea why
const char* webserver = "api.openweathermap.org";
//The type of data that we want to extract from the page
struct ClientData {
char temp[8];
char humidity[8];
};
ClientData clientData; // Declare it as a global variable
unsigned long lastTransmitTime = 0;
Oregon_TM transmitter(6, 19);
int status = WL_IDLE_STATUS; // the Wifi radio's status
void setup() {
transmitter.setType(THGN132);
transmitter.setChannel(1);
transmitter.setBatteryFlag(1);
transmitter.setTemperature(24.3);
transmitter.setHumidity(30);
transmitter.setComfort(24.3, 30);
transmitter.buffer_size = 19;
//Initialize Serial1 and wait for port to open:
Serial1.begin(9600);
while (!Serial1)
;
// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
Serial1.print("Attempting to connect to network: ");
Serial1.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial1.println("You're connected to the network");
Serial1.println("----------------------------------------");
printData();
Serial1.println("----------------------------------------");
}
void loop() {
//WiFiClient client;
unsigned long currentTime = millis();
if (transmitter.transmit()) {
PrintSentData(transmitter.SendBuffer, transmitter.buffer_size);
lastTransmitTime = currentTime;
}
// Reconnect WiFi if connection is lost
if (currentTime - lastTransmitTime < 19000) {
checkWiFiConnection();
}
// check the network connection once every 10 seconds:
// if (currentTime - lastTransmitTime < 19000) {
// delay(10000);
// printData();
// Serial1.println("----------------------------------------");
// }
if (currentTime - lastTransmitTime < 9000) {
if (MakeApiReqFlag) {
makeApiRequest();
//transmitter.setTemperature(tempOut); // -49.9C...+69.9C
//transmitter.setHumidity(humiOut); // 2...98%
}
}
//Trigger Api request, if Api request interval has passed
if ((millis() - lastApiRequestTime) >= apiRequestInterval) {
MakeApiReqFlag = true;
}
}
void printData() {
Serial1.println("Board Information:");
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial1.print("IP Address: ");
Serial1.println(ip);
Serial1.println();
Serial1.println("Network Information:");
Serial1.print("SSID: ");
Serial1.println(WiFi.SSID());
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial1.print("signal strength (RSSI):");
Serial1.println(rssi);
byte encryption = WiFi.encryptionType();
Serial1.print("Encryption Type:");
Serial1.println(encryption, HEX);
Serial1.println();
Serial1.print("WiFi status:");
Serial1.println(WiFi.status());
Serial1.println();
}
void PrintSentData(byte* buf, int buf_size) {
Serial1.print(millis() / 1000);
Serial1.print("s \t\t");
for (byte i = 0; i < buf_size; i++) {
byte trmbuf = *buf;
Serial1.print(trmbuf >> 4, HEX);
i++;
if (i >= buf_size) break;
Serial1.print(trmbuf & 0x0F, HEX);
buf++;
}
Serial1.println();
delay(1000);
}
void checkWiFiConnection() {
if (WiFi.status() != WL_CONNECTED || WiFi.RSSI() == 0) {
WiFi.disconnect();
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial1.print(".");
}
Serial1.println("Reconnected to WiFi");
}
}
bool makeApiRequest() {
unsigned long StartTime = millis();
WiFiClient client; // Local client instance
while ((millis() - StartTime) < 35000) {
MakeApiReqFlag = false;
if (!connect(client, webserver)) {
return false;
}
if (!sendRequest(client, webserver, resource)) {
return cleanup(client, false);
return false;
}
if (!skipResponseHeaders(client)) {
return cleanup(client, false);
return false;
}
if (readResponseContent(client)) {
printclientData();
tempOut = String(clientData.temp).toFloat();
humiOut = String(clientData.humidity).toFloat();
transmitter.setTemperature(tempOut); // -49.9C...+69.9C
transmitter.setHumidity(humiOut); // 2...98%
lastApiRequestTime = millis();
}
return cleanup(client, true);
return true;
}
}
bool cleanup(WiFiClient& client, bool result) {
disconnect(client);
return result;
}
bool connect(WiFiClient& client, const char* hostName) {
// WiFiClient client;
delay(5000);
Serial1.print("Connect to ");
Serial1.println(hostName);
bool ok = client.connect(hostName, 80);
Serial1.println(ok ? "Connected" : "Connection Failed!");
return ok;
}
//Send the HTTP GET request to the server
bool sendRequest(WiFiClient& client, const char* host, const char* resource) {
// WiFiClient client;
Serial1.print("GET ");
Serial1.println(resource);
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(host);
client.println("Connection: close");
client.println();
return true;
}
// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders(WiFiClient& client) {
// WiFiClient client;
// HTTP headers end with an empty line
char endOfHeaders[] = "\r\n\r\n";
client.setTimeout(HTTP_TIMEOUT);
bool ok = client.find(endOfHeaders);
if (!ok) {
Serial1.println("No response or invalid response!");
}
return ok;
}
void disconnect(WiFiClient& client) {
// WiFiClient client;
Serial1.println("Disconnect");
client.stop();
}
//Json parsing
bool readResponseContent(WiFiClient& client) {
// WiFiClient client;
const size_t bufferSize = JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 30;
DynamicJsonDocument jsonBuffer(bufferSize);
StaticJsonDocument<200> filter;
filter["main"]["humidity"] = true;
filter["main"]["temp"] = true;
DeserializationError error = deserializeJson(jsonBuffer, client, DeserializationOption::Filter(filter));
if (error) {
Serial1.print(F("deserializeJson() failed with code "));
Serial1.println(error.c_str());
return false;
}
JsonObject root = jsonBuffer.as<JsonObject>();
// Use filters to extract only the required fields
JsonVariant tempVar = root["main"]["temp"];
JsonVariant humidityVar = root["main"]["humidity"];
// Check if the required fields are present
if (tempVar.isNull() || humidityVar.isNull()) {
Serial1.println("Required fields not present in JSON response");
return false;
}
// Convert the values to strings and store in the clientData struct
String tempString = tempVar.as<String>();
String humidityString = humidityVar.as<String>();
tempString.toCharArray(clientData.temp, sizeof(clientData.temp));
humidityString.toCharArray(clientData.humidity, sizeof(clientData.humidity));
return true;
}
// Print the data extracted from the JSON
void printclientData() {
Serial1.print("Temp = ");
Serial1.println(clientData.temp);
Serial1.print("Humidity = ");
Serial1.println(clientData.humidity);
}