I’m currently working on a library to integrate with a home automation platform, revolving around Cloud APIs and Webhooks.
As part of this, my library provides for the library user to create devices and nodes that will register on the Home Automation platform. When the Home Automation platform requests to GET or SET a value (e.g. onoff or room temp or thermostat mode) from the Particle device the library calls a user provided callback function.
I’m trying my best to keep things OOP and DRY… I’m not a great programmer, so bear with me please…
During Setup() the library is initialised and device/node capabilities are setup. Callbacks are attached. As I need to support callbacks to deal with bool, int and float I am overloading the methods in my intermediate class.
The code work fine with int and float callbacks, I can call my Cloud Function and the callbacks GET and SET perfectly, and my reports are published to my event stream. All good. But if I try to SET a bool callback, my photon blinks red and dies.
It could be a dumb error, but I can’t see it… So… here’s the code, it’s long so I’m just showing pertinent bits in the hope someone will know why bool callbacks might be different.
lib.h
class AthomGetSetObject: public AthomBaseObject {
// Extends AthomBaseObject to support Get Set and Callbacks
public:
AthomGetSetObject();
AthomGetSetObject(const String myName); // Constructor override
int setSetCallback( int (*yourFunc)(int) ); // callback func for set
int setSetCallback( float (*yourFunc)(float) ); // callback func for set
int setSetCallback( bool (*yourFunc)(bool) ); // callback func for set
//
int setGetCallback( int (*yourFunc)() ); // callback func for get
int setGetCallback( float (*yourFunc)() ); // callback func for get
int setGetCallback( bool (*yourFunc)() ); // callback func for get
//
int doSet(const int myValue);
float doSet(const float myValue);
bool doSet(const bool myValue);
int doGet(const int myValue);
int doGetInt();
float doGet(const float myValue);
float doGetFloat();
bool doGet(const bool myValue);
bool doGetBool();
bool isGetable();
bool isSetable();
bool isInt();
bool isFloat();
bool isBool();
String getType(); // String representation of type
protected:
bool _isSetable; // true when callback attached
bool _isGetable; // true when callback attached
bool _isInt;
bool _isFloat;
bool _isBool;
int (*_setCallbacki)(int); // set callback function
float (*_setCallbackf)(float); // set callback function
bool (*_setCallbackb)(bool); // set callback function
int (*_getCallbacki)(); // get callback function
float (*_getCallbackf)(); // get callback function
bool (*_getCallbackb)(); // get callback function
};
lib.cpp
int AthomGetSetObject::doSet(const int myValue) {
if (_isInt && _isSetable) {
return _setCallbacki(myValue); // THIS WORKS FINE :)
} else {
return -1;
}
}
float AthomGetSetObject::doSet(const float myValue) {
if (_isFloat && _isSetable) {
return _setCallbackf(myValue); // THIS WORKS FINE :)
} else {
return -1;
}
}
bool AthomGetSetObject::doSet(const bool myValue) {
debug("doSet bool Called: " + String(myValue));
delay(1000);
if (_isBool && _isSetable && _getCallbackb!=nullptr) {
debug("doSet bool calling callback");
delay(1000);
bool result = _setCallbackb(myValue); // DEBUGS CONFIRM THIS IS WHERE IT DIES
debug("Got result on bool set callback");
delay(1000);
return result;
} else {
return false;
}
}
For reference, here is how I set the the callback:
int AthomGetSetObject::setSetCallback( bool (*yourFunc)(bool) ) {
if (yourFunc==nullptr || (_isGetable && (_isFloat || _isInt))) {
// Get and set type must match
return -1;
}
_setCallbackb = yourFunc;
_setCallbackf = nullptr;
_setCallbackb = nullptr;
_isInt = false;
_isFloat = false;
_isBool = true;
_isSetable = true;
return 0;
}
I’m not including anything higher in the class/object hierarchy for brevity.
However, these are my test functions that I’m attaching from my test ino
int TestSetCallBackInt(int myVal) {
debug("Int Test Set Callback Called OK - returning: " + String(myVal));
delay(1000);
return myVal;
}
float TestSetCallBackFloat(float myVal) {
debug("Float Test Set Callback Called OK - returning: " + String(myVal));
delay(1000);
return myVal;
}
bool TestSetCallBackBool(bool myVal) {
debug("Bool Test Set Callback Called OK - returning same bool" + String(myVal));
delay(1000);
return myVal;
}
The delays are just there to ensure I see the debug output.
My callbacks are set as so:
myDevice.setCapabilityGetCallback(2,"thermostat_mode",&TestCallBackInt);
myDevice.setCapabilitySetCallback(2,"thermostat_mode",&TestSetCallBackInt);
myDevice.setCapabilityGetCallback(3,"dim",&TestCallBackFloat);
myDevice.setCapabilitySetCallback(3,"dim",&TestSetCallBackFloat);
myDevice.setCapabilityGetCallback(3,"onoff",&TestCallBackBool);
myDevice.setCapabilitySetCallback(3,"onoff",&TestSetCallBackBool);
These calls overload as follows:
template <class FuncType>
void AthomDevice::setCapabilitySetCallback(const int nodeId, const String myCapability, FuncType (*yourFunc)(FuncType) ) {
// TODO Add return values
int myCapId = findCapabilityByName(nodeId, myCapability);
if (myCapId > 0) {
getCapability(nodeId, myCapId)->setSetCallback(yourFunc);
}
}
template void AthomDevice::setCapabilitySetCallback<int>(const int nodeId, const String myCapability, int (*yourFunc)(int) );
template void AthomDevice::setCapabilitySetCallback<float>(const int nodeId, const String myCapability, float (*yourFunc)(float) );
template void AthomDevice::setCapabilitySetCallback<bool>(const int nodeId, const String myCapability, bool (*yourFunc)(bool) );
Debug output shows I can get and set my ints and my float fine, but when I try to SET a value associated with a boolean callback, the Photon dies (Red LED and restart) when I call the bool callback function
bool result = _setCallbackb(myValue);
Anyone any idea why a bool callback function would behave differently?
Complete code here: https://github.com/specialcircumstances/AthomIntDev/tree/dev