How I can use spark/status to notify offline to another photon?

Hi All,

I am working on software to communicate two particles photons for display alarm triggering. I am trying to get the status “offline” from spark/status event. here below the software I don’t know if its correct.

int LED7=D7;
String CDATA; // STRING CALLED FROM CLOULD 
String TEST="NORMAL"; // TEST VALUE FOR COMPEARATION 
String OnL;


void setup() {


Particle.subscribe("FAP", RunAlarm, "40002500164736333XXXX");
Particle.subscribe("spark/status", OnLineStatus, "40002500164736333XXXX");
pinMode(LED7, OUTPUT);
digitalWrite(LED7, HIGH);
delay(5000);
digitalWrite(LED7, LOW);


Serial.begin(9600);


}

void loop()
{
    Serial.print(" CDATA= ");
    Serial.println(CDATA);
    
      Serial.print(" Online Status= ");
      Serial.println(OnL);
    
     if (CDATA.equals("NORMAL")){
           
           
         digitalWrite(LED7, LOW);
        }
        
    if (CDATA.equals("ALARM!"))
        {

        digitalWrite(LED7, HIGH);
        }
        
    if (OnL.equals("offline"))
    {
        digitalWrite(LED7, HIGH);
        delay(1000);
        digitalWrite(LED7, LOW);
    }
}

// the handeler function 
void RunAlarm(const char *event, const char *data)
{
 
 CDATA=data; // convert from Car to String
 
 
        
}


void OnLineStatus(const char *event, const char *data)
{
 
 OnL=data; // convert from Car to String
 
 
        
}








Hi @Lahmdi -

Have you tested this code? The reasoning seems solid enough. This is what will be running on the Photon checking the status of the other device correct?

Alternatively you can have on device sending small packet data to the other and then have the second one acknowledge receipt i.e:

send packet data from Photon 1
Photon 2 receives data
Photon 2 acknowledge
IF no acknowledgement from Photon 2, RETRY five times.  
IF still no acknowledgement from Photon 2, Photon 1 assumes Photon 2 is offline

Just a thought :slight_smile:

Regards, Friedl.

@friedl_1977
My code doesn’t work! yes I need to check the status of other photon.

sending packet data you mean using the publish and subscribe I guess. but using these code will give the last event every time when I call the data.

I’m not convinced you can actually subscribe to a specific device ID.
https://docs.particle.io/reference/device-os/firmware/photon/#particle-subscribe-

AFAICT a spark/... (better particle/...) event response will only ever be sent to the device that publishes the request and not to any of its “siblings”.

2 Likes

Hi @Lahmdi -

My apologies, I made some assumptions i.e. the devices are on the same network. In my humble opinion, and providing this on on the same network, I suppose you can use I2C, SPI or some other protocols for comms.

We used Server (Master) - Client (Slave) setup on a local installation to get 10+ devices to communicate as waiting for handshakes over internet was just too slow and we did not want the system to go down due to possible internet downtime.

Maybe have a look at these links;

If communication is via internet, this brief video should get you going :slight_smile:

Here is another video that might clarify particle.publish(); and particle.subscribe(); further:

Hope this helps!
Friedl.

1 Like

@friedl_1977
Many Thanks Friedl I will try it.

1 Like

Hi @ScruffR ,
Do you mean I shouldn’t add my device ID number in particle.subscription code?
instead of that I replace it with “MY_DEVICES” or “ALL_DEVICES”…

Exactly, you should subscribe to MY_DEVICES to receive events published as PRIVATE.

However, you will still not receive other device’s online status this way.

Thanks @ScruffR
I just know that! :sweat_smile:

actually you and @friedl_1977 give me idea to publish other event from TX photon has time data.
then compare it with last time in RX photons.
here below the code.
could you please check and give your opinion.

int LED7=D7;
String CDATA; // STRING CALLED FROM CLOULD 
String TEST="NORMAL"; // TEST VALUE FOR COMPEARATION 

String Date;
String DateLast;


void setup() {


Particle.subscribe("FAP", RunAlarm, MY_DEVICES);
Particle.subscribe("time", TimeEvent, MY_DEVICES);

pinMode(LED7, OUTPUT);
digitalWrite(LED7, HIGH);
delay(5000);
digitalWrite(LED7, LOW);


Serial.begin(9600);


}

void loop()
{
    delay (5000);
    
    
    

      
    if(Date.equals(DateLast))
    {
            Serial.print(" System Disconnected!   ");
            Serial.println(Date);
            
            digitalWrite(LED7, HIGH);
            delay(300);
            digitalWrite(LED7, LOW);
            delay(300);
            digitalWrite(LED7, HIGH);
            delay(300);
            digitalWrite(LED7, LOW);
            delay(300);
            digitalWrite(LED7, HIGH);
            delay(300);
            digitalWrite(LED7, LOW);
            
            
    }
    
    else 
    {
        if (CDATA.equals("NORMAL"))
        {
           digitalWrite(LED7, LOW);
           Serial.print(" CDATA= ");
           Serial.println(CDATA);
           
           Serial.print(" Date= ");
           Serial.println(Date);
           Date=DateLast;
        }
        if (CDATA.equals("ALARM!"))
        {
        digitalWrite(LED7, HIGH);
        Serial.print(" CDATA= ");
        Serial.println(CDATA);
           
        Serial.print(" Date= ");
        Serial.println(Date);
        Date=DateLast;
        }
        
    
    }
     
        
   
   
}

