So I guess there’s two reasons for posting this. One is in case anyone in the future might benefit from this code, which is ‘my’ implementation of a heartbeat check between Particle devices. Big thanks to @BulldogLowell, @ScruffR, @nrobinson2000, @Grenello for their massive helps, various.
Secondly, it’s in case anyone can help me work out why my boolean flag “RemoteFail” is seemingly never ‘true’.
I should point that that the code does work, to a point, it’s just the second check I wanted to get working if possible.
INO
#include "VineAlert.h"
using namespace RetailAlert;
SYSTEM_THREAD(ENABLED);
// PUB-SUB constants
constexpr char * DEVICE_NAME = "ALERT";
constexpr char * Remote_FAIL_MSSG = "COMMS FAIL FROM Remote";
constexpr char * Remote_FAIL2_MSSG = "2nd COMMS FAIL FROM Remote";
int slidingstate = 3;
int Remotekeepstate = 3;
boolean RemoteFail = false;
MillisTimer HeartbeatRemote(960000, HBRemoteCallback, false);
MillisTimer ResetHBRemote(3600000, ResetRemoteCallback, false);
void eventHandler(const char * event,
const char * data);
void printDetail(uint8_t type, int value);
void setup() {
Particle.subscribe(DEVICE_NAME, eventHandler, MY_DEVICES);
HeartbeatRemote.begin();
ResetHBRemote.begin();
HeartbeatRemote.start();
}
void loop() {
MillisTimer::processTimers();
static unsigned long timer = millis();
}
void HBRemoteCallback(void) {
if (RemoteFail == false) {
HeartbeatRemote.stop();
RemoteFail = true;
Particle.publish(DEVICE_NAME, Remote_FAIL_MSSG, 60, PRIVATE);
HeartbeatRemote.start();
ResetHBRemote.start();
}
else if (RemoteFail == true) {
HeartbeatRemote.stop();
Particle.publish(DEVICE_NAME, Remote_FAIL2_MSSG, 60, PRIVATE);
RemoteFail = false;
}
}
void ResetRemoteCallback(void) {
RemoteFail = false;
}
void eventHandler(const char * event,
const char * data) {
if (sscanf(data, "K%d, S%d", & Remotekeepstate, & slidingstate)) {
HeartbeatRemote.stop();
HeartbeatRemote.start();
}
}
.H
#ifndef RETAILALERT_H
#define RETAILALERT_H
#include "Particle.h"
#include <vector>
constexpr uint16_t DEBOUNCE_TIME = 2500; //milliseconds
template <class T> inline Print& operator <<(Print& obj, T arg)
{
obj.print(arg);
return obj;
}
namespace RetailAlert{
using functionPtr = void(*)(void);
class MillisTimer{
public:
MillisTimer(uint32_t time, functionPtr action, bool repeat);
static void processTimers(void);
void start(void);
void start (bool repeat);
void stop(void);
void begin(void);
private:
enum TimerState{
STOPPED,
RUNNING,
}state = STOPPED;
functionPtr callback;
uint32_t delay;
uint32_t lastMillis = 0;
bool repeats;
static std::vector<MillisTimer*>timerArray;
};
};
#endif
.CPP
#include "Particle.h"
#include <vector>
#include "VineAlert.h"
// ButtonPressAction
using namespace RetailAlert;
// MillisTimer
std::vector<MillisTimer*> MillisTimer::timerArray;
MillisTimer::MillisTimer(uint32_t milliseconds, functionPtr action, bool repeat) {
//timerArray.push_back(this);
delay = milliseconds;
callback = action;
repeats = repeat;
}
void MillisTimer::begin(void) {
timerArray.push_back(this);
Serial << "Timer Added" << "\n";
}
void MillisTimer::processTimers(void) {
uint32_t currentMillis = millis();
int count = 0;
for (auto& i : timerArray)
{
if(currentMillis - i->lastMillis >= i->delay)
{
if (i->state == RUNNING){
if(i->callback){
i->callback();
}
if (!i->repeats){
i->state = STOPPED;
}
else {
i->lastMillis = currentMillis;
}
}
}
}
}
void MillisTimer::start (void){
lastMillis = millis();
state = RUNNING;
Serial << "Timer Start\n";
}
void MillisTimer::start (bool repeat){
repeats = repeat;
lastMillis = millis();
state = RUNNING;
Serial << "Timer Start\n";
}
void MillisTimer::stop(void){
lastMillis = millis();
state = STOPPED;
}
Many thanks!