Code Within a Particle Subscription Not Running After Device OS Update 1.2.1 to 1.4.0

I have the below code running on a Particle Photon. It had been running fine for some time and a few weeks back I decided to update the Device OS from 1.2.1 to 1.4.0. After doing this, one of the Particle Subscriptions in my code wouldn’t run anymore (or at least the two particle variables that get updated within it don’t update). The problem subscription is “Fireplace_Temp” and the two variables that don’t get updated are “Fireplace_Temp” & “FP_Temp_TimeStamp”. I’ve played around with removing pieces of the code to see if something is blocking within that part of the code (including getting rid of the other Particle Subscription) without any luck.

When I originally had this issue several weeks ago, in the process of multiple flashes setting targets of older Device OS’s it started working again, but today I noticed it had stopped working and after playing with it quite a bit (both through troubleshooting the code and trying other target Device OS’s) I haven’t gotten it to work again. I’ve verified that the originating/publishing device is indeed publishing the event, so that’s not the issue.

Any ideas? I’m guessing that maybe I’m doing something improper and I was just getting lucky with it working before? Please, teach me the errors of my ways. :slight_smile:

// This #include statement was automatically added by the Particle IDE.
#include <OneWire.h>

#include "DS18.h"
DS18 sensor(D0);

#define Extra_Low D1
#define Low D2
#define Medium D3
#define High D5
#define Power D4

bool Heating_Season = true;
String Mode = "Heating";
String Status = "Off";
bool Status_Change_Flag = false;
bool On = false;
int Setting = 0;
int Old_Setting = 0;
int Extra_Low_Current;
int Low_Current;
int Medium_Current;
int High_Current;
int Power_Current;
int Extra_Low_Previous;
int Low_Previous;
int Medium_Previous;
int High_Previous;
int Power_Previous;
int Fireplace_Temp;
bool Fireplace_Temp_Flag = false;
double Fireplace_Battery;
String FP_Temp_TimeStamp;
String FP_Battery_TimeStamp;


String Temp_String;
String Battery_String;


int Fan_TempF;

//Timer to read digital temp sensor every 3 seconds
Timer timer(3000, Read_Temp);
bool Read_Temp_Flag = false;

SYSTEM_THREAD(ENABLED);

void setup() {
    
    timer.start(); 

    pinMode(Extra_Low, INPUT);
    pinMode(Low, INPUT);
    pinMode(Medium, INPUT);
    pinMode(High, INPUT);
    pinMode(Power, INPUT);
    
    Particle.subscribe("Fan_Command", Fan_Command, MY_DEVICES);
    Particle.subscribe("Fireplace_Temp", Fireplace_Temp_Action, MY_DEVICES);
    Particle.subscribe("Fireplace_Battery", Fireplace_Battery_Action, MY_DEVICES);
    
    Particle.variable("Status", Status);
    Particle.variable("Mode", Mode);
    Particle.variable("Fireplace_Temp", Fireplace_Temp);
    Particle.variable("Fireplace_Battery", Fireplace_Battery);
    Particle.variable("FP_Temp_TimeStamp", FP_Temp_TimeStamp);
    Particle.variable("FP_Battery_TimeStamp", FP_Battery_TimeStamp);
    Particle.variable("Fan_Temp", Fan_TempF);
    
    Time.zone(-5);

}

void loop() {
    
    //Read the fan temp sensor
    if (Read_Temp_Flag==true and sensor.read()) {
        Fan_TempF = sensor.fahrenheit();
        Read_Temp_Flag=false;
    }
    
    //Read all of the fan button pins to see if a button was pressed
    Extra_Low_Current = digitalRead(Extra_Low);
    Low_Current = digitalRead(Low);
    Medium_Current = digitalRead(Medium);
    High_Current = digitalRead(High);
    Power_Current = digitalRead(Power);
    
    //Series of if-statements to update fan settings and status based on button presses and current status
    if (Extra_Low_Current == 0 and Extra_Low_Current != Extra_Low_Previous and On == true) {
        Setting = 1;
        Status = "Low-Low";
    }
    else if (Low_Current == 0 and Low_Current != Low_Previous and On == true) {
        Setting = 2;
        Status = "Low";
    }
    else if (Medium_Current == 0 and Medium_Current != Medium_Previous and On == true) {
        Setting = 3;
        Status = "Medium";
    }
    else if (High_Current == 0 and High_Current != High_Previous and On == true) {
        Setting = 4;
        Status = "High";
    }
    else if (Power_Current == 0 and Power_Current != Power_Previous and On == true) {
        Setting = 0;
        Status = "Off";
        On = false;
    }
    else if (Power_Current == 0 and Power_Current != Power_Previous and On == false) {
        Setting = 5;
        Status = "High";
        On = true;
    }
    
    //Update 'previous' button values to current values
    Extra_Low_Previous = Extra_Low_Current;
    Low_Previous = Low_Current;
    Medium_Previous = Medium_Current;
    High_Previous = High_Current;
    Power_Previous = Power_Current;
    
    //Heating Mode fan speed evaluation
    if (Fireplace_Temp_Flag == true and Heating_Season == true) {
        Fireplace_Temp_Flag = false;
        if (Fireplace_Temp < 100) {
            Setting = 0;
        }
        else if (Fireplace_Temp >= 100 and Fireplace_Temp < 120) {
            Setting = 1;
        }
        else if (Fireplace_Temp >= 120 and Fireplace_Temp < 140) {
            Setting = 2;
        }
        else if (Fireplace_Temp >= 140) {
            Setting = 3;
        }
    }
    
    //Cooling Mode fan speed evaluation
    if (Fireplace_Temp_Flag == true and Heating_Season == false) {
        Fireplace_Temp_Flag = false;
        if ((Fireplace_Temp-Fan_TempF) < 5) {
            Setting = 0;
        }
        else if ((Fireplace_Temp-Fan_TempF) >= 5 and (Fireplace_Temp-Fan_TempF) < 10) {
            Setting = 1;
        }
        else if ((Fireplace_Temp-Fan_TempF) >= 10 and (Fireplace_Temp-Fan_TempF) < 15) {
            Setting = 2;
        }
        else if ((Fireplace_Temp-Fan_TempF) >= 15 and (Fireplace_Temp-Fan_TempF) < 20) {
            Setting = 3;
        }
        else if ((Fireplace_Temp-Fan_TempF) >= 20) {
            Setting = 4;
        }
    }
    
    //If-statement to check whether the setting changed, requiring a fan speed change
    if (Setting != Old_Setting) {
        Status_Change_Flag = true;
    }
    
    //If-statements to evaluate if a fan-speed change is needed
    if (Status_Change_Flag == true) {
        if (Setting == 0 and On == true) {
            pinMode(Power, OUTPUT);
            digitalWrite(Power, LOW);
            delay(75);
            pinMode(Power, INPUT);
            On = false;
            Status = "Off";
        }
        else if (Setting == 5 and On == false) {
            pinMode(Power, OUTPUT);
            digitalWrite(Power, LOW);
            delay(75);
            pinMode(Power, INPUT);
            On = true;
            Status = "High";
        }
        else if (Setting == 1) {
            if (On == false) {
                pinMode(Power, OUTPUT);
                digitalWrite(Power, LOW);
                delay(75);
                pinMode(Power, INPUT);
                On = true;
                Status = "High";
                delay(75);
                pinMode(Extra_Low, OUTPUT);
                digitalWrite(Extra_Low, LOW);
                delay(75);
                pinMode(Extra_Low, INPUT);
                Status = "Low-Low";
            }
            else {
                pinMode(Extra_Low, OUTPUT);
                digitalWrite(Extra_Low, LOW);
                delay(75);
                pinMode(Extra_Low, INPUT);
                Status = "Low-Low";
            }
        }
        else if (Setting == 2) {
            if (On == false) {
                pinMode(Power, OUTPUT);
                digitalWrite(Power, LOW);
                delay(75);
                pinMode(Power, INPUT);
                On = true;
                Status = "High";
                delay(75);
                pinMode(Low, OUTPUT);
                digitalWrite(Low, LOW);
                delay(75);
                pinMode(Low, INPUT);
                Status = "Low";
            }
            else {
                pinMode(Low, OUTPUT);
                digitalWrite(Low, LOW);
                delay(75);
                pinMode(Low, INPUT);
                Status = "Low";
            }
        }
        else if (Setting == 3) {
            if (On == false) {
                pinMode(Power, OUTPUT);
                digitalWrite(Power, LOW);
                delay(75);
                pinMode(Power, INPUT);
                On = true;
                Status = "High";
                delay(75);
                pinMode(Medium, OUTPUT);
                digitalWrite(Medium, LOW);
                delay(75);
                pinMode(Medium, INPUT);
                Status = "Medium";
            }
            else {
                pinMode(Medium, OUTPUT);
                digitalWrite(Medium, LOW);
                delay(75);
                pinMode(Medium, INPUT);
                Status = "Medium";
            }
        }
        else if (Setting == 4) {
            if (On == false) {
                pinMode(Power, OUTPUT);
                digitalWrite(Power, LOW);
                delay(75);
                pinMode(Power, INPUT);
                On = true;
                Status = "High";
            }
            else {
                pinMode(High, OUTPUT);
                digitalWrite(High, LOW);
                delay(75);
                pinMode(High, INPUT);
                Status = "High";
            }
        }
        Status_Change_Flag = false;
    }
    
    Old_Setting = Setting;
}

//Update variables based on commands published
void Fan_Command(const char *event, const char *data)
{
    Status_Change_Flag = true;
    if (strcmp(data,"Off")==0) {
        Setting = 0;
    }
    else if (strcmp(data,"On")==0) {
        Setting = 5;
    }
    else if (strcmp(data,"1")==0) {
        Setting = 1;
    }
    else if (strcmp(data,"2")==0) {
        Setting = 2;
    }
    else if (strcmp(data,"3")==0) {
        Setting = 3;
    }
    else if (strcmp(data,"4")==0) {
        Setting = 4;
    }
    else if (strcmp(data,"Heating")==0) {
        Heating_Season = true;
        Mode = "Heating";
    }
    else if (strcmp(data,"Cooling")==0) {
        Heating_Season = false;
        Mode = "Cooling";
    }
}

//Update variables and flags when fireplace temp sensor data published

void Fireplace_Temp_Action(const char *event, const char *data)
{
    Temp_String = data;
    Fireplace_Temp = Temp_String.toInt();
    FP_Temp_TimeStamp = Time.timeStr();
    Fireplace_Temp_Flag = true;
}

//Update variables when fireplace battery level data published
void Fireplace_Battery_Action(const char *event, const char *data)
{
    Battery_String = data;
    Fireplace_Battery = Battery_String.toInt();
    FP_Battery_TimeStamp = Time.timeStr();
}

//Timer to set a flag true for reading the digital fan temp sensor
void Read_Temp()
{
    Read_Temp_Flag = true;
}

Can you also post the code that publishes the event and a screenshot of the event in console?
Do your other subscriptions work?
Have you tried emitting the event via console.particle.io/events?