// the handeler function 
void RunAlarm(const char *event, const char *data)
{
 
 CDATA=data; // convert from Car to String

        
}


void TimeEvent(const char *event, const char *data)
{
 
 Date=data; // convert from Car to String

        
}


Hi @Lahmdi -

I am sure @ScruffR will give you much better advice/opinion than I could in terms of your code, so lets await his feedback :relaxed:

With regards to the architecture; In pseudo, here is how we approached a similar situation to check whether Node is online:

All nodes listening waiting for instructions
MASTER: “Hello Node1, please turn 50 revolutions.”
NODE1: "Hello Master, ok.
**Master receives feedback, wait for DONE feedback from Node1 before sending Node2 instruction.
// IF no reply from NODE1:
// MASTER: “Hello Node1, please turn 50 revolutions.” - Repeat 5 times
// IF still no reply, MASTER reports NODE1 as Off-line

**ELSE **:
Node1 carries out instruction.
NODE1: “Hello MASTER, I am done”
NODE1 sleeps
MASTER sends Node2 instruction etc.

This way we did not have to check and compare dates, we used a necessary instruction and just waited for reply. This was imperative as the system is dispensing volumes of product to mix recipes, so if one product did not dispense, the system had to stop and report, in order not to incorrectly mix the recipe.

Depending on how frequently you want to check, or other events you are publishing, I think you have several options to determine whether a Photon is online or not. Just some ideas… :wink:

Best of luck!
Friedl.

1 Like

I’d first address the usual topics

  • don’t use String but C-strings
  • don’t use delay() - especially not for 5 seconds
1 Like

Thanks @friedl_1977
I shall try it.

1 Like

Could you please explain or give the topic link if you have to read about C-string.
and Why we don’t use delay();

Hi @Lahmdi -

Well, in my opinion you an use short delays for simple code snippets but I agree with @ScruffR, even I wont implement 5s blocking delays :slight_smile:

Thanks to a lot of help from @ScruffR and @peekay123 over the months, I learned about non-blocking delays. They are a bit more involved and require little bit more work than simple delay(1000s); but helps a lot!

Here is a small example:

nt period = 1000;
unsigned long time_now = 0;
 
void setup() {
    Serial.begin(115200);
}
 
void loop() {
    time_now = millis();
   
    Serial.println("Hello");
   
    while(millis() < time_now + period){
        // add the code you want to keep running here
        //wait approx. [period] ms
    }
       // handle whatever you want to handle after the pause here, than start allover again
}

The problem with blocking delay is exactly what the name indicates. It will block the rest of your code for that time. Also remember, you must add up all the delays you have in your loop();sections which will effectively give you the time it will take for each loop to run. In your case there seems to be a couple also (what seems to me) blinking your LED. all of this add’s up.

Here is a link to Adafruit site with code example of how to blink LED without blocking your code.

Blink without delay

I will let Scruff get back to you in C-Strings :wink:

Regards, Friedl.

2 Likes

I see,
I will search for that in more details.
Thanks for the link of blinking LED without delay.
off course i need to run the alarm and LED without blocking the code.

Thanks a lot @friedl_1977

1 Like

If you could imagine using the on-board RGB LED for your signalling you could also have a look at this
https://docs.particle.io/reference/device-os/firmware/photon/#led-signaling

Since you also can mirror the on-board LED to other pins you could even use external LEDs for that.

Using String objects may have adverse side effects which can easily be avoided using C-string (aka char arrays).
Looking at your code, I’d not substitute all String objects with C-strings but rather replace some of them with numeric variables (e.g. Date and DateLast) as it’s not a human that wants to read these values but a machine and they are typically happier dealing with numbers (including enum).

But when you want to use strings you could do something like this

char CDATA[16];
...
void RunAlarm(const char *event, const char *data)
{
   strncpy(CDATA, data, sizeof(CDATA));
}
...
  if (strcmp(CDATA, "NORMAL") == 0) {
    // do what's required when CDATA == "NORMAL"
    Serial.printlnf(" CDATA = %s \r\n Data = %s", CDATA, (const char*)Time.format(nDate)); 
  }
  else if (....) {
    // other cases
  }
2 Likes

@ScruffR is making a good point, I have been using function more and more lately. You can also ‘release’ your LED from this function and indicate custom colours and then revert back to mirroring the onboard LED i.e:

Void setup() {
    
    Serial.begin(115200);
    RGB.mirrorTo(D3, D1, D2);

and then somewhere in a loop something like this…

 if (powersaving == 1 && widgetTimerEnable == 1 && hibernate == 0) {         // Do Power Saving On stuff 
          RGB.control(true); // taking manual control of PCB LED
          RGB.color(0, 255, 0);
          digitalWrite(relay, HIGH);
          Blynk.virtualWrite(V7,HIGH);

              } else if (powersaving == 0 && widgetTimerEnable == 1) {                 // Turn switch off
                RGB.control(false); // giving automatic control back to Photon
                digitalWrite(relay, LOW);
                Blynk.virtualWrite(V7,LOW);
 
    }

In this in segment I took manual control of my RGB LED on the PCB, used it to display a custom colour and then handed control back to the device to mirror LED.

Hope this helps!
Friedl.

Wow amazing

I still need to read more about C string library. I couldn’t find it in the particle references.
do you have a link about C string reference (strncpy, strcpy,…)

My preferred source for legacy C functions would be this
http://www.cplusplus.com/reference/cstring/

snprintf() is another great function you may want to look into - for further insight into the format string you should follow the printf() link too.

3 Likes

Thanks @ScruffR
interesting website.