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.
This commit is contained in:
Gregg 2020-10-28 19:48:53 -05:00
parent 254406c802
commit c7f762da5f
2 changed files with 74 additions and 5 deletions

View File

@ -71,11 +71,19 @@ void Span::poll() {
} }
if(!isInitialized){ if(!isInitialized){
if(logLevel>0 || nFatalErrors>0){ if(!homeSpan.Accessories.empty()){
Serial.print(configLog);
Serial.print("\n*** End Config Log ***\n"); 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){ if(nFatalErrors>0){
Serial.print("\n*** PROGRAM HALTED DUE TO "); Serial.print("\n*** PROGRAM HALTED DUE TO ");
@ -1006,6 +1014,14 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){
/////////////////////////////// ///////////////////////////////
SpanAccessory::SpanAccessory(){ 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); homeSpan.Accessories.push_back(this);
aid=homeSpan.Accessories.size(); aid=homeSpan.Accessories.size();
@ -1015,6 +1031,35 @@ SpanAccessory::SpanAccessory(){
/////////////////////////////// ///////////////////////////////
void SpanAccessory::validate(){
boolean foundInfo=false;
boolean foundProtocol=false;
for(int i=0;i<Services.size();i++){
if(!strcmp(Services[i]->type,"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 SpanAccessory::sprintfAttributes(char *cBuf){
int nBytes=0; int nBytes=0;
@ -1037,6 +1082,9 @@ int SpanAccessory::sprintfAttributes(char *cBuf){
SpanService::SpanService(const char *type, const char *hapName){ 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->type=type;
this->hapName=hapName; this->hapName=hapName;
@ -1093,6 +1141,23 @@ int SpanService::sprintfAttributes(char *cBuf){
return(nBytes); return(nBytes);
} }
///////////////////////////////
void SpanService::validate(){
for(int i=0;i<req.size();i++){
boolean valid=false;
for(int j=0;!valid && j<Characteristics.size();j++)
valid=!strcmp(req[i]->id,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 // // SpanCharacteristic //
/////////////////////////////// ///////////////////////////////
@ -1110,7 +1175,7 @@ SpanCharacteristic::SpanCharacteristic(char *type, uint8_t perms, char *hapName)
return; return;
} }
char valid=false; boolean valid=false;
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]->id); valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->id);

View File

@ -56,6 +56,7 @@ struct Span{
boolean isInitialized=false; // flag indicating HomeSpan has been initialized boolean isInitialized=false; // flag indicating HomeSpan has been initialized
int nFatalErrors=0; // number of fatal errors in user-defined configuration 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 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 char *defaultSetupCode=DEFAULT_SETUP_CODE; // Setup Code used for pairing
uint8_t statusPin=DEFAULT_STATUS_PIN; // pin for status LED uint8_t statusPin=DEFAULT_STATUS_PIN; // pin for status LED
@ -121,6 +122,7 @@ struct SpanAccessory{
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 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 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 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 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 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" 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"