Photon: Multiple Issues. Please clarify?

I’m trying to make an alarm system here! And I’m executing two loops:

What I think I’ve done is…

  1. One loop every second for Fire/Smoke Alarm (I’ve included an Activity LED at D7, Photon’s LED, as this runs every second)
  2. Another loop every ten seconds for Temperature/Humidity Alarm

Stability Issues:-
After flashing code, breathing cyan, activity LED blinks every second as it should… But, mostly within five minutes of running, these events happen…

  1. LED to warn Temp/Humidity raise, addressed as buzzPin on my code, goes high at D6 (I’ve included an alert function, which set D6 to HIGH. But I don’t see the function getting called… I’ve checked this with a serial monitor.)
  2. Activity LED stops at D7
  3. Photon blinks RED!
  4. Blinks GREEN!
  5. Blinks CYAN!
  6. Breathes CYAN!
  7. Activity LED blinks at D7
  8. After a few minutes… Starts again from Step 1…

To test if this happens on the alert function getting called, anyway. I’ve set a low threshold limit of 30 degrees while temperature is already 32 here… Did that, and yes! This happens only when the alert function is called…

I’ve tried these with and without SYSTEM_THREAD(ENABLED);

So there are two issues here…

  1. Why is the Alert Function getting called even when the threshold is not met?
  2. And even if its called why is the series of 8 events mentioned above happening?

As per my requirement at no point, should the code should stop running the timed events!
Let me know, what’s stopping these events from running forever?

Also there’s another issue, after a few hours the device starts to breathe green and doesn’t recover itself. I’ll have to press the reset button on the device…

Guide me on this guys!

SYSTEM_THREAD(ENABLED);
// This #include statement was automatically added by the Particle IDE.
#include "blynk/blynk.h"

// This #include statement was automatically added by the Particle IDE.
#include "PietteTech_DHT/PietteTech_DHT.h"

// For Mathematical Operations
#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 resultstr[64]; //String to store the sensor data

//DANGER - DO NOT SHARE!!!!
char auth[] = "????"; // Put your blynk token here
//DANGER - DO NOT SHARE!!!!
char VERSION[64] = "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 tcount = 0;
int t1;
int t2;
int hcount = 0;
int h1;
int h2;
int first = true;

// Device Location //
String Location = "ilak2k Home";

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

void Alert(String Sensor, int AlertType, int LEDAlert)
{
  if (Buzzer == HIGH)
  {
    Serial.println("Buzzer Activated!");
    digitalWrite(buzzPin, HIGH); // Activate Buzzer
  }
  if (Push == HIGH)
  {
    if (AlertType == 1)
    {
//      Blynk.notify(Location + ": Emergency " + Sensor + " Alert!");   // Notification with Location First
      Serial.println("Emergency Notification Sent!");
      Blynk.notify("Emergency: " + Sensor + " Alert! @" + Location);  // Notification with Situation First
    }
    else
    {
//      Blynk.notify(Location + ": " + Sensor + " Surge Detected!");
      Blynk.notify(Sensor + " Surge Detected! @" + Location);
      Serial.println("Surge Notification Sent!");
    }
  }
  if (Email == HIGH)
  {
    if (AlertType == 1)
    {
      Blynk.email("ilak2k@gmail.com", "Emergency: " + Sensor + " Alert! @" + Location, "This is a sensor-triggered alert, from Monitoring System! Investigate specified location");
      Serial.println("Emergency Email Sent!");
    }
    else
    {
      Blynk.email("ilak2k@gmail.com", Sensor + " Surge Detected! @" + Location, "This is a sensor-triggered alert, from Monitoring System! Investigate specified location");
      Serial.println("Surge Email Sent!");
    }
  }
  Blynk.virtualWrite(LEDAlert, 1023);  // Write HIGH to Virtual Pin 3
}

