Add new macro CUSTOM_SERV() to created custom services
Also, updated error checking so that the UUID for both custom Services and custom Characteristics are checked for syntax. A fatal error is thrown if an ill-formatted UUID is found, since this will definitely prevent pairing with the HomeApp. The UUID for HAP Services and Characteristics are NOT error checked, since these are fixed in HomeSpan. Also, the custom Characteristics are not validated against the optional list for a service. If the user adds a custom Characteristic to a HAP Service, it is assumed to be valid. Similarly, none of the Characteristics (HAP of Custom) in a Custom Service are validated at all.
This commit is contained in:
parent
bf2e1354b1
commit
170e0b61b1
|
|
@ -917,12 +917,12 @@ void Span::processSerialCommand(const char *c){
|
||||||
Serial.print("\n\n");
|
Serial.print("\n\n");
|
||||||
|
|
||||||
char d[]="------------------------------";
|
char d[]="------------------------------";
|
||||||
Serial.printf("%-30s %s %10s %s %s %s %s %s\n","Service","UUID","AID","IID","Update","Loop","Button","Linked Services");
|
Serial.printf("%-30s %8s %10s %s %s %s %s %s\n","Service","UUID","AID","IID","Update","Loop","Button","Linked Services");
|
||||||
Serial.printf("%.30s %.4s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d);
|
Serial.printf("%.30s %.8s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d);
|
||||||
for(int i=0;i<Accessories.size();i++){ // identify all services with over-ridden loop() methods
|
for(int i=0;i<Accessories.size();i++){ // identify all services with over-ridden loop() methods
|
||||||
for(int j=0;j<Accessories[i]->Services.size();j++){
|
for(int j=0;j<Accessories[i]->Services.size();j++){
|
||||||
SpanService *s=Accessories[i]->Services[j];
|
SpanService *s=Accessories[i]->Services[j];
|
||||||
Serial.printf("%-30s %4s %10u %3d %6s %4s %6s ",s->hapName,s->type,Accessories[i]->aid,s->iid,
|
Serial.printf("%-30s %8.8s %10u %3d %6s %4s %6s ",s->hapName,s->type,Accessories[i]->aid,s->iid,
|
||||||
(void(*)())(s->*(&SpanService::update))!=(void(*)())(&SpanService::update)?"YES":"NO",
|
(void(*)())(s->*(&SpanService::update))!=(void(*)())(&SpanService::update)?"YES":"NO",
|
||||||
(void(*)())(s->*(&SpanService::loop))!=(void(*)())(&SpanService::loop)?"YES":"NO",
|
(void(*)())(s->*(&SpanService::loop))!=(void(*)())(&SpanService::loop)?"YES":"NO",
|
||||||
(void(*)(int,boolean))(s->*(&SpanService::button))!=(void(*)(int,boolean))(&SpanService::button)?"YES":"NO"
|
(void(*)(int,boolean))(s->*(&SpanService::button))!=(void(*)(int,boolean))(&SpanService::button)?"YES":"NO"
|
||||||
|
|
@ -1489,13 +1489,14 @@ int SpanAccessory::sprintfAttributes(char *cBuf){
|
||||||
// SpanService //
|
// SpanService //
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
SpanService::SpanService(const char *type, const char *hapName){
|
SpanService::SpanService(const char *type, const char *hapName, boolean isCustom){
|
||||||
|
|
||||||
if(!homeSpan.Accessories.empty() && !homeSpan.Accessories.back()->Services.empty()) // this is not the first Service to be defined for this Accessory
|
if(!homeSpan.Accessories.empty() && !homeSpan.Accessories.back()->Services.empty()) // this is not the first Service to be defined for this Accessory
|
||||||
homeSpan.Accessories.back()->Services.back()->validate();
|
homeSpan.Accessories.back()->Services.back()->validate();
|
||||||
|
|
||||||
this->type=type;
|
this->type=type;
|
||||||
this->hapName=hapName;
|
this->hapName=hapName;
|
||||||
|
this->isCustom=isCustom;
|
||||||
|
|
||||||
homeSpan.configLog+=" \u279f Service " + String(hapName);
|
homeSpan.configLog+=" \u279f Service " + String(hapName);
|
||||||
|
|
||||||
|
|
@ -1508,7 +1509,12 @@ SpanService::SpanService(const char *type, const char *hapName){
|
||||||
homeSpan.Accessories.back()->Services.push_back(this);
|
homeSpan.Accessories.back()->Services.push_back(this);
|
||||||
iid=++(homeSpan.Accessories.back()->iidCount);
|
iid=++(homeSpan.Accessories.back()->iidCount);
|
||||||
|
|
||||||
homeSpan.configLog+=": IID=" + String(iid) + ", UUID=\"" + String(type) + "\"";
|
homeSpan.configLog+=": IID=" + String(iid) + ", " + (isCustom?"Custom-":"") + "UUID=\"" + String(type) + "\"";
|
||||||
|
|
||||||
|
if(Span::invalidUUID(type,isCustom)){
|
||||||
|
homeSpan.configLog+=" *** ERROR! Format of UUID is invalid. ***";
|
||||||
|
homeSpan.nFatalErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
if(!strcmp(this->type,"3E") && iid!=1){
|
if(!strcmp(this->type,"3E") && iid!=1){
|
||||||
homeSpan.configLog+=" *** ERROR! The AccessoryInformation Service must be defined before any other Services in an Accessory. ***";
|
homeSpan.configLog+=" *** ERROR! The AccessoryInformation Service must be defined before any other Services in an Accessory. ***";
|
||||||
|
|
@ -1600,12 +1606,13 @@ void SpanService::validate(){
|
||||||
// SpanCharacteristic //
|
// SpanCharacteristic //
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
SpanCharacteristic::SpanCharacteristic(HapChar *hapChar){
|
SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){
|
||||||
type=hapChar->type;
|
type=hapChar->type;
|
||||||
perms=hapChar->perms;
|
perms=hapChar->perms;
|
||||||
hapName=hapChar->hapName;
|
hapName=hapChar->hapName;
|
||||||
format=hapChar->format;
|
format=hapChar->format;
|
||||||
staticRange=hapChar->staticRange;
|
staticRange=hapChar->staticRange;
|
||||||
|
this->isCustom=isCustom;
|
||||||
|
|
||||||
homeSpan.configLog+=" \u21e8 Characteristic " + String(hapName);
|
homeSpan.configLog+=" \u21e8 Characteristic " + String(hapName);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,13 @@ struct Span{
|
||||||
void enableOTA(boolean auth=true){otaEnabled=true;otaAuth=auth;reserveSocketConnections(1);} // enables Over-the-Air updates, with (auth=true) or without (auth=false) authorization password
|
void enableOTA(boolean auth=true){otaEnabled=true;otaAuth=auth;reserveSocketConnections(1);} // enables Over-the-Air updates, with (auth=true) or without (auth=false) authorization password
|
||||||
|
|
||||||
[[deprecated("Please use reserveSocketConnections(n) method instead.")]]
|
[[deprecated("Please use reserveSocketConnections(n) method instead.")]]
|
||||||
void setMaxConnections(uint8_t n){requestedMaxCon=n;} // sets maximum number of simultaneous HAP connections
|
void setMaxConnections(uint8_t n){requestedMaxCon=n;} // sets maximum number of simultaneous HAP connections
|
||||||
|
|
||||||
|
static boolean invalidUUID(const char *uuid, boolean isCustom){
|
||||||
|
int x=0;
|
||||||
|
sscanf(uuid,"%*8[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*12[0-9a-fA-F]%n",&x);
|
||||||
|
return(isCustom && (strlen(uuid)!=36 || x!=36));
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -233,8 +239,9 @@ struct SpanService{
|
||||||
vector<HapChar *> req; // vector of pointers to all required HAP Characteristic Types for this Service
|
vector<HapChar *> req; // vector of pointers to all required HAP Characteristic Types for this Service
|
||||||
vector<HapChar *> opt; // vector of pointers to all optional HAP Characteristic Types for this Service
|
vector<HapChar *> opt; // vector of pointers to all optional HAP Characteristic Types for this Service
|
||||||
vector<SpanService *> linkedServices; // vector of pointers to any optional linked Services
|
vector<SpanService *> linkedServices; // vector of pointers to any optional linked Services
|
||||||
|
boolean isCustom; // flag to indicate this is a Custom Service
|
||||||
|
|
||||||
SpanService(const char *type, const char *hapName);
|
SpanService(const char *type, const char *hapName, boolean isCustom=false); // constructor
|
||||||
|
|
||||||
SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self
|
SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self
|
||||||
SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self
|
SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self
|
||||||
|
|
@ -280,6 +287,7 @@ struct SpanCharacteristic{
|
||||||
const char *validValues=NULL; // Optional JSON array of valid values. Applicable only to uint8 Characteristics
|
const char *validValues=NULL; // Optional JSON array of valid values. Applicable only to uint8 Characteristics
|
||||||
boolean *ev; // Characteristic Event Notify Enable (per-connection)
|
boolean *ev; // Characteristic Event Notify Enable (per-connection)
|
||||||
char *nvsKey=NULL; // key for NVS storage of Characteristic value
|
char *nvsKey=NULL; // key for NVS storage of Characteristic value
|
||||||
|
boolean isCustom; // flag to indicate this is a Custom Characteristic
|
||||||
|
|
||||||
uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic
|
uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic
|
||||||
boolean isUpdated=false; // set to true when new value has been requested by PUT /characteristic
|
boolean isUpdated=false; // set to true when new value has been requested by PUT /characteristic
|
||||||
|
|
@ -287,7 +295,7 @@ struct SpanCharacteristic{
|
||||||
UVal newValue; // the updated value requested by PUT /characteristic
|
UVal newValue; // the updated value requested by PUT /characteristic
|
||||||
SpanService *service=NULL; // pointer to Service containing this Characteristic
|
SpanService *service=NULL; // pointer to Service containing this Characteristic
|
||||||
|
|
||||||
SpanCharacteristic(HapChar *hapChar); // contructor
|
SpanCharacteristic(HapChar *hapChar, boolean isCustom=false); // contructor
|
||||||
|
|
||||||
int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator
|
int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator
|
||||||
StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intiial HAP status code (checks to see if characteristic is found, is writable, etc.)
|
StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intiial HAP status code (checks to see if characteristic is found, is writable, etc.)
|
||||||
|
|
@ -457,11 +465,6 @@ struct SpanCharacteristic{
|
||||||
uvSet(stepValue,0);
|
uvSet(stepValue,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int x=0;
|
|
||||||
sscanf(type,"%*8[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*4[0-9a-fA-F]-%*12[0-9a-fA-F]%n",&x);
|
|
||||||
|
|
||||||
boolean isCustom=(strlen(type)==36 && x==36);
|
|
||||||
|
|
||||||
homeSpan.configLog+="(" + uvPrint(value) + ")" + ": IID=" + String(iid) + ", " + (isCustom?"Custom-":"") + "UUID=\"" + String(type) + "\"";
|
homeSpan.configLog+="(" + uvPrint(value) + ")" + ": IID=" + String(iid) + ", " + (isCustom?"Custom-":"") + "UUID=\"" + String(type) + "\"";
|
||||||
if(format!=FORMAT::STRING && format!=FORMAT::BOOL)
|
if(format!=FORMAT::STRING && format!=FORMAT::BOOL)
|
||||||
homeSpan.configLog+= ", Range=[" + String(uvPrint(minValue)) + "," + String(uvPrint(maxValue)) + "]";
|
homeSpan.configLog+= ", Range=[" + String(uvPrint(minValue)) + "," + String(uvPrint(maxValue)) + "]";
|
||||||
|
|
@ -471,7 +474,12 @@ struct SpanCharacteristic{
|
||||||
else if(nvsFlag==1)
|
else if(nvsFlag==1)
|
||||||
homeSpan.configLog+=" (storing)";
|
homeSpan.configLog+=" (storing)";
|
||||||
|
|
||||||
boolean valid=isCustom;
|
if(Span::invalidUUID(type,isCustom)){
|
||||||
|
homeSpan.configLog+=" *** ERROR! Format of UUID is invalid. ***";
|
||||||
|
homeSpan.nFatalErrors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean valid=isCustom|service->isCustom; // automatically set valid if either Characteristic or containing Service is Custom
|
||||||
|
|
||||||
for(int i=0; !valid && i<homeSpan.Accessories.back()->Services.back()->req.size(); i++)
|
for(int i=0; !valid && i<homeSpan.Accessories.back()->Services.back()->req.size(); i++)
|
||||||
valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type);
|
valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type);
|
||||||
|
|
|
||||||
21
src/Span.h
21
src/Span.h
|
|
@ -43,7 +43,7 @@ namespace Service {
|
||||||
REQ(Model);
|
REQ(Model);
|
||||||
REQ(Name);
|
REQ(Name);
|
||||||
REQ(SerialNumber);
|
REQ(SerialNumber);
|
||||||
OPT(HardwareRevision);
|
OPT(HardwareRevision);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
struct AirPurifier : SpanService { AirPurifier() : SpanService{"BB","AirPurifier"}{
|
struct AirPurifier : SpanService { AirPurifier() : SpanService{"BB","AirPurifier"}{
|
||||||
|
|
@ -521,14 +521,23 @@ namespace Characteristic {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// MACRO TO ADD CUSTOM CHARACTERISTICS //
|
// MACROS TO ADD CUSTOM SERVICES AND CHARACTERISTICS //
|
||||||
//////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define CUSTOM_CHAR(NAME,UUID,PERMISISONS,FORMAT,DEFVAL,MINVAL,MAXVAL,STATIC_RANGE) \
|
#define CUSTOM_CHAR(NAME,UUID,PERMISISONS,FORMAT,DEFVAL,MINVAL,MAXVAL,STATIC_RANGE) \
|
||||||
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),FORMAT,STATIC_RANGE}; \
|
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),FORMAT,STATIC_RANGE}; \
|
||||||
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(FORMAT##_t val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME} { init(val,nvsStore,(FORMAT##_t)MINVAL,(FORMAT##_t)MAXVAL); } }; }
|
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(FORMAT##_t val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore,(FORMAT##_t)MINVAL,(FORMAT##_t)MAXVAL); } }; }
|
||||||
|
|
||||||
#define CUSTOM_CHAR_STRING(NAME,UUID,PERMISISONS,DEFVAL) \
|
#define CUSTOM_CHAR_STRING(NAME,UUID,PERMISISONS,DEFVAL) \
|
||||||
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),STRING,true}; \
|
HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),STRING,true}; \
|
||||||
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME} { init(val,nvsStore); } }; }
|
namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; }
|
||||||
|
|
||||||
|
#define CUSTOM_SERV(NAME,UUID) \
|
||||||
|
namespace Service { struct NAME : SpanService { NAME() : SpanService{#UUID,#NAME,true}{} }; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue