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
}
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
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”.
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
Here is another video that might clarify particle.publish(); and particle.subscribe(); further:
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”…
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
}
I am sure @ScruffR will give you much better advice/opinion than I could in terms of your code, so lets await his feedback
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…
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
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.
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.
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
}
@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:
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.
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,...)