void TemperatureHumidity() {
//  Temperature, Relative Humidity, Dew Point

float temp;
float relhumid;
float dewpt;
float humidex;

    if (!DHTStarted) {	// start the sample
        DHT.acquire();
	    DHTStarted = true;
	}
	
	if (!DHT.acquiring()) {		// has sample completed?

        temp = (float)DHT.getCelsius();
        String temps = String(temp, 1);
        // Serial.print(String("Temmperature, in Celcius: "));
        Serial.println(temps);
        Blynk.virtualWrite(V1, temps);
        Particle.publish("Temperature:", temps, 60, PRIVATE);
        
        relhumid = (float)DHT.getHumidity();
        String relhumids = String(relhumid, 1);
        // Serial.print(String("Relative Humidity, in %: "));
        Serial.println(relhumids);
        Blynk.virtualWrite(V2, relhumids);
        Particle.publish("Relative Humidity:", relhumids, 60, PRIVATE);

        dewpt = (float)DHT.getDewPoint();
        String dewpts = String(dewpt, 1);
        // Serial.print(String("Dew Point, in Celcius: "));
        Serial.println(dewpts);
        Blynk.virtualWrite(V3, dewpts);
        Particle.publish("Dew Point:", dewpts, 60, PRIVATE);

        humidex = calc_humidex(temp, dewpt);
        String humidexs = String(humidex, 1);
        // Serial.print(String("Humidex, in Celcius: "));
        Serial.println(humidexs);
        Blynk.virtualWrite(V4, humidexs);
        Particle.publish("Humidex:", humidexs, 60, PRIVATE);

        // double heatindex = calc_heatIndexFast(temp, relhumid);
        // String heatindexs = String(heatindex, 1);
        // Serial.print(String("Dew Point, in Celcius: "));
        // Serial.println(heatindexs);
        // Blynk.virtualWrite(V5, heatindexs);
        // Particle.publish("Heat Index:", heatindexs, 60, PRIVATE);

        DHTStarted = false;
    }
    
    // Temperature/Humidity Surge Alert System
        tcount = tcount + 1;
        if (tcount == 1)
        {
        t1 = temp;
        //    Serial.print("Temp Value: ");
        //    Serial.println(t1);
        }
        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 = hcount + 1;
        if (hcount == 1)
        {
        h1 = relhumid;
        //    Serial.print("Humidity Value 1: ");
        //    Serial.println(h1);
        }
        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)
        {
            Alert("Temperature", 1, 3);
        }
        
        // Relative Humidity Alarm System
        if (relhumid >= HumidThreshold)
        {
            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 = analogRead(LDRPin);
    lightlevel = map(lightlevel, 0, 4095, 0, 100);
    int smokelevel = analogRead(SmokePin);
    Blynk.virtualWrite(V11, lightlevel);
    Blynk.virtualWrite(V12, smokelevel);
    
    //Blynk Activity LED Status
    if (actState == LOW)
    {
        digitalWrite(ActLED, HIGH);
        Blynk.virtualWrite(V0, 1023); // Write HIGH to Virtual Pin 0
        actState = HIGH;
    }
    else
    {
        digitalWrite(ActLED, LOW);
        Blynk.virtualWrite(V0, 0); // Write LOW to Virtual Pin 0
        actState = LOW;
    }
}

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();
}

It might be superstition, but try to avoid the use of String and rather use char[] strings in conjunction with snprintf()
Also make sure none of your divisions will ever run into a div/0 condition.
Check for any buffer operation violating the buffer size.
Try to incorporate your four publishes into one single message (e.g. again via snprintf()).

This can be simplified

    //Blynk Activity LED Status
    if (actState == LOW)
    {
        digitalWrite(ActLED, HIGH);
        Blynk.virtualWrite(V0, 1023); // Write HIGH to Virtual Pin 0
        actState = HIGH;
    }
    else
    {
        digitalWrite(ActLED, LOW);
        Blynk.virtualWrite(V0, 0); // Write LOW to Virtual Pin 0
        actState = LOW;
    }

to this

    //Blynk Activity LED Status
    digitalWrite(ActLED, !actState);
    Blynk.virtualWrite(V0, actState ? 0 : 1023); // Write HIGH to Virtual Pin 0

Wow! That simple… I’m very new to programming… Thanks for the optimization! @ScruffR

Any idea why the alert would be triggered? I forgot to post the updated code… I missed the Surge Alert System Part… I’ve edited the code section posted above with it… Can you examine that part of the code and let me know why would it trigger a false alarm?

Based on the current values I’ve set, it should trigger an alert, if temperature increases by 4 degrees Celsius in 3 minutes… But it gets triggered without the temperature raising… And when this alert is triggered, I get the photon’s blinking red…

May be if the temperature doesn’t change in three minutes and the difference I calculate returns zero, then there’s an issue with that?

@ScruffR Just so you don’t miss… I’ve updated the code with the Surge Alert portion…

I have not yet checked that new code, but it might be what I talked about here

Oh well… @ScruffR No! I just do subtraction. Nothing gets divided by 0, in my part of this code… But the PietteTech DHT’s library, I’ve slightly modified to use it for my case. What I modified in that part to read values from DHT might cause the issue you’re talking about. Do you see anything wrong with that?

What do you mean with that

How did you modify that?
Since your include looks like this #include "Piettetech_DHT/Piettetech_DHT.h", I'd rather think that you are still using the original - or have you forked the github repo and "contributed" your own version as private library?

No! Sorry @ScruffR, my bad! No change in his library… I just changed the part where I read values from DHT22. He used something like a counter to, when to sample the reading from DHT. I used a timer instead and set to read values every ten seconds…

Also I’ve already read 4 values from DHT22. Temperature, Humidity, Dew Point, Humidex. I also tried to calculate Heat Index and for some reason it wouldn’t give any readings at all from that loop…

Also if I do a serial print to debug the issue, i need to reduce the reads to three values… temperature, humidity and dew point. Otherwise it wouldn’t give any readings at all. I think we’re not allowed to load the timer with too many events… Is there a limit to how many values I can read or execute per loop?

Or is the 1 second loop breaking the 10 second loop’s execution? What should I do to stop this from happening?

Try this slightly altered code

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();
}

That's the reason why I wrote this before

And have done that in the code above, since there is a rate limit on the publishes per second.

@ScruffR Thank you very much. Appreciate your help in this… Will update this code and let you know, how it worked…

1 Like

@ScruffR You’re my hero! Awesome code optimizations! And I’ve found the problem line in my code!

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

Here goes the sequence:

  1. Alert() is called…
  2. LEDAlert is read as integer (Beeeeep!)
    This works for Arduino, not with Particle Photon!

Based on current code its executed as:

Blynk.virtualWrite(3, 1023); //[Particle crashes right here! And restart happening right here]

While particle expects it to be:

Blynk.virtualWrite(V3, 1023);

Particle Team: Please take note here… We’re already executing a virtualWrite, then why mention “V” again? And mainly, its limiting the use case of this function…

@ilak2k, the issue has nothing to do with Particle. It has to do with the Blynk library and how it works in the Particle environment.

1 Like

@peekay123 I get it! I’ll have to forward this issue to Blynk then… Thanks!

1 Like

But using the more explicit naming over the anonymous numbering would be better coding style in any case.
If you want to iterate over a sequence of virtual pins you can always use an array.
If you just want explicit naming, consider an enum - which would be better coding practice again as it provides some degree of type safety for your functions and prevents you from using disallowed values in a call.

BTW: V1, D1, A1 are macros that will be evaluated to some arbitrary value or even an expression/function call/…, so its wrong (“dangerous”) to assume the number part of the variable name is its actual value.

1 Like

@ScruffR You’re saying addressing the pins as V1, D1 & A1 is better than just plain numbers? So can I just call the Alert function as, “Alert (“Temperature”, 1, V1);”

I’ll do that… But, whatever I try, I’m stuck at this line:

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

I tried calling Alert () with “21”, " 21V". And even tried this:

Blynk.virtualWrite(V21, 1023);  // Write HIGH to Virtual Pin

The moment this line is executed, Particle Photon stops breathing CYAN and starts to blink RED.

This is a Blynk Virtual LED that I’m trying to switch on here and I’ve assigned it as V21. I’m confused, how the Blynk Virtual Activity LED at V0 works fine and this one doesn’t… They’re both same code…

If you only want to write HIGH/LOW to a virtual pin I’d go with exactly these

Blynk.virtualWrite(V1, LOW);  // instead of 0
Blynk.virtualWrite(V1, HIGH);  // instead of 1023

@ScruffR, the documentation from Blynk on virtual pins is really bad. I have code that uses 1 for the virtual pin value and it works fine. However, functions like BLYNK_WRITE() and BLYNK_READ() require the Vn syntax.

However, I’m unclear as to what is connected to the virtual pin. It if is a LED widget, then the entire approach is wrong. Take a look at the LED documentation!

I agree on the doc front :stuck_out_tongue_closed_eyes:
About the HIGH/LOW I jus went with the comment

If it was a LED widget the values would range from 0 to 255.

1 Like

@ScruffR I was expecting to set the Virtual LED’s brightness based on severity of the alert! That’s why the numbered approach… @peekay123 This code is basically for the digital pins… I just tried this for the LED Widget with my arduino and it just worked! I didn’t use the Widget LED function there. Now, I’m trying to transfer the same code here to photon… Note I’ll try to replace the virtual led part of the code with Widget LED as you suggested… Thanks!