diff --git a/src/HAP.cpp b/src/HAP.cpp index 86d50ec..bad8448 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -40,11 +40,9 @@ void HAPClient::init(){ nvs_open("SRP",NVS_READWRITE,&srpNVS); // open SRP data namespace in NVS nvs_open("HAP",NVS_READWRITE,&hapNVS); // open HAP data namespace in NVS - nvs_open("OTA",NVS_READWRITE,&otaNVS); // open OTA data namespace in NVS - nvs_open("STATE",NVS_READWRITE,&stateNVS); // open STATE data namespace in NVS - if(!nvs_get_str(otaNVS,"OTADATA",NULL,&len)){ // if found OTA data in NVS - nvs_get_str(otaNVS,"OTADATA",homeSpan.spanOTA.otaPwd,&len); // retrieve data + if(!nvs_get_str(homeSpan.otaNVS,"OTADATA",NULL,&len)){ // if found OTA data in NVS + nvs_get_str(homeSpan.otaNVS,"OTADATA",homeSpan.spanOTA.otaPwd,&len); // retrieve data } else { MD5Builder otaPwdHash; otaPwdHash.begin(); @@ -1750,8 +1748,6 @@ void Nonce::inc(){ TLV HAPClient::tlv8; nvs_handle HAPClient::hapNVS; nvs_handle HAPClient::srpNVS; -nvs_handle HAPClient::otaNVS; -nvs_handle HAPClient::stateNVS; uint8_t HAPClient::httpBuf[MAX_HTTP+1]; HKDF HAPClient::hkdf; pairState HAPClient::pairStatus; diff --git a/src/HAP.h b/src/HAP.h index 2f35b47..707f438 100644 --- a/src/HAP.h +++ b/src/HAP.h @@ -80,8 +80,6 @@ struct HAPClient { static TLV tlv8; // TLV8 structure (HAP Section 14.1) with space for 10 TLV records of type kTLVType (HAP Table 5-6) static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data static nvs_handle srpNVS; // handle for non-volatile-storage of SRP data - static nvs_handle otaNVS; // handle for non-volatile-storage of OTA data - static nvs_handle stateNVS; // handle for non-volatile-storage of HomeSpan STATE data static uint8_t httpBuf[MAX_HTTP+1]; // buffer to store HTTP messages (+1 to leave room for storing an extra 'overflow' character) static HKDF hkdf; // generates (and stores) HKDF-SHA-512 32-byte keys derived from an inputKey of arbitrary length, a salt string, and an info string static pairState pairStatus; // tracks pair-setup status diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index cff9a12..7c4340f 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -74,6 +74,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa nvs_flash_init(); // initialize non-volatile-storage partition in flash nvs_open("CHAR",NVS_READWRITE,&charNVS); // open Characteristic data namespace in NVS nvs_open("WIFI",NVS_READWRITE,&wifiNVS); // open WIFI data namespace in NVS + nvs_open("OTA",NVS_READWRITE,&otaNVS); // open OTA data namespace in NVS size_t len; @@ -136,9 +137,18 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(" "); Serial.print(__TIME__); + uint8_t prevSHA[32]={0}; + uint8_t sha256[32]; + if(!nvs_get_blob(otaNVS,"SHA256",NULL,&len)) // get previous app SHA256 (if it exists) + nvs_get_blob(otaNVS,"SHA256",prevSHA,&len); + esp_partition_get_sha256(esp_ota_get_running_partition(),sha256); // get current app SHA256 + newCode=(memcmp(prevSHA,sha256,32)!=0); // set newCode flag based on comparison of previous and current SHA256 values + nvs_set_blob(otaNVS,"SHA256",sha256,sizeof(sha256)); // save current SHA256 + nvs_commit(otaNVS); + esp_ota_img_states_t otaState; esp_ota_get_state_partition(esp_ota_get_running_partition(),&otaState); - Serial.printf("\nPartition: %s (%X)",esp_ota_get_running_partition()->label,otaState); + Serial.printf("\nPartition: %s (%s-0x%0X)",esp_ota_get_running_partition()->label,newCode?"NEW":"REBOOTED",otaState); Serial.print("\n\nDevice Name: "); Serial.print(displayName); @@ -521,6 +531,45 @@ void Span::checkConnect(){ mbedtls_base64_encode((uint8_t *)setupHash,9,&len,hashOutput,4); // Step 3: Encode the first 4 bytes of hashOutput in base64, which results in an 8-character, null-terminated, setupHash mdns_service_txt_item_set("_hap","_tcp","sh",setupHash); // Step 4: broadcast the resulting Setup Hash + int otaStatus=SpanOTA::OTA_OPTIONAL; + nvs_get_i32(otaNVS,"OTASTATUS",&otaStatus); + + Serial.printf("*** OTA STATUS: %d ***\n\r",otaStatus); + + if(otaStatus==SpanOTA::OTA_REQUIRED){ // most recent reboot was a result of new code being downloaded via OTA + spanOTA.enabled=true; // must enable OTA even if it is not set + Serial.printf("AUTO-ENABLING OTA-1\n\r"); + nvs_set_i32(otaNVS,"OTASTATUS",SpanOTA::OTA_MAINTAIN); // reset flag to OTA_MAINTAIN + + } // OTA_REQUIRED + + else if(otaStatus==SpanOTA::OTA_MAINTAIN){ // most recent reboot was NOT a direct result of new code being downloaded via OTA + if(!newCode){ // codebase has not changed - this is just a reboot of code previously downloaded via OTA + spanOTA.enabled=true; // must enable OTA even if it is not set + Serial.printf("AUTO-ENABLING OTA-2\n\r"); + } else { // codebase has changed, but was NOT a result of an OTA update (must be serial download) + Serial.printf("SKIPPING OTA\n\r"); + nvs_set_i32(otaNVS,"OTASTATUS",SpanOTA::OTA_OPTIONAL); // reset flag to OTA_OPTIONAL + } + } // OTA_MAINTAIN + + nvs_commit(otaNVS); + + Serial.printf("\n\rRESET REASON=%d\n\r",esp_reset_reason()); + +// for(int i=0;i<32;i++) +// Serial.printf("%02X",prevSHA[i]); +// Serial.printf("\n"); +// +// for(int i=0;i<32;i++) +// Serial.printf("%02X",sha256[i]); +// Serial.printf("\n"); +// +// if(memcmp(prevSHA,sha256,32)) +// Serial.printf("SHAs are DIFFERENT\n"); +// else +// Serial.printf("SHAs do MATCH\n"); + if(spanOTA.enabled){ if(esp_ota_get_running_partition()!=esp_ota_get_next_update_partition(NULL)){ ArduinoOTA.setHostname(hostName); @@ -696,8 +745,8 @@ void Span::processSerialCommand(const char *c){ otaPwdHash.add(textPwd); otaPwdHash.calculate(); otaPwdHash.getChars(spanOTA.otaPwd); - nvs_set_str(HAPClient::otaNVS,"OTADATA",spanOTA.otaPwd); // update data - nvs_commit(HAPClient::otaNVS); + nvs_set_str(otaNVS,"OTADATA",spanOTA.otaPwd); // update data + nvs_commit(otaNVS); Serial.print("... Accepted! Password change will take effect after next restart.\n"); if(!spanOTA.enabled) @@ -865,7 +914,9 @@ void Span::processSerialCommand(const char *c){ nvs_erase_all(wifiNVS); nvs_commit(wifiNVS); nvs_erase_all(charNVS); - nvs_commit(charNVS); + nvs_commit(charNVS); + nvs_erase_all(otaNVS); + nvs_commit(otaNVS); Serial.print("\n*** FACTORY RESET! Restarting...\n\n"); delay(1000); ESP.restart(); @@ -1995,8 +2046,11 @@ void SpanOTA::start(){ /////////////////////////////// void SpanOTA::end(){ + nvs_set_i32(homeSpan.otaNVS,"OTASTATUS",OTA_REQUIRED); + nvs_commit(homeSpan.otaNVS); Serial.printf(" DONE! Rebooting...\n"); homeSpan.statusLED.off(); + delay(100); // make sure commit it finished before reboot } /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 8cc3179..7046bdb 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -128,6 +128,12 @@ struct SpanWebLog{ // optional web status/log data /////////////////////////////// struct SpanOTA{ // manages OTA process + enum { // keep track of whether OTA need to be required based on prior download + OTA_OPTIONAL, + OTA_MAINTAIN, + OTA_REQUIRED + }; + boolean enabled=false; // enables OTA - default if not enabled boolean auth; // indicates whether OTA password is required char otaPwd[33]; // MD5 Hash of OTA password, represented as a string of hexidecimal characters @@ -160,8 +166,10 @@ struct Span{ const char *sketchVersion="n/a"; // version of the sketch nvs_handle charNVS; // handle for non-volatile-storage of Characteristics data nvs_handle wifiNVS=0; // handle for non-volatile-storage of WiFi data + nvs_handle otaNVS; // handle for non-volatile storaget of OTA data char pairingCodeCommand[12]=""; // user-specified Pairing Code - only needed if Pairing Setup Code is specified in sketch using setPairingCode() String lastClientIP="0.0.0.0"; // IP address of last client accessing device through encrypted channel + boolean newCode; // flag indicating new application code has been loaded (based on keeping track of app SHA256) boolean connected=false; // WiFi connection status unsigned long waitTime=60000; // time to wait (in milliseconds) between WiFi connection attempts diff --git a/src/src.ino b/src/src.ino index 8ac2f66..58c5dae 100644 --- a/src/src.ino +++ b/src/src.ino @@ -21,7 +21,7 @@ void setup() { homeSpan.setPortNum(1201); // homeSpan.setMaxConnections(6); // homeSpan.setQRID("One1"); - homeSpan.enableOTA(); +// homeSpan.enableOTA(false); homeSpan.setSketchVersion("OTA Test 5"); homeSpan.setWifiCallback(wifiEstablished);