From 7546350775d6c5bceae0b6aaa3429a420f968045 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 6 May 2022 17:04:15 -0500 Subject: [PATCH] Added "C" CLI command and updated/fixed config number logic The "C" command computes a hash of the current database config and updates the config number if needed. If config number has changed, the MDNS "c#" record is updated and the new config number is rebroadcast. This triggers HomeKit to immediately request an update of the HAP database so that the changes can be shortly reflected in the Home App without the need to close any Client connections or reboot the device. The config number logic has also been updated/fixed. Previously it would create a hash from the full HAP database, which includes the value of each characteristic. Thus, initial value changes of Characteristics, as a result of stored values in NVS, would cause an update to the config number upon reboot. This is not problematic, but also not intended, as a change in value is not really a change in the database config. The new logic computes a hash of the database that EXCLUDES all Characteristic values. --- src/HAP.cpp | 26 +++----------------------- src/HomeSpan.cpp | 46 +++++++++++++++++++++++++++++++++++++++------- src/HomeSpan.h | 1 + 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 3001c64..9599503 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -142,34 +142,14 @@ void HAPClient::init(){ nvs_get_blob(hapNVS,"HAPHASH",&homeSpan.hapConfig,&len); // retrieve data } else { Serial.print("Resetting Accessory Configuration number...\n"); - nvs_set_blob(hapNVS,"HAPHASH",&homeSpan.hapConfig,sizeof(homeSpan.hapConfig)); // update data + nvs_set_blob(hapNVS,"HAPHASH",&homeSpan.hapConfig,sizeof(homeSpan.hapConfig)); // save data (will default to all zero values, which will then be updated below) nvs_commit(hapNVS); // commit to NVS } Serial.print("\n"); - uint8_t tHash[48]; - TempBuffer tBuf(homeSpan.sprintfAttributes(NULL,GET_META|GET_PERMS|GET_TYPE|GET_DESC)+1); - homeSpan.sprintfAttributes(tBuf.buf,GET_META|GET_PERMS|GET_TYPE|GET_DESC); - mbedtls_sha512_ret((uint8_t *)tBuf.buf,tBuf.len(),tHash,1); // create SHA-384 hash of JSON (can be any hash - just looking for a unique key) - - if(memcmp(tHash,homeSpan.hapConfig.hashCode,48)){ // if hash code of current HAP database does not match stored hash code - memcpy(homeSpan.hapConfig.hashCode,tHash,48); // update stored hash code - homeSpan.hapConfig.configNumber++; // increment configuration number - if(homeSpan.hapConfig.configNumber==65536) // reached max value - homeSpan.hapConfig.configNumber=1; // reset to 1 - - Serial.print("Accessory configuration has changed. Updating configuration number to "); - Serial.print(homeSpan.hapConfig.configNumber); - Serial.print("\n\n"); - nvs_set_blob(hapNVS,"HAPHASH",&homeSpan.hapConfig,sizeof(homeSpan.hapConfig)); // update data - nvs_commit(hapNVS); // commit to NVS - } else { - Serial.print("Accessory configuration number: "); - Serial.print(homeSpan.hapConfig.configNumber); - Serial.print("\n\n"); - } - + homeSpan.updateConfigNum(); + for(int i=0;iServices.size();j++){ SpanService *s=homeSpan.Accessories[i]->Services[j]; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 0b611d4..2b16a58 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -899,14 +899,13 @@ void Span::processSerialCommand(const char *c){ } break; - case 'C': { - char cNum[16]; - sprintf(cNum,"%d",++hapConfig.configNumber); - mdns_service_txt_item_set("_hap","_tcp","c#",cNum); // Accessory Current Configuration Number (updated whenever config of HAP Accessory Attribute Database is updated) - - Serial.printf("\n*** Configuration number updated to: %d\n\n",hapConfig.configNumber); + if(updateConfigNum()){ // if config number changed, update MDNS record + char cNum[16]; + sprintf(cNum,"%d",hapConfig.configNumber); + mdns_service_txt_item_set("_hap","_tcp","c#",cNum); + } } break; @@ -1055,7 +1054,8 @@ void Span::processSerialCommand(const char *c){ Serial.print(" S - change the HomeKit Pairing Setup Code to \n"); Serial.print(" Q - change the HomeKit Setup ID for QR Codes to \n"); Serial.print(" O - change the OTA password\n"); - Serial.print(" A - start the HomeSpan Setup Access Point\n"); + Serial.print(" A - start the HomeSpan Setup Access Point\n"); + Serial.print(" C - update database configuration number\n"); Serial.print("\n"); Serial.print(" V - delete value settings for all saved Characteristics\n"); Serial.print(" U - unpair device by deleting all Controller data\n"); @@ -1459,6 +1459,38 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){ return(nChars); } +/////////////////////////////// + +boolean Span::updateConfigNum(){ + + uint8_t tHash[48]; + TempBuffer tBuf(sprintfAttributes(NULL,GET_META|GET_PERMS|GET_TYPE|GET_DESC)+1); + sprintfAttributes(tBuf.buf,GET_META|GET_PERMS|GET_TYPE|GET_DESC); + mbedtls_sha512_ret((uint8_t *)tBuf.buf,tBuf.len(),tHash,1); // create SHA-384 hash of JSON (can be any hash - just looking for a unique key) + + boolean changed=false; + + if(memcmp(tHash,hapConfig.hashCode,48)){ // if hash code of current HAP database does not match stored hash code + memcpy(hapConfig.hashCode,tHash,48); // update stored hash code + hapConfig.configNumber++; // increment configuration number + if(hapConfig.configNumber==65536) // reached max value + hapConfig.configNumber=1; // reset to 1 + + Serial.print("Accessory configuration has changed. Updating configuration number to "); + Serial.print(hapConfig.configNumber); + Serial.print("\n\n"); + nvs_set_blob(HAPClient::hapNVS,"HAPHASH",&hapConfig,sizeof(hapConfig)); // update data + nvs_commit(HAPClient::hapNVS); // commit to NVS + changed=true; + } else { + Serial.print("Accessory configuration number: "); + Serial.print(hapConfig.configNumber); + Serial.print("\n\n"); + } + + return(changed); +} + /////////////////////////////// // SpanAccessory // /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index cc364ae..2a8ead2 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -214,6 +214,7 @@ struct Span{ void checkConnect(); // check WiFi connection; connect if needed void commandMode(); // allows user to control and reset HomeSpan settings with the control button void processSerialCommand(const char *c); // process command 'c' (typically from readSerial, though can be called with any 'c') + boolean updateConfigNum(); // updates HAP configuration number (MDNS 'c#' record) if hash of current config database is different from previously-stored hash; returns true if config number changed int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator