From 72294bde8b82926a6e53775d18a4ea21d25e8b04 Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 28 Sep 2022 21:16:29 -0500 Subject: [PATCH] Move all SpanPoint code into separate HomePoint.cpp and HomePoint.h files This enables SpanPoint to operate as a standalone library with no reliance on anything in HomeSpan. To Do: migrate all HomePeer code into SpanPoint. This will yield a universal standalone HomePoint library that can be used for BOTH the receiver and the sender (which automatically means two-way communication is always possible) --- src/HomePoint.cpp | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/HomePoint.h | 54 ++++++++++++++++++++++++ src/HomeSpan.cpp | 76 ++-------------------------------- src/HomeSpan.h | 26 ------------ src/src.ino | 6 ++- 5 files changed, 164 insertions(+), 101 deletions(-) create mode 100644 src/HomePoint.cpp create mode 100644 src/HomePoint.h diff --git a/src/HomePoint.cpp b/src/HomePoint.cpp new file mode 100644 index 0000000..dc771d5 --- /dev/null +++ b/src/HomePoint.cpp @@ -0,0 +1,103 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2020-2022 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. + * + ********************************************************************************/ + +#include "HomePoint.h" +#include +#include + +SpanPoint::SpanPoint(const char *macAddress, int qLength, int nItems){ + + 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); + } + + init(); // initialize SpanPoint + 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 + + this->qLength=qLength; + dataQueue = xQueueCreate(nItems,qLength); + + SpanPoints.push_back(this); +} + +/////////////////////////////// + +void SpanPoint::init(const char *password){ + + if(initialized) + return; + + if(WiFi.getMode()!=WIFI_AP_STA) + WiFi.mode(WIFI_AP_STA); // set mode to mixed AP/STA. This does not start any servers, just configures the WiFi radio to ensure it does not sleep (required for ESP-NOW) + + 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; +} + +/////////////////////////////// + +boolean SpanPoint::get(void *dataBuf){ + + return(xQueueReceive(dataQueue, dataBuf, 0)); +} + +/////////////////////////////// + +void SpanPoint::dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len){ + + auto it=SpanPoints.begin(); + for(;it!=SpanPoints.end() && memcmp((*it)->peerInfo.peer_addr,mac,6)!=0; it++); + + if(it==SpanPoints.end()) + return; + + if(len!=(*it)->qLength){ + Serial.printf("SpanPoint Warning! %d bytes received from %02X:%02X:%02X:%02X:%02X:%02X does not match %d-byte queue size\n",len,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],(*it)->qLength); + return; + } + + xQueueSend((*it)->dataQueue, incomingData, pdMS_TO_TICKS(1000)); +} + +/////////////////////////////// + +uint8_t SpanPoint::lmk[16]; +boolean SpanPoint::initialized=false; +vector SpanPoint::SpanPoints; diff --git a/src/HomePoint.h b/src/HomePoint.h new file mode 100644 index 0000000..0b1b83a --- /dev/null +++ b/src/HomePoint.h @@ -0,0 +1,54 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2020-2022 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. + * + ********************************************************************************/ + +#include +#include +#include + +using std::vector; + +class SpanPoint { + + int qLength; // length of 1 queue item (in bytes) + esp_now_peer_info_t peerInfo; // structure for all ESP-NOW peer data + QueueHandle_t dataQueue; // queue to store data after it is received + + static uint8_t lmk[16]; + static boolean initialized; + static vector SpanPoints; + + 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, int qLength, int nItems=1); + static void setPassword(const char *pwd){init(pwd);}; + boolean get(void *dataBuf); +}; + +/////////////////////////////// diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 07873d1..768b7c3 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -58,7 +58,8 @@ void Span::begin(Category catID, const char *displayName, const char *hostNameBa this->modelName=modelName; sprintf(this->category,"%d",(int)catID); - WiFi.mode(WIFI_AP_STA); // set mode to mixed AP/STA. This does not start any servers, just configures the WiFi radio to ensure it does not sleep (required for ESP-NOW) + if(WiFi.getMode()!=WIFI_AP_STA) + WiFi.mode(WIFI_AP_STA); // set mode to mixed AP/STA. This does not start any servers, just configures the WiFi radio to ensure it does not sleep (required for ESP-NOW) statusLED=new Blinker(statusDevice,autoOffLED); // create Status LED, even is statusDevice is NULL @@ -2150,75 +2151,6 @@ void SpanOTA::error(ota_error_t err){ else if (err == OTA_END_ERROR) Serial.println("End Failed\n"); } -/////////////////////////////// -// SpanPoint // -/////////////////////////////// - -SpanPoint::SpanPoint(const char *macAddress, int qLength, int nItems){ - - - 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); - } - - init(); // initialize SpanPoint - 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 - - this->qLength=qLength; - dataQueue = xQueueCreate(nItems,qLength); - - SpanPoints.push_back(this); -} - -/////////////////////////////// - -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; -} - -/////////////////////////////// - -boolean SpanPoint::get(void *dataBuf){ - - return(xQueueReceive(dataQueue, dataBuf, 0)); -} - -/////////////////////////////// - -void SpanPoint::dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len){ - - auto it=SpanPoints.begin(); - for(;it!=SpanPoints.end() && memcmp((*it)->peerInfo.peer_addr,mac,6)!=0; it++); - - if(it==SpanPoints.end()) - return; - - if(len!=(*it)->qLength){ - Serial.printf("SpanPoint Warning! %d bytes received from %02X:%02X:%02X:%02X:%02X:%02X does not match %d-byte queue size\n",len,mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],(*it)->qLength); - return; - } - - xQueueSend((*it)->dataQueue, incomingData, pdMS_TO_TICKS(1000)); -} - /////////////////////////////// // MISC // /////////////////////////////// @@ -2232,8 +2164,6 @@ int SpanOTA::otaPercent; boolean SpanOTA::safeLoad; boolean SpanOTA::enabled=false; boolean SpanOTA::auth; -uint8_t SpanPoint::lmk[16]; -boolean SpanPoint::initialized=false; -vector SpanPoint::SpanPoints; + diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 57f358d..8d5ec0a 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -39,7 +39,6 @@ #include #include #include -#include #include "extras/Blinker.h" #include "extras/Pixel.h" @@ -156,29 +155,6 @@ struct SpanOTA{ // manages OTA process // USER API CLASSES BEGINS HERE // ////////////////////////////////////// -class SpanPoint { - - friend class Span; - - int qLength; // length of 1 queue item (in bytes) - esp_now_peer_info_t peerInfo; // structure for all ESP-NOW peer data - QueueHandle_t dataQueue; // queue to store data after it is received - - static uint8_t lmk[16]; - static boolean initialized; - static vector SpanPoints; - - 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, int qLength, int nItems=1); - boolean get(void *dataBuf); -}; - -/////////////////////////////// - class Span{ friend class SpanAccessory; @@ -191,7 +167,6 @@ 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 @@ -308,7 +283,6 @@ 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 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 diff --git a/src/src.ino b/src/src.ino index 16c3da2..81e5b81 100644 --- a/src/src.ino +++ b/src/src.ino @@ -8,6 +8,7 @@ #include "extras/RFControl.h" #include "extras/Blinker.h" #include "extras/PwmPin.h" +#include "HomePoint.h" #define STRING_t const char * // WORK-AROUND @@ -50,11 +51,12 @@ void setup() { // homeSpan.enableAutoStartAP(); // homeSpan.setApFunction(myWiFiAP); + SpanPoint::setPassword("Hello Thert"); + dev1=new SpanPoint("AC:67:B2:77:42:20",sizeof(message_t)); + homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); - homeSpan.setSpanPointPassword("Hello Thert"); - dev1=new SpanPoint("AC:67:B2:77:42:20",sizeof(message_t)); dev2=new SpanPoint("7C:DF:A1:61:E4:A8",sizeof(message_t)); new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments