From b87a3d1dc3fee96c43c7b263eb96309900c5c478 Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 21 Jan 2021 08:07:57 -0600 Subject: [PATCH 1/7] Added new method homeSpan.setHostNameSuffix() Allows user to replace the 6-byte AccessoryID "suffix" in the hostName with a custom suffix, included a blank string. To do: Add to documentation. --- src/HomeSpan.cpp | 16 +++++++++++++--- src/HomeSpan.h | 4 +++- src/src.ino | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index a37e8f8..2cf9e1c 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -362,10 +362,20 @@ void Span::checkConnect(){ id[17]='\0'; // add terminating null // create broadcaset name from server base name plus accessory ID (without ':') - - int nChars=snprintf(NULL,0,"%s-%.2s%.2s%.2s%.2s%.2s%.2s",hostNameBase,id,id+3,id+6,id+9,id+12,id+15); + + int nChars; + + if(!hostNameSuffix) + nChars=snprintf(NULL,0,"%s-%.2s%.2s%.2s%.2s%.2s%.2s",hostNameBase,id,id+3,id+6,id+9,id+12,id+15); + else + nChars=snprintf(NULL,0,"%s%s",hostNameBase,hostNameSuffix); + char hostName[nChars+1]; - sprintf(hostName,"%s-%.2s%.2s%.2s%.2s%.2s%.2s",hostNameBase,id,id+3,id+6,id+9,id+12,id+15); + + if(!hostNameSuffix) + sprintf(hostName,"%s-%.2s%.2s%.2s%.2s%.2s%.2s",hostNameBase,id,id+3,id+6,id+9,id+12,id+15); + else + sprintf(hostName,"%s%s",hostNameBase,hostNameSuffix); Serial.print("\nStarting MDNS...\n"); Serial.print("Broadcasting as: "); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index ebbf623..09c0d49 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -75,7 +75,8 @@ struct SpanConfig { struct Span{ const char *displayName; // display name for this device - broadcast as part of Bonjour MDNS - const char *hostNameBase; // base of host name of this device - full host name broadcast by Bonjour MDNS will have 6-byte accessoryID as well as '.local' automatically appended + const char *hostNameBase; // base of hostName of this device - full host name broadcast by Bonjour MDNS will have 6-byte accessoryID as well as '.local' automatically appended + const char *hostNameSuffix=NULL; // optional "suffix" of hostName of this device. If specified, will be used as the hostName suffix instead of the 6-byte accessoryID char *hostName; // full host name of this device - constructed from hostNameBase and 6-byte AccessoryID const char *modelName; // model name of this device - broadcast as Bonjour field "md" char category[3]=""; // category ID of primary accessory - broadcast as Bonjour field "ci" (HAP Section 13) @@ -141,6 +142,7 @@ struct Span{ void setCommandTimeout(uint16_t nSec){comModeLife=nSec*1000;} // sets Command Mode Timeout (seconds) void setLogLevel(uint8_t level){logLevel=level;} // sets Log Level for log messages (0=baseline, 1=intermediate, 2=all) void setMaxConnections(uint8_t nCon){maxConnections=nCon;} // sets maximum number of simultaneous HAP connections (HAP requires devices support at least 8) + void setHostNameSuffix(const char *suffix){hostNameSuffix=suffix;} // sets the hostName suffix to be used instead of the 6-byte AccessoryID }; /////////////////////////////// diff --git a/src/src.ino b/src/src.ino index 9c1967b..87725b6 100644 --- a/src/src.ino +++ b/src/src.ino @@ -10,6 +10,8 @@ void setup() { homeSpan.setLogLevel(2); + homeSpan.setHostNameSuffix(""); + homeSpan.begin(Category::Lighting,"HomeSpanTest"); new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments From 750a65824163f7346e77503bd05c9b5986a441ef Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 22 Jan 2021 09:45:50 -0600 Subject: [PATCH 2/7] Added new method homeSpan.setPortNum(port) HomeSpan defaults to running the HAP Server on port 80 (the standard HTTP port). This method allows the user to over-ride the default and have HomeSpan run the HAP Server on any other port. ALSO: In updating this portion of the code, identified an additional parameter to the ESP32 version of WiFiServer that allows one to specify the number of simultaneous Server connections. The ESP32 default is 4, which suggests that the ESP32 was internally juggling connections that HomeSpan was keeping open (since the HomeSpan default is 8 connections). This WiFiServer call has been updated to now specify both the port number AND the number of maximum simultaneous connections (to match whatever has been set by HomeSpan). This may or may not result in improving performance when more than 4 clients are connected. --- src/HomeSpan.cpp | 27 ++++++++++++++------------- src/HomeSpan.h | 5 ++++- src/SRP.cpp | 1 - src/Settings.h | 1 + src/src.ino | 1 + 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 2cf9e1c..3ce1a08 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -35,8 +35,6 @@ using namespace Utils; -WiFiServer hapServer(80); // HTTP Server (i.e. this acccesory) running on usual port 80 (local-scoped variable to this file only) - HAPClient **hap; // HAP Client structure containing HTTP client connections, parsing routines, and state variables (global-scoped variable) Span homeSpan; // HAP Attributes database and all related control functions for this Accessory (global-scoped variable) @@ -127,6 +125,7 @@ void Span::poll() { statusLED.start(LED_WIFI_NEEDED); } else { homeSpan.statusLED.start(LED_WIFI_CONNECTING); + hapServer=new WiFiServer(tcpPortNum,maxConnections); } controlButton.reset(); @@ -150,7 +149,7 @@ void Span::poll() { WiFiClient newClient; - if(newClient=hapServer.available()){ // 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 @@ -377,18 +376,20 @@ void Span::checkConnect(){ else sprintf(hostName,"%s%s",hostNameBase,hostNameSuffix); - Serial.print("\nStarting MDNS...\n"); - Serial.print("Broadcasting as: "); + Serial.print("\nStarting MDNS...\n\n"); + Serial.print("HostName: "); Serial.print(hostName); - Serial.print(".local ("); + Serial.print(".local:"); + Serial.print(tcpPortNum); + Serial.print("\nDisplay Name: "); Serial.print(displayName); - Serial.print(" / "); + Serial.print("\nModel Name: "); Serial.print(modelName); - Serial.print(")\n"); + Serial.print("\n"); - MDNS.begin(hostName); // set server host name (.local implied) - MDNS.setInstanceName(displayName); // set server display name - MDNS.addService("_hap","_tcp",80); // advertise HAP service on HTTP port (80) + MDNS.begin(hostName); // set server host name (.local implied) + MDNS.setInstanceName(displayName); // set server display name + MDNS.addService("_hap","_tcp",tcpPortNum); // advertise HAP service on specified port // add MDNS (Bonjour) TXT records for configurable as well as fixed values (HAP Table 6-7) @@ -412,7 +413,7 @@ void Span::checkConnect(){ Serial.print("\nStarting Web (HTTP) Server supporting up to "); Serial.print(maxConnections); Serial.print(" simultaneous connections...\n\n"); - hapServer.begin(); + hapServer->begin(); if(!HAPClient::nAdminControllers()){ Serial.print("DEVICE NOT YET PAIRED -- PLEASE PAIR WITH HOMEKIT APP\n\n"); @@ -560,7 +561,7 @@ void Span::processSerialCommand(const char *c){ if(strlen(network.wifiData.ssid)>0){ Serial.print("*** Stopping all current WiFi services...\n\n"); - hapServer.end(); + hapServer->end(); MDNS.end(); WiFi.disconnect(); } diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 09c0d49..35c1687 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -96,7 +96,9 @@ struct Span{ uint8_t logLevel=DEFAULT_LOG_LEVEL; // level for writing out log messages to serial monitor 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 + WiFiServer *hapServer; // pointer to the HAP Server connection Blinker statusLED; // indicates HomeSpan status PushButton controlButton; // controls HomeSpan configuration and resets Network network; // configures WiFi and Setup Code via either serial monitor or temporary Access Point @@ -142,7 +144,8 @@ struct Span{ void setCommandTimeout(uint16_t nSec){comModeLife=nSec*1000;} // sets Command Mode Timeout (seconds) void setLogLevel(uint8_t level){logLevel=level;} // sets Log Level for log messages (0=baseline, 1=intermediate, 2=all) void setMaxConnections(uint8_t nCon){maxConnections=nCon;} // sets maximum number of simultaneous HAP connections (HAP requires devices support at least 8) - void setHostNameSuffix(const char *suffix){hostNameSuffix=suffix;} // sets the hostName suffix to be used instead of the 6-byte AccessoryID + 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 }; /////////////////////////////// diff --git a/src/SRP.cpp b/src/SRP.cpp index 3112b53..8565cd0 100644 --- a/src/SRP.cpp +++ b/src/SRP.cpp @@ -225,7 +225,6 @@ int SRP6A::verifyProof(){ void SRP6A::createProof(){ uint8_t tBuf[512]; // temporary buffer for staging - uint8_t tHash[64]; // temporary buffer for storing SHA-512 results // compute M2 = H( A | M1 | K ) diff --git a/src/Settings.h b/src/Settings.h index a4dfce4..9b2a88b 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -73,6 +73,7 @@ #define DEFAULT_LOG_LEVEL 0 // change with homeSpan.setLogLevel(level) #define DEFAULT_MAX_CONNECTIONS 8 // change with homeSpan.setMaxConnections(num); +#define DEFAULT_TCP_PORT 80 // change with homeSpan.setPort(port); ///////////////////////////////////////////////////// diff --git a/src/src.ino b/src/src.ino index 87725b6..519b1cb 100644 --- a/src/src.ino +++ b/src/src.ino @@ -11,6 +11,7 @@ void setup() { homeSpan.setLogLevel(2); homeSpan.setHostNameSuffix(""); + homeSpan.setPortNum(1200); homeSpan.begin(Category::Lighting,"HomeSpanTest"); From d41b335aeef825a52474a8fd1fadcd2f87bfe639 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 22 Jan 2021 21:37:29 -0600 Subject: [PATCH 3/7] Cleaned up various compiler warnings when compiled with max warning level Also added a missing check on hapServer existing before it is used (bug introduced in last update where hapServer became dynamically initialized). --- src/HAP.cpp | 25 ++++++++++++++----------- src/HomeSpan.cpp | 28 +++++++++++++++++----------- src/Network.cpp | 6 +++--- src/TLV.h | 4 +++- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 150a8df..0ccd436 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -647,6 +647,8 @@ int HAPClient::postPairSetupURL(){ } // switch + return(1); + } // postPairSetup ////////////////////////////////////// @@ -701,7 +703,7 @@ int HAPClient::postPairVerifyURL(){ memcpy(iosCurveKey,tlv8.buf(kTLVType_PublicKey),32); // save iosCurveKey (will persist until end of verification process) - int rVal=crypto_scalarmult_curve25519(sharedCurveKey,secretCurveKey,iosCurveKey); // generate (and persist) Pair Verify SharedSecret CurveKey from Accessory's Curve25519 secret key and Controller's Curve25519 public key (32 bytes) + crypto_scalarmult_curve25519(sharedCurveKey,secretCurveKey,iosCurveKey); // generate (and persist) Pair Verify SharedSecret CurveKey from Accessory's Curve25519 secret key and Controller's Curve25519 public key (32 bytes) uint8_t *accessoryPairingID = accessory.ID; // set accessoryPairingID size_t accessoryPairingIDLen = 17; @@ -842,6 +844,8 @@ int HAPClient::postPairVerifyURL(){ break; } // switch + + return(1); } // postPairVerify @@ -925,7 +929,7 @@ int HAPClient::postPairingsURL(){ break; } - if(newCont=findController(tlv8.buf(kTLVType_Identifier))){ + if((newCont=findController(tlv8.buf(kTLVType_Identifier)))){ tlv8.clear(); // clear TLV records tlv8.val(kTLVType_State,pairState_M2); // set State= if(!memcmp(cPair->LTPK,newCont->LTPK,32)){ // requested Controller already exists and LTPK matches @@ -1187,10 +1191,10 @@ int HAPClient::putPrepareURL(char *json){ uint32_t ttl; uint64_t pid; - if(cBuf=strstr(json,ttlToken)) - sscanf(cBuf+strlen(ttlToken),"%lu",&ttl); + if((cBuf=strstr(json,ttlToken))) + sscanf(cBuf+strlen(ttlToken),"%u",&ttl); - if(cBuf=strstr(json,pidToken)) + if((cBuf=strstr(json,pidToken))) sscanf(cBuf+strlen(ttlToken),"%llu",&pid); char jsonBuf[32]; @@ -1202,7 +1206,7 @@ int HAPClient::putPrepareURL(char *json){ status=StatusCode::InvalidValue; } - sprintf(jsonBuf,"{\"status\":%d}",status); + sprintf(jsonBuf,"{\"status\":%d}",(int)status); int nBytes=strlen(jsonBuf); int nChars=snprintf(NULL,0,"HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes); // create Body with Content Length = size of JSON Buf char body[nChars+1]; @@ -1264,7 +1268,7 @@ void HAPClient::checkTimedWrites(){ for(auto tw=homeSpan.TimedWrites.begin(); tw!=homeSpan.TimedWrites.end(); tw++){ // loop over all Timed Writes using an iterator if(cTime>tw->second){ // timer has expired - sprintf(c,"Removing PID=%llu ALARM=%lu\n",tw->first,tw->second); + sprintf(c,"Removing PID=%llu ALARM=%u\n",tw->first,tw->second); LOG2(c); homeSpan.TimedWrites.erase(tw); } @@ -1338,7 +1342,6 @@ void HAPClient::tlvRespond(){ int HAPClient::receiveEncrypted(){ uint8_t buf[1042]; // maximum size of encoded message = 2+1024+16 bytes (HAP Section 6.5.2) - int nFrames=0; int nBytes=0; while(client.read(buf,2)==2){ // read initial 2-byte AAD record @@ -1498,7 +1501,7 @@ Controller *HAPClient::addController(uint8_t *id, uint8_t *ltpk, boolean admin){ Controller *slot; - if(slot=findController(id)){ + if((slot=findController(id))){ memcpy(slot->LTPK,ltpk,32); slot->admin=admin; LOG2("\n*** Updated Controller: "); @@ -1508,7 +1511,7 @@ Controller *HAPClient::addController(uint8_t *id, uint8_t *ltpk, boolean admin){ return(slot); } - if(slot=getFreeController()){ + if((slot=getFreeController())){ slot->allocated=true; memcpy(slot->ID,id,36); memcpy(slot->LTPK,ltpk,32); @@ -1553,7 +1556,7 @@ void HAPClient::removeController(uint8_t *id){ Controller *slot; - if(slot=findController(id)){ // remove controller if found + if((slot=findController(id))){ // remove controller if found LOG2("\n***Removed Controller: "); if(homeSpan.logLevel>1) charPrintRow(id,36); diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 3ce1a08..6747fba 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -47,7 +47,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa this->displayName=displayName; this->hostNameBase=hostNameBase; this->modelName=modelName; - sprintf(this->category,"%d",catID); + sprintf(this->category,"%d",(int)catID); controlButton.init(controlPin); statusLED.init(statusPin); @@ -149,10 +149,10 @@ void Span::poll() { WiFiClient newClient; - if(newClient=hapServer->available()){ // found a new HTTP client - int freeSlot=getFreeSlot(); // get next free slot + if(hapServer && (newClient=hapServer->available())){ // found a new HTTP client + int freeSlot=getFreeSlot(); // get next free slot - if(freeSlot==-1){ // no available free slots + if(freeSlot==-1){ // no available free slots freeSlot=randombytes_uniform(maxConnections); LOG2("=======================================\n"); LOG1("** Freeing Client #"); @@ -817,7 +817,7 @@ int Span::countCharacteristics(char *buf){ int nObj=0; const char tag[]="\"aid\""; - while(buf=strstr(buf,tag)){ // count number of characteristic objects in PUT JSON request + while((buf=strstr(buf,tag))){ // count number of characteristic objects in PUT JSON request nObj++; buf+=strlen(tag); } @@ -999,7 +999,7 @@ int Span::sprintfAttributes(SpanBuf *pObj, int nObj, char *cBuf){ nChars+=snprintf(cBuf,cBuf?64:0,"{\"characteristics\":["); for(int i=0;i::create(tagType tag, int maxLen, const char *name){ tlv[numTags].name=name; tlv[numTags].len=-1; tlv[numTags].val=(uint8_t *)malloc(maxLen); - numTags++; + numTags++; + + return(1); } ////////////////////////////////////// From d68c34c53f5c3085721a8b10f040dd5860b3a1c8 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 22 Jan 2021 22:05:13 -0600 Subject: [PATCH 4/7] Update HomeSpan.h Fixed a few more compiler warnings related to const char * --- src/HomeSpan.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 35c1687..3cc2da6 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -138,8 +138,8 @@ struct Span{ void setControlPin(uint8_t pin){controlPin=pin;} // sets Control Pin void setStatusPin(uint8_t pin){statusPin=pin;} // sets Status Pin int getStatusPin(){return(statusPin);} // gets Status Pin - void setApSSID(char *ssid){network.apSSID=ssid;} // sets Access Point SSID - void setApPassword(char *pwd){network.apPassword=pwd;} // sets Access Point Password + void setApSSID(const char *ssid){network.apSSID=ssid;} // sets Access Point SSID + void setApPassword(const char *pwd){network.apPassword=pwd;} // sets Access Point Password void setApTimeout(uint16_t nSec){network.lifetime=nSec*1000;} // sets Access Point Timeout (seconds) void setCommandTimeout(uint16_t nSec){comModeLife=nSec*1000;} // sets Command Mode Timeout (seconds) void setLogLevel(uint8_t level){logLevel=level;} // sets Log Level for log messages (0=baseline, 1=intermediate, 2=all) From 9f7d288d18ada7c7e81b6db359b1158206ec5df7 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 23 Jan 2021 20:55:06 -0600 Subject: [PATCH 5/7] Ignore any '\r' characters received from Serial Monitor This allows the Serial Monitor to send NL or CR/NL at end of each line. A newline ('\n') must be at the end to terminate reading from the Serial Monitor, but any preceeding carriage returns are stripped out. --- src/Utils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 9ba88dc..38664e6 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -55,10 +55,11 @@ char *Utils::readSerial(char *c, int max){ return(c); // return updated string } - c[i]=buf; // store new character - - if(i Date: Sun, 24 Jan 2021 12:02:24 -0600 Subject: [PATCH 6/7] Updated licenses and version number Change copyright years to 2020-2021, and updated version number to 1.1.4 in preparation for next patch. --- library.properties | 2 +- src/HAP.cpp | 2 +- src/HAP.h | 2 +- src/HAPConstants.h | 2 +- src/HKDF.cpp | 2 +- src/HKDF.h | 2 +- src/HomeSpan.cpp | 2 +- src/HomeSpan.h | 2 +- src/Network.cpp | 2 +- src/Network.h | 2 +- src/SRP.cpp | 2 +- src/SRP.h | 2 +- src/Services.h | 2 +- src/Settings.h | 4 ++-- src/TLV.h | 2 +- src/Utils.cpp | 2 +- src/Utils.h | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/library.properties b/library.properties index 18d876c..4d04fdc 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HomeSpan -version=1.1.3 +version=1.1.4 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/HAP.cpp b/src/HAP.cpp index 0ccd436..947c021 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HAP.h b/src/HAP.h index e71c6ed..9730215 100644 --- a/src/HAP.h +++ b/src/HAP.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HAPConstants.h b/src/HAPConstants.h index a332ff8..fdef845 100644 --- a/src/HAPConstants.h +++ b/src/HAPConstants.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HKDF.cpp b/src/HKDF.cpp index 1ed8fe2..9c75be5 100644 --- a/src/HKDF.cpp +++ b/src/HKDF.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HKDF.h b/src/HKDF.h index 20eb713..c2057ba 100644 --- a/src/HKDF.h +++ b/src/HKDF.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 6747fba..4823b3d 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 3cc2da6..d1864a3 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Network.cpp b/src/Network.cpp index f0ae368..5d33383 100644 --- a/src/Network.cpp +++ b/src/Network.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Network.h b/src/Network.h index 8a1226e..035c3eb 100644 --- a/src/Network.h +++ b/src/Network.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/SRP.cpp b/src/SRP.cpp index 8565cd0..adce154 100644 --- a/src/SRP.cpp +++ b/src/SRP.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/SRP.h b/src/SRP.h index 01aef09..6b8a64d 100644 --- a/src/SRP.h +++ b/src/SRP.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Services.h b/src/Services.h index 664e034..ed3bb5f 100644 --- a/src/Services.h +++ b/src/Services.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Settings.h b/src/Settings.h index 9b2a88b..6631e06 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * @@ -34,7 +34,7 @@ #define HS_MAJOR 1 #define HS_MINOR 1 -#define HS_PATCH 3 +#define HS_PATCH 4 #define STRINGIFY(x) _STR(x) #define _STR(x) #x diff --git a/src/TLV.h b/src/TLV.h index 19906b6..ce11cde 100644 --- a/src/TLV.h +++ b/src/TLV.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Utils.cpp b/src/Utils.cpp index 38664e6..0bf1578 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Utils.h b/src/Utils.h index c311297..a16d53d 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020 Gregg E. Berman + * Copyright (c) 2020-2021 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * From 9b71d6928a98b8508c0079e4c85b7da44a4b544e Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 24 Jan 2021 18:46:55 -0600 Subject: [PATCH 7/7] Added QR Code logic HomeSpan now broadcasts a Hashed Setup ID as MDNS "sh", which is used when pairing with a QR Code instead of a Setup Code. A text version of the resulting QR code is output to the Serial Monitor whenever the 9-digit Setup Code is generated or changed. The text version of the QR code can then be input into any QR Code Generator to create a pairable QR Code. The default Setup ID used to create the Hashed Setup ID is "HSPN". This can be changed with homeSpan.setQRCode(const char *id), where id is exactly 4 alphanumeric characters. If not, the request to change the Setup ID is silently ignored and remains "HSPN." --- src/HAP.cpp | 7 +++++-- src/HomeSpan.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ src/HomeSpan.h | 4 ++++ src/SRP.h | 1 + src/Settings.h | 2 ++ src/src.ino | 5 +---- 6 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 947c021..f788d6a 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -58,11 +58,14 @@ void HAPClient::init(){ } else { char c[128]; - sprintf(c,"Generating SRP verification data for default Setup Code: %.3s-%.2s-%.3s\n\n",homeSpan.defaultSetupCode,homeSpan.defaultSetupCode+3,homeSpan.defaultSetupCode+5); + sprintf(c,"Generating SRP verification data for default Setup Code: %.3s-%.2s-%.3s\n",homeSpan.defaultSetupCode,homeSpan.defaultSetupCode+3,homeSpan.defaultSetupCode+5); Serial.print(c); srp.createVerifyCode(homeSpan.defaultSetupCode,verifyData.verifyCode,verifyData.salt); // create verification code from default Setup Code and random salt nvs_set_blob(srpNVS,"VERIFYDATA",&verifyData,sizeof(verifyData)); // update data - nvs_commit(srpNVS); // commit to NVS + nvs_commit(srpNVS); // commit to NVS + Serial.print("Optional QR Code: "); + Serial.print(homeSpan.getQRCode(homeSpan.defaultSetupCode)); + Serial.print("\n\n"); } if(!nvs_get_blob(hapNVS,"ACCESSORY",NULL,&len)){ // if found long-term Accessory data in NVS diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 4823b3d..caab137 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -410,6 +410,17 @@ void Span::checkConnect(){ else mdns_service_txt_item_set("_hap","_tcp","sf","0"); // set Status Flag = 0 + uint8_t hashInput[22]; + uint8_t hashOutput[64]; + char setupHash[9]; + size_t len; + + memcpy(hashInput,qrID,4); // Create the Seup ID for use with optional QR Codes. This is an undocumented feature of HAP R2! + memcpy(hashInput+4,id,17); // Step 1: Concatenate 4-character Setup ID and 17-character Accessory ID into hashInput + mbedtls_sha512_ret(hashInput,21,hashOutput,0); // Step 2: Perform SHA-512 hash on combined 21-byte hashInput to create 64-byte hashOutput + 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\n"); @@ -426,6 +437,19 @@ void Span::checkConnect(){ /////////////////////////////// +void Span::setQRID(const char *id){ + + char tBuf[5]; + sscanf(id,"%4[0-9A-Za-z]",tBuf); + + if(strlen(id)==4 && strlen(tBuf)==4){ + qrID=id; + } + +} // setQRID + +/////////////////////////////// + void Span::processSerialCommand(const char *c){ switch(c[0]){ @@ -515,6 +539,10 @@ void Span::processSerialCommand(const char *c){ nvs_set_blob(HAPClient::srpNVS,"VERIFYDATA",&verifyData,sizeof(verifyData)); // update data nvs_commit(HAPClient::srpNVS); // commit to NVS Serial.print("New Code Saved!\n"); + + Serial.print("Optional QR Code: "); + Serial.print(getQRCode(setupCode)); + Serial.print("\n\n"); } } break; @@ -725,6 +753,32 @@ void Span::processSerialCommand(const char *c){ /////////////////////////////// +const char *Span::getQRCode(const char *setupCode){ + + uint64_t n; + uint64_t iSetupCode; + uint64_t iCategory; + + sscanf(category,"%llu",&iCategory); + sscanf(setupCode,"%llu",&iSetupCode); + + n=(iCategory << 31) | (0xA << 27) | iSetupCode; + + qrCode=""; + + while(n>0){ + char c=n%36+48; + if(c>57) + c+=7; + qrCode=c+qrCode; + n/=36; + } + qrCode="X-HM://00" + qrCode + qrID; + return(qrCode.c_str()); +} + +/////////////////////////////// + int Span::sprintfAttributes(char *cBuf){ int nBytes=0; diff --git a/src/HomeSpan.h b/src/HomeSpan.h index d1864a3..3ead256 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -85,6 +85,7 @@ struct Span{ int nFatalErrors=0; // number of fatal errors in user-defined configuration 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) + String qrCode; // optional QR Code to use for pairing boolean connected=false; // WiFi connection status unsigned long waitTime=60000; // time to wait (in milliseconds) between WiFi connection attempts @@ -97,6 +98,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 WiFiServer *hapServer; // pointer to the HAP Server connection Blinker statusLED; // indicates HomeSpan status @@ -146,6 +148,8 @@ struct Span{ void setMaxConnections(uint8_t nCon){maxConnections=nCon;} // sets maximum number of simultaneous HAP connections (HAP requires devices support at least 8) 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 + const char *getQRCode(const char *setupCode); // gets an optional QR code from setupCode }; /////////////////////////////// diff --git a/src/SRP.h b/src/SRP.h index 6b8a64d..d5f1066 100644 --- a/src/SRP.h +++ b/src/SRP.h @@ -29,6 +29,7 @@ #include #include +#include #include "HAPConstants.h" diff --git a/src/Settings.h b/src/Settings.h index 6631e06..9b1ccc6 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -61,6 +61,8 @@ #define DEFAULT_SETUP_CODE "46637726" // changed during network setup or with 'S' command +#define DEFAULT_QR_ID "HSPN" // change with homeSpan.setQRID(qrID); + #define DEFAULT_CONTROL_PIN 21 // change with homeSpan.setControlPin(pin) #define DEFAULT_STATUS_PIN 13 // change with homeSpan.setStatusPin(pin) diff --git a/src/src.ino b/src/src.ino index 519b1cb..1a83208 100644 --- a/src/src.ino +++ b/src/src.ino @@ -8,10 +8,7 @@ void setup() { Serial.begin(115200); - homeSpan.setLogLevel(2); - - homeSpan.setHostNameSuffix(""); - homeSpan.setPortNum(1200); + homeSpan.setLogLevel(1); homeSpan.begin(Category::Lighting,"HomeSpanTest");