From 4f983051ce7b14a47cdafb0225c1ebf3a659af54 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 25 Sep 2022 13:53:54 -0500 Subject: [PATCH] Created SpanPoint Verified ESP-NOW is communicating correctly with HomeSpan. Verified encryption works. Next step - create linkages between incoming data and Services; create queue structure to transfer data. --- src/HomeSpan.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++------ src/HomeSpan.h | 29 ++++++++++++++++++---- src/src.ino | 3 +++ 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 70a9086..c77ed3f 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -31,10 +31,10 @@ #include #include #include +#include #include #include #include -#include #include "HomeSpan.h" #include "HAP.h" @@ -140,11 +140,7 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa Serial.print(__TIME__); Serial.printf("\nPartition: %s",esp_ota_get_running_partition()->label); - - if(espNowEnabled){ - esp_now_init(); // initialize ESP NOW - Serial.print("\nESP-NOW: ENABLED"); - } + Serial.printf("\nMAC Address: %s",WiFi.macAddress().c_str()); Serial.print("\n\nDevice Name: "); Serial.print(displayName); @@ -449,7 +445,6 @@ void Span::checkConnect(){ connected++; addWebLog(true,"WiFi Connected! IP Address = %s",WiFi.localIP().toString().c_str()); - Serial.printf("MAC Address = %s, Channel = %d\n",WiFi.macAddress().c_str(),WiFi.channel()); if(connected>1) // Do not initialize everything below if this is only a reconnect return; @@ -2155,6 +2150,57 @@ void SpanOTA::error(ota_error_t err){ else if (err == OTA_END_ERROR) Serial.println("End Failed\n"); } +/////////////////////////////// +// SpanPoint // +/////////////////////////////// + +SpanPoint::SpanPoint(const char *macAddress){ + + if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ + Serial.printf("\nFATAL ERROR! Can't create new SpanPoint(\"%s\") without a defined Service ***\n",macAddress); + Serial.printf("\n=== PROGRAM HALTED ==="); + while(1); + } + + init(); + + if(sscanf(macAddress,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",peerInfo.peer_addr,peerInfo.peer_addr+1,peerInfo.peer_addr+2,peerInfo.peer_addr+3,peerInfo.peer_addr+4,peerInfo.peer_addr+5)!=6){ + Serial.printf("\nFATAL ERROR! Can't create new SpanPoint(\"%s\") - Invalid MAC Address ***\n",macAddress); + Serial.printf("\n=== PROGRAM HALTED ==="); + while(1); + } + + peerInfo.channel=0; // 0=matches current WiFi channel + peerInfo.ifidx=WIFI_IF_STA; // must specify interface + peerInfo.encrypt=true; // turn on encryption for this peer + memcpy(peerInfo.lmk, lmk, 16); // set local key + esp_now_add_peer(&peerInfo); // add peer to ESP-NOW +} + +/////////////////////////////// + +void SpanPoint::init(const char *password){ + + if(initialized) + return; + + uint8_t hash[32]; + mbedtls_sha256_ret((const unsigned char *)password,strlen(password),hash,0); // produce 256-bit bit hash from password + + esp_now_init(); // initialize ESP-NOW + memcpy(lmk, hash, 16); // store first 16 bytes of hash for later use as local key + esp_now_set_pmk(hash+16); // set hash for primary key using last 16 bytes of hash + esp_now_register_recv_cb(dataReceived); // set callback for receiving data + + initialized=true; +} + +/////////////////////////////// + +void SpanPoint::dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len){ + Serial.printf("SpanPoint: %d bytes received from %02X:%02X:%02X:%02X:%02X:%02X\n",len,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); +} + /////////////////////////////// void __attribute__((weak)) loop(){ @@ -2166,5 +2212,7 @@ int SpanOTA::otaPercent; boolean SpanOTA::safeLoad; boolean SpanOTA::enabled=false; boolean SpanOTA::auth; +uint8_t SpanPoint::lmk[16]; +boolean SpanPoint::initialized=false; diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 205aac8..75ed259 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -39,6 +39,7 @@ #include #include #include +#include #include "extras/Blinker.h" #include "extras/Pixel.h" @@ -155,6 +156,25 @@ struct SpanOTA{ // manages OTA process // USER API CLASSES BEGINS HERE // ////////////////////////////////////// +class SpanPoint { + + friend class Span; + + esp_now_peer_info_t peerInfo; + + static uint8_t lmk[16]; + static boolean initialized; + + static void dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len); + static void init(const char *password="HomeSpan"); + + public: + + SpanPoint(const char *macAddress); +}; + +/////////////////////////////// + class Span{ friend class SpanAccessory; @@ -167,6 +187,7 @@ class Span{ friend class SpanOTA; friend class Network; friend class HAPClient; + friend class SpanPoint; const char *displayName; // display name for this device - broadcast as part of Bonjour MDNS 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 @@ -185,7 +206,6 @@ class Span{ char pairingCodeCommand[12]=""; // user-specified Pairing Code - only needed if Pairing Setup Code is specified in sketch using setPairingCode() String lastClientIP="0.0.0.0"; // IP address of last client accessing device through encrypted channel boolean newCode; // flag indicating new application code has been loaded (based on keeping track of app SHA256) - boolean espNowEnabled=false; // flag indicating if ESP-NOW is enabled int connected=0; // WiFi connection status (increments upon each connect and disconnect) unsigned long waitTime=60000; // time to wait (in milliseconds) between WiFi connection attempts @@ -284,8 +304,8 @@ class Span{ void setApFunction(void (*f)()){apFunction=f;} // sets an optional user-defined function to call when activating the WiFi Access Point void enableAutoStartAP(){autoStartAPEnabled=true;} // enables auto start-up of Access Point when WiFi Credentials not found void setWifiCredentials(const char *ssid, const char *pwd); // sets WiFi Credentials - void enableEspNOW(){espNowEnabled=true;}; // enables ESP-NOW - + void setSpanPointPassword(const char *pwd){SpanPoint::init(pwd);}; // sets SpanPoint password + void setPairingCode(const char *s){sprintf(pairingCodeCommand,"S %9s",s);} // sets the Pairing Code - use is NOT recommended. Use 'S' from CLI instead void deleteStoredValues(){processSerialCommand("V");} // deletes stored Characteristic values from NVS @@ -305,7 +325,7 @@ class Span{ void autoPoll(uint32_t stackSize=CONFIG_ARDUINO_LOOP_STACK_SIZE){xTaskCreateUniversal([](void *parms){for(;;)homeSpan.pollTask();}, "pollTask", stackSize, NULL, 1, &pollTaskHandle, 0);} // start pollTask() void setTimeServerTimeout(uint32_t tSec){webLog.waitTime=tSec*1000;} // sets wait time (in seconds) for optional web log time server to connect - + [[deprecated("Please use reserveSocketConnections(n) method instead.")]] void setMaxConnections(uint8_t n){requestedMaxCon=n;} // sets maximum number of simultaneous HAP connections }; @@ -319,6 +339,7 @@ class SpanAccessory{ friend class SpanCharacteristic; friend class SpanButton; friend class SpanRange; + friend class SpanPoint; uint32_t aid=0; // Accessory Instance ID (HAP Table 6-1) int iidCount=0; // running count of iid to use for Services and Characteristics associated with this Accessory diff --git a/src/src.ino b/src/src.ino index 892c050..11f4331 100644 --- a/src/src.ino +++ b/src/src.ino @@ -42,6 +42,8 @@ void setup() { homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); + homeSpan.setSpanPointPassword("Hello Thert"); + 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 @@ -63,6 +65,7 @@ void setup() { new Characteristic::Name("Light 1"); new Characteristic::ColorTemperature(); new Characteristic::Active(); + new SpanPoint("AC:67:B2:77:42:20"); new Service::LightBulb(); new Characteristic::On(0,true); (new Characteristic::Brightness(50,false))->setRange(10,100,5);