From 03e43e0bbb379644a5986f98d6e2a7689a550204 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 31 Jan 2021 18:58:45 -0600 Subject: [PATCH 01/55] Added 'Q' command to change default Setup ID and store in NVS Setup ID can now be stored in NVS and set dynamically with the 'Q' command. However, homeSpan.setQRID(char *id) will override if present, but will not change the default stored in the NVS. This default wil be used once again if homeSpan.setQRID() is removed from the sektch. If the NVS is empty, the default is set to "HSPN" as in version 1.1.4. --- src/HAP.cpp | 8 ++++++++ src/HomeSpan.cpp | 25 ++++++++++++++++++++++++- src/HomeSpan.h | 2 +- src/src.ino | 2 +- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 09c74b8..2fd8b05 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -67,6 +67,14 @@ void HAPClient::init(){ Serial.print(homeSpan.qrCode.get(atoi(homeSpan.defaultSetupCode),homeSpan.qrID,atoi(homeSpan.category))); Serial.print("\n\n"); } + + if(!strlen(homeSpan.qrID)){ // Setup ID has not been specified in sketch + if(!nvs_get_str(hapNVS,"SETUPID",NULL,&len)){ // check for saved value + nvs_get_str(hapNVS,"SETUPID",homeSpan.qrID,&len); // retrieve data + } else { + sprintf(homeSpan.qrID,"%s",DEFAULT_QR_ID); // use default + } + } if(!nvs_get_blob(hapNVS,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS nvs_get_blob(hapNVS,"ACCESSORY",&accessory,&len); // retrieve data diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 7f106d2..1267e84 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -385,6 +385,8 @@ void Span::checkConnect(){ Serial.print(displayName); Serial.print("\nModel Name: "); Serial.print(modelName); + Serial.print("\nSetup ID: "); + Serial.print(qrID); Serial.print("\n"); MDNS.begin(hostName); // set server host name (.local implied) @@ -443,7 +445,7 @@ void Span::setQRID(const char *id){ sscanf(id,"%4[0-9A-Za-z]",tBuf); if(strlen(id)==4 && strlen(tBuf)==4){ - qrID=id; + sprintf(qrID,"%s",id); } } // setQRID @@ -513,6 +515,26 @@ void Span::processSerialCommand(const char *c){ } break; + case 'Q': { + char tBuf[5]; + const char *s=c+1+strspn(c+1," "); + sscanf(s," %4[0-9A-Za-z]",tBuf); + + if(strlen(s)==4 && strlen(tBuf)==4){ + sprintf(qrID,"%s",tBuf); + Serial.print("\n\nChanging default Setup ID for QR Code to : '"); + Serial.print(qrID); + Serial.print("'. Will take effect after next restart.\n\n"); + nvs_set_str(HAPClient::hapNVS,"SETUPID",qrID); // update data + nvs_commit(HAPClient::hapNVS); + } else { + Serial.print("\n*** Invalid request to change Setup ID for QR Code to: '"); + Serial.print(s); + Serial.print("'. Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z).\n\n"); + } + } + break; + case 'S': { char buf[128]; @@ -725,6 +747,7 @@ void Span::processSerialCommand(const char *c){ Serial.print(" W - configure WiFi Credentials and restart\n"); Serial.print(" X - delete WiFi Credentials and restart\n"); 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(" A - start the HomeSpan Setup Access Point\n"); Serial.print("\n"); Serial.print(" U - unpair device by deleting all Controller data\n"); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 281ee36..5960bb0 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -99,7 +99,7 @@ struct Span{ uint8_t maxConnections=DEFAULT_MAX_CONNECTIONS; // number of simultaneous HAP connections unsigned long comModeLife=DEFAULT_COMMAND_TIMEOUT*1000; // length of time (in milliseconds) to keep Command Mode alive before resuming normal operations uint16_t tcpPortNum=DEFAULT_TCP_PORT; // port for TCP communications between HomeKit and HomeSpan - const char *qrID=DEFAULT_QR_ID; // optional Setup ID used to pair with QR Code + char qrID[5]=""; // Setup ID used for pairing with QR Code WiFiServer *hapServer; // pointer to the HAP Server connection Blinker statusLED; // indicates HomeSpan status diff --git a/src/src.ino b/src/src.ino index b60eb48..635b658 100644 --- a/src/src.ino +++ b/src/src.ino @@ -12,7 +12,7 @@ void setup() { homeSpan.setHostNameSuffix(""); homeSpan.setPortNum(1200); - homeSpan.setQRID("One1"); +// homeSpan.setQRID("One1"); homeSpan.begin(Category::Lighting,"HomeSpanTest"); From 170f972d3b37d62e4ebdeaa84a23066eda6178b2 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 6 Feb 2021 16:29:55 -0600 Subject: [PATCH 02/55] Fixed bug in pairing logic that would drop leading zeros when transmitting SALT A 16-byte SALT with a leading zero would be sent as only a 15-byte number. The chance of this occuring is 1 in 256, which is small but still significant. Solution is to specify required size of MPI output in loadTLV. This forces mbedtls_mpi_write_binary() to pad with leading zeros. Also eliminated unused code (TLV pack_old). --- src/HAP.cpp | 6 +++--- src/SRP.cpp | 3 +-- src/SRP.h | 5 +++-- src/TLV.h | 24 ------------------------ src/src.ino | 2 +- 5 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 2fd8b05..32c854d 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -451,8 +451,8 @@ int HAPClient::postPairSetupURL(){ tlv8.clear(); tlv8.val(kTLVType_State,pairState_M2); // set State= srp.createPublicKey(); // create accessory public key from random Pair-Setup code (displayed to user) - srp.loadTLV(kTLVType_PublicKey,&srp.B); // load server public key, B - srp.loadTLV(kTLVType_Salt,&srp.s); // load salt, s + srp.loadTLV(kTLVType_PublicKey,&srp.B,384); // load server public key, B + srp.loadTLV(kTLVType_Salt,&srp.s,16); // load salt, s tlvRespond(); // send response to client pairStatus=pairState_M3; // set next expected pair-state request from client @@ -489,7 +489,7 @@ int HAPClient::postPairSetupURL(){ srp.createProof(); // M1 has been successully verified; now create accessory proof M2 tlv8.clear(); // clear TLV records tlv8.val(kTLVType_State,pairState_M4); // set State= - srp.loadTLV(kTLVType_Proof,&srp.M2); // load M2 counter-proof + srp.loadTLV(kTLVType_Proof,&srp.M2,64); // load M2 counter-proof tlvRespond(); // send response to client pairStatus=pairState_M5; // set next expected pair-state request from client diff --git a/src/SRP.cpp b/src/SRP.cpp index adce154..d18259a 100644 --- a/src/SRP.cpp +++ b/src/SRP.cpp @@ -238,9 +238,8 @@ void SRP6A::createProof(){ ////////////////////////////////////// -int SRP6A::loadTLV(kTLVType tag, mbedtls_mpi *mpi){ +int SRP6A::loadTLV(kTLVType tag, mbedtls_mpi *mpi, int nBytes){ - int nBytes=mbedtls_mpi_size(mpi); uint8_t *buf=HAPClient::tlv8.buf(tag,nBytes); if(!buf) diff --git a/src/SRP.h b/src/SRP.h index d5f1066..01c5f47 100644 --- a/src/SRP.h +++ b/src/SRP.h @@ -81,8 +81,9 @@ struct SRP6A { void createPublicKey(); // computes x, v, and B from random s, P, and b void createSessionKey(); // computes u from A and B, and then S from A, v, u, and b - int loadTLV(kTLVType tag, mbedtls_mpi *mpi); // load binary contents of mpi into a TLV record and set its length - int writeTLV(kTLVType tag, mbedtls_mpi *mpi); // write binary contents of a TLV record into an mpi + int loadTLV(kTLVType tag, mbedtls_mpi *mpi, int nBytes); // load binary contents of mpi into a TLV record and set its length + int writeTLV(kTLVType tag, mbedtls_mpi *mpi); // write binary contents of a TLV record into an mpi + int verifyProof(); // verify M1 SRP6A Proof received from HAP client (return 1 on success, 0 on failure) void createProof(); // create M2 server-side SRP6A Proof based on M1 as received from HAP Client diff --git a/src/TLV.h b/src/TLV.h index ce11cde..30ddb67 100644 --- a/src/TLV.h +++ b/src/TLV.h @@ -215,30 +215,6 @@ void TLV::print(){ } // loop over all TLVs } -////////////////////////////////////// -// TLV pack_old(buf) - -template -int TLV::pack_old(uint8_t *buf){ - - int n=0; - - for(int i=0;i0){ - *buf++=tlv[i].tag; - *buf++=tlv[i].len; - memcpy(buf,tlv[i].val,tlv[i].len); - buf+=tlv[i].len; - n+=tlv[i].len+2; - } // len>0 - - } // loop over all TLVs - -return(n); - -} - ////////////////////////////////////// // TLV pack(tlvBuf) diff --git a/src/src.ino b/src/src.ino index 635b658..54b38c0 100644 --- a/src/src.ino +++ b/src/src.ino @@ -8,7 +8,7 @@ void setup() { Serial.begin(115200); - homeSpan.setLogLevel(1); + homeSpan.setLogLevel(2); homeSpan.setHostNameSuffix(""); homeSpan.setPortNum(1200); From 208905419c5398c57b013e6556cdba3f02cdbe2f Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 6 Feb 2021 18:10:48 -0600 Subject: [PATCH 03/55] Added OTA logic - enable with homeSpan.enableOTA(); TO DO: Add password for OTA (and require it) --- src/HomeSpan.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/HomeSpan.h | 2 ++ src/Settings.h | 1 + src/src.ino | 4 +++- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 1267e84..d3b300d 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "HomeSpan.h" #include "HAP.h" @@ -207,6 +208,9 @@ void Span::poll() { HAPClient::checkNotifications(); HAPClient::checkTimedWrites(); + if(otaEnabled) + ArduinoOTA.handle(); + if(controlButton.primed()){ statusLED.start(LED_ALERT); } @@ -425,9 +429,48 @@ void Span::checkConnect(){ Serial.print("\nStarting Web (HTTP) Server supporting up to "); Serial.print(maxConnections); - Serial.print(" simultaneous connections...\n\n"); + Serial.print(" simultaneous connections...\n"); hapServer->begin(); + if(otaEnabled){ + ArduinoOTA.setHostname(hostName); + + ArduinoOTA + .onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + Serial.println("\n*** OTA Starting:" + type); + homeSpan.statusLED.start(LED_OTA_STARTED); + }) + .onEnd([]() { + Serial.println("\n*** OTA Completed. Rebooting..."); + homeSpan.statusLED.off(); + }) + .onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("*** Progress: %u%%\r", (progress / (total / 100))); + }) + .onError([](ota_error_t error) { + Serial.printf("*** OTA Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed\n"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed\n"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed\n"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed\n"); + else if (error == OTA_END_ERROR) Serial.println("End Failed\n"); + }); + + ArduinoOTA.begin(); + Serial.print("Starting OTA: "); + Serial.print(displayName); + Serial.print(" at "); + Serial.print(WiFi.localIP()); + Serial.print("\n"); + } + + Serial.print("\n"); + if(!HAPClient::nAdminControllers()){ Serial.print("DEVICE NOT YET PAIRED -- PLEASE PAIR WITH HOMEKIT APP\n\n"); statusLED.start(LED_PAIRING_NEEDED); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 5960bb0..7a8777f 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -100,6 +100,7 @@ struct Span{ unsigned long comModeLife=DEFAULT_COMMAND_TIMEOUT*1000; // length of time (in milliseconds) to keep Command Mode alive before resuming normal operations uint16_t tcpPortNum=DEFAULT_TCP_PORT; // port for TCP communications between HomeKit and HomeSpan char qrID[5]=""; // Setup ID used for pairing with QR Code + boolean otaEnabled=false; // enables Over-the-Air updates WiFiServer *hapServer; // pointer to the HAP Server connection Blinker statusLED; // indicates HomeSpan status @@ -150,6 +151,7 @@ struct Span{ void setHostNameSuffix(const char *suffix){hostNameSuffix=suffix;} // sets the hostName suffix to be used instead of the 6-byte AccessoryID void setPortNum(uint16_t port){tcpPortNum=port;} // sets the TCP port number to use for communications between HomeKit and HomeSpan void setQRID(const char *id); // sets the Setup ID for optional pairing with a QR Code + void enableOTA(){otaEnabled=true;} // enables Over-the-Air updates }; /////////////////////////////// diff --git a/src/Settings.h b/src/Settings.h index 9b1ccc6..fb1417b 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -87,6 +87,7 @@ #define LED_WIFI_CONNECTING 2000 // slow flashing #define LED_AP_STARTED 100,0.5,2,300 // rapid double-blink #define LED_AP_CONNECTED 300,0.5,2,400 // medium double-blink +#define LED_OTA_STARTED 300,0.5,5,500 // rapid 5-blink ///////////////////////////////////////////////////// // Message Log Level Control Macros // diff --git a/src/src.ino b/src/src.ino index 54b38c0..d337fbf 100644 --- a/src/src.ino +++ b/src/src.ino @@ -10,9 +10,11 @@ void setup() { homeSpan.setLogLevel(2); - homeSpan.setHostNameSuffix(""); +// homeSpan.setHostNameSuffix(""); homeSpan.setPortNum(1200); + homeSpan.setMaxConnections(16); // homeSpan.setQRID("One1"); + homeSpan.enableOTA(); homeSpan.begin(Category::Lighting,"HomeSpanTest"); From 29470e4dd9bd84f5563d8de2789ee61bdf095ce0 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 7 Feb 2021 09:58:52 -0600 Subject: [PATCH 04/55] Completed OTA logic OTA pasword now stored in NVS. Use 'O' command to change from default. Note password is stored as MD5 hash, and is therefore unrecoverable. Changes to password DO NOT take effect until next reboot. Password CAN be changed even if OTA has not been enabled for sketch. Blank passwords are not allowed. Stored password can only be erased with 'E' command. --- src/HAP.cpp | 15 ++++++++++++++- src/HAP.h | 1 + src/HomeSpan.cpp | 34 +++++++++++++++++++++++++++++++--- src/HomeSpan.h | 3 ++- src/Settings.h | 5 +++-- 5 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 32c854d..c29658b 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "HAP.h" #include "HomeSpan.h" @@ -43,10 +44,21 @@ void HAPClient::init(){ nvs_open("WIFI",NVS_READWRITE,&wifiNVS); // open WIFI data namespace in NVS 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 if(!nvs_get_blob(wifiNVS,"WIFIDATA",NULL,&len)) // if found WiFi data in NVS nvs_get_blob(wifiNVS,"WIFIDATA",&homeSpan.network.wifiData,&len); // retrieve data - + + if(!nvs_get_str(otaNVS,"OTADATA",NULL,&len)){ // if found OTA data in NVS + nvs_get_str(otaNVS,"OTADATA",homeSpan.otaPwd,&len); // retrieve data + } else { + MD5Builder otaPwdHash; + otaPwdHash.begin(); + otaPwdHash.add(DEFAULT_OTA_PASSWORD); + otaPwdHash.calculate(); + otaPwdHash.getChars(homeSpan.otaPwd); + } + struct { // temporary structure to hold SRP verification code and salt stored in NVS uint8_t salt[16]; uint8_t verifyCode[384]; @@ -1643,6 +1655,7 @@ TLV HAPClient::tlv8; nvs_handle HAPClient::hapNVS; nvs_handle HAPClient::wifiNVS; nvs_handle HAPClient::srpNVS; +nvs_handle HAPClient::otaNVS; uint8_t HAPClient::httpBuf[MAX_HTTP+1]; HKDF HAPClient::hkdf; pairState HAPClient::pairStatus; diff --git a/src/HAP.h b/src/HAP.h index 9730215..070a170 100644 --- a/src/HAP.h +++ b/src/HAP.h @@ -82,6 +82,7 @@ struct HAPClient { static nvs_handle hapNVS; // handle for non-volatile-storage of HAP data static nvs_handle wifiNVS; // handle for non-volatile-storage of WiFi 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 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 d3b300d..7516093 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -434,7 +434,8 @@ void Span::checkConnect(){ if(otaEnabled){ ArduinoOTA.setHostname(hostName); - + ArduinoOTA.setPasswordHash(otaPwd); + ArduinoOTA .onStart([]() { String type; @@ -539,7 +540,7 @@ void Span::processSerialCommand(const char *c){ Serial.print("\n"); } - Serial.print("\n*** End Status ***\n"); + Serial.print("\n*** End Status ***\n\n"); } break; @@ -565,7 +566,7 @@ void Span::processSerialCommand(const char *c){ if(strlen(s)==4 && strlen(tBuf)==4){ sprintf(qrID,"%s",tBuf); - Serial.print("\n\nChanging default Setup ID for QR Code to : '"); + Serial.print("\nChanging default Setup ID for QR Code to: '"); Serial.print(qrID); Serial.print("'. Will take effect after next restart.\n\n"); nvs_set_str(HAPClient::hapNVS,"SETUPID",qrID); // update data @@ -578,6 +579,32 @@ void Span::processSerialCommand(const char *c){ } break; + case 'O': { + + char textPwd[33]="\0"; + + while(!strlen(textPwd)){ + Serial.print("\n>>> OTA Password (32 characters max): "); + readSerial(textPwd,32); + Serial.print(mask(textPwd,2)); + Serial.print("\n"); + } + + MD5Builder otaPwdHash; + otaPwdHash.begin(); + otaPwdHash.add(textPwd); + otaPwdHash.calculate(); + otaPwdHash.getChars(otaPwd); + nvs_set_str(HAPClient::otaNVS,"OTADATA",otaPwd); // update data + nvs_commit(HAPClient::otaNVS); + + Serial.print("\nPassword change will take effect after next restart.\n"); + if(!otaEnabled) + Serial.print("Note: OTA has not been enabled in this sketch.\n"); + Serial.print("\n"); + } + break; + case 'S': { char buf[128]; @@ -791,6 +818,7 @@ void Span::processSerialCommand(const char *c){ Serial.print(" X - delete WiFi Credentials and restart\n"); 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("\n"); Serial.print(" U - unpair device by deleting all Controller data\n"); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 7a8777f..c84e6eb 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -100,7 +100,8 @@ struct Span{ unsigned long comModeLife=DEFAULT_COMMAND_TIMEOUT*1000; // length of time (in milliseconds) to keep Command Mode alive before resuming normal operations uint16_t tcpPortNum=DEFAULT_TCP_PORT; // port for TCP communications between HomeKit and HomeSpan char qrID[5]=""; // Setup ID used for pairing with QR Code - boolean otaEnabled=false; // enables Over-the-Air updates + boolean otaEnabled=false; // enables Over-the-Air ("OTA") updates + char otaPwd[33]; // MD5 Hash of OTA password, represented as a string of hexidecimal characters WiFiServer *hapServer; // pointer to the HAP Server connection Blinker statusLED; // indicates HomeSpan status diff --git a/src/Settings.h b/src/Settings.h index fb1417b..8cfff31 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -66,8 +66,9 @@ #define DEFAULT_CONTROL_PIN 21 // change with homeSpan.setControlPin(pin) #define DEFAULT_STATUS_PIN 13 // change with homeSpan.setStatusPin(pin) -#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(pwd) +#define DEFAULT_AP_SSID "HomeSpan-Setup" // change with homeSpan.setApSSID(ssid) #define DEFAULT_AP_PASSWORD "homespan" // change with homeSpan.setApPassword(pwd) +#define DEFAULT_OTA_PASSWORD "homespan-ota" // change with 'O' command #define DEFAULT_AP_TIMEOUT 300 // change with homeSpan.setApTimeout(nSeconds) #define DEFAULT_COMMAND_TIMEOUT 120 // change with homeSpan.setCommandTimeout(nSeconds) @@ -87,7 +88,7 @@ #define LED_WIFI_CONNECTING 2000 // slow flashing #define LED_AP_STARTED 100,0.5,2,300 // rapid double-blink #define LED_AP_CONNECTED 300,0.5,2,400 // medium double-blink -#define LED_OTA_STARTED 300,0.5,5,500 // rapid 5-blink +#define LED_OTA_STARTED 300,0.5,3,400 // medium triple-blink ///////////////////////////////////////////////////// // Message Log Level Control Macros // From 78b7900f19a2293c4ea1275a17449afbed0c2372 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 7 Feb 2021 10:07:37 -0600 Subject: [PATCH 05/55] Added ARDUINO_VARIANT to initial info output --- src/HomeSpan.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 7516093..9fade12 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -75,6 +75,12 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(HOMESPAN_VERSION); Serial.print("\nESP-IDF Version: "); Serial.print(esp_get_idf_version()); + + #ifdef ARDUINO_VARIANT + Serial.print("\nESP32 Board: "); + Serial.print(ARDUINO_VARIANT); + #endif + Serial.print("\nSketch Compiled: "); Serial.print(__DATE__); Serial.print(" "); From db3e1c4bb8d439a5a305fc8f8537732dd82ca007 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 7 Feb 2021 11:49:55 -0600 Subject: [PATCH 06/55] Added ability to specify optional sketch version number. Specify with homeSpan.setSketchVersion(char *). Read back with homeSpan.getSketchVersion(). Also, MDNS now broadcasts three new fields: hspn = HomeSpan Version sketch = Sketch Version ota = "yes" if OTA enabled, else "no" These are all optional to HAP but useful if trying to keep track of version updates when using OTA and Serial Monitor is not available. --- src/HomeSpan.cpp | 8 +++++++- src/HomeSpan.h | 3 +++ src/src.ino | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 9fade12..f44cc35 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -70,7 +70,9 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print("\nStatus LED: Pin "); Serial.print(statusPin); Serial.print("\nDevice Control: Pin "); - Serial.print(controlPin); + Serial.print(controlPin); + Serial.print("\nSketch Version: "); + Serial.print(getSketchVersion()); Serial.print("\nHomeSpan Version: "); Serial.print(HOMESPAN_VERSION); Serial.print("\nESP-IDF Version: "); @@ -422,6 +424,10 @@ void Span::checkConnect(){ else mdns_service_txt_item_set("_hap","_tcp","sf","0"); // set Status Flag = 0 + mdns_service_txt_item_set("_hap","_tcp","hspn",HOMESPAN_VERSION); // HomeSpan Version Number (info only - NOT used by HAP) + mdns_service_txt_item_set("_hap","_tcp","sketch",sketchVersion); // Sketch Version (info only - NOT used by HAP) + mdns_service_txt_item_set("_hap","_tcp","ota",otaEnabled?"yes":"no"); // OTA Enabled (info only - NOT used by HAP) + uint8_t hashInput[22]; uint8_t hashOutput[64]; char setupHash[9]; diff --git a/src/HomeSpan.h b/src/HomeSpan.h index c84e6eb..ac11576 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -87,6 +87,7 @@ struct Span{ String configLog; // 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) HapQR qrCode; // optional QR Code to use for pairing + const char *sketchVersion="n/a"; // version of the sketch boolean connected=false; // WiFi connection status unsigned long waitTime=60000; // time to wait (in milliseconds) between WiFi connection attempts @@ -153,6 +154,8 @@ struct Span{ void setPortNum(uint16_t port){tcpPortNum=port;} // sets the TCP port number to use for communications between HomeKit and HomeSpan void setQRID(const char *id); // sets the Setup ID for optional pairing with a QR Code void enableOTA(){otaEnabled=true;} // enables Over-the-Air updates + void setSketchVersion(const char *sVer){sketchVersion=sVer;} // set optional sketch version number + const char *getSketchVersion(){return sketchVersion;} // get sketch version number }; /////////////////////////////// diff --git a/src/src.ino b/src/src.ino index d337fbf..6df17bf 100644 --- a/src/src.ino +++ b/src/src.ino @@ -15,6 +15,7 @@ void setup() { homeSpan.setMaxConnections(16); // homeSpan.setQRID("One1"); homeSpan.enableOTA(); + homeSpan.setSketchVersion("Test 1.2.3"); homeSpan.begin(Category::Lighting,"HomeSpanTest"); From 5c002708f96b847ea08e401b0b657ab27a9c3575 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 7 Feb 2021 19:25:59 -0600 Subject: [PATCH 07/55] Update version numbers --- library.properties | 2 +- src/Settings.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 4d04fdc..c155501 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HomeSpan -version=1.1.4 +version=1.1.5 author=Gregg maintainer=Gregg sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE. diff --git a/src/Settings.h b/src/Settings.h index 8cfff31..0e8d337 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -34,7 +34,7 @@ #define HS_MAJOR 1 #define HS_MINOR 1 -#define HS_PATCH 4 +#define HS_PATCH 5 #define STRINGIFY(x) _STR(x) #define _STR(x) #x From 5e4c3f5127ef33f01341dc3ed56258489c063ed9 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 20:32:38 -0600 Subject: [PATCH 08/55] Update CLI.md --- docs/CLI.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/CLI.md b/docs/CLI.md index 411b0f2..6506ed9 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -44,6 +44,10 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * **S** \ - change the HomeKit Pairing Setup Code to \ * Every HomeKit device requires a unique 8-digit Setup code used for pairing. When HomeSpan is run for the first time on a new device it sets the HomeKit Setup Code to a default value of **466-37-726**, and stores it in a dedicated NVS partition. This command allows you to update the stored Setup Code to any other 8-digit code. Note that in accordance with HAP specifications, HomeSpan actually stores a hashed version of the Setup Code, rather than the Setup Code itself. This means the actual value is not recoverable, so if you forget your Setup Code you'll need to run this command and create a new one. +* **Q** \ - change HomeSpan's default Pairing Setup ID to \ + * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). + * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)` (see [HomeSpan API Reference](Reference.md) for details). + * **A** - start the HomeSpan Setup Access Point * This command starts HomeSpan's temporary Access Point, which provides users with an alternate methods for configuring a device's WiFi Credentials and HomeKit Setup Code. Starting the Access Point with this command is identical to starting it via the Control Button. See the [HomeSpan User Guide](UserGuide.md) for complete details. From 8453582626215c1ae8a1e32c91d35fe306d9912b Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 20:40:50 -0600 Subject: [PATCH 09/55] Update Reference.md --- docs/Reference.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index 6f206fa..7e106c9 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -60,12 +60,13 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * `void setHostNameSuffix(const char *suffix)` * sets the suffix HomeSpan appends to *hostNameBase* to create the full hostName * if not specified, the default is for HomeSpan to append a dash "-" followed the 6-byte Accessory ID of the HomeSpan device - * setting *suffix* to a null string "" is permitted. + * setting *suffix* to a null string "" is permitted * example: `homeSpan.begin(Category::Fans, "Living Room Ceiling Fan", "LivingRoomFan");` will yield a default *hostName* of the form *LivingRoomFan-A1B2C3D4E5F6.local*. Calling `homeSpan.setHostNameSuffix("v2")` prior to `homeSpan.begin()` will instead yield a *hostName* of *LivingRoomFanv2.local* * `void setQRID(const char *ID)` - * changes the Setup ID from the HomeSpan default ("HSPN") to *ID* - * *ID* must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). If not, the request to change the Setup ID is silently ignored and remains "HSPN" + * changes the QR Setup ID from the HomeSpan default to *ID* + * the HomeSpan default is "HSPN" unless permanently changed for the device via the [HomeSpan CLI](CLI.md) using the 'Q' command + * *ID* must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). If not, the request to change the Setup ID is silently ignored and the default is used instead * The Setup ID is an optional parameter used when pairing the device to HomeKit with a QR Code (instead of the usual Setup Code) From 46ede137ee1fd050f9d639c143d921e37c1b3361 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 20:42:31 -0600 Subject: [PATCH 10/55] Update Reference.md --- docs/Reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index 7e106c9..7b55eb2 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -67,7 +67,7 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * changes the QR Setup ID from the HomeSpan default to *ID* * the HomeSpan default is "HSPN" unless permanently changed for the device via the [HomeSpan CLI](CLI.md) using the 'Q' command * *ID* must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). If not, the request to change the Setup ID is silently ignored and the default is used instead - * The Setup ID is an optional parameter used when pairing the device to HomeKit with a QR Code (instead of the usual Setup Code) + * The Setup ID is an optional parameter used only for pairing the device to HomeKit with a [QR Code](QRCodes.md) (instead of the usual Setup Code) ## *SpanAccessory(uint32_t aid)* From 64fd64a8ba08420a1085214c9b7e9bcbcf74f586 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 20:48:27 -0600 Subject: [PATCH 11/55] Update QRCodes.md --- docs/QRCodes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/QRCodes.md b/docs/QRCodes.md index 8976b44..009180d 100644 --- a/docs/QRCodes.md +++ b/docs/QRCodes.md @@ -26,7 +26,7 @@ As shown above, the Simulator's QR Code Generator requires the input of the foll * **Category**. Set this to match the Category of your HomeSpan device (e.g. Lightbulb, Fan, Door Lock). Note the Home App only uses this for display purposes when you first scan the QR Code. The Home App does not actually check that the Category listed in the QR Code matches the Category of the device you are pairing. * **Setup Flags**. These flags provide information on which methods of pairing are supported by a HomeKit device. HomeSpan only supports IP Pairing, so you check that box and leave the other two blank. However, it does not seem to matter which boxes (if any) you check since the Home App does not appear to use this information for anything. * **Setup Code**. This is the 8-digit *Setup Code* you set for your device using either the [HomeSpan Command-Line Interface (CLI)](https://github.com/HomeSpan/HomeSpan/blob/master/docs/CLI.md) or [HomeSpan's WiFi Setup Web Page](https://github.com/HomeSpan/HomeSpan/blob/master/docs/UserGuide.md#setting-homespans-wifi-credentials-and-setup-code). Note the code shown in the above screenshot is the default HomeSpan uses if you do not set your own. -* **Setup ID**. This is the 4-character *Setup ID* you set for your HomeSpan device from within your sketch using the method `homeSpan.setQRID(const char *id)`. Note the ID shown in the above screenshot is the default HomeSpan uses if you do not set your own. Also note case matters! HSPN is not the same as "hspn". +* **Setup ID**. This is the 4-character *Setup ID* you set for your HomeSpan device from within your sketch using the method `homeSpan.setQRID(const char *id)`. If you do not specify a QR Setup ID in your sketch, HomeSpan uses a default value of "HSPN" (as shown in the example above) unless you've updated the default for this device via the [CLI](CLI.md) using the 'Q' command. Note case matters! HSPN is not the same as "hspn". * **Setup Payload**. This is the output that results from the above inputs, and is the text that is represented by the QR Code shown. The Setup Payload for a HomeKit device always begins with "X-HM://", followed by 9 alphanumeric characters, and ending with the *Setup ID* in plain text. If you've not changed HomeSpan's default *Setup Code* or *Setup ID*, you can pair your device by scanning this graphic with the Home App. Even easier is to scan it right from your camera - your iPhone will recognize that this is a HomeKit QR Code and open the Home App for you. You probably noticed that the QR Code contains extra graphics, such as Apple's HomeKit logo in the upper left. This is purely cosmetic and not required by the Home App for pairing. Similarly, having the device's 8-digit *Setup Code* shown in big numerals in the upper right is also cosmetic and not needed for pairing, though it may be handy if you have problems scanning the QR Code and want to manually type the *Setup Code* into the Home App. From 9689db9773a7ec1b502a40be8ed6e92daa680f49 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 21:01:59 -0600 Subject: [PATCH 12/55] Update CLI.md --- docs/CLI.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/CLI.md b/docs/CLI.md index 6506ed9..2c3c819 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -48,6 +48,10 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)` (see [HomeSpan API Reference](Reference.md) for details). +* **O** - prompts you to set the password used for *optional* Over-the-Air (OTA) Updates + * HomeSpan supports [OTA Updates](OTA.md) but requires a password to always used. For security, HomeSpan saves a *hashed* version of the password you specify in NVS, not the actual password. If you forget the password you specified, you'll need to reset it using this command. + * If left unspecified, HomeSpan uses a "homespan-ota" as its default OTA password. + * **A** - start the HomeSpan Setup Access Point * This command starts HomeSpan's temporary Access Point, which provides users with an alternate methods for configuring a device's WiFi Credentials and HomeKit Setup Code. Starting the Access Point with this command is identical to starting it via the Control Button. See the [HomeSpan User Guide](UserGuide.md) for complete details. From c499616b34e4c1ada4f6d4a05e5f6187716ae22c Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 21:04:09 -0600 Subject: [PATCH 13/55] Update CLI.md --- docs/CLI.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 2c3c819..6f07706 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -48,9 +48,9 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)` (see [HomeSpan API Reference](Reference.md) for details). -* **O** - prompts you to set the password used for *optional* Over-the-Air (OTA) Updates - * HomeSpan supports [OTA Updates](OTA.md) but requires a password to always used. For security, HomeSpan saves a *hashed* version of the password you specify in NVS, not the actual password. If you forget the password you specified, you'll need to reset it using this command. - * If left unspecified, HomeSpan uses a "homespan-ota" as its default OTA password. +* **O** - prompts you to set the password used for Over-the-Air (OTA) Updates + * HomeSpan supports [OTA Updates](OTA.md) but requires a password to always be used. For security, HomeSpan saves a *hashed* version of the password you specify in NVS, not the actual password. If you forget the password you specified, you'll need to reset it using this command. + * If left unspecified, HomeSpan uses "homespan-ota" as its default OTA password. * **A** - start the HomeSpan Setup Access Point * This command starts HomeSpan's temporary Access Point, which provides users with an alternate methods for configuring a device's WiFi Credentials and HomeKit Setup Code. Starting the Access Point with this command is identical to starting it via the Control Button. See the [HomeSpan User Guide](UserGuide.md) for complete details. From 22c9dfd957004e633e10831c6cebbec78adefa0e Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Feb 2021 21:10:51 -0600 Subject: [PATCH 14/55] Update CLI.md --- docs/CLI.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 6f07706..5b7136e 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -46,11 +46,11 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * **Q** \ - change HomeSpan's default Pairing Setup ID to \ * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). - * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)` (see [HomeSpan API Reference](Reference.md) for details). + * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)`. See [HomeSpan API Reference](Reference.md) for details. * **O** - prompts you to set the password used for Over-the-Air (OTA) Updates * HomeSpan supports [OTA Updates](OTA.md) but requires a password to always be used. For security, HomeSpan saves a *hashed* version of the password you specify in NVS, not the actual password. If you forget the password you specified, you'll need to reset it using this command. - * If left unspecified, HomeSpan uses "homespan-ota" as its default OTA password. + * If left unspecified, HomeSpan uses "homespan-ota" as its default OTA password. * **A** - start the HomeSpan Setup Access Point * This command starts HomeSpan's temporary Access Point, which provides users with an alternate methods for configuring a device's WiFi Credentials and HomeKit Setup Code. Starting the Access Point with this command is identical to starting it via the Control Button. See the [HomeSpan User Guide](UserGuide.md) for complete details. From 7b3358af10f20e64b5f5b4a5600bd8030ff83e04 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 07:28:43 -0600 Subject: [PATCH 15/55] Update CLI.md --- docs/CLI.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 5b7136e..94420df 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -46,11 +46,13 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * **Q** \ - change HomeSpan's default Pairing Setup ID to \ * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). - * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)`. See [HomeSpan API Reference](Reference.md) for details. + * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)`. See the [HomeSpan API Reference](Reference.md) for details. * **O** - prompts you to set the password used for Over-the-Air (OTA) Updates * HomeSpan supports [OTA Updates](OTA.md) but requires a password to always be used. For security, HomeSpan saves a *hashed* version of the password you specify in NVS, not the actual password. If you forget the password you specified, you'll need to reset it using this command. - * If left unspecified, HomeSpan uses "homespan-ota" as its default OTA password. + * HomeSpan uses "homespan-ota" as its default OTA password for new devices. + * Changes to the OTA password do not take effect until the device is restarted. + * OTA is not active unless specifically enabled for a sketch using the method `homeSpan.enableOTA()`. See the [HomeSpan API Reference](Reference.md) for details. * **A** - start the HomeSpan Setup Access Point * This command starts HomeSpan's temporary Access Point, which provides users with an alternate methods for configuring a device's WiFi Credentials and HomeKit Setup Code. Starting the Access Point with this command is identical to starting it via the Control Button. See the [HomeSpan User Guide](UserGuide.md) for complete details. From d02cfe63b7c63d9fab6c60f9cec9d67e8dc2283e Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 07:46:51 -0600 Subject: [PATCH 16/55] Update Reference.md --- docs/Reference.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index 7b55eb2..3665c4c 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -63,12 +63,16 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * setting *suffix* to a null string "" is permitted * example: `homeSpan.begin(Category::Fans, "Living Room Ceiling Fan", "LivingRoomFan");` will yield a default *hostName* of the form *LivingRoomFan-A1B2C3D4E5F6.local*. Calling `homeSpan.setHostNameSuffix("v2")` prior to `homeSpan.begin()` will instead yield a *hostName* of *LivingRoomFanv2.local* -* `void setQRID(const char *ID)` - * changes the QR Setup ID from the HomeSpan default to *ID* +* `void setQRID(const char *id)` + * changes the Setup ID, which is used for pairing a device with a [QR Code](QRCodes.md), from the HomeSpan default to *id* * the HomeSpan default is "HSPN" unless permanently changed for the device via the [HomeSpan CLI](CLI.md) using the 'Q' command - * *ID* must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). If not, the request to change the Setup ID is silently ignored and the default is used instead - * The Setup ID is an optional parameter used only for pairing the device to HomeKit with a [QR Code](QRCodes.md) (instead of the usual Setup Code) + * *id* must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). If not, the request to change the Setup ID is silently ignored and the default is used instead +* `void enableOTA()` + * enables [Over-the-Air (OTA) Updating](OTA.md) of a HomeSpan device, which is otherwise disabled + * HomeSpan OTA always requires the use of an authorizing OTA password + * the default OTA password for new HomeSpan devices is "homespan-ota" + * this can be changed via the [HomeSpan CLI](CLI.md) using the 'Q' command ## *SpanAccessory(uint32_t aid)* From 36f302f01e236093b5466a4718d8c32abec7b0b7 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 07:53:02 -0600 Subject: [PATCH 17/55] Update CLI.md --- docs/CLI.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 94420df..f6a0072 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -48,8 +48,8 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)`. See the [HomeSpan API Reference](Reference.md) for details. -* **O** - prompts you to set the password used for Over-the-Air (OTA) Updates - * HomeSpan supports [OTA Updates](OTA.md) but requires a password to always be used. For security, HomeSpan saves a *hashed* version of the password you specify in NVS, not the actual password. If you forget the password you specified, you'll need to reset it using this command. +* **O** - prompts you to set the password used for Over-the-Air (OTA) Updating + * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to reset it using this command. * HomeSpan uses "homespan-ota" as its default OTA password for new devices. * Changes to the OTA password do not take effect until the device is restarted. * OTA is not active unless specifically enabled for a sketch using the method `homeSpan.enableOTA()`. See the [HomeSpan API Reference](Reference.md) for details. From dd04f9967dc6178e42b75c9830a670339df45b7e Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 07:53:56 -0600 Subject: [PATCH 18/55] Update CLI.md --- docs/CLI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index f6a0072..47bb6d5 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -42,7 +42,7 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * This command deletes whatever WiFi Credentials have been stored in the device NVS, and restarts. * **S** \ - change the HomeKit Pairing Setup Code to \ - * Every HomeKit device requires a unique 8-digit Setup code used for pairing. When HomeSpan is run for the first time on a new device it sets the HomeKit Setup Code to a default value of **466-37-726**, and stores it in a dedicated NVS partition. This command allows you to update the stored Setup Code to any other 8-digit code. Note that in accordance with HAP specifications, HomeSpan actually stores a hashed version of the Setup Code, rather than the Setup Code itself. This means the actual value is not recoverable, so if you forget your Setup Code you'll need to run this command and create a new one. + * Every HomeKit device requires a unique 8-digit Setup Code used for pairing. When HomeSpan is run for the first time on a new device it sets the HomeKit Setup Code to a default value of **466-37-726**, and stores it in a dedicated NVS partition. This command allows you to update the stored Setup Code to any other 8-digit code. Note that in accordance with HAP specifications, HomeSpan actually stores a hashed version of the Setup Code, rather than the Setup Code itself. This means the actual value is not recoverable, so if you forget your Setup Code you'll need to run this command and create a new one. * **Q** \ - change HomeSpan's default Pairing Setup ID to \ * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). From 749e239c9ff8df0fba3de4c93ba563851ae5b7ea Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 08:15:41 -0600 Subject: [PATCH 19/55] Update Reference.md --- docs/Reference.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index 3665c4c..45b2540 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -72,7 +72,16 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * enables [Over-the-Air (OTA) Updating](OTA.md) of a HomeSpan device, which is otherwise disabled * HomeSpan OTA always requires the use of an authorizing OTA password * the default OTA password for new HomeSpan devices is "homespan-ota" - * this can be changed via the [HomeSpan CLI](CLI.md) using the 'Q' command + * this can be changed via the [HomeSpan CLI](CLI.md) using the 'O' command + +* `void setSketchVersion(const char *sVer)` + * sets the version of a HomeSpan sketch to *sVer*, which can be any arbitrary character string + * if unspecified, HomeSpan uses "n/a" as the default version text + * HomeSpan displays the version of the sketch in the Arduino IDE Serial Monitor upon start-up + * HomeSpan also includes both the version of the sketch, as well as the version of the HomeSpan library used to compile the sketch, as part of its HAP MDNS broadcast. This data is *not* used by HAP. Rather, it is for informational purposes and allows you to identify the version of a sketch for a device that is updated via [OTA](OTA.md), rather than connected to a computer + +* `const char *getSketchVersion()` + * returns the version of a HomeSpan sketch, as set using `void setSketchVersion(const char *sVer)`, or "n/a" if not set ## *SpanAccessory(uint32_t aid)* From 5554bec70fe300e98899c58162f039f28ff9fa0f Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 08:24:23 -0600 Subject: [PATCH 20/55] Update CLI.md --- docs/CLI.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 47bb6d5..5b81914 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -42,14 +42,14 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * This command deletes whatever WiFi Credentials have been stored in the device NVS, and restarts. * **S** \ - change the HomeKit Pairing Setup Code to \ - * Every HomeKit device requires a unique 8-digit Setup Code used for pairing. When HomeSpan is run for the first time on a new device it sets the HomeKit Setup Code to a default value of **466-37-726**, and stores it in a dedicated NVS partition. This command allows you to update the stored Setup Code to any other 8-digit code. Note that in accordance with HAP specifications, HomeSpan actually stores a hashed version of the Setup Code, rather than the Setup Code itself. This means the actual value is not recoverable, so if you forget your Setup Code you'll need to run this command and create a new one. + * Every HomeKit device requires a unique 8-digit Setup Code used for pairing. When HomeSpan is run for the first time on a new device it sets the HomeKit Setup Code to a default value of **466-37-726**, and stores it in a dedicated NVS partition. This command allows you to update the stored Setup Code to any other 8-digit code. Note that in accordance with HAP specifications, HomeSpan actually stores a hashed version of the Setup Code, rather than the Setup Code itself. This means the actual value is not recoverable, so if you forget your Setup Code you'll need to run this command and create a new one. Alternatively, you can restore the default Setup Code by fully erasing the NVS with the 'E' command. * **Q** \ - change HomeSpan's default Pairing Setup ID to \ * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)`. See the [HomeSpan API Reference](Reference.md) for details. * **O** - prompts you to set the password used for Over-the-Air (OTA) Updating - * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to reset it using this command. + * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to create it using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. * HomeSpan uses "homespan-ota" as its default OTA password for new devices. * Changes to the OTA password do not take effect until the device is restarted. * OTA is not active unless specifically enabled for a sketch using the method `homeSpan.enableOTA()`. See the [HomeSpan API Reference](Reference.md) for details. @@ -68,7 +68,7 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * This command simply reboots HomeSpan. * **F** - factory reset and restart - * This deletes all data stored in the NVS, *except* for the HomeKit Pairing Setup Code, and restarts the device. This is effectively the same as executing the 'X' command followed by the 'H' command. + * This deletes all data stored in the NVS, *except* for the HomeKit Pairing Setup Code and OTA password, and restarts the device. This is effectively the same as executing the 'X' command followed by the 'H' command. * **E** - erase ALL stored data and restart * This completely erases the NVS, deleting all stored data, *including* the HomeKit Pairing Setup code. The device is then restarted and initialized as if it were new. From b0b2f6c753e6e719d79ad9576df035e660594e6a Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 08:33:51 -0600 Subject: [PATCH 21/55] Update CLI.md --- docs/CLI.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index 5b81914..ab163ec 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -44,9 +44,10 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * **S** \ - change the HomeKit Pairing Setup Code to \ * Every HomeKit device requires a unique 8-digit Setup Code used for pairing. When HomeSpan is run for the first time on a new device it sets the HomeKit Setup Code to a default value of **466-37-726**, and stores it in a dedicated NVS partition. This command allows you to update the stored Setup Code to any other 8-digit code. Note that in accordance with HAP specifications, HomeSpan actually stores a hashed version of the Setup Code, rather than the Setup Code itself. This means the actual value is not recoverable, so if you forget your Setup Code you'll need to run this command and create a new one. Alternatively, you can restore the default Setup Code by fully erasing the NVS with the 'E' command. -* **Q** \ - change HomeSpan's default Pairing Setup ID to \ +* **Q** \ - change HomeSpan's default QR-pairing Setup ID to \ * This command changes HomeSpan's default Setup ID, which is used when pairing with a QR Code, from the new-device value of "HSPN" to \. See [HomeSpan QR Codes](QRCodes.md) for details on how the Setup ID is used. The Setup ID must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). * Note the new Setup ID is retained in HomeSpan's NVS and used as the default for all sketches, unless a specific Setup ID is set in the sketch using the method `homeSpan.setQRID(const char *id)`. See the [HomeSpan API Reference](Reference.md) for details. + * Deleting a device's HomeKit ID and Controller data with the 'H' command (see below) also restores the default Setup ID to "HSPN". * **O** - prompts you to set the password used for Over-the-Air (OTA) Updating * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to create it using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. @@ -63,6 +64,7 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * **H** - delete HomeKit Device ID as well as all Controller data and restart * In addition to deleting all Controller data (as if the 'U' command was run), this command also deletes the device's HomeKit ID. This unique ID is broadcast to all HomeKit Controllers so the device can be uniquely recognized. When HomeSpan first runs on a new device, it creates this unique ID and stores it permanently in an NVS partition. Normally, this ID should not changed once set. However, if you are actively developing and testing a HomeSpan sketch, you may find that HomeKit is cacheing information about your device and the changes you have made to your HAP Accessory Database are not always reflected in the Home App. Sometimes simply unpairing and re-pairing the device solves this HomeKit issue. If not, deleting your device's HomeKit ID with this command forces HomeSpan to generate a new one after restarting, which means HomeKit will think this is a completely different device, thereby ignoring any prior data it had cached. + * This command also restores the device's default Setup ID, which is used for optional pairing with QR codes, to "HSPN". * **R** - restart the device * This command simply reboots HomeSpan. From 01d48e73ecccf2f04a4b869e98c7de99ae8d0b90 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 8 Feb 2021 12:33:51 -0600 Subject: [PATCH 22/55] Update CLI.md --- docs/CLI.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CLI.md b/docs/CLI.md index ab163ec..62a9504 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -50,7 +50,7 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * Deleting a device's HomeKit ID and Controller data with the 'H' command (see below) also restores the default Setup ID to "HSPN". * **O** - prompts you to set the password used for Over-the-Air (OTA) Updating - * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to create it using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. + * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to create a new one using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. * HomeSpan uses "homespan-ota" as its default OTA password for new devices. * Changes to the OTA password do not take effect until the device is restarted. * OTA is not active unless specifically enabled for a sketch using the method `homeSpan.enableOTA()`. See the [HomeSpan API Reference](Reference.md) for details. From 98cfde8aa9d112ebb807faf5ea809281654006c0 Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 8 Feb 2021 18:31:51 -0600 Subject: [PATCH 23/55] Modified 'O' command so that a blank entry cancels the request to update the OTA password --- src/HomeSpan.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index f44cc35..5426cbd 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -593,14 +593,23 @@ void Span::processSerialCommand(const char *c){ case 'O': { - char textPwd[33]="\0"; + char textPwd[34]="\0"; - while(!strlen(textPwd)){ - Serial.print("\n>>> OTA Password (32 characters max): "); - readSerial(textPwd,32); - Serial.print(mask(textPwd,2)); - Serial.print("\n"); + Serial.print("\n>>> New OTA Password, or to cancel request: "); + readSerial(textPwd,33); + + if(strlen(textPwd)==0){ + Serial.print("(cancelled)\n\n"); + return; } + + if(strlen(textPwd)==33){ + Serial.print("\n*** Sorry, 32 character limit - request cancelled\n\n"); + return; + } + + Serial.print(mask(textPwd,2)); + Serial.print("\n"); MD5Builder otaPwdHash; otaPwdHash.begin(); @@ -610,9 +619,9 @@ void Span::processSerialCommand(const char *c){ nvs_set_str(HAPClient::otaNVS,"OTADATA",otaPwd); // update data nvs_commit(HAPClient::otaNVS); - Serial.print("\nPassword change will take effect after next restart.\n"); + Serial.print("... Accepted! Password change will take effect after next restart.\n"); if(!otaEnabled) - Serial.print("Note: OTA has not been enabled in this sketch.\n"); + Serial.print("... Note: OTA has not been enabled in this sketch.\n"); Serial.print("\n"); } break; From 3a519bdc542bfd2ccc3f96f996dbb7f42f77373b Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 9 Feb 2021 21:23:37 -0600 Subject: [PATCH 24/55] Added logic to check for OTA partitions Warning will be thrown If OTA is enabled but partition table is not configured for OTA. OTA will not be started. --- src/HomeSpan.cpp | 73 ++++++++++++++++++++++++++---------------------- src/src.ino | 4 +-- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 5426cbd..41851a3 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "HomeSpan.h" #include "HAP.h" @@ -445,41 +446,45 @@ void Span::checkConnect(){ hapServer->begin(); if(otaEnabled){ - ArduinoOTA.setHostname(hostName); - ArduinoOTA.setPasswordHash(otaPwd); + if(esp_ota_get_running_partition()!=esp_ota_get_next_update_partition(NULL)){ + ArduinoOTA.setHostname(hostName); + ArduinoOTA.setPasswordHash(otaPwd); - ArduinoOTA - .onStart([]() { - String type; - if (ArduinoOTA.getCommand() == U_FLASH) - type = "sketch"; - else // U_SPIFFS - type = "filesystem"; - Serial.println("\n*** OTA Starting:" + type); - homeSpan.statusLED.start(LED_OTA_STARTED); - }) - .onEnd([]() { - Serial.println("\n*** OTA Completed. Rebooting..."); - homeSpan.statusLED.off(); - }) - .onProgress([](unsigned int progress, unsigned int total) { - Serial.printf("*** Progress: %u%%\r", (progress / (total / 100))); - }) - .onError([](ota_error_t error) { - Serial.printf("*** OTA Error[%u]: ", error); - if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed\n"); - else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed\n"); - else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed\n"); - else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed\n"); - else if (error == OTA_END_ERROR) Serial.println("End Failed\n"); - }); - - ArduinoOTA.begin(); - Serial.print("Starting OTA: "); - Serial.print(displayName); - Serial.print(" at "); - Serial.print(WiFi.localIP()); - Serial.print("\n"); + ArduinoOTA + .onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) + type = "sketch"; + else // U_SPIFFS + type = "filesystem"; + Serial.println("\n*** OTA Starting:" + type); + homeSpan.statusLED.start(LED_OTA_STARTED); + }) + .onEnd([]() { + Serial.println("\n*** OTA Completed. Rebooting..."); + homeSpan.statusLED.off(); + }) + .onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("*** Progress: %u%%\r", (progress / (total / 100))); + }) + .onError([](ota_error_t error) { + Serial.printf("*** OTA Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed\n"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed\n"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed\n"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed\n"); + else if (error == OTA_END_ERROR) Serial.println("End Failed\n"); + }); + + ArduinoOTA.begin(); + Serial.print("Starting OTA: "); + Serial.print(displayName); + Serial.print(" at "); + Serial.print(WiFi.localIP()); + Serial.print("\n"); + } else { + Serial.print("\n*** Warning: Can't enable OTA - Partition table used to compile this sketch is not configured for OTA.\n\n"); + } } Serial.print("\n"); diff --git a/src/src.ino b/src/src.ino index 6df17bf..b12712f 100644 --- a/src/src.ino +++ b/src/src.ino @@ -8,13 +8,13 @@ void setup() { Serial.begin(115200); - homeSpan.setLogLevel(2); + homeSpan.setLogLevel(1); // homeSpan.setHostNameSuffix(""); homeSpan.setPortNum(1200); homeSpan.setMaxConnections(16); // homeSpan.setQRID("One1"); - homeSpan.enableOTA(); +// homeSpan.enableOTA(); homeSpan.setSketchVersion("Test 1.2.3"); homeSpan.begin(Category::Lighting,"HomeSpanTest"); From 7e03998865007eefe17792dde48e39bb104ab8c7 Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 11 Feb 2021 07:27:29 -0600 Subject: [PATCH 25/55] Added WiFi callback functionality HomeSpan will call a user-defined function upon establishing WiFi connectivity. Set function with homeSpan.setWifiCallback(f), where f must be of form void f(). --- src/HomeSpan.cpp | 3 +++ src/HomeSpan.h | 2 ++ src/src.ino | 11 +++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 41851a3..da6360f 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -495,6 +495,9 @@ void Span::checkConnect(){ } else { statusLED.on(); } + + if(wifiCallback) + wifiCallback(); } // initWiFi diff --git a/src/HomeSpan.h b/src/HomeSpan.h index ac11576..00250b0 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -103,6 +103,7 @@ struct Span{ char qrID[5]=""; // Setup ID used for pairing with QR Code boolean otaEnabled=false; // enables Over-the-Air ("OTA") updates char otaPwd[33]; // MD5 Hash of OTA password, represented as a string of hexidecimal characters + void (*wifiCallback)()=NULL; // optional callback function to invoke once WiFi connectivity is established WiFiServer *hapServer; // pointer to the HAP Server connection Blinker statusLED; // indicates HomeSpan status @@ -156,6 +157,7 @@ struct Span{ void enableOTA(){otaEnabled=true;} // enables Over-the-Air updates void setSketchVersion(const char *sVer){sketchVersion=sVer;} // set optional sketch version number const char *getSketchVersion(){return sketchVersion;} // get sketch version number + void setWifiCallback(void (*f)()){wifiCallback=f;} // sets an optional user-defined function to call once WiFi connectivity is established }; /////////////////////////////// diff --git a/src/src.ino b/src/src.ino index b12712f..3869a79 100644 --- a/src/src.ino +++ b/src/src.ino @@ -14,8 +14,9 @@ void setup() { homeSpan.setPortNum(1200); homeSpan.setMaxConnections(16); // homeSpan.setQRID("One1"); -// homeSpan.enableOTA(); - homeSpan.setSketchVersion("Test 1.2.3"); + homeSpan.enableOTA(); + homeSpan.setSketchVersion("Test 1.2.4"); + homeSpan.setWifiCallback(wifiEstablished); homeSpan.begin(Category::Lighting,"HomeSpanTest"); @@ -44,3 +45,9 @@ void loop(){ homeSpan.poll(); } // end of loop() + +////////////////////////////////////// + +void wifiEstablished(){ + Serial.println("\n\nIN CALLBACK FUNCTION\n\n"); +} From 7400383b0ad525276b182a5bfd6d710f9176f1b5 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 12 Feb 2021 13:23:02 -0600 Subject: [PATCH 26/55] Increased number of sockets in WiFiServer to maxConnection+1 This should account for the extra connection opened when all slots are already filled. --- src/HomeSpan.cpp | 2 +- src/src.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index da6360f..f3cc6d5 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -135,7 +135,7 @@ void Span::poll() { statusLED.start(LED_WIFI_NEEDED); } else { homeSpan.statusLED.start(LED_WIFI_CONNECTING); - hapServer=new WiFiServer(tcpPortNum,maxConnections); + hapServer=new WiFiServer(tcpPortNum,maxConnections+1); } controlButton.reset(); diff --git a/src/src.ino b/src/src.ino index 3869a79..df7c1d1 100644 --- a/src/src.ino +++ b/src/src.ino @@ -12,7 +12,7 @@ void setup() { // homeSpan.setHostNameSuffix(""); homeSpan.setPortNum(1200); - homeSpan.setMaxConnections(16); + homeSpan.setMaxConnections(4); // homeSpan.setQRID("One1"); homeSpan.enableOTA(); homeSpan.setSketchVersion("Test 1.2.4"); From f1c3684e1cfc544011aeebcceea44a58619a3c5b Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 13 Feb 2021 14:28:10 -0600 Subject: [PATCH 27/55] Updated maxConnections logic and added Socket numbers to output homeSpan.begin() automatically resizes maxConnections to ensure it is at or below maxLimit, where maxLimit=CONFIG_LWIP_MAX_SOCKETS-2-otaEnabled. maxConnections still defaults to 8 if unspecified, which means it is reduced to 7 if OTA is enabled. Users should set maxConnections to a lower number is they have implemented other socket-based services in their sketch --- src/HomeSpan.cpp | 38 +++++++++++++++++++++++++------------- src/src.ino | 12 ++++++++---- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index f3cc6d5..2c87099 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -54,10 +54,16 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa controlButton.init(controlPin); statusLED.init(statusPin); + int maxLimit=CONFIG_LWIP_MAX_SOCKETS-2-otaEnabled; + if(maxConnections>maxLimit) + maxConnections=maxLimit; + hap=(HAPClient **)calloc(maxConnections,sizeof(HAPClient *)); for(int i=0;iavailable())){ // found a new HTTP client + if(newClient=hapServer->available()){ // found a new HTTP client int freeSlot=getFreeSlot(); // get next free slot if(freeSlot==-1){ // no available free slots @@ -184,6 +189,10 @@ void Span::poll() { LOG1(millis()/1000); LOG1(" sec) "); LOG1(hap[freeSlot]->client.remoteIP()); + LOG1(" on Socket "); + LOG1(hap[freeSlot]->client.fd()-LWIP_SOCKET_OFFSET+1); + LOG1("/"); + LOG1(CONFIG_LWIP_MAX_SOCKETS); LOG1("\n"); LOG2("\n"); @@ -400,7 +409,7 @@ void Span::checkConnect(){ Serial.print(modelName); Serial.print("\nSetup ID: "); Serial.print(qrID); - Serial.print("\n"); + Serial.print("\n\n"); MDNS.begin(hostName); // set server host name (.local implied) MDNS.setInstanceName(displayName); // set server display name @@ -440,11 +449,6 @@ 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 - Serial.print("\nStarting Web (HTTP) Server supporting up to "); - Serial.print(maxConnections); - Serial.print(" simultaneous connections...\n"); - hapServer->begin(); - if(otaEnabled){ if(esp_ota_get_running_partition()!=esp_ota_get_next_update_partition(NULL)){ ArduinoOTA.setHostname(hostName); @@ -487,6 +491,11 @@ void Span::checkConnect(){ } } + Serial.print("Starting Web (HTTP) Server supporting up to "); + Serial.print(maxConnections); + Serial.print(" simultaneous connections...\n"); + hapServer->begin(); + Serial.print("\n"); if(!HAPClient::nAdminControllers()){ @@ -543,14 +552,17 @@ void Span::processSerialCommand(const char *c){ if(hap[i]->client){ Serial.print(hap[i]->client.remoteIP()); - Serial.print(" "); - + Serial.print(" on Socket "); + Serial.print(hap[i]->client.fd()-LWIP_SOCKET_OFFSET+1); + Serial.print("/"); + Serial.print(CONFIG_LWIP_MAX_SOCKETS); + if(hap[i]->cPair){ - Serial.print("ID="); + Serial.print(" ID="); HAPClient::charPrintRow(hap[i]->cPair->ID,36); Serial.print(hap[i]->cPair->admin?" (admin)":" (regular)"); } else { - Serial.print("(unverified)"); + Serial.print(" (unverified)"); } } else { diff --git a/src/src.ino b/src/src.ino index df7c1d1..d1cc9df 100644 --- a/src/src.ino +++ b/src/src.ino @@ -12,14 +12,18 @@ void setup() { // homeSpan.setHostNameSuffix(""); homeSpan.setPortNum(1200); - homeSpan.setMaxConnections(4); + homeSpan.setMaxConnections(6); // homeSpan.setQRID("One1"); homeSpan.enableOTA(); - homeSpan.setSketchVersion("Test 1.2.4"); + homeSpan.setSketchVersion("Test 1.2.6"); homeSpan.setWifiCallback(wifiEstablished); homeSpan.begin(Category::Lighting,"HomeSpanTest"); + Serial.printf("\nFD_SETSIZE: %d\n",FD_SETSIZE); + Serial.printf("CONFIG_LWIP_MAX_SOCKETS: %d\n",CONFIG_LWIP_MAX_SOCKETS); + Serial.printf("LWIP_SOCKET_OFFSET: %d\n\n",LWIP_SOCKET_OFFSET); + new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, which has 6 required Characteristics @@ -43,11 +47,11 @@ void setup() { void loop(){ homeSpan.poll(); - + } // end of loop() ////////////////////////////////////// void wifiEstablished(){ - Serial.println("\n\nIN CALLBACK FUNCTION\n\n"); + Serial.print("IN CALLBACK FUNCTION\n\n"); } From 35c8f5b48ca347eec6d8188a6c5788f6a0c28209 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 13 Feb 2021 21:24:46 -0600 Subject: [PATCH 28/55] Added option to disable OTA password homeSpan.enableOTA() is now homeSpan.enableOTA(boolean auth=true). Set auth=false to disable password authentication. Set to true, or leave blank, to enable password authentication. --- src/HomeSpan.cpp | 7 +++++-- src/HomeSpan.h | 3 ++- src/src.ino | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 2c87099..dd4f453 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -452,7 +452,9 @@ void Span::checkConnect(){ if(otaEnabled){ if(esp_ota_get_running_partition()!=esp_ota_get_next_update_partition(NULL)){ ArduinoOTA.setHostname(hostName); - ArduinoOTA.setPasswordHash(otaPwd); + + if(otaAuth) + ArduinoOTA.setPasswordHash(otaPwd); ArduinoOTA .onStart([]() { @@ -485,7 +487,8 @@ void Span::checkConnect(){ Serial.print(displayName); Serial.print(" at "); Serial.print(WiFi.localIP()); - Serial.print("\n"); + Serial.print("\nAuthorization Password: "); + Serial.print(otaAuth?"Enabled\n\n":"DISABLED!\n\n"); } else { Serial.print("\n*** Warning: Can't enable OTA - Partition table used to compile this sketch is not configured for OTA.\n\n"); } diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 00250b0..07cd569 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -103,6 +103,7 @@ struct Span{ char qrID[5]=""; // Setup ID used for pairing with QR Code boolean otaEnabled=false; // enables Over-the-Air ("OTA") updates char otaPwd[33]; // MD5 Hash of OTA password, represented as a string of hexidecimal characters + boolean otaAuth; // OTA requires password when set to true void (*wifiCallback)()=NULL; // optional callback function to invoke once WiFi connectivity is established WiFiServer *hapServer; // pointer to the HAP Server connection @@ -154,7 +155,7 @@ struct Span{ void setHostNameSuffix(const char *suffix){hostNameSuffix=suffix;} // sets the hostName suffix to be used instead of the 6-byte AccessoryID void setPortNum(uint16_t port){tcpPortNum=port;} // sets the TCP port number to use for communications between HomeKit and HomeSpan void setQRID(const char *id); // sets the Setup ID for optional pairing with a QR Code - void enableOTA(){otaEnabled=true;} // enables Over-the-Air updates + void enableOTA(boolean auth=true){otaEnabled=true;otaAuth=auth;} // enables Over-the-Air updates, with (auth=true) or without (auth=false) authorization password void setSketchVersion(const char *sVer){sketchVersion=sVer;} // set optional sketch version number const char *getSketchVersion(){return sketchVersion;} // get sketch version number void setWifiCallback(void (*f)()){wifiCallback=f;} // sets an optional user-defined function to call once WiFi connectivity is established diff --git a/src/src.ino b/src/src.ino index d1cc9df..cf8bb6f 100644 --- a/src/src.ino +++ b/src/src.ino @@ -14,7 +14,7 @@ void setup() { homeSpan.setPortNum(1200); homeSpan.setMaxConnections(6); // homeSpan.setQRID("One1"); - homeSpan.enableOTA(); +// homeSpan.enableOTA(false); homeSpan.setSketchVersion("Test 1.2.6"); homeSpan.setWifiCallback(wifiEstablished); From bccecc81277631281da5c392acc1b519b8cb17ec Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 13 Feb 2021 21:30:32 -0600 Subject: [PATCH 29/55] Update Reference.md --- docs/Reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index 45b2540..dd96832 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -68,9 +68,9 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * the HomeSpan default is "HSPN" unless permanently changed for the device via the [HomeSpan CLI](CLI.md) using the 'Q' command * *id* must be exactly 4 alphanumeric characters (0-9, A-Z, and a-z). If not, the request to change the Setup ID is silently ignored and the default is used instead -* `void enableOTA()` +* `void enableOTA(boolean auth=true)` * enables [Over-the-Air (OTA) Updating](OTA.md) of a HomeSpan device, which is otherwise disabled - * HomeSpan OTA always requires the use of an authorizing OTA password + * HomeSpan OTA requires an authorizing password unless *auth* is specified and set to *false* * the default OTA password for new HomeSpan devices is "homespan-ota" * this can be changed via the [HomeSpan CLI](CLI.md) using the 'O' command From a0f4a46adf5320edb6a75f24f0acfe240645c2b8 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 13 Feb 2021 21:36:16 -0600 Subject: [PATCH 30/55] Update CLI.md --- docs/CLI.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 62a9504..72181b5 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -50,10 +50,11 @@ In addition to listening for incoming HAP requests, HomeSpan also continuously p * Deleting a device's HomeKit ID and Controller data with the 'H' command (see below) also restores the default Setup ID to "HSPN". * **O** - prompts you to set the password used for Over-the-Air (OTA) Updating - * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but requires the use of a (non-blank) password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to create a new one using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. + * HomeSpan supports [Over-the-Air (OTA) Updating](OTA.md) but, by default, requires the use of a password. Similar to a device's Setup Code, HomeSpan saves a non-recoverable *hashed* version of the OTA password you set with this command in NVS. If you forget the password you specified, you'll need to create a new one using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. * HomeSpan uses "homespan-ota" as its default OTA password for new devices. * Changes to the OTA password do not take effect until the device is restarted. - * OTA is not active unless specifically enabled for a sketch using the method `homeSpan.enableOTA()`. See the [HomeSpan API Reference](Reference.md) for details. + * OTA is not active unless specifically enabled for a sketch using the method `homeSpan.enableOTA()`. + * You can disable the use an authorizing password by invoking `homeSpan.enableOTA(false)` instead, though this creates a security risk and is therefore **not** recommended. See the [HomeSpan API Reference](Reference.md) for details. * **A** - start the HomeSpan Setup Access Point * This command starts HomeSpan's temporary Access Point, which provides users with an alternate methods for configuring a device's WiFi Credentials and HomeKit Setup Code. Starting the Access Point with this command is identical to starting it via the Control Button. See the [HomeSpan User Guide](UserGuide.md) for complete details. From 24cc2486e278e2d743a8044613d52944ff0b1291 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 14 Feb 2021 18:32:54 -0600 Subject: [PATCH 31/55] Added Linked Services logic New SpanService method addLink(SpanService *svc), where svc is a pointer to the SpanService that is being specified as a Linked Service for the current Service. addLink() returns a pointer to "this" so may be chained --- src/HomeSpan.cpp | 35 ++++++++++++++++++++++++++++------- src/HomeSpan.h | 2 ++ src/src.ino | 16 ++++++++++------ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index dd4f453..4c30e43 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -831,20 +831,24 @@ void Span::processSerialCommand(const char *c){ Serial.print("\n\n"); char d[]="------------------------------"; - char cBuf[256]; - sprintf(cBuf,"%-30s %s %10s %s %s %s %s\n","Service","Type","AID","IID","Update","Loop","Button"); - Serial.print(cBuf); - sprintf(cBuf,"%.30s %.4s %.10s %.3s %.6s %.4s %.6s\n",d,d,d,d,d,d,d); - Serial.print(cBuf); + Serial.printf("%-30s %s %10s %s %s %s %s %s\n","Service","Type","AID","IID","Update","Loop","Button","Linked Services"); + Serial.printf("%.30s %.4s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d); for(int i=0;iServices.size();j++){ SpanService *s=Accessories[i]->Services[j]; - sprintf(cBuf,"%-30s %4s %10u %3d %6s %4s %6s\n",s->hapName,s->type,Accessories[i]->aid,s->iid, + Serial.printf("%-30s %4s %10u %3d %6s %4s %6s ",s->hapName,s->type,Accessories[i]->aid,s->iid, (void(*)())(s->*(&SpanService::update))!=(void(*)())(&SpanService::update)?"YES":"NO", (void(*)())(s->*(&SpanService::loop))!=(void(*)())(&SpanService::loop)?"YES":"NO", (void(*)(int,boolean))(s->*(&SpanService::button))!=(void(*)(int,boolean))(&SpanService::button)?"YES":"NO" ); - Serial.print(cBuf); + if(s->linkedServices.empty()) + Serial.print("-"); + for(int k=0;klinkedServices.size();k++){ + Serial.print(s->linkedServices[k]->iid); + if(klinkedServices.size()-1) + Serial.print(","); + } + Serial.print("\n"); } } Serial.print("\n*** End Info ***\n"); @@ -1378,6 +1382,13 @@ SpanService *SpanService::setHidden(){ /////////////////////////////// +SpanService *SpanService::addLink(SpanService *svc){ + linkedServices.push_back(svc); + return(this); +} + +/////////////////////////////// + int SpanService::sprintfAttributes(char *cBuf){ int nBytes=0; @@ -1388,6 +1399,16 @@ int SpanService::sprintfAttributes(char *cBuf){ if(primary) nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"\"primary\":true,"); + + if(!linkedServices.empty()){ + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"\"linked\":["); + for(int i=0;iiid); + if(i+1 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 + vector linkedServices; // vector of pointers to any optional linked Services SpanService(const char *type, const char *hapName); SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self + SpanService *addLink(SpanService *svc); // adds svc as a Linked Service int sprintfAttributes(char *cBuf); // prints Service JSON records into buf; return number of characters printed, excluding null terminator void validate(); // error-checks Service diff --git a/src/src.ino b/src/src.ino index cf8bb6f..434b93d 100644 --- a/src/src.ino +++ b/src/src.ino @@ -20,10 +20,6 @@ void setup() { homeSpan.begin(Category::Lighting,"HomeSpanTest"); - Serial.printf("\nFD_SETSIZE: %d\n",FD_SETSIZE); - Serial.printf("CONFIG_LWIP_MAX_SOCKETS: %d\n",CONFIG_LWIP_MAX_SOCKETS); - Serial.printf("LWIP_SOCKET_OFFSET: %d\n\n",LWIP_SOCKET_OFFSET); - new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, which has 6 required Characteristics @@ -37,8 +33,16 @@ void setup() { new Service::HAPProtocolInformation(); // Create the HAP Protcol Information Service new Characteristic::Version("1.1.0"); // Set the Version Characteristic to "1.1.0" as required by HAP - new Service::LightBulb(); // Create the Light Bulb Service - new Characteristic::On(); // This Service requires the "On" Characteristic to turn the light on and off + SpanService *v1=new Service::Valve(); + new Characteristic::Active(); + new Characteristic::InUse(); + new Characteristic::ValveType(); + SpanService *v2=new Service::Valve(); + new Characteristic::Active(); + new Characteristic::InUse(); + new Characteristic::ValveType(); + (new Service::Faucet())->addLink(v1)->addLink(v2); + new Characteristic::Active(); } // end of setup() From 2e3f90851afd20bdd9761ba9d6b4f493ab59d60a Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 15 Feb 2021 19:40:07 -0600 Subject: [PATCH 32/55] Create 17-LinkedServices.ino --- .../17-LinkedServices/17-LinkedServices.ino | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 examples/17-LinkedServices/17-LinkedServices.ino diff --git a/examples/17-LinkedServices/17-LinkedServices.ino b/examples/17-LinkedServices/17-LinkedServices.ino new file mode 100644 index 0000000..cd7a319 --- /dev/null +++ b/examples/17-LinkedServices/17-LinkedServices.ino @@ -0,0 +1,148 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2020-2021 Gregg E. Berman + * + * https://github.com/HomeSpan/HomeSpan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + ********************************************************************************/ + +//////////////////////////////////////////////////////////// +// // +// HomeSpan: A HomeKit implementation for the ESP32 // +// ------------------------------------------------ // +// // +// Example 17: Linked Services // +// * implementing a multi-head Spa Shower // +// // +//////////////////////////////////////////////////////////// + +#include "HomeSpan.h" + + // HAP normally treats multiple Services created within the same Accessory as independent of one another. However, certain HAP Services are designed to represent a central point + // of control over other, more typical Services. For example, you can create an Accessory with one or more Valve Services, each operating independently. But HAP also includes a + // Faucet Service that can be used to "control" one or more Valve Services. This is done by LINKING the Faucet Service to one or more Valve Services. + // + // Only a few types of HAP Services allow/require links to be made to other Services, and only a few types of Services can be selected as a link. + // + // Linked Services can be created in HomeSpan using the addLink() method. For example, if spaShower is a pointer to a Faucet Service, and showerHead and handSprayer are both + // pointers to Valve Services, you can link the faucet to the valves as follows: + // + // spaShower->addLink(showerHead); + // spaShower->addLink(handSprayer); + // + // The addLink method returns a pointer to the object that called it, which provides you with the option of combining both methods above into a single line as follows: + // + // spaShower->addLink(showerHead)->addLink(handSprayer); + // + + // Note that HAP does *not* provide any of the actual logic that's needed for the "controlling" Service to operate the "linked" Services. This must still be programmed by the user. + // More so, the logic needs to conform with the behavior HAP expects for the Service as outlined in the HAP documention for the controlling Service. The only thing HAP really does with + // Linked Services, besides making you do extra work, is to provide a customized Tile that shows you the controlling Service and the Services to which it is linked. + + // Also as noted above, only a few Services support the Linked Services protcol. If you use the addLink() method with Services that do not support linkages, HAP will simply ignore + // the linkage request. But the reverse is not true. If you implement a Service that requires other Linked Services (such as a Faucet) you MUST create those linkages for the + // Service to operate properly. + + // Example 17 below demonstrates Linked Services by implementing a multi-head Spa Shower using one HAP Faucet Service and muliple HAP Valve Services. As usual, we will create + // our own "child" Services from HAP's Faucet and Valve Services so we can add the logic required to implement our device. However, instead of placing all that logic in separate + // *.h files, we include them directly in the main sketch file (below) to illustrate an alternative way of organizing your sketch code. + + // This Example further illustrates yet another coding style option: instead of instantiating all the Services needed in the setup() portion of the sketch, we only instantiate + // the Shower Service, and have the Shower Service itself instantiate all the Valve Services. In fact, our entire definition of the Value Service is fully encapsulated + // in the definition of the Shower Service. + + // This hopefully provides a good example of the flexibility of HomeSpan. Because all HomeSpan components are defined using standard C++ structures (as opposed to external files + // based on some pre-defined format), you can choose whatever coding style you'd like. The style below was chosen since it seemed to fit well for illustating how Linked Services work. + // But note that it is only the addLink() method that creates the actual linkages. The fact that the WaterValve Service is defined within the Shower Service is purely a style choice + // and does not itself create the linkages. We could have used a standalone structure for the WaterValve definitions and the results would be the same. + +////////////////////////////////////// + +struct Shower:Service::Faucet{ // this is our Shower structure, which we define as a child class of the HomeSpan Faucet structure + + SpanCharacteristic *active=new Characteristic::Active(); // our implementation only requires the Active Characteristic + + Shower(int nHeads){ // this is the constructor for Shower. It takes a single argument that specifies the number of spray heads (WaterValves) + for(int i=0;iactive->getVal()) // Here's where we use the pointer to Shower. ONLY if the Shower object itself is active--- + inUse->setVal(active->getNewVal()); // --- do we update the InUse Characteristic to reflect a change in the status of flowing water. + return(true); // Note that the Valve itself will still change from Active to Inactive (or vice versa) regardless of the status of the Shower + } + + void loop() override { // Here we check if the Shower is turned on or off, and determine if that means we need to update the Valve + if(shower->active->getVal() && active->getVal() && !inUse->getVal()) // If the Shower is Active, and the Valve is Active, but InUse is NOT Active + inUse->setVal(1); // set the InUse Characteristic to Active + else if(!shower->active->getVal() && inUse->getVal()) + inUse->setVal(0); + } + + }; // WaterValve +}; + +////////////////////////////////////// + +void setup() { + + Serial.begin(115200); + + homeSpan.begin(Category::ShowerSystems,"HomeSpan Shower"); + + new SpanAccessory(); + + new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, which has 6 required Characteristics + new Characteristic::Name("Spa Shower"); + new Characteristic::Manufacturer("HomeSpan"); + new Characteristic::SerialNumber("HSL-123"); + new Characteristic::Model("HSL Test"); + new Characteristic::FirmwareRevision(HOMESPAN_VERSION); + new Characteristic::Identify(); + + new Service::HAPProtocolInformation(); // Create the HAP Protcol Information Service + new Characteristic::Version("1.1.0"); + + new Shower(4); // Create a Spa Shower with 4 spray heads + +} // end of setup() + +////////////////////////////////////// + +void loop(){ + + homeSpan.poll(); + +} // end of loop() + +////////////////////////////////////// From c52ae7bdfed27af3eaec79a7daa4c0b3c49eac21 Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 15 Feb 2021 20:38:32 -0600 Subject: [PATCH 33/55] Update 17-LinkedServices.ino --- .../17-LinkedServices/17-LinkedServices.ino | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/examples/17-LinkedServices/17-LinkedServices.ino b/examples/17-LinkedServices/17-LinkedServices.ino index cd7a319..2210989 100644 --- a/examples/17-LinkedServices/17-LinkedServices.ino +++ b/examples/17-LinkedServices/17-LinkedServices.ino @@ -52,7 +52,6 @@ // The addLink method returns a pointer to the object that called it, which provides you with the option of combining both methods above into a single line as follows: // // spaShower->addLink(showerHead)->addLink(handSprayer); - // // Note that HAP does *not* provide any of the actual logic that's needed for the "controlling" Service to operate the "linked" Services. This must still be programmed by the user. // More so, the logic needs to conform with the behavior HAP expects for the Service as outlined in the HAP documention for the controlling Service. The only thing HAP really does with @@ -76,6 +75,32 @@ // and does not itself create the linkages. We could have used a standalone structure for the WaterValve definitions and the results would be the same. ////////////////////////////////////// + + // The HAP Valve Service requires both an Active Characteristic and an InUse Characteristic. The Active Characteristic controls whether a Valve is open (active) or closed (inactive). + // This Characteristic is normally controlled by the user through the Home App. The InUse Characteristic specifies whether there is water (or gas, etc.) actually flowing + // through the Valve. This is because opening a Valve does not necessarily mean water will be flowing. There may be another real-world "master" Valve that also needs to be open + // before water can begin flowing. Or there may be another Service that must also be Active to enable water to flow through the Valve. Hence, InUse can either be true or false + // if the Valve is open, but it can only be false if the Valve is closed. The Home App cannot change the InUse Characteristic. It is only read by the Home App as a status. + + // It is possible to create a multi-valve Accessory where each Valve is controlled independently from the Home App, and HomeSpan uses internal logic to determine, based + // on the combination of Valves that are open or closed, which Valves have water flowing (InUse=true) and which do not (InUse=false). + + // The HAP Faucet Service is used to create a "central control switch" for all the Valves linked to it. The Home App displays each Valve as a small icon on the control + // page of the Faucet. Clicking a Valve icon toggles it open/close, and changes the icon accordingly. However, water is not supposed to flow unless the Shower control switch + // itself is also turned on. Thus, the logic you need to encode to implement a HAP Faucet is to set the InUse Characteristic of a Valve to true ONLY if the Valve is open + // AND the Shower is switched on. If the Shower is then switched off, the Valve remains open, but the InUse Characteristic needs to be reset to false. Similarly, if the Shower + // is switched back on, the InUse Characteristic of each Valve that is open needs to be set to true. This mimics how an actual Shower with a central controlling switch + // would operate. + + // In addition, the Home App displays one of 4 status messages as you operate the Shower and Valve controls: + + // OFF: The Shower switch is OFF, AND the InUse Characteristic for EVERY Valve is set to FALSE (no water flowing anywhere); + // STOPPING: The Shower switch is OFF, BUT at least one Valve still has its InUse Characteristic set to TRUE. Presumably this means the Valve is in the process of turning off; + // STARTING: The Shower switch is ON, BUT the InUse Characteristic for EVERY Valve is set to FALSE. This indicates the Shower is waiting for water to start flowing; + // RUNNING: The Shower switch in ON, AND at least one of the Valves has its InUse Characteristic set to TRUE. This indicates water is flowing. + + // Note that the Shower Service only monitors the InUse Characteristics of its Linked Valves. It does not monitor the Active Characteristics of the Linked Valves. Also, turning + // on and off the Shower Switch should NOT change the Active Characteristic of any Valve. Below is the code that implements all of this HAP-required logic: struct Shower:Service::Faucet{ // this is our Shower structure, which we define as a child class of the HomeSpan Faucet structure @@ -83,30 +108,30 @@ struct Shower:Service::Faucet{ // this is our Shower structure, Shower(int nHeads){ // this is the constructor for Shower. It takes a single argument that specifies the number of spray heads (WaterValves) for(int i=0;iactive->getVal()) // Here's where we use the pointer to Shower. ONLY if the Shower object itself is active--- + boolean update() override { // HomeSpan calls this whenever the Home App requests a change in a Valve's Active Characteristic + if(shower->active->getVal()) // here's where we use the pointer to Shower: ONLY if the Shower object itself is active--- inUse->setVal(active->getNewVal()); // --- do we update the InUse Characteristic to reflect a change in the status of flowing water. return(true); // Note that the Valve itself will still change from Active to Inactive (or vice versa) regardless of the status of the Shower } void loop() override { // Here we check if the Shower is turned on or off, and determine if that means we need to update the Valve - if(shower->active->getVal() && active->getVal() && !inUse->getVal()) // If the Shower is Active, and the Valve is Active, but InUse is NOT Active - inUse->setVal(1); // set the InUse Characteristic to Active - else if(!shower->active->getVal() && inUse->getVal()) - inUse->setVal(0); + if(shower->active->getVal() && active->getVal() && !inUse->getVal()) // If the Shower is Active, and the Valve is Active, but InUse is NOT Active... + inUse->setVal(1); // ...set the InUse Characteristic to Active + else if(!shower->active->getVal() && inUse->getVal()) // Otherwise, if the Shower is NOT Active but InUse is Active... + inUse->setVal(0); // ...set the InUse Characteristic to NOT Active } }; // WaterValve From 06da58954110ba126e66904efa9b4f40ce228b4c Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 15 Feb 2021 20:45:58 -0600 Subject: [PATCH 34/55] Update Reference.md --- docs/Reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Reference.md b/docs/Reference.md index dd96832..13e3f4d 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -116,6 +116,9 @@ The following methods are supported: * `SpanService *setHidden()` * specifies that this is hidden Service for the Accessory. Returns a pointer to the Service itself so that the method can be chained during instantiation. +* `SpanService *addLink(SpanService *svc)` + * adds *svc* as a Linked Service. Returns a pointer to the calling Service itself so that the method can be chained during instantiation. Note Linked Services are only applicable for select HAP Services. See HAP R2 documentation for full details. + * `virtual boolean update()` * HomeSpan calls this method upon receiving a request from a HomeKit Controller to update one or more Characteristics associated with the Service. Users should override this method with code that implements that requested updates using one or more of the SpanCharacteristic methods below. Method **must** return *true* if update succeeds, or *false* if not. From 1cbac51a43e4c3f374b39cb9ec86e0dbc11d9836 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 15 Feb 2021 20:47:54 -0600 Subject: [PATCH 35/55] Update Reference.md --- docs/Reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index 13e3f4d..73b3121 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -117,7 +117,7 @@ The following methods are supported: * specifies that this is hidden Service for the Accessory. Returns a pointer to the Service itself so that the method can be chained during instantiation. * `SpanService *addLink(SpanService *svc)` - * adds *svc* as a Linked Service. Returns a pointer to the calling Service itself so that the method can be chained during instantiation. Note Linked Services are only applicable for select HAP Services. See HAP R2 documentation for full details. + * adds *svc* as a Linked Service. Returns a pointer to the calling Service itself so that the method can be chained during instantiation. Note Linked Services are only applicable for select HAP Services. See Apple's [HAP-R2](https://developer.apple.com/support/homekit-accessory-protocol/) documentation for full details. * `virtual boolean update()` * HomeSpan calls this method upon receiving a request from a HomeKit Controller to update one or more Characteristics associated with the Service. Users should override this method with code that implements that requested updates using one or more of the SpanCharacteristic methods below. Method **must** return *true* if update succeeds, or *false* if not. From 0602b8ac3f655b321a4c29acfaea3e5755d6f993 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 15 Feb 2021 21:00:59 -0600 Subject: [PATCH 36/55] Update Reference.md --- docs/Reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Reference.md b/docs/Reference.md index 73b3121..a806646 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -83,6 +83,9 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * `const char *getSketchVersion()` * returns the version of a HomeSpan sketch, as set using `void setSketchVersion(const char *sVer)`, or "n/a" if not set +* `void setWifiCallback(void (*func)(void))` + * Sets an optional user-defined callback function, *func*, to be called by HomeSpan upon start-up just after WiFi connectivity has been established. This one-time call to *func* is provided for users that are implementing other network-related services as part of their sketch, but that cannot be started until WiFi connectivity is established. The function *func* must be of type *void* and have no arguments + ## *SpanAccessory(uint32_t aid)* Creating an instance of this **class** adds a new HAP Accessory to the HomeSpan HAP Database. From f8b0e906bf43872b61bb049fe6d0d1fac109dcf0 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 15 Feb 2021 21:13:24 -0600 Subject: [PATCH 37/55] Update Tutorials.md --- docs/Tutorials.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/Tutorials.md b/docs/Tutorials.md index f7ce5a9..05780d4 100644 --- a/docs/Tutorials.md +++ b/docs/Tutorials.md @@ -87,6 +87,11 @@ This example introduces HomeSpan functionality that lets you easily connect real ### [Example 16 - ProgrammableSwitches](../examples/16-ProgrammableSwitches) Example 16 does not introduce any new HomeSpan functionality, but instead showcases a unique feature of HomeKit that you can readily access with HomeSpan. In all prior examples we used the ESP32 to control a local appliance - something connected directly to the ESP32 device. We've then seen how you can control the device via HomeKit's iOS or MacOS Home App, or by the addition of local pushbuttons connected directly to the ESP32 device. In this example we do the opposite, and use pushbuttons connected to the ESP32 to control OTHER HomeKit devices of any type. To do so, we use HomeKit's Stateless Programmable Switch Service. +### [Example 17 - LinkedServices](../examples/17-LinkedServices) +Example 17 introduces the HAP concept of Linked Services and demonstrates how they are used through the implementation of a multi-head Shower. This example also illustrates some different coding styles that showcase the power and flexibility of HomeSpan's C++ *structure-based* design paradigm. New HomeSpan API topics covered in this example include: + +* creating Linked Services using the `addLink()` method + --- [↩️](README.md) Back to the Welcome page From 94505519474734a20c859d97a3d2c94565b2b765 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 06:30:01 -0600 Subject: [PATCH 38/55] Update Reference.md --- docs/Reference.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index a806646..5383fbb 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -52,7 +52,11 @@ The following **optional** `homeSpan` methods override various HomeSpan initiali * this parameter can also be changed at runtime via the [HomeSpan CLI](CLI.md) * `void setMaxConnections(uint8_t nCon)` - * sets the maximum number of HAP Controllers that be simultaneously connected to HomeSpan (default=8) + * sets the desired maximum number of HAP Controllers that can be simultaneously connected to HomeSpan (default=8) + * due to limitations of the ESP32 Arduino library, HomeSpan will override *nCon* if it exceed the following internal limits: + * if OTA is not enabled, *nCon* will be reduced to 8 if it has been set to a value greater than 8 + * if OTA is enabled, *nCon* will be reduced to 7 if it has been set to a value greater than 7 + * if you add code to a sketch that uses it own network resources, you will need to determine how many TCP sockets your code may need to use, and use this method to reduce the maximum number of connections available to HomeSpan accordingly * `void setPortNum(uint16_t port)` * sets the TCP port number used for communication between HomeKit and HomeSpan (default=80) From 45e7c60dd118957ee5f237bcf952dfcc8639ef02 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 07:01:34 -0600 Subject: [PATCH 39/55] Update Reference.md --- docs/Reference.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index 5383fbb..d6a36d3 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -118,13 +118,16 @@ This is a **base class** from which all HomeSpan Services are derived, and shoul The following methods are supported: * `SpanService *setPrimary()` - * specifies that this is the primary Service for the Accessory. Returns a pointer to the Service itself so that the method can be chained during instantiation. Example: `new Service::Fan->setPrimary();` + * specifies that this is the primary Service for the Accessory. Returns a pointer to the Service itself so that the method can be chained during instantiation. + * example: `(new Service::Fan)->setPrimary();` * `SpanService *setHidden()` * specifies that this is hidden Service for the Accessory. Returns a pointer to the Service itself so that the method can be chained during instantiation. * `SpanService *addLink(SpanService *svc)` - * adds *svc* as a Linked Service. Returns a pointer to the calling Service itself so that the method can be chained during instantiation. Note Linked Services are only applicable for select HAP Services. See Apple's [HAP-R2](https://developer.apple.com/support/homekit-accessory-protocol/) documentation for full details. + * adds *svc* as a Linked Service. Returns a pointer to the calling Service itself so that the method can be chained during instantiation. + * note that Linked Services are only applicable for select HAP Services. See Apple's [HAP-R2](https://developer.apple.com/support/homekit-accessory-protocol/) documentation for full details. + * example: `(new Service::Faucet)->addLink(new Service::Valve)->addLink(new Service::Valve);` (links two Valves to a Faucet) * `virtual boolean update()` * HomeSpan calls this method upon receiving a request from a HomeKit Controller to update one or more Characteristics associated with the Service. Users should override this method with code that implements that requested updates using one or more of the SpanCharacteristic methods below. Method **must** return *true* if update succeeds, or *false* if not. From 121864ba36c04073da60270e51eb37e7d7c68312 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 07:18:19 -0600 Subject: [PATCH 40/55] Update Reference.md --- docs/Reference.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Reference.md b/docs/Reference.md index d6a36d3..aeb2a9f 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -123,6 +123,7 @@ The following methods are supported: * `SpanService *setHidden()` * specifies that this is hidden Service for the Accessory. Returns a pointer to the Service itself so that the method can be chained during instantiation. + * note this does not seem to have any affect on the Home App. Services marked as hidden still appear as normal * `SpanService *addLink(SpanService *svc)` * adds *svc* as a Linked Service. Returns a pointer to the calling Service itself so that the method can be chained during instantiation. From 269d749b5bba49c836e6411badbff63052e8a221 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 16 Feb 2021 07:19:48 -0600 Subject: [PATCH 41/55] Update src.ino --- src/src.ino | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/src.ino b/src/src.ino index 434b93d..122b785 100644 --- a/src/src.ino +++ b/src/src.ino @@ -33,16 +33,16 @@ void setup() { new Service::HAPProtocolInformation(); // Create the HAP Protcol Information Service new Characteristic::Version("1.1.0"); // Set the Version Characteristic to "1.1.0" as required by HAP - SpanService *v1=new Service::Valve(); - new Characteristic::Active(); - new Characteristic::InUse(); - new Characteristic::ValveType(); - SpanService *v2=new Service::Valve(); - new Characteristic::Active(); - new Characteristic::InUse(); - new Characteristic::ValveType(); - (new Service::Faucet())->addLink(v1)->addLink(v2); - new Characteristic::Active(); + new Service::LightBulb(); + new Characteristic::On(); + new Characteristic::Brightness(); + new Characteristic::Name("Light 1"); + new Service::LightBulb(); + new Characteristic::On(); + new Characteristic::Brightness(); + new Characteristic::Name("Light 2"); + new Service::Switch(); + new Characteristic::On(); } // end of setup() From 7e2115968529641a97344609b386912b684cbbcc Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 17:30:13 -0600 Subject: [PATCH 42/55] Create OTA.md --- docs/OTA.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 docs/OTA.md diff --git a/docs/OTA.md b/docs/OTA.md new file mode 100644 index 0000000..2aad703 --- /dev/null +++ b/docs/OTA.md @@ -0,0 +1,2 @@ +# Over-the-Air (OTA) Updates + From d60f9db3c58d08f470262b0421adf140b8702546 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 18:41:28 -0600 Subject: [PATCH 43/55] Update OTA.md --- docs/OTA.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/OTA.md b/docs/OTA.md index 2aad703..f6b398c 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -1,2 +1,8 @@ # Over-the-Air (OTA) Updates +HomeSpan integrates the ArduinoOTA library, which allows you to wirelessly update sketches directly from the Arduino IDE. To save resources (as well as maximize security) HomeSpan does not enable OTA unless specifically requested. To do so, simply call the method `homeSpan.enableOTA()` somewhere in your sketch *before* the call to `homeSpan.begin()`. + +By default, HomeSpan requires the use of a password when updating a sketch via OTA from the Arduino IDE. The default OTA password is "homespan-ota". You can change this password from the [HomeSpan CLI](CLI.md) with the 'O' command. Similar to a device's Setup Code, HomeSpan saves a non-recoverable hashed version of the OTA password you specify in its non-volatile storage (NVS). If you forget the password you specified, you'll need to create a new one using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. + +Though not recommended, you can disable the requirement for a password by enabling OTA with *false* as the parameter as such: `homeSpan.enableOTA(false)`. Use with caution! Anyone who can access the device over your network will be able to upload a new sketch. + From 2aea557a3a09c26429f005f3fec63ec6b4832b0e Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 18:58:00 -0600 Subject: [PATCH 44/55] Update OTA.md --- docs/OTA.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/OTA.md b/docs/OTA.md index f6b398c..097417e 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -6,3 +6,6 @@ By default, HomeSpan requires the use of a password when updating a sketch via O Though not recommended, you can disable the requirement for a password by enabling OTA with *false* as the parameter as such: `homeSpan.enableOTA(false)`. Use with caution! Anyone who can access the device over your network will be able to upload a new sketch. +If OTA is enabled, HomeSpan will check that the sketch has been compiled with OTA partitions, and output a confirmation message to the Arduino Serial Monitor upon start-up immediately after establishing WiFi connectivity. If OTA is enabled in a sketch but OTA partitions are not found, HomeSpan will instead report a warning that it can't start OTA. Partition selection is found under the *Tools* menu of the Arduino IDE. Note that depending on your specific ESP32 device, the Partition Scheme labeled "default" may bne configured with OTA partitions. The easiest way to find out is to select that scheme and check for verification by HomeSpan. + + From 3010e4934724762f6da6e047bb57e1c5cef87bbc Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 21:53:18 -0600 Subject: [PATCH 45/55] Update OTA.md --- docs/OTA.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/OTA.md b/docs/OTA.md index 097417e..5dcac1d 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -1,11 +1,31 @@ # Over-the-Air (OTA) Updates -HomeSpan integrates the ArduinoOTA library, which allows you to wirelessly update sketches directly from the Arduino IDE. To save resources (as well as maximize security) HomeSpan does not enable OTA unless specifically requested. To do so, simply call the method `homeSpan.enableOTA()` somewhere in your sketch *before* the call to `homeSpan.begin()`. +HomeSpan supports Over-the-Air (OTA) updates, which allows you to *wirelessly* upload sketches directly from the Arduino IDE. To activate this feature for your sketch, simply call the method `homeSpan.enableOTA()` prior to calling `homeSpan.begin()`. -By default, HomeSpan requires the use of a password when updating a sketch via OTA from the Arduino IDE. The default OTA password is "homespan-ota". You can change this password from the [HomeSpan CLI](CLI.md) with the 'O' command. Similar to a device's Setup Code, HomeSpan saves a non-recoverable hashed version of the OTA password you specify in its non-volatile storage (NVS). If you forget the password you specified, you'll need to create a new one using this command. Alternatively, you can restore the default OTA password by fully erasing the NVS with the 'E' command. +When a HomeSpan sketch is run with OTA enabled, the device shows up as a "network" port that can be selected under *Tools → Port* in the Arduino IDE. Once selected, the IDE will direct all uploads to the device via WiFi instead of looking for it on a serial port. Note that you can upload via OTA even if your device is still connected to a serial port, but the IDE does not presently support multiple port connections at the same time and will automatically close the Serial Monitor upon selecting your device via a network port. + +By default, HomeSpan requires the use of a password whenever you begin an OTA upload. The default OTA password is "homespan-ota". The Arduino will prompt you for this when you attempt the first OTA upload after opening the Arduino IDE, after which it will remember the password until the IDE is shut down. + +You can change the password for a HomeSpan device from the [HomeSpan CLI](CLI.md) with the 'O' command. Similar to a device's Setup Code, HomeSpan saves a non-recoverable hashed version of the OTA password you specify in non-volatile storage (NVS). If you forget the password you specified, you'll need to create a new one using the 'O' command, or you can restore the default OTA password by fully erasing the NVS with the 'E' command. + +> :exclamation: Though not recommended, you can override the requirement for a password by enabling OTA with *false* as the parameter as such: `homeSpan.enableOTA(false)`. Use with caution! Anyone who can access the device over your network will now be able to upload a new sketch. + +Note that in in order for OTA to properly operate, your sketch must be compiled using by selecting a Parition Scheme under the *Tools* menut that includes OTA partitions. These are usually labeled to indicate if OTA is supported, though sometimes the "default" scheme is also set up for OTA. + +When OTA is enabled in a sketch, HomeSpan checks that it has been compiled with OTA partitions, and will output a warning to the Arduino Serial Monitor if it does not detect partition scheme that includes OTA partitions, and therefore cannot enable OTA. This checking is done upon start-up of a sketch immediately after WiFi connectivity has been established. + +### OTA Tips and Tricks + +The name of the device HomeSpan uses for OTA is the same as the name you assigned in your call to `homeSpan.begin()`. If you have more than one device you intend to maintain with OTA, use `homeSpan.begin()` to give them different names so you can tell them apart when selecting which one to connect to from the Arduino IDE. + +Use the `homeSpan.setSketchVersion()` method to set a version number for you sketch. HomeSpan includes this value as part of its HAP MDNS broadcast, which means that by simply inspecting this broadcast you can learn which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version, HomeSpan also broadcasts two other useful fields: the version number of the HomeSpan library used when the sketch was compiled, and an indicator of whether OTA is enabled. + +The easiest way to inspect HAP MDNS broadcasts is with an MDNS browser. There are a number of free ones available in the App Store. HAP broadcasts will be found under the MDNS service name "_hap._tcp." + +Always test out a new sketch on a local device connected to your computer before uploading it to a remote device via OTA. If the sketch doesn't operate as expected, you can always upload the previous version, unless the new sketch causes crashes that continously reboot HomeSpan. If HomeSpan can't run the OTA code, you won't be able to upload any sketches via OTA and you'll need to connect the device to a computer for programming via the serial port instead. + +The ESP32 supports automated rollbacks that are designed to restore a device with a previouslt-working sketch under exactly these circumstances. However, the current Arduino-ESP32 library does not support this feature. -Though not recommended, you can disable the requirement for a password by enabling OTA with *false* as the parameter as such: `homeSpan.enableOTA(false)`. Use with caution! Anyone who can access the device over your network will be able to upload a new sketch. -If OTA is enabled, HomeSpan will check that the sketch has been compiled with OTA partitions, and output a confirmation message to the Arduino Serial Monitor upon start-up immediately after establishing WiFi connectivity. If OTA is enabled in a sketch but OTA partitions are not found, HomeSpan will instead report a warning that it can't start OTA. Partition selection is found under the *Tools* menu of the Arduino IDE. Note that depending on your specific ESP32 device, the Partition Scheme labeled "default" may bne configured with OTA partitions. The easiest way to find out is to select that scheme and check for verification by HomeSpan. From d5757e6ab884bbf00fbdd111a1b5f456b7b253df Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 16 Feb 2021 21:55:10 -0600 Subject: [PATCH 46/55] Update OTA.md --- docs/OTA.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/OTA.md b/docs/OTA.md index 5dcac1d..372e821 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -2,7 +2,7 @@ HomeSpan supports Over-the-Air (OTA) updates, which allows you to *wirelessly* upload sketches directly from the Arduino IDE. To activate this feature for your sketch, simply call the method `homeSpan.enableOTA()` prior to calling `homeSpan.begin()`. -When a HomeSpan sketch is run with OTA enabled, the device shows up as a "network" port that can be selected under *Tools → Port* in the Arduino IDE. Once selected, the IDE will direct all uploads to the device via WiFi instead of looking for it on a serial port. Note that you can upload via OTA even if your device is still connected to a serial port, but the IDE does not presently support multiple port connections at the same time and will automatically close the Serial Monitor upon selecting your device via a network port. +When a HomeSpan sketch is run with OTA enabled, the device shows up as a "network" port that can be selected under the *Tools → Port* menu in the Arduino IDE. Once selected, the IDE will direct all uploads to the device via WiFi instead of looking for it on a serial port. Note that you can upload via OTA even if your device is still connected to a serial port, but the Arduino IDE does not presently support multiple port connections at the same time and will automatically close the Serial Monitor upon selecting your device via a network port. By default, HomeSpan requires the use of a password whenever you begin an OTA upload. The default OTA password is "homespan-ota". The Arduino will prompt you for this when you attempt the first OTA upload after opening the Arduino IDE, after which it will remember the password until the IDE is shut down. From be71798836f34d6effdd21ee62b0025c4dc0de98 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Wed, 17 Feb 2021 08:02:12 -0600 Subject: [PATCH 47/55] Update OTA.md --- docs/OTA.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/OTA.md b/docs/OTA.md index 372e821..70b74c2 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -1,30 +1,28 @@ # Over-the-Air (OTA) Updates -HomeSpan supports Over-the-Air (OTA) updates, which allows you to *wirelessly* upload sketches directly from the Arduino IDE. To activate this feature for your sketch, simply call the method `homeSpan.enableOTA()` prior to calling `homeSpan.begin()`. +HomeSpan supports Over-the-Air (OTA) updates, which allows you to *wirelessly* upload sketches directly from the Arduino IDE - no serial connection needed. To activate this feature for your sketch, simply call the method `homeSpan.enableOTA()` prior to calling `homeSpan.begin()`. -When a HomeSpan sketch is run with OTA enabled, the device shows up as a "network" port that can be selected under the *Tools → Port* menu in the Arduino IDE. Once selected, the IDE will direct all uploads to the device via WiFi instead of looking for it on a serial port. Note that you can upload via OTA even if your device is still connected to a serial port, but the Arduino IDE does not presently support multiple port connections at the same time and will automatically close the Serial Monitor upon selecting your device via a network port. +When a HomeSpan sketch is run with OTA enabled, the device shows up as a "network" port that can be selected under the *Tools → Port* menu in the Arduino IDE. Once selected, the IDE will direct all uploads to the device via WiFi instead of looking for it on a serial port. Note that you can upload via OTA even if your device is still connected to a serial port, but the Arduino IDE does not presently support multiple port connections at the same time. If you select a "network" port, the IDE will automatically close the Serial Monitor if it is open. To re-instate uploads via the "serial" port, simply choose that port from the *Tools → Port* menu in the Arduino IDE. Uploading via the serial port is always possible regardless of whether you have enabled OTA for a sketch. -By default, HomeSpan requires the use of a password whenever you begin an OTA upload. The default OTA password is "homespan-ota". The Arduino will prompt you for this when you attempt the first OTA upload after opening the Arduino IDE, after which it will remember the password until the IDE is shut down. +By default, HomeSpan requires the use of a password whenever you begin an OTA upload. The default OTA password is "homespan-ota". The Arduino will prompt you for this password upon your first attempt to upload a sketch to a newly-connected device. However, once the password for a specific device is entered, the Arduino IDE retains it in memory as long as the IDE is running, thereby saving you from having to type it again every time you re-upload a sketch via OTA. You can change the password for a HomeSpan device from the [HomeSpan CLI](CLI.md) with the 'O' command. Similar to a device's Setup Code, HomeSpan saves a non-recoverable hashed version of the OTA password you specify in non-volatile storage (NVS). If you forget the password you specified, you'll need to create a new one using the 'O' command, or you can restore the default OTA password by fully erasing the NVS with the 'E' command. -> :exclamation: Though not recommended, you can override the requirement for a password by enabling OTA with *false* as the parameter as such: `homeSpan.enableOTA(false)`. Use with caution! Anyone who can access the device over your network will now be able to upload a new sketch. +> :exclamation: Though not recommended, you can override the requirement for a password when enabling OTA for your sketch by including *false* as a parameter to the enabling method as such: `homeSpan.enableOTA(false)`. Use with caution! Anyone who can access the device over your network will now be able to upload a new sketch. -Note that in in order for OTA to properly operate, your sketch must be compiled using by selecting a Parition Scheme under the *Tools* menut that includes OTA partitions. These are usually labeled to indicate if OTA is supported, though sometimes the "default" scheme is also set up for OTA. +Note that in in order for OTA to properly operate, your sketch must be compiled with a partition scheme that includes OTA partitions. Partition schemes are found under the *Tools → Partition Scheme* menu of the Arduino IDE. Select a scheme that indicates it supports OTA. Note that schemes labeled "default" usually include OTA partitions. If unsure, try it out. HomeSpan will let you know if it does or does not. -When OTA is enabled in a sketch, HomeSpan checks that it has been compiled with OTA partitions, and will output a warning to the Arduino Serial Monitor if it does not detect partition scheme that includes OTA partitions, and therefore cannot enable OTA. This checking is done upon start-up of a sketch immediately after WiFi connectivity has been established. +This is because HomeSpan checks that a sketch has been compiled with OTA partitions if OTA has been enabled for that sketch. If OTA has been enabled but HomeSpan does not find any OTA partitioms, it will indicate it cannot start the OTA Server via a warning message sent to the Serial Monitor immediately after WiFi connectivity has been established. Otherwise it will output a confirmation message indicating the OTA Server has sucessfully started. ### OTA Tips and Tricks -The name of the device HomeSpan uses for OTA is the same as the name you assigned in your call to `homeSpan.begin()`. If you have more than one device you intend to maintain with OTA, use `homeSpan.begin()` to give them different names so you can tell them apart when selecting which one to connect to from the Arduino IDE. +* The name of the device HomeSpan uses for OTA is the same as the name you assigned in your call to `homeSpan.begin()`. If you have multiple devices you intend to maintain with OTA, use `homeSpan.begin()` to give them each different names so you can tell them apart when selecting which one to connect to from the Arduino IDE. -Use the `homeSpan.setSketchVersion()` method to set a version number for you sketch. HomeSpan includes this value as part of its HAP MDNS broadcast, which means that by simply inspecting this broadcast you can learn which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version, HomeSpan also broadcasts two other useful fields: the version number of the HomeSpan library used when the sketch was compiled, and an indicator of whether OTA is enabled. +* Use the `homeSpan.setSketchVersion()` method to set a version name or number for your sketch. If specified, HomeSpan will include the sketch version name/number as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version name/number, HomeSpan also broadcasts two other useful fields: the version number of the HomeSpan library used when the sketch was compiled, and field indicating whether or not OTA is enabled for the sketch. See [HomeSpan MDNS](MDNS.md) for details on this broadcast and how to browse the data. -The easiest way to inspect HAP MDNS broadcasts is with an MDNS browser. There are a number of free ones available in the App Store. HAP broadcasts will be found under the MDNS service name "_hap._tcp." +* Always test out a new sketch on a local device connected to your computer before uploading it to a remote device via OTA. If the sketch doesn't operate as * expected, you can always upload the previous version, unless the new sketch causes crashes that continously reboot HomeSpan. If HomeSpan can't run the OTA code, you won't be able to upload any sketches via OTA and you'll need to connect the device to a computer for programming via the serial port instead. -Always test out a new sketch on a local device connected to your computer before uploading it to a remote device via OTA. If the sketch doesn't operate as expected, you can always upload the previous version, unless the new sketch causes crashes that continously reboot HomeSpan. If HomeSpan can't run the OTA code, you won't be able to upload any sketches via OTA and you'll need to connect the device to a computer for programming via the serial port instead. - -The ESP32 supports automated rollbacks that are designed to restore a device with a previouslt-working sketch under exactly these circumstances. However, the current Arduino-ESP32 library does not support this feature. +* The ESP32 supports automated rollbacks that are designed to restore a device with a previouslt-working sketch under exactly these circumstances. However, the current Arduino-ESP32 library does not support this feature. From edefa1380c058f03367728c8fb5863611ef667f3 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Wed, 17 Feb 2021 08:15:08 -0600 Subject: [PATCH 48/55] Update OTA.md --- docs/OTA.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/OTA.md b/docs/OTA.md index 70b74c2..5f9795d 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -18,7 +18,7 @@ This is because HomeSpan checks that a sketch has been compiled with OTA partiti * The name of the device HomeSpan uses for OTA is the same as the name you assigned in your call to `homeSpan.begin()`. If you have multiple devices you intend to maintain with OTA, use `homeSpan.begin()` to give them each different names so you can tell them apart when selecting which one to connect to from the Arduino IDE. -* Use the `homeSpan.setSketchVersion()` method to set a version name or number for your sketch. If specified, HomeSpan will include the sketch version name/number as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version name/number, HomeSpan also broadcasts two other useful fields: the version number of the HomeSpan library used when the sketch was compiled, and field indicating whether or not OTA is enabled for the sketch. See [HomeSpan MDNS](MDNS.md) for details on this broadcast and how to browse the data. +* Use the `homeSpan.setSketchVersion()` method to set a version name or number for your sketch. If specified, HomeSpan will include the sketch version name/number as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version name/number, HomeSpan also broadcasts two other useful fields: the version number of the HomeSpan library used when the sketch was compiled, and a field indicating whether or not OTA is enabled for the sketch. See [HomeSpan MDNS](MDNS.md) for details on this broadcast and how to browse its data. * Always test out a new sketch on a local device connected to your computer before uploading it to a remote device via OTA. If the sketch doesn't operate as * expected, you can always upload the previous version, unless the new sketch causes crashes that continously reboot HomeSpan. If HomeSpan can't run the OTA code, you won't be able to upload any sketches via OTA and you'll need to connect the device to a computer for programming via the serial port instead. From 66cd30fa80400f1f2163d420a1184f6174437ed3 Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 17 Feb 2021 08:54:29 -0600 Subject: [PATCH 49/55] Small tweak to diagnostic message when OTA is started --- src/HomeSpan.cpp | 4 ++-- src/src.ino | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 4c30e43..637aec2 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -483,14 +483,14 @@ void Span::checkConnect(){ }); ArduinoOTA.begin(); - Serial.print("Starting OTA: "); + Serial.print("Starting OTA Server: "); Serial.print(displayName); Serial.print(" at "); Serial.print(WiFi.localIP()); Serial.print("\nAuthorization Password: "); Serial.print(otaAuth?"Enabled\n\n":"DISABLED!\n\n"); } else { - Serial.print("\n*** Warning: Can't enable OTA - Partition table used to compile this sketch is not configured for OTA.\n\n"); + Serial.print("\n*** Warning: Can't start OTA Server - Partition table used to compile this sketch is not configured for OTA.\n\n"); } } diff --git a/src/src.ino b/src/src.ino index 122b785..c2ed9eb 100644 --- a/src/src.ino +++ b/src/src.ino @@ -11,14 +11,14 @@ void setup() { homeSpan.setLogLevel(1); // homeSpan.setHostNameSuffix(""); - homeSpan.setPortNum(1200); - homeSpan.setMaxConnections(6); + homeSpan.setPortNum(1201); +// homeSpan.setMaxConnections(6); // homeSpan.setQRID("One1"); -// homeSpan.enableOTA(false); - homeSpan.setSketchVersion("Test 1.2.6"); + homeSpan.enableOTA(); + homeSpan.setSketchVersion("Test 1.3.0"); homeSpan.setWifiCallback(wifiEstablished); - homeSpan.begin(Category::Lighting,"HomeSpanTest"); + homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespanlamp"); new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments @@ -41,8 +41,9 @@ void setup() { new Characteristic::On(); new Characteristic::Brightness(); new Characteristic::Name("Light 2"); - new Service::Switch(); + (new Service::Switch())->setPrimary(); new Characteristic::On(); + new Characteristic::Name("Switch 3"); } // end of setup() From e0b9958001f2c7f80cea7618f837f6c49225ebc9 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 18 Feb 2021 07:28:14 -0600 Subject: [PATCH 50/55] Update OTA.md --- docs/OTA.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/OTA.md b/docs/OTA.md index 5f9795d..4a87bd0 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -18,11 +18,11 @@ This is because HomeSpan checks that a sketch has been compiled with OTA partiti * The name of the device HomeSpan uses for OTA is the same as the name you assigned in your call to `homeSpan.begin()`. If you have multiple devices you intend to maintain with OTA, use `homeSpan.begin()` to give them each different names so you can tell them apart when selecting which one to connect to from the Arduino IDE. -* Use the `homeSpan.setSketchVersion()` method to set a version name or number for your sketch. If specified, HomeSpan will include the sketch version name/number as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version name/number, HomeSpan also broadcasts two other useful fields: the version number of the HomeSpan library used when the sketch was compiled, and a field indicating whether or not OTA is enabled for the sketch. See [HomeSpan MDNS](MDNS.md) for details on this broadcast and how to browse its data. +* Use the `homeSpan.setSketchVersion()` method to set a version for your sketch (see the [HomeSpan API](Reference.md) for details). If specified, HomeSpan will include the sketch version as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version, HomeSpan also includes two other fields in its MDNS broadcast: the version number of the HomeSpan *library* used to compile the sketch, and a field indicating whether or not OTA is enabled for the sketch. See [HomeSpan MDNS](MDNS.md) for details. -* Always test out a new sketch on a local device connected to your computer before uploading it to a remote device via OTA. If the sketch doesn't operate as * expected, you can always upload the previous version, unless the new sketch causes crashes that continously reboot HomeSpan. If HomeSpan can't run the OTA code, you won't be able to upload any sketches via OTA and you'll need to connect the device to a computer for programming via the serial port instead. +* If a sketch you've uploaded with OTA does not operate as expected, you can continue making modifications to the code and re-upload again. Or, you can upload a prior version that was working properly. However, this assumes that the sketch you uploaded does not have major problems, such as causing a kernel panic that leads to an endless cycle of device reboots. If this happens, HomeSpan won't be able to run the OTA Server code, and further OTA updates will *not* ne possible. Instead, you'll have to connect the device through a serial port to upload a new, working sketch. **For this reason you should always fully test out a new sketch on a local device connected to your computer *before* uploading it to a remote, hard-to-access device via OTA.** -* The ESP32 supports automated rollbacks that are designed to restore a device with a previouslt-working sketch under exactly these circumstances. However, the current Arduino-ESP32 library does not support this feature. +* The ESP32 itself supports "automated" rollbacks that are designed to restore a device with a previously-working sketch if the latest sketch causes a reboot before being able to set a self-test flag verifiying the code is operating correctly. However, the version of the ESP32-IDF library (3.2.3) used by the latest version of the Arduino-ESP32 Library (1.0.4, at the time of this posting) does not support this feature. From b1a0b32b3b630d864800c5d984f93fba623bc596 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 18 Feb 2021 20:57:49 -0600 Subject: [PATCH 51/55] Update OTA.md --- docs/OTA.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/OTA.md b/docs/OTA.md index 4a87bd0..dcda25c 100644 --- a/docs/OTA.md +++ b/docs/OTA.md @@ -18,7 +18,7 @@ This is because HomeSpan checks that a sketch has been compiled with OTA partiti * The name of the device HomeSpan uses for OTA is the same as the name you assigned in your call to `homeSpan.begin()`. If you have multiple devices you intend to maintain with OTA, use `homeSpan.begin()` to give them each different names so you can tell them apart when selecting which one to connect to from the Arduino IDE. -* Use the `homeSpan.setSketchVersion()` method to set a version for your sketch (see the [HomeSpan API](Reference.md) for details). If specified, HomeSpan will include the sketch version as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version, HomeSpan also includes two other fields in its MDNS broadcast: the version number of the HomeSpan *library* used to compile the sketch, and a field indicating whether or not OTA is enabled for the sketch. See [HomeSpan MDNS](MDNS.md) for details. +* Use the `homeSpan.setSketchVersion()` method to set a version for your sketch (see the [HomeSpan API](Reference.md) for details). If specified, HomeSpan will include the sketch version as part of its HAP MDNS broadcast. This allows you determine which version of a sketch is running on a remote HomeSpan device, even if you can't plug it into a serial port for use with the Arduino Serial Monitor. In addition to the sketch version, HomeSpan also includes two other fields in its MDNS broadcast: the version number of the HomeSpan *library* used to compile the sketch, and a field indicating whether or not OTA is enabled for the sketch. * If a sketch you've uploaded with OTA does not operate as expected, you can continue making modifications to the code and re-upload again. Or, you can upload a prior version that was working properly. However, this assumes that the sketch you uploaded does not have major problems, such as causing a kernel panic that leads to an endless cycle of device reboots. If this happens, HomeSpan won't be able to run the OTA Server code, and further OTA updates will *not* ne possible. Instead, you'll have to connect the device through a serial port to upload a new, working sketch. **For this reason you should always fully test out a new sketch on a local device connected to your computer *before* uploading it to a remote, hard-to-access device via OTA.** From 96d3877ef63ae7a2bbbd2a33597bc9d837267c19 Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 18 Feb 2021 21:02:41 -0600 Subject: [PATCH 52/55] Added check to ensure HostName is valid Must be 255 or less alphanumeric characters or a hyphen, except hyphen can't be first or last character. --- src/HomeSpan.cpp | 10 ++++++++++ src/src.ino | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 637aec2..c9463a2 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -398,6 +398,16 @@ void Span::checkConnect(){ else sprintf(hostName,"%s%s",hostNameBase,hostNameSuffix); + char d[strlen(hostName)+1]; + sscanf(hostName,"%[A-Za-z0-9-]",d); + + if(strlen(hostName)>255|| hostName[0]=='-' || hostName[strlen(hostName)-1]=='-' || strlen(hostName)!=strlen(d)){ + Serial.printf("\n*** Error: Can't start MDNS due to invalid hostname '%s'.\n",hostName); + Serial.print("*** Hostname must consist of 255 or less alphanumeric characters or a hyphen, except that the hyphen cannot be the first or last character.\n"); + Serial.print("*** PROGRAM HALTED!\n\n"); + while(1); + } + Serial.print("\nStarting MDNS...\n\n"); Serial.print("HostName: "); Serial.print(hostName); diff --git a/src/src.ino b/src/src.ino index c2ed9eb..eff4b47 100644 --- a/src/src.ino +++ b/src/src.ino @@ -10,15 +10,15 @@ void setup() { homeSpan.setLogLevel(1); -// homeSpan.setHostNameSuffix(""); + homeSpan.setHostNameSuffix("-lamp1"); homeSpan.setPortNum(1201); // homeSpan.setMaxConnections(6); // homeSpan.setQRID("One1"); homeSpan.enableOTA(); - homeSpan.setSketchVersion("Test 1.3.0"); + homeSpan.setSketchVersion("Test 1.3.1"); homeSpan.setWifiCallback(wifiEstablished); - homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespanlamp"); + homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments From c7447b061ce864075d6ba032b363fa4390e53c93 Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 18 Feb 2021 21:09:28 -0600 Subject: [PATCH 53/55] Set Version to 1.2.0 --- library.properties | 2 +- src/Settings.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library.properties b/library.properties index c155501..3972eb8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HomeSpan -version=1.1.5 +version=1.2.0 author=Gregg maintainer=Gregg sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE. diff --git a/src/Settings.h b/src/Settings.h index 0e8d337..a7a445b 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -33,8 +33,8 @@ // HomeSpan Version // #define HS_MAJOR 1 -#define HS_MINOR 1 -#define HS_PATCH 5 +#define HS_MINOR 2 +#define HS_PATCH 0 #define STRINGIFY(x) _STR(x) #define _STR(x) #x From dd4f8f34f83e11c77f1e72565489229d83df844c Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 18 Feb 2021 21:31:57 -0600 Subject: [PATCH 54/55] Update README.md --- docs/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 24d9181..d30da62 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,9 +37,9 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A * Launch the WiFi Access Point * A standalone, detailed End-User Guide -## Latest Update (1/24/2021) +## Latest Update (2/18/2021) -* HomeSpan 1.1.4 - HomeSpan now recognizes QR Codes for pairing! This release also includes a new method allowing you to change the TCP port used for communication to-and-from HomeKit, as well as a new method to modify the hostname suffix (or eliminate it all together). Improved parsing of text input through the Serial Monitor addresses (hopefully!) an issue using HomeSpan with Platform IO. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details. +* HomeSpan 1.2.0 - HomeSpan now suports Over-the-Air ([OTA](https://github.com/HomeSpan/HomeSpan/blob/master/docs/OTA.md)) updates directly from the Arduino IDE (no serial connection needed)! This release also adds support for Linked Services and includes a new [tutorial example](https://github.com/HomeSpan/HomeSpan/blob/release-1.2.0/docs/Tutorials.md#example-17---linkedservices) demonstrating how Linked Services can be used to implement a multi-headed spa shower. Other new features include the ability to set the version number of your sketch (helpful when using OTA updates), and a method for specifying a user-defined function to callback after WiFi connectivity is established. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details. # HomeSpan Resources @@ -55,6 +55,7 @@ HomeSpan includes the following documentation: * [HomeSpan User Guide](https://github.com/HomeSpan/HomeSpan/blob/master/docs/UserGuide.md) - turnkey instructions on how to configure an already-programmed HomeSpan device's WiFi Credentials, modify its HomeKit Setup Code, and pair the device to HomeKit. No computer needed! * [HomeSpan API Reference](https://github.com/HomeSpan/HomeSpan/blob/master/docs/Reference.md) - a complete guide to the HomeSpan Library API * [HomeSpan QR Codes](https://github.com/HomeSpan/HomeSpan/blob/master/docs/QRCodes.md) - create and use QR Codes for pairing HomeSpan devices +* [HomeSpan OTA](https://github.com/HomeSpan/HomeSpan/blob/master/docs/OTA.md) - update your sketches Over-the-Air directly from the Arduino IDE without a serial connection * [HomeSpan Extras](https://github.com/HomeSpan/HomeSpan/blob/master/docs/Extras.md) - integrated access to the ESP32's on-chip PWM and Remote Control peripherals! * [HomeSpan Projects](https://github.com/topics/homespan) - real-world applications of the HomeSpan Library From b666fe7c6919d5edd06b7fa68c9627ab40963b1c Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 18 Feb 2021 21:34:34 -0600 Subject: [PATCH 55/55] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index d30da62..938027f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -39,7 +39,7 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A ## Latest Update (2/18/2021) -* HomeSpan 1.2.0 - HomeSpan now suports Over-the-Air ([OTA](https://github.com/HomeSpan/HomeSpan/blob/master/docs/OTA.md)) updates directly from the Arduino IDE (no serial connection needed)! This release also adds support for Linked Services and includes a new [tutorial example](https://github.com/HomeSpan/HomeSpan/blob/release-1.2.0/docs/Tutorials.md#example-17---linkedservices) demonstrating how Linked Services can be used to implement a multi-headed spa shower. Other new features include the ability to set the version number of your sketch (helpful when using OTA updates), and a method for specifying a user-defined function to callback after WiFi connectivity is established. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details. +* HomeSpan 1.2.0 - HomeSpan now suports Over-the-Air ([OTA](https://github.com/HomeSpan/HomeSpan/blob/master/docs/OTA.md)) updates directly from the Arduino IDE (no serial connection needed)! This release also adds support for Linked Services and includes a new [tutorial example](https://github.com/HomeSpan/HomeSpan/blob/master/docs/Tutorials.md#example-17---linkedservices) demonstrating how Linked Services can be used to implement a multi-headed spa shower. Other new features include the ability to set the version number of your sketch (helpful when using OTA updates), and a method for specifying a user-defined function to callback after WiFi connectivity is established. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details. # HomeSpan Resources