I’d also recommend to use char arrays instead of String for long term stability.
Instead of lots of if(Setting==x) ... else if(Setting==) ... a switch(Settinhg) case x: … case y: …may also make for better style. Also using numeric values (or evenenum) forModeandStatuswould help streamlining your code and avoid the need for a translation function like inFan_Command`.

e.g.

enum Settings            { OFF , S1, S2, S3, S4, ON , HEATING , COOLING , INVALID };
char settingsText[][8] = {"Off","1","2","3","4","On","Heating","Cooling","Invalid"};
const int settings = sizeof(settingsText) / sizeof(settingsText[0]) - 1; // -1 to ignore last entry
Settings setting = OFF;
...

  switch (setting) {
    case OFF:
      ...
      break;
    case ON:
      ...
      break;
    ...
    default:
      Log.warn("Unknown setting %d", setting);
      setting = INVALID;
      [[fallthrough]]
    case INVALID:
      // do something about an invalid state
  }
...
void Fan_Command(const char *event, const char *data) {
  setting = atoi(data);       // try to translate data to numeric 
  if (!data) {                // if that failed (or happened to be 0) search for the correct settingsText
    for (;setting < settings && !strcmp(data, settingsText[setting]; setting++);     
  }
  // are variables Mode & Heating_Season really required?
  // Cannot setting used for the same purpose?
  Status_Change_Flag = true;  // force update
}

Below is the code that publishes the event(s) and a screenshot of the publishes in the console. As you’ll see, it’s just my Argon listening for mesh publishes and forwarding them on as particle publishes.

All of my other subscriptions are working fine. For whatever reason, the button for publishing events via the console hasn’t worked for me for a week or so, however I was able to publish the events via the Android app and they still didn’t work (even though I could see them in the console).

As far as your other suggestions, thank you very much and I’ll definitely look into implementing those. I’m still pretty weak on the coding front and appreciate the advice! I won’t be able to work on incorporating them for a little while; do you think they could be the culprit or are they more ‘best-practices’ kinds of things?

String Status = "Startup";
String Fireplace_Temp_String;
bool Fireplace_Temp_Flag = false;
String Fireplace_Battery_String;
bool Fireplace_Battery_Flag = false;

SYSTEM_THREAD(ENABLED);

void setup() {
    
    //Manually select the external mesh antenna
    digitalWrite(ANTSW1, 1);
    digitalWrite(ANTSW2, 0);
    
    Mesh.subscribe("Fireplace_Temp", Fireplace_Temp);
    Mesh.subscribe("Fireplace_Battery", Fireplace_Battery);
    
    Status = "Running";
	Particle.variable("Status", Status);
	//Particle.connect(); //added because of System_Thread(ENABLED) to keep from blocking if not connected yet
}

void loop() {
    
    if (Fireplace_Temp_Flag == true) {
        Particle.publish("Fireplace_Temp", Fireplace_Temp_String, 60, PRIVATE, WITH_ACK); //WITH_ACK
        Fireplace_Temp_Flag = false;
    }
    if (Fireplace_Battery_Flag == true) {
        Particle.publish("Fireplace_Battery", Fireplace_Battery_String, 60, PRIVATE, WITH_ACK); //WITH_ACK
        Fireplace_Battery_Flag = false;
    }
}

void Fireplace_Temp(const char *event, const char *data)
{
    Fireplace_Temp_String = data;
    Fireplace_Temp_Flag = true;
}

void Fireplace_Battery(const char *event, const char *data)
{
    Fireplace_Battery_String = data;
    Fireplace_Battery_Flag = true;
}

To debug issues like that I’d do multiple things

  • flash some intermediate code to the misbehaving device (e.g. LED blink) to double check updates actually stick
  • add some Serial.print() or Log.trace() statements to the event handlers to check whether they are firing and what data comes in
  • try to change the subscribe filter and test that via console.particle.io/events
  • copy the misbehaving code to a separate project and strip down to the bare minimum connected to the issue

I tested your code on my Argon 1.4.0 using this command particle publish --private Fireplace_Temp 123 and it works as expected.

Sorry for the late reply, I was out of the country for a few weeks. I left it running while I was gone (but never checked it). Upon my return, it was working and has continued to for the past few days. Additionally, we happened to lose power several times today and even after the hard resets it is still working fine.

Left scratching my head a bit… Any ideas why it would behave as it did so persistently and then subsequently start working as it should? Any changes to the particle cloud in the last few weeks?

Regardless, thank you very much for the help (and testing the code on your Argon). I’ll definitely look into incorporating your other suggestions into my code going forward.