From 9f71c67f14261cd7c6828e85b4189da0fd2f7736 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 30 Apr 2022 22:20:42 -0500 Subject: [PATCH] Updated logic for required/optional Characteristics Logic now embedded in 'i' CLI command. --- src/HomeSpan.cpp | 81 ++++++++++++++---------------------------------- src/HomeSpan.h | 24 ++++---------- src/Span.h | 4 +-- 3 files changed, 32 insertions(+), 77 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 1549340..53a4da3 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -179,17 +179,6 @@ void Span::pollTask() { if(!isInitialized){ - if(!homeSpan.Accessories.empty()){ - - if(!homeSpan.Accessories.back()->Services.empty()) - homeSpan.Accessories.back()->Services.back()->validate(); - - } - - if(nWarnings>0){ - configLog+="\n*** CAUTION: There " + String((nWarnings>1?"are ":"is ")) + String(nWarnings) + " WARNING" + (nWarnings>1?"S":"") + " associated with this configuration that may lead to the device becoming non-responsive, or operating in an unexpected manner. ***\n"; - } - processSerialCommand("i"); // print homeSpan configuration info if(nFatalErrors>0){ @@ -926,7 +915,7 @@ void Span::processSerialCommand(const char *c){ Serial.print("\n*** HomeSpan Info ***\n\n"); - std::set aidValues; + unordered_set aidValues; for(auto acc=Accessories.begin(); acc!=Accessories.end(); acc++){ Serial.printf("\u27a4 Accessory: AID=%d\n",(*acc)->aid); @@ -951,7 +940,9 @@ void Span::processSerialCommand(const char *c){ } else if((*acc)->aid==1) // this is an Accessory with aid=1, but it has more than just AccessoryInfo. So... isBridge=false; // ...this is not a bridge device - + + unordered_set hapChar; + for(auto chr=(*svc)->Characteristics.begin(); chr!=(*svc)->Characteristics.end(); chr++){ Serial.printf(" \u21e8 Characteristic %s(%s): IID=%d, %sUUID=\"%s\"",(*chr)->hapName,(*chr)->uvPrint((*chr)->value).c_str(),(*chr)->iid,(*chr)->isCustom?"Custom-":"",(*chr)->type); @@ -966,13 +957,13 @@ void Span::processSerialCommand(const char *c){ Serial.printf(" (nvs)"); Serial.printf("\n"); - if(!(*chr)->isSupported) + if(!(*chr)->isCustom && !(*svc)->isCustom && (*svc)->req.find((*chr)->hapChar)==(*svc)->req.end() && (*svc)->opt.find((*chr)->hapChar)==(*svc)->opt.end()) Serial.printf(" *** WARNING! Service does not support this Characteristic ***\n"); else if(invalidUUID((*chr)->type,(*chr)->isCustom)) Serial.printf(" *** ERROR! Format of UUID is invalid ***\n"); else - if((*chr)->isRepeated) + if(hapChar.find((*chr)->hapChar)!=hapChar.end()) Serial.printf(" *** ERROR! Characteristic already defined for this Service ***\n"); if((*chr)->setRangeError) @@ -981,15 +972,19 @@ void Span::processSerialCommand(const char *c){ if((*chr)->format!=STRING && ((*chr)->uvGet((*chr)->value) < (*chr)->uvGet((*chr)->minValue) || (*chr)->uvGet((*chr)->value) > (*chr)->uvGet((*chr)->maxValue))) Serial.printf(" *** WARNING! Value of %llg is out of range [%llg,%llg] ***\n",(*chr)->uvGet((*chr)->value),(*chr)->uvGet((*chr)->minValue),(*chr)->uvGet((*chr)->maxValue)); - // 2. MISSING REQUIRED CHARACTERISTICS - // 3. AID CHECK - + hapChar.insert((*chr)->hapChar); + } // Characteristics + + for(auto req=(*svc)->req.begin(); req!=(*svc)->req.end(); req++){ + if(hapChar.find(*req)==hapChar.end()) + Serial.printf(" *** WARNING! Required '%s' Characteristic for this Service not found ***\n",(*req)->hapName); + } } // Services if(!foundInfo) - Serial.printf(" *** ERROR! Required Accessory Information Service not found ***\n"); + Serial.printf(" *** ERROR! Required 'AccessoryInformation' Service not found ***\n"); } // Accessories @@ -1458,10 +1453,7 @@ SpanAccessory::SpanAccessory(uint32_t aid){ } this->aid=homeSpan.Accessories.back()->aid+1; - - if(!homeSpan.Accessories.back()->Services.empty()) - homeSpan.Accessories.back()->Services.back()->validate(); - + } else { this->aid=1; } @@ -1498,22 +1490,18 @@ int SpanAccessory::sprintfAttributes(char *cBuf){ 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(); + if(homeSpan.Accessories.empty()){ + Serial.printf("\nFATAL ERROR! Can't create new Service '%s' without a defined Accessory ***\n",hapName); + Serial.printf("\n=== PROGRAM HALTED ==="); + while(1); + } this->type=type; this->hapName=hapName; this->isCustom=isCustom; - if(homeSpan.Accessories.empty()){ - homeSpan.configLog+=" *** ERROR! Can't create new Service without a defined Accessory! ***\n"; - homeSpan.nFatalErrors++; - return; - } - homeSpan.Accessories.back()->Services.push_back(this); iid=++(homeSpan.Accessories.back()->iidCount); - } /////////////////////////////// @@ -1573,26 +1561,6 @@ int SpanService::sprintfAttributes(char *cBuf){ return(nBytes); } -/////////////////////////////// - -void SpanService::validate(){ - - for(int i=0;itype,Characteristics[j]->type); - - if(!valid){ - homeSpan.configLog+=" \u2718 Characteristic " + String(req[i]->hapName); - homeSpan.configLog+=" *** WARNING! Required Characteristic for this Service not found. ***\n"; - homeSpan.nWarnings++; - } - } - - vector().swap(opt); - vector().swap(req); -} - /////////////////////////////// // SpanCharacteristic // /////////////////////////////// @@ -1604,13 +1572,12 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){ format=hapChar->format; staticRange=hapChar->staticRange; this->isCustom=isCustom; - - homeSpan.configLog+=" \u21e8 Characteristic " + String(hapName); + this->hapChar=hapChar; if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ - homeSpan.configLog+=" *** ERROR! Can't create new Characteristic without a defined Service! ***\n"; - homeSpan.nFatalErrors++; - return; + Serial.printf("\nFATAL ERROR! Can't create new Characteristic '%s' without a defined Service ***\n",hapName); + Serial.printf("\n=== PROGRAM HALTED ==="); + while(1); } iid=++(homeSpan.Accessories.back()->iidCount); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index b538823..ff76397 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -49,6 +49,7 @@ using std::vector; using std::unordered_map; +using std::unordered_set; enum { GET_AID=1, @@ -297,8 +298,8 @@ struct SpanService{ boolean hidden=false; // optional property indicating service is hidden boolean primary=false; // optional property indicating service is primary vector Characteristics; // vector of pointers to all Characteristics in this Service - 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 + unordered_set req; // unordered set of pointers to all required HAP Characteristic Types for this Service + unordered_set opt; // unordered set 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 @@ -310,7 +311,6 @@ struct SpanService{ vector getLinks(){return(linkedServices);} // returns linkedServices vector for use as range in "for-each" loops int sprintfAttributes(char *cBuf); // prints Service JSON records into buf; return number of characters printed, excluding null terminator - void validate(); // error-checks Service virtual boolean update() {return(true);} // placeholder for code that is called when a Service is updated via a Controller. Must return true/false depending on success of update virtual void loop(){} // loops for each Service - called every cycle and can be over-ridden with user-defined code @@ -333,6 +333,7 @@ struct SpanCharacteristic{ }; int iid=0; // Instance ID (HAP Table 6-3) + HapChar *hapChar; // pointer to HAP Characteristic structure const char *type; // Characteristic Type const char *hapName; // HAP Name UVal value; // Characteristic Value @@ -349,8 +350,6 @@ struct SpanCharacteristic{ 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 - boolean isSupported; // flag to indicate this Characteristic is supported by the containing Service (it's either required or optional) - boolean isRepeated=false; // flag to indicate this Characteristic is defined repeated times within the same Service (reports an error) boolean setRangeError=false; // flag to indicate attempt to set range on Characteristic that does not support changes to range uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic @@ -512,18 +511,7 @@ struct SpanCharacteristic{ uvSet(maxValue,max); uvSet(stepValue,0); } - - isSupported=isCustom|service->isCustom; // automatically set valid if either Characteristic or containing Service is Custom - - for(int i=0; !isSupported && iServices.back()->req.size(); i++) - isSupported=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type); - - for(int i=0; !isSupported && iServices.back()->opt.size(); i++) - isSupported=!strcmp(type,homeSpan.Accessories.back()->Services.back()->opt[i]->type); - - for(int i=0; !isRepeated && iServices.back()->Characteristics.size(); i++) - isRepeated=!strcmp(type,homeSpan.Accessories.back()->Services.back()->Characteristics[i]->type); - + homeSpan.Accessories.back()->Services.back()->Characteristics.push_back(this); } // init() diff --git a/src/Span.h b/src/Span.h index 8b7e4b9..9d01787 100644 --- a/src/Span.h +++ b/src/Span.h @@ -31,8 +31,8 @@ // Macros to define vectors of required and optional characteristics for each Span Service structure -#define REQ(HAPCHAR) req.push_back(&hapChars.HAPCHAR) -#define OPT(HAPCHAR) opt.push_back(&hapChars.HAPCHAR) +#define REQ(HAPCHAR) req.insert(&hapChars.HAPCHAR) +#define OPT(HAPCHAR) opt.insert(&hapChars.HAPCHAR) namespace Service {