Photon: Multiple Issues. Please clarify?

@ScruffR @peekay123 Still I’m wondering how the virtual led at V0 works and V21 doesn’t???

@ilak2k, can you describe you Blynk widget configuration please?

@peekay123 Refer to the attached pictures for both the LED Widgets

Virtual LED 0:

Virtual LED 21:

Blynk Screen:

So for my case this code works as expected


int dmy(String cmd)
{
    static int v0 = 0;
    static int v21 = 0;
    
    
    if(cmd.length())
      Blynk.virtualWrite(V21, ((v21 = !v21) ? 0 : 1023));
    else
      Blynk.virtualWrite(V0, ((v0 = !v0) ? 0 : 1023));

    return cmd.length();    
}

In this code, what value you pass through cmd?

It’s just a dummy test which only distinguishes if there is anything sent (length > 0 -> V21) or not (V0)

@ScruffR I’ve set the timer1 to execute every 10 seconds for Temp/Humidity readings and looking at the Particle Dashboard Log, readings are received only every 20 seconds… It takes twice the time of the actual set timer… Do we need to make the adjustment of dividing by 2?

Some code would be helpful…

@Moors7 Oh! It’s the same code ScruffR helped me with… At this link: Photon: Multiple Issues. Please clarify?

@ScruffR Timers not keeping up after a few minutes of execution… When timers don’t keep up and start to act slow, Photon stops publishing data to particle dashboard. Refer to the attached pictures:


Started at: April 29th at 4:31:03 am
Stopped at: April 29th at 4:39:33 am
Suggest me on how to make this run consistent, as long as possible without issues…

SYSTEM_THREAD(ENABLED);
#include "PietteTech_DHT/PietteTech_DHT.h"
#include "blynk/blynk.h"
#include "math.h"

#define ActLED D7
#define buzzPin D6
#define LDRPin A2
#define SmokePin A1
#define DHTTYPE DHT22   // Choose if you're using DHT11 / DHT22
#define DHTPIN 2 // DHT22's Data Pin to Arduino's Digital Pin 7

int calibrationTime = 10; // Sensors Calibration Time, in seconds

// DHT Declaration
void dht_wrapper(); // must be declared before the lib initialization
// Initializing DHT Library
PietteTech_DHT DHT(DHTPIN, DHTTYPE, dht_wrapper);

// DHT Globals
bool DHTStarted;   // flag to indicate we started acquisition

//this is coming from http://www.instructables.com/id/Datalogging-with-Spark-Core-Google-Drive/?ALLSTEPS
char szMsg[256]; // buffer for all sorts of messages

//DANGER - DO NOT SHARE!!!!
char auth[] = "????"; // Put your blynk token here
//DANGER - DO NOT SHARE!!!!
char VERSION[8] = "0.04";

// Initial Alert States //
int actState = LOW;       // Arduino & Blynk's Initial Activity State
int Buzzer = HIGH;
int Push = HIGH;
int Email = HIGH;

// Initial Alert Threshold Values //
int SmokeThreshold = 220;
int FireThreshold = 220;
int TempThreshold = 30;
int HumidThreshold = 90;

// Variables for Fire/Smoke Surge Detection
int ttimer = 3;   // Value in Minutes
int htimer = 3;   // Value in Minutes
int tdiff = 4;    // Value in Degrees
int hdiff = 20;   // Value in Percentage%
int first = true;

// Device Location //
char Location[] = "ilak2k Home";

Timer timer1(10000, TemperatureHumidity);
Timer timer2(1000, SmokeFireMotion);

void Alert(char* Sensor, int AlertType, int LEDAlert)
{
  if (Buzzer)
  {
    Serial.println("Buzzer Activated!");
    digitalWrite(buzzPin, HIGH); // Activate Buzzer
  }

  if (AlertType == 1)
  {
    snprintf(szMsg, sizeof(szMsg), "Emergency: %s Alert! @%s", Sensor, Location);
  }
  else
  {
    snprintf(szMsg, sizeof(szMsg), "%s Surge Detected! @%s", Sensor, Location);
  }
  
  if (Push)
  {
    Serial.print("Sent Notification: ");
    Serial.println(szMsg);
    Blynk.notify(szMsg);
  }

  if (Email)
  {
    Serial.print("Sent Email: ");
    Serial.println(szMsg);
    Blynk.email("ilak2k@gmail.com", szMsg, "This is a sensor-triggered alert, from Monitoring System! Investigate specified location");
  }

  Blynk.virtualWrite(LEDAlert, 1023);  // Write HIGH to Virtual Pin 3
}

void TemperatureHumidity() 
{
    // to reduce global variables make them local and static
    static int tcount = 0;
    static int t1;
    static int t2;
    static int hcount = 0;
    static int h1;
    static int h2;

    //  Temperature, Relative Humidity, Dew Point
    if (!DHTStarted) {	// start the sample
        DHT.acquire();
	    DHTStarted = true;
	}
	
	if (!DHT.acquiring()) {		// has sample completed?
        double temp     = DHT.getCelsius();
        double relhumid = DHT.getHumidity();
        double dewpt    = DHT.getDewPoint();
        double humidex  = calc_humidex(temp, dewpt);

        // if V1..V4 were numeric values these four snprintf() statements could be saves
        snprintf(szMsg, sizeof(szMsg), "%.1lf", temp);
        Blynk.virtualWrite(V1, szMsg);
        snprintf(szMsg, sizeof(szMsg), "%.1lf", relhumid);
        Blynk.virtualWrite(V2, szMsg);
        snprintf(szMsg, sizeof(szMsg), "%.1lf", dewpt);
        Blynk.virtualWrite(V3, szMsg);
        snprintf(szMsg, sizeof(szMsg), "%.1lf", humidex);
        Blynk.virtualWrite(V3, szMsg);

        snprintf(szMsg, sizeof(szMsg), 
                 "Temperature: %.1lf°C Relative Humidity %.1lf%% Dew Point: %.1lf°C Humidex: %.1lf°C", 
                 temp, relhumid, dewpt, humidex);
        Serial.print("Ambient Data: ");
        Serial.println(szMsg);
        Particle.publish("AmbientData", szMsg, PRIVATE);

        DHTStarted = false;
    
        // Temperature/Humidity Surge Alert System
        tcount++;
        if (tcount == 1)
        {
            t1 = temp;
            //    Serial.print("Temp Value: ");
            //    Serial.println(t1);
        }
        else if (tcount == (ttimer * 6)) // Multiplied by 6 instead of 60, cause the Temperature Function runs only every 10 seconds
        {
            t2 = temp;
            //    Serial.print("Temp Difference: ");
            //    Serial.println(t2-t1);
            if ((t2 - t1) > tdiff)
            {
                //   Alert("Temperature", 2, 3);
            }
            tcount = 0;
        }
            
        hcount++;
        if (hcount == 1)
        {
            h1 = relhumid;
            //    Serial.print("Humidity Value 1: ");
            //    Serial.println(h1);
        }
        else if (hcount == (htimer * 6)) // Multiplied by 6 instead of 60, cause the Temperature Function runs only every 10 seconds
        {
            h2 = relhumid;
            //    Serial.print("Humidity Value 2: ");
            //    Serial.println(h2);
            //    Serial.print("Humidity Difference: ");
            //    Serial.println(h2-h1);
            if ((h2 - h1) > hdiff)
            {
                //   Alert("Humidity", 2, 4);
            }
            hcount = 0;
        }
    
        // Temperature Alarm System
        if (temp >= TempThreshold)
        {
            Serial.printlnf("%.1lf >= %d", temp, TempThreshold);  // check in case of false positive
            Alert("Temperature", 1, 3);
        }
            
        // Relative Humidity Alarm System
        if (relhumid >= HumidThreshold)
        {
            Serial.printlnf("%.1lf >= %d", relhumid, HumidThreshold);  // check in case of false positive
            Alert("Humidity", 1, 4);
        }
    }
}

double calc_humidex(double tempC, double DewPoint)
{
    double e = 5417.7530*((1/273.16)-(1/(273.16 + DewPoint)));
    double h = tempC + 0.5555 * ( 6.11 *  exp (e) - 10);
    return h;
}

void SmokeFireMotion()  
{
    int lightlevel = map(analogRead(LDRPin), 0, 4095, 0, 100);
    int smokelevel = analogRead(SmokePin);
    Blynk.virtualWrite(V11, lightlevel);
    Blynk.virtualWrite(V12, smokelevel);
    
    //Blynk Activity LED Status
    actState = !actState; // toggle the state
    digitalWrite(ActLED, actState);
    Blynk.virtualWrite(V0, actState ? 1023 : 0);
}

void dht_wrapper() {
    DHT.isrCallback();
}

void setup() {
    Serial.begin(9600);
    Serial.println("Hi!");
    Blynk.begin(auth);
    Particle.publish("DHT22 - firmware version", VERSION, 60, PRIVATE);
    pinMode(ActLED, OUTPUT);
    pinMode(buzzPin, OUTPUT);
    pinMode(LDRPin, INPUT);
    pinMode(SmokePin, INPUT);
    
    // Sensors Calibration & Warmup Delay, at startup
    Serial.print("Calibrating Sensors");
    for(int i = 0; i < calibrationTime; i++)
    {
        Serial.print(".");
        delay(1000);
    }
    Serial.println(" Complete!");
    Serial.println("Sensors, ACTIVE!!!");
    delay(100);
    
    timer1.start();
    timer2.start();
}

void loop() {
    Blynk.run();
}

The reason for that is that you start DHT.acquire() on the first go, but don't enter into the publishing branch immediately since DHT.acquiring() is true at that time, so you will have to wait for the next turn round to actually retrieve the data.

I also tested the reliability of publishes, but couldn't find anything wrong, apart from the occasional WiFi dropout abd reconnection gaps.
When you see this next time, try to refresh the browser page - I had that a couple of times, that my Chrome just stopped pulling in the events but still shifting the chart. After a refresh it worked again (so not the Photon's fault)

@ScruffR I did refresh the dashboard several times after it stopped responding. Screenshots of the publishes included here are after these refreshes. I waited for some 20 minutes… And I’m sure the loop is stuck… The physical and virtual activity LED’s at D7 & V0 also stopped… Both the LED’s begin to miss their rhythm after a few minutes of execution…

First it blinks every second!
Then the interval increases and becomes inconsistent…
Then at some point it totally stops!

Have you got your Blynk App set to keep the phone on?
I haven’t so Blynk disconnects after a while but the publishing and D7 LED carries on working for a few hours now.
But I only got a DHT22 connected and nothing else.

@ScruffR, @ilak2k, I hate to bring this up but making all those Blynk calls in the timer callbacks may be an issue. All Software Timers run on a single separate thread shared by all timers. The timers run in a daisy chain fashion (one after the other). The code that runs in a timer callback needs to be short like an ISR since, while running, will prevent other timers from running until the callback returns.

It is best to use timers to trigger events and/or gather data but not do more system intensive work like calling blynk functions which ultimately calls TCPClient. Instead, do that work in loop() and coordinate data and events using flags. This will allow the timer callbacks to be short. :wink:

1 Like

Never thought about the blynk calls when altering the code - mainly focused of getting rid of String and “improving” the C coding style :wink: :blush:

1 Like

@ScruffR Improving the C coding style and you did an impressive job at that…
“Keep Screen Always On” is ON!

This actually fixed the issue for now…
Removed SYSTEM_THREAD(ENABLED); from the sketch…
aND ITS BEEN Working fine so far…
Activity LED’s at D7 and V0 are stable. And blinks every second without delays for more than 15 minutes now… So, I believe its fixed!

@peekay123 As suggested, I’ll try take the Blynk calls out of the timer, of course with some help from @ScruffR and see if it improves stability!

@ScruffR @peekay123 Ok, I was too quick to say its stable… Its not! I’m taking the Blynk calls into the loop

2 Likes

I’m wondering if we should add an application thread queue so that rather than using flags, you can schedule things to happen on the next call to loop(). This will make triggering actions from timers much simpler.

Something like this:

void stuff_that_cannot_be_done_in_a_timer()
{
    TCP client;
    client.connect(...);
    delay(5000);   // really not a good idea in a timer
    // but this is ok since it will run before calling loop()
}

// the timer handler
void on_timer()
{
    Application.do(stuff_that_cannot_be_done_in_a_timer);
}

The Application.do call would run stuff_that_cannot_be_done_in_a_timer() on the next call to loop() or if the app calls Particle.process()

How does that sound? Does it make things simpler than using flags, or is having explicit control over flags and when things are run in loop preferred?

5 Likes

I couldn’t figure out to move just the Blynk calls alone to void loop()

So I took the entire Sensor Reading & Reporting in to void loop(), just like how PietteTech DHT did with millis()… Am I in the right direction? I used the same flow as his sketch with
10000 milliseconds INTERVAL for Temp/Humidity
1000 milliseconds INTERVAL for Smoke
And… Its been running without hiccups, so far! That is for more than 18 hours… Thanks @ScruffR & @peekay123

@mdma We could use timers for its intended use and still manage to do stuff that cannot be done in a timer… If this is possible, while the device is still stable… Awesome!

New issue! Blinking Cyan and not recovering without pressing reset. After reset works fine for a few more hours and then blinking Cyan again…

  1. Everything works fine for a few hrs (1-4 hrs)
  2. Starts to blink Cyan (Not flickering fast like just before Wifi connecting, but still blinking fast like 3-4 times a second)
  3. Activity LED’s stops blinking at D7 and V0 (Means the device’s function is already stopped)
  4. Doesn’t seem to recover by itself, even if left by itself for hours together
  5. Had to press the reset button
  6. Once pressed, immediately connects and starts to breathe Cyan
  7. After few more hours… Starts to blink Cyan again!

Issues to be resolved:-
@ScruffR @peekay123 I’m trying to make this as an alerting device and it cannot stop its primary function at any point… Suggest code level changes to make the device more stable…

  1. Photon shouldn’t disconnect from the internet at any point, at least when my router is close…
  2. Even if there’s an issue with the router or, if internet connection is lost, the device should continue to do its basic function, in my case… continue to detect fire/smoke and check for temp/humidity and alert locally…

I’m on a Home Network, photon in the same room, just 5 feet from my router…