ESP32 websocket server: Task watchdog got triggered - c++

The Microcontroller I am using is a ESP-WROOM-32:
board model: ESP32-ST
software: ESP-IDF
working on windows with arduino 1.8.19
includes:
#include <Arduino.h>
#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <SPIFFS.h>
I am writing the code for a machine that receives orders via a websocket. As soon as this machine starts processing the task from the JSON string of the websocket message, it doesn't take long (5-7 seconds) before the ESP32's watchdog triggers.
After some changes to the code, I assume that the error is that the websocket server has to wait too long for a response from the function it has called.
Error message from the console
14:38:45.881 -> E (359189) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
14:38:45.881 -> E (359189) task_wdt: - async_tcp (CPU 0/1)
14:38:45.881 -> E (359189) task_wdt: Tasks currently running:
14:38:45.881 -> E (359189) task_wdt: CPU 0: IDLE0
14:38:45.881 -> E (359189) task_wdt: CPU 1: loopTask
14:38:45.881 -> E (359189) task_wdt: Aborting.
14:38:45.881 -> abort() was called at PC 0x4014c194 on core 0
14:38:45.881 ->
14:38:45.881 -> ELF file SHA256: 0000000000000000
14:38:45.881 ->
14:38:45.881 -> Backtrace: 0x40088798:0x3ffbf830 0x40088a15:0x3ffbf850 0x4014c194:0x3ffbf870 0x40086f61:0x3ffbf890 0x4017d957:0x3ffbc320 0x4014da9f:0x3ffbc340 0x4008b1d5:0x3ffbc360 0x40089a26:0x3ffbc380
14:38:45.881 ->
Webserver & Websocket Code
AsyncWebServer server(80);
AsyncWebSocket wss("/ws");
void initWebServer() {
server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.html");
server.begin();
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
handleEvent(arg, data, len, client);
break;
case WS_EVT_PONG:
case WS_EVT_ERROR:
break;
}
}
wss.onEvent(onEvent);
void loop() {
wss.cleanupClients();
}
Possible Websocket Event
{
"event":"driveTask",
"data": [
{
"driveToPos": 500,
"driveVerticalCount": 3
}
]
}
Eventhandler code
void handleEvent(void *arg, uint8_t *data, size_t len, AsyncWebSocketClient *client) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
DynamicJsonDocument json(1024);
deserializeJson(json, (char*) data);
serializeJson(json, Serial); Serial.println("<- event");
String eventData = json["data"]; // save the data for driving the motors
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
Serial.print(eventData);Serial.println("<- Event Data");
if(strcmp(json["event"], "driveTask") == 0) {
DynamicJsonDocument task(1024);
deserializeJson(task, eventData);
serializeJson(task, Serial);Serial.println("<- task");
for(JsonVariant elem : task.as<JsonArray>()) {
yield();
serializeJson(elem, Serial);Serial.println("<- inside for");
int driveToPos = elem["driveToPos"];
if(driveToPos != 0) {
vAchse = driveToPos;
for(int i=0; i<elem["driveVerticalCount"]; i++) {
yield();
hAchse+300;
delay(2000);
hAchse-300;
delay(2000);
}
}
}
delay(500);
vAchse.driveHome();
}
}
}
Motor Drive Code (ES stands for endstop)
// Class private
void Motor::drive(){
//Serial.println("inside Drive");
yield();
digitalWrite(this->Signal, HIGH);
delayMicroseconds(this->pulsetime);
digitalWrite(this->Signal, LOW);
delayMicroseconds(this->velocity);
}
void Motor::driveMotor(int distance) {
// break in for loop if endstop activates
digitalWrite(this->Enable,HIGH);
if ((this->currPos + distance) > (this->startPos)) {
distance = ((-1) * this->currPos);
} else if ((this->currPos + distance) < (this->maxRange)) {
distance = this->maxRange - this->currPos;
}
if (( ( distance ) > ( 0 ) ))
{digitalWrite(this->Direction, HIGH);}
else
{digitalWrite(this->Direction, LOW);}
for (int index =1; index <= ( abs( distance ) ) && !(this->endStop != -1 && digitalRead(this->endStop) == 1); index++ ){
this->drive();
}
digitalWrite(this->Enable,LOW);
Serial.println("drove");
this->currPos += distance;
if(this->endStop != -1 && digitalRead(this->endStop) == 1) {
Serial.println("Stopped by ES");
this->ignoreESnDrive(this->distFromES);
this->currPos = 0;
}
}
void Motor::ignoreESnDrive(int distance) {
// break in for loop if endstop activates
digitalWrite(this->Enable,HIGH);
Serial.println("ESnDrive");
if ((this->currPos + distance) > (this->startPos)) {
distance = ((-1) * this->currPos);
} else if ((this->currPos + distance) < (this->maxRange)) {
distance = this->maxRange - this->currPos;
}
if (( ( distance ) > ( 0 ) ))
{digitalWrite(this->Direction, HIGH);}
else
{digitalWrite(this->Direction, LOW);}
for (int index =1; index <= ( abs( distance ) ); index++ ){
//Serial.println("drive ESn");
this->drive();
}
digitalWrite(this->Enable,LOW);
Serial.println("drove ESn");
this->currPos += distance;
}
// Class public
void Motor::level() {
if(this->endStop == -1 ) return;
Serial.println("Leveling");
Serial.println(digitalRead(this->endStop));
if(digitalRead(this->endStop) == 0){
digitalWrite(this->Enable,HIGH);
digitalWrite(this->Direction, HIGH);
while (/*this->endStop != -1 && */digitalRead(this->endStop) == 0 ) {
this->drive();
}
digitalWrite(this->Enable,LOW);
}
delay(500);
this->ignoreESnDrive(this->distFromES);
this->currPos = 0;
}
void Motor::driveHome() {
this->driveMotor(((-1) * this->currPos));
}
void Motor:: operator= (int newPos) {
Serial.println(newPos);
this->driveMotor(newPos - this->currPos);
}
void Motor:: operator+ (int distance) {
Serial.println(abs(distance));
this->driveMotor(abs(distance));
}
void Motor:: operator- (int distance) {
Serial.println(abs(distance));
this->driveMotor((-1)*abs(distance));
}
Attempts to bypass the watchdog trigger with delay() and yield() functions have failed.
The code for moving the axes works without problems if it levels the vaxis at the start. The level loop runs for minutes without crashing. Only when a call is made within the event is the process aborted by the watchdog.
I am looking forward to suggestions on how to circumvent the watchdog.
Improvements to the code are secondary here, as first of all the code should run without wdt crashes.

You're using websockets with the ESPAsyncWebServer.
Your event handler callback is calling yield() and delay(). This is explicitly forbidden in ESPAsyncWebServer's README:
You can not use yield or delay or any function that uses them inside
the callbacks
To make this work, you'll need to rewrite your code to not call yield() or delay() or any function that might call them (which means almost any third party library since you don't know what it might do internally) in the callback handler.
The easiest way to do that is to have the callback handler stash any important data for later use, set a global flag that indicates there's work to be done and then return. Rewrite your loop() function to do the work using the saved data and then clear the flag. If you need to write anything to the websockets client, you can do that from inside loop() as well.

Related

Using ESP_NOW with loop and delays

I'm trying to receive a data from one esp32 to another.
I'm also doing some looping with delays for reading a sensor data and switch on/off relay cooling.
This device also use ESPAsyncWebServer as API server (not included in code for the size).
I'm receiving the data from one eps32 in POST request to API right now. I would like to change this as to be able to recieve with esp_now. I was doing some experiments, but the data receving is delayed because of delay method in loop.
Is there a way to make this asynchronized as for example the ESPA above?
I also tried a way with comparing a milis() (time) to wait for a loop, but I thing that is too "resource consuming" task, to let it compare in full speed in loop like a vortex forever.
here is my loop
it's just a simple loop with some vars and delay function for example
void loop() {
if (WiFi.status() == WL_CONNECTED) {
float temp_check = dht.readTemperature();
if (temp_check == 0) {
delay(1000);
temp_check = dht.readTemperature();
}
if (temp_check > 32.0 && *cooling_switch_p == false) {
Serial.println("[ INF ] Too high temperature, switch on a cooling system");
digitalWrite(COOLING_RELAY, LOW);
*cooling_switch_p = true;
}
else if (temp_check < 30.0 && *cooling_switch_p == true) {
Serial.println("[ INF ] Normal temperature, switch off a cooling system");
digitalWrite(COOLING_RELAY, HIGH);
*cooling_switch_p = false;
}
Serial.print("[ DBG ] Light Switch: ");
Serial.println(String(light_switch));
Serial.println("");
Serial.print("[ DBG ] Pump Switch: ");
Serial.println(String(pump_switch));
Serial.println("");
delay(5000);
}
else {
Serial.println("[ ERR ] Wifi not connected. Exiting program");
delay(9999);
exit(0);
}
}
I assume you're trying to send your sensor data from this device to another one while more or less accurately maintaining the 5-second sampling interval. You can create a simple asynchronous architecture yourself using 2 threads.
The existing thread (created by Arduino) runs your current loop() which reads the sensor every 5 seconds. You add a second thread which deals with transmitting the sample to other devices. The first thread posts the sample to the second thread through a FreeRTOS queue; second thread immediately goes to work transmitting. The first thread continues to mind its own business without waiting for transmission to complete.
Using the FreeRTOS documentation on creating tasks and queues:
#include <task.h>
#include <queue.h>
#include <assert.h>
TaskHandle_t hTxTask;
QueueHandle_t hTxQueue;
constexpr size_t TX_QUEUE_LEN = 10;
// The task which transmits temperature samples to wherever needed
void txTask(void* parm) {
while (true) {
float temp;
// Block until a sample is posted to queue
const BaseType_t res = xQueueReceive(hTxQueue, static_cast<void*>(&temp), portMAX_DELAY);
assert(res);
// Here you write your code to send the temperature to other device
// e.g.: esp_now_send(temp);
}
}
void setup() {
// Create the queue
hTxQueue = xQueueCreate(TX_QUEUE_LEN, sizeof(float));
assert(hTxQueue);
// Create and start the TX task
const BaseType_t res = xTaskCreate(txTask, "TX task", 8192, nullptr, tskIDLE_PRIORITY, &hTxTask);
assert(res);
// ... rest of your setup()
}
void loop() {
if (WiFi.status() == WL_CONNECTED) {
float temp_check = dht.readTemperature();
// Post fresh sample to queue
const BaseType_t res = xQueueSendToBack(hTxQueue, &temp_check, 0);
if (!res) {
Serial.println("Error: TX queue full!");
}
// ... Rest of your loop code
}
}

ESP32 Bluetooth connection status

I am running into some problems finding a solution when it comes to performing some form of Bluetooth connection check for my project that will allow me to have a connection status light.
My project consists of creating a Bluetooth speaker that has Led Strips controlled over Bluetooth serial (an app will be made to handle this) and audio stream over Bluetooth from a single ESP32.
I have found plenty of examples and had success with performing an spp callback event, however, of course this only works if I connect to the Bluetooth serial side of things through my 'Serial Bluetooth Terminal' app on my phone. If I just go into my phone Bluetooth list and connect to the audio side of things, nothing is registered, which isn't very useful for a Bluetooth speaker!
Basically I really need some help finding a way of registering that a device has connected to the Bluetooth audio so that I can have some form of indication light to tell the user that they are successfully connected to the speaker to play music.
Below is my code:
#include <btAudio.h> //<-------this is the library that I am using to handle Bluetooth audio to an external I2s DAC
#include "BluetoothSerial.h"
#include <FastLED.h>
TaskHandle_t Task1;
//POWER/BT-LIGHT-SETUP----------------------------------------
int powerPinR = 4;
int powerPinG = 16;
int powerPinB = 17;
bool BTisConnected;
//FAST-LED-STUFF----------------------------------------------
CRGB leds[NUM_STRIPS][NUM_LEDS];
CRGB leds_temp[NUM_STRIPS][NUM_LEDS/2];
//BLUETOOTH-SETUP---------------------------------------------
btAudio audio = btAudio("");
BluetoothSerial SerialBT;
//CONNECTION-CHECK--------------------------------------------
void callback(esp_spp_cb_event_t event, esp_spp_cb_param_t*param){
if(event == ESP_SPP_SRV_OPEN_EVT){
Serial.println("Client Connected");
BTisConnected = true;
}
else {
BTisConnected = false;
}
}
//------------------------------------------------------------
void setup() {
//CORE-1-INITIALISE
xTaskCreatePinnedToCore(
codeForTask1, /* Task function. */
"Task_1", /* name of task. */
1000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* Core */
//POWER/BLUETOOTH-CONNECTION-LIGHT-SETUP
pinMode(powerPinR, OUTPUT);
pinMode(powerPinG, OUTPUT);
pinMode(powerPinB, OUTPUT);
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, HIGH);
digitalWrite (powerPinB, HIGH);
//COOLDOWN-DELAY
delay(3000);
//AUDIO-INITIALISE
audio.begin();
int bck = 26;
int ws = 27;
int dout = 25;
audio.I2S(bck, dout, ws);
//LED-STRIP-SETUP-&-CLEAR-ALL
FastLED.addLeds<WS2812B,STRIP1PIN,GRB>(leds[0], NUM_LEDS);
FastLED.addLeds<WS2812B,STRIP2PIN,GRB>(leds[1], NUM_LEDS);
FastLED.clear();
FastLED.show();
//SERIAL-INITIALISE-&-CLIENT-CONNECTION-CHECK
Serial.begin(115200);
SerialBT.begin("Pilot"); //<-----BLUETOOTH NAME
SerialBT.register_callback(callback); //<-- SerialBT connection check works perfectly, but nothing for audio connection! :(
}
//CORE-0-VOID-LOOP--------------------------------------------
void codeForTask1( void * parameter )
{
for (;;) {
manageData();
delay(10);
}
}
//CORE-1-VOID-LOOP--------------------------------------------
void loop() {
BTconnectionCheck();
playScene();
}
//MANAGE-INCOMING-BLUETOOTH-SERIAL-DATA-----------------------------------------------
void manageData() {
//READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT ** READ FROM SERIAL AND PARSE OUT **
char rawData[100] = "";
char keyword[] = "Mydata=";
if (SerialBT.available() > 0) {//new data in
size_t byteCount = SerialBT.readBytesUntil('\n', rawData, sizeof(rawData) - 1); //read in data to buffer
rawData[byteCount] = NULL;//put an end character on the data
const char delimiter[] = ",";
char parsedStrings[5][8]; //first number = how many bits of data - 2nd number = max size of eeach data
int dataCount = 0;
int dataPosition = 0;
char *token = strtok(&rawData[dataPosition], delimiter);//look for first piece of data after keyword until comma
if (token != NULL && strlen(token) < sizeof(parsedStrings[0])) {
strncpy(parsedStrings[0], token, sizeof(parsedStrings[0]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[0], NULL);
}
for (int i = 1; i < 5; i++) {
token = strtok(NULL, delimiter);
if (token != NULL && strlen(token) < sizeof(parsedStrings[i])) {
strncpy(parsedStrings[i], token, sizeof(parsedStrings[i]));
dataCount++;
} else {
Serial.println("token to big");
strcpy(parsedStrings[i], NULL);
}
}
if (dataCount == 5) {
scene = atoi (parsedStrings[0]);
hue = atoi(parsedStrings[1]);
saturation = atoi(parsedStrings[2]);
brightness = atoi(parsedStrings[3]);
eventInterval = atol (parsedStrings[4]);
}
}
}
//BLUETOOTH-CONNECTION-CHECK---------------------------------------------------------
void BTconnectionCheck(){
SerialBT.register_callback(callback);
if (BTisConnected == true){
bluetoothConnected();
}
else {
bluetoothSearch();
}
}
void bluetoothSearch(){
digitalWrite (powerPinR, LOW);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
void bluetoothConnected(){
digitalWrite (powerPinR, HIGH);
digitalWrite (powerPinG, LOW);
digitalWrite (powerPinB, HIGH);
}
I have cut lots of the code to do with the LEDs out but its still quite long, If it would help to have a more condensed version then I will chop it down further. Or if it helps to have the full code then I can also post it.
Any help would be greatly appreciated as I am well and truly stuck with this one and its a pretty important part of the project.
Thanks in advance!

Arduino Motion Sensor Light timer

currently trying to make a motion sensor light that i can turn on and off with sensor detection but also have auto turn off after lets say 15 minutes if left on.
I've got it so i can turn it off and on now using motion but not sure how to have it auto turn off after a set time since delay blocks me from turning it off with motion if i try using that.
I'm thinking I'll have to use the millis function? but not sure where to start and feel like I've hit a wall so any guidance would be appreciated.
here's the code i have so far to have the sensor turn it off and on.
int pir = 2;
int val;
int state = 0;
void setup() {
pinMode(led, OUTPUT);
pinMode(pir, INPUT);
}
void loop() {
val = digitalRead(pir);
if (val == HIGH)
{
if (state == 0)
{
state = 1;
digitalWrite(led, HIGH);
delay (4000);
}
else {
state = 0;
digitalWrite(led, LOW);
delay (4000);
}
}
}```
have a global variable unsigned long sleep_start;. Set sleep_start = 0 everytime you turn the LED off andsleep_start = millis(); every time the LED goes on.
Then at the start of loop():
if (sleep_start > 0 && millis() > sleep_start + 15 * 60 * 1000) {
// it is now over 15 minutes since the LED went on
// do whatever you want - turn LED off and set state = 0 ?
}
I not you have your actions and state tied together - i.e. you set the state and then turn on/off the LED at the same time. Much better to set the state separately and then set the LED based on the state.
void loop()
{
unsigned long now = millis();
val = digitalRead(pir);
bool state_changed = false;
if (val == HIGH)
{
if (state == 0)
state = 1;
else
state = 0;
state_changed = true;
}
// state was not changed by the sensor so look for timeout
if (!state_changed)
{
if (state == 1 && now > sleep_start + 15 * 60 * 1000)
{
state = 0;
state_changed = true;
}
}
if (state_changed)
{
switch(state) {
case 0: digitalWrite(led, LOW);
break;
case 1: digitalWrite(led, HIGH);
sleep_start = now;
break;
}
}
delay(4000);
}

Arduino simple timed loop without delay() - millis() doesn't work?

Have some arduino code for temp loggers that is VERY NEARLY working....!
I've built an OTA routine so I can update them remotely, however the delay() loop I had to ensure it only logged temperatures every 15 mins is now causing problems as it effectively freezes the arduino by design for 15mins, meaning OTA wouldn't work whilst it is in this state.
Some suggestions say just to flip to millis() instead, but I can't seem to get this working and it's logging ~20 records every second at the moment.
Ideally I just want delay_counter counting up to the value in DELAY_TIME, then running the rest of the code and resetting the counter.
Can anyone help me and point out what I'm doing daft in my code???
// v2 Temp sensor
// Connecting to Home NAS
#include <DHT.h>
#include <DHT_U.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <InfluxDbClient.h>
#define SSID "xxx" //your network name
#define PASS "xxx" //your network password
#define VersionID "v3"
#define SensorName "ServerUnit" //name of sensor used for InfluxDB and Home Assistant
// Temp Sensor 1 - GardenTropical
// Temp Sensor 2 - GardenRoom
// Temp Sensor 3 - Greenhouse
// Temp Sensor 4 - OutsideGreenhouse
// Temp Sensor 5 - ServerUnit
// Connection Parameters for Jupiter InfluxDB
#define INFLUXDB_URL "http://192.168.1.5:8086"
#define INFLUXDB_DB_NAME "home_assistant"
#define INFLUXDB_USER "xxx"
#define INFLUXDB_PASSWORD "xxx"
// Single InfluxDB instance
InfluxDBClient client(INFLUXDB_URL, INFLUXDB_DB_NAME);
// Define data point with measurement name 'DaveTest`
Point sensor("BrynyneuaddSensors");
#define PORT 80
#define DHTPIN 4 // what pin the DHT sensor is connected to
#define DHTTYPE DHT22 // Change to DHT22 if that's what you have
#define BAUD_RATE 115200 //Another common value is 9600
#define DELAY_TIME 900000 //time in ms between posting data to Home Server
unsigned long delay_counter = 0;
DHT dht(DHTPIN, DHTTYPE);
//this runs once
void setup()
{
Serial.begin(BAUD_RATE);
// Connect to WIFI
WiFi.begin(SSID, PASS);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print("*");
}
// Initialise OTA Routine
ArduinoOTA.onStart([]() {
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
//initalize DHT sensor
dht.begin();
// set InfluxDB database connection parameters
client.setConnectionParamsV1(INFLUXDB_URL, INFLUXDB_DB_NAME, INFLUXDB_USER, INFLUXDB_PASSWORD);
// Add constant tags - only once
sensor.addTag("device", SensorName);
// Check server connection
if (client.validateConnection()) {
Serial.print("Connected to InfluxDB: ");
Serial.println(client.getServerUrl());
} else {
Serial.print("InfluxDB connection failed: ");
Serial.println(client.getLastErrorMessage());
Serial.println(client.getServerUrl());
Serial.println("Exiting DB Connection");
}
}
//this runs over and over
void loop() {
ArduinoOTA.handle();
float h = dht.readHumidity();
Serial.print("Humidity: ");
Serial.println(h);
// Read temperature as Fahrenheit (isFahrenheit = true)
float c = dht.readTemperature();
Serial.print("Temperature: ");
Serial.println(c);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(c)) {
Serial.println("Reading DHT22 Failed, exiting");
return;
}
//update Influx DB channel with new values
updateTemp(c, h);
Serial.print("Writing to InfluxDB: ");
//INFLUXDB - clear temp data so it doesn't repeat
sensor.clearFields();
// Update Influx DB
sensor.addField("Temperature", c);
sensor.addField("Humidity", h);
Serial.println(sensor.toLineProtocol());
// Write data
client.writePoint(sensor);
//wait for delay time before attempting to post again
if(millis() >= DELAY_TIME){
delay_counter += 0;
}
//Increment Delay Counter
delay_counter++;
}
bool updateTemp(float tempC, float humid) {
WiFiClient client; // Create a WiFiClient to for TCP connection
Serial.println("Receiving HTTP response");
while (client.available()) {
char ch = static_cast<char>(client.read());
Serial.print(ch);
}
Serial.println();
Serial.println("Closing TCP connection");
client.stop();
return true;
}
Set a TimerObject. this seems to be what you want.
Download the Arduino TimerObject code from github and follow the installation instructions
#include "TimerObject.h"
Create the callback function
Create the TimerObject
Setup the TimerObject and periodically call update() in your loop():
// make sure to include the header
#include "TimerObject.h"
...
// setup your TimerObject
TimerObject* sensor_timer = new TimerObject(15 * 60 * 1000); // milliseconds
...
// define the stuff you want to do every 15 minutes and
// stick it in a function
// not sure what from your loop() needs to go in here
void doSensor()
{
float h = dht.readHumidity();
Serial.print("Humidity: ");
Serial.println(h);
// Read temperature as Fahrenheit (isFahrenheit = true)
float c = dht.readTemperature();
Serial.print("Temperature: ");
Serial.println(c);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(c)) {
Serial.println("Reading DHT22 Failed, exiting");
return;
}
//update Influx DB channel with new values
updateTemp(c, h);
Serial.print("Writing to InfluxDB: ");
//INFLUXDB - clear temp data so it doesn't repeat
sensor.clearFields();
// Update Influx DB
sensor.addField("Temperature", c);
sensor.addField("Humidity", h);
Serial.println(sensor.toLineProtocol());
// Write data
client.writePoint(sensor);
}
...
// add the timer setup to your setup()
// probably at the end is a good place
void setup()
{
...
// lots of stuff above here
sensor_timer->setOnTimer(&doSensor);
sensor_timer->Start();
}
// modify your loop() to check the timer on every pass
void loop()
{
ArduinoOTA.handle();
sensor_timer->Update();
}
If you don't want to wait 15 minutes for the first call of doSensor, you can explicitly call it at the end of your setup() function before you start the timer.
Here is an simple example how to use millis()
int last_report = -777;//dummy value
int REPORT_INTERVAL = 15 *60 ; // 15 minutes
void loop() {
ArduinoOTA.handle();
int interval = millis() / 1000 - last_report;
if (interval < REPORT_INTERVAL) {
return;
}
last_report = millis() / 1000;
//do some important stuff
}
Make it simole and use easy code:
const unsigned long timeIntervall = 15*60*1000; // 15 minutes
unsigned long timeStamp = 0;
void setup(){....}
void loop() {
ArduinoOTA.handle(); // is running all the time
// Code in this section only runs every timeIntervall - rollover safe
if(millis() - timeStamp > timeIntervall ){
float h = dht.readHumidity();
......
// Write data
client.writePoint(sensor);
timeStamp = millis(); // reset the timer
}
}

Arduino How can i store the last IR code to check if it needs repeating?

I'm just learning Arduino and i've got a DC Motor & IR Receiver connected. It's working fine if i press the button once but i can't figure out how to keep the motor spinning if i hold the button down as the REPEAT command is the same numbers.
I figured i would store the last code sent and check if the repeat command and last code match but it doesn't seem to be working and can't figure out why.
#include <IRremote.h>
int IRpin = 11; // pin for the IR sensor
IRrecv irrecv(IRpin);
decode_results results;
int lastCode;
void setup() {
// put your setup code here, to run once:
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(13, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn(); // Enable IR Receiver.
}
void loop() {
// put your main code here, to run repeatedly:
if
(irrecv.decode(&results)) {
Serial.println(results.value);
irrecv.resume();
Serial.println("Last Code is set to: ");
Serial.write(lastCode);
if(results.value== 16748655 || (results.value== 4294967295 && lastCode== 16748655)) // Your ON button value
{
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
analogWrite(9, 255);
delay(1000);
analogWrite(9, 0);
lastCode= 16748655;
}
else if(results.value == 16769055 || (results.value== 4294967295 && lastCode== 16769055)) // Your OFF button value
{
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
analogWrite(9, 255);
delay(1000);
analogWrite(9, 0);
lastCode= 16769055;
}
}
}
A more reliable approach to running the motor until the button is released is to use a "no-code" timeout. That is, if the "no code" state persists for a period longer than the auto-repeat period, then it has been released.
It is not clear in your code what the 1 second analogue pulse is for, but placing long delays in your loop() function makes your system far less responsive. Better to poll the system tick and "do stuff" when it is time to do so. Also magic numbers should be avoided if you want anyone to understand your code and avoid errors in maintenance.
The following uses system tick polling to implement the "no-code" timeout. I have omitted the motor on/off code because it is not clear what you are doing there with the 1 second delays.
#define NO_CODE 0xFFFFFFFFul
#define MOTOR_ON_CODE 0xFF906Ful
#define MOTOR_OFF_CODE 0xFFE01Ful
#define STOP_TIME_MS 250ul // stop after button release for 250ms
void loop( )
{
static unsigned long last_on_time = 0 ;
if( irrecv.decode( &results ) )
{
irrecv.resume() ;
unsigned long code = results.value ;
// If motor off code or no code timeout...
if( code == MOTOR_OFF_CODE ||
(code == NO_CODE && millis() - last_on_time > STOP_TIME_MS) )
{
// Motor off
...
}
else if( code == MOTOR_ON_CODE )
{
// Continuously update last on time while button is held
last_on_time = millis() ;
// Motor on
...
}
}
}
I have included response to the motor-off code, but that may not be necessary, since the motor will be switched off 250ms (or whatever time you choose) after the ON button is released in any case. You might instead have a forward/reverse button and release either to stop:
#define NO_CODE 0xFFFFFFFFul
#define MOTOR_FWD_CODE 0xFF906Ful
#define MOTOR_REV_CODE 0xFFE01Ful
#define STOP_TIME_MS 250ul // stop after button release for 250ms
void loop( )
{
static unsigned long last_on_time = 0 ;
if( irrecv.decode( &results ) )
{
irrecv.resume() ;
unsigned long code = results.value ;
switch( code )
{
case NO_CODE :
{
if( millis() - last_on_time > STOP_TIME_MS )
{
// Motor off
...
}
}
break ;
case MOTOR_FWD_CODE :
{
// Continuously update last on time while button is held
last_on_time = millis() ;
// Motor forward
...
}
break ;
case MOTOR_FWD_CODE :
{
// Continuously update last on time while button is held
last_on_time = millis() ;
// Motor reverse
...
}
break ;
}
}
}