diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index b945744..6f523cf 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -917,12 +917,12 @@ void Span::processSerialCommand(const char *c){ Serial.print("\n\n"); 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 %.4s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d); + Serial.printf("%-30s %8s %10s %s %s %s %s %s\n","Service","UUID","AID","IID","Update","Loop","Button","Linked Services"); + Serial.printf("%.30s %.8s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d); for(int i=0;iServices.size();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::loop))!=(void(*)())(&SpanService::loop)?"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(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 homeSpan.Accessories.back()->Services.back()->validate(); this->type=type; this->hapName=hapName; + this->isCustom=isCustom; 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); 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){ 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(HapChar *hapChar){ +SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){ type=hapChar->type; perms=hapChar->perms; hapName=hapChar->hapName; format=hapChar->format; staticRange=hapChar->staticRange; + this->isCustom=isCustom; homeSpan.configLog+=" \u21e8 Characteristic " + String(hapName); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index d692064..79ca2d2 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -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 [[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 req; // vector of pointers to all required HAP Characteristic Types for this Service vector opt; // vector of pointers to all optional HAP Characteristic Types for this Service vector 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 *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 boolean *ev; // Characteristic Event Notify Enable (per-connection) 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 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 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 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); } - 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) + "\""; if(format!=FORMAT::STRING && format!=FORMAT::BOOL) homeSpan.configLog+= ", Range=[" + String(uvPrint(minValue)) + "," + String(uvPrint(maxValue)) + "]"; @@ -471,7 +474,12 @@ struct SpanCharacteristic{ else if(nvsFlag==1) 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 && iServices.back()->req.size(); i++) valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type); diff --git a/src/Span.h b/src/Span.h index 03fd31a..c0155f7 100644 --- a/src/Span.h +++ b/src/Span.h @@ -43,7 +43,7 @@ namespace Service { REQ(Model); REQ(Name); REQ(SerialNumber); - OPT(HardwareRevision); + OPT(HardwareRevision); }}; 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) \ 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) \ 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}{} }; } + + + + + +