From c7f762da5f6df516a22ddfa380d0b5ebfd0ffc35 Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 28 Oct 2020 19:48:53 -0500 Subject: [PATCH] Completed error-checking/validation Added validation to ensure all Accessories have a AccessoryInformation Service and all Accessories have a HAPProtocolInformation Service, unless the device is configured as a bridge, in which case only the first Accessory requires a HAPProtocolInformation Service. --- src/HomeSpan.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++---- src/HomeSpan.h | 4 +++ 2 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 6f1ba84..f71f64a 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -71,11 +71,19 @@ void Span::poll() { } if(!isInitialized){ - - if(logLevel>0 || nFatalErrors>0){ - Serial.print(configLog); - Serial.print("\n*** End Config Log ***\n"); + + if(!homeSpan.Accessories.empty()){ + + if(!homeSpan.Accessories.back()->Services.empty()) + homeSpan.Accessories.back()->Services.back()->validate(); + + homeSpan.Accessories.back()->validate(); } + + Serial.print(configLog); + Serial.print("\nConfigured as Bridge: "); + Serial.print(homeSpan.isBridge?"YES":"NO"); + Serial.print("\n\n*** End Config Log ***\n"); if(nFatalErrors>0){ Serial.print("\n*** PROGRAM HALTED DUE TO "); @@ -1006,6 +1014,14 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){ /////////////////////////////// SpanAccessory::SpanAccessory(){ + + if(!homeSpan.Accessories.empty()){ + + if(!homeSpan.Accessories.back()->Services.empty()) + homeSpan.Accessories.back()->Services.back()->validate(); + + homeSpan.Accessories.back()->validate(); + } homeSpan.Accessories.push_back(this); aid=homeSpan.Accessories.size(); @@ -1015,6 +1031,35 @@ SpanAccessory::SpanAccessory(){ /////////////////////////////// +void SpanAccessory::validate(){ + + boolean foundInfo=false; + boolean foundProtocol=false; + + for(int i=0;itype,"3E")) + foundInfo=true; + else if(!strcmp(Services[i]->type,"A2")) + foundProtocol=true; + else if(aid==1) // this is the first Accessory and it has more than just AccessoryInfo and HAPProtocolInformation + homeSpan.isBridge=false; // this is not a bridge device + } + + if(!foundInfo){ + homeSpan.configLog+=" !Service AccessoryInformation"; + homeSpan.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n"; + homeSpan.nFatalErrors++; + } + + if(!foundProtocol && (aid==1 || !homeSpan.isBridge)){ // HAPProtocolInformation must always be present in first Accessory, and any other Accessory is the device is not a bridge) + homeSpan.configLog+=" !Service HAPProtocolInformation"; + homeSpan.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n"; + homeSpan.nFatalErrors++; + } +} + +/////////////////////////////// + int SpanAccessory::sprintfAttributes(char *cBuf){ int nBytes=0; @@ -1037,6 +1082,9 @@ int SpanAccessory::sprintfAttributes(char *cBuf){ SpanService::SpanService(const char *type, const char *hapName){ + if(!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; @@ -1093,6 +1141,23 @@ int SpanService::sprintfAttributes(char *cBuf){ return(nBytes); } +/////////////////////////////// + +void SpanService::validate(){ + + for(int i=0;iid,Characteristics[j]->type); + + if(!valid){ + homeSpan.configLog+=" !Characteristic " + String(req[i]->name); + homeSpan.configLog+=" *** ERROR! Required Characteristic for this Service not found. ***\n"; + homeSpan.nFatalErrors++; + } + } +} + /////////////////////////////// // SpanCharacteristic // /////////////////////////////// @@ -1110,7 +1175,7 @@ SpanCharacteristic::SpanCharacteristic(char *type, uint8_t perms, char *hapName) return; } - char valid=false; + boolean valid=false; for(int i=0; !valid && iServices.back()->req.size(); i++) valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->id); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 5acf320..9b3afc6 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -56,6 +56,7 @@ struct Span{ boolean isInitialized=false; // flag indicating HomeSpan has been initialized int nFatalErrors=0; // number of fatal errors in user-defined configuration String configLog="\n*** Config Log ***\n\n"; // log of configuration process, including any errors + boolean isBridge=true; // flag indicating whether device is configured as a bridge (i.e. first Accessory contains nothing but AccessoryInformation and HAPProtocolInformation) char *defaultSetupCode=DEFAULT_SETUP_CODE; // Setup Code used for pairing uint8_t statusPin=DEFAULT_STATUS_PIN; // pin for status LED @@ -121,6 +122,7 @@ struct SpanAccessory{ SpanAccessory(); int sprintfAttributes(char *cBuf); // prints Accessory JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator, even if buf=NULL + void validate(); // error-checks Accessory }; /////////////////////////////// @@ -142,6 +144,8 @@ struct SpanService{ SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self 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 virtual void button(int pin, boolean isLong){} // method called for a Service when a button attached to "pin" has a Short-Press or Long-Press, according to "isLong"