From 484f1c4f2e6955fc427e7f28abfcf647515ee65b Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 2 Dec 2022 17:49:54 -0600 Subject: [PATCH 01/41] Cleaned up compiler warnings * Changed ~SpanService to virtual function to ensure any user-defined destructor is also called * Found/corrected bug in error message related to defining a Characteristic without any Service * Added warning/error ID numbers to warning/error messages * Other misc changes to clean up compiler warnings --- src/HAP.cpp | 4 ++-- src/HomeSpan.cpp | 44 ++++++++++++++++++++++++-------------------- src/HomeSpan.h | 16 ++++++++-------- src/src.ino | 4 +--- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/HAP.cpp b/src/HAP.cpp index 6505307..29f9f6e 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -705,7 +705,7 @@ int HAPClient::postPairVerifyURL(){ memcpy(iosCurveKey,tlv8.buf(kTLVType_PublicKey),32); // save iosCurveKey (will persist until end of verification process) - int _x = 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; @@ -1235,7 +1235,7 @@ int HAPClient::getStatusURL(){ sprintf(clocktime,"Unknown"); } - char uptime[16]; + char uptime[32]; int seconds=esp_timer_get_time()/1e6; int secs=seconds%60; int mins=(seconds/=60)%60; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 2c3e9b5..e5328ee 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -40,7 +40,7 @@ #include "HomeSpan.h" #include "HAP.h" -const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartition = {HOMESPAN_MAGIC_COOKIE}; +const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartition = {HOMESPAN_MAGIC_COOKIE,0}; using namespace Utils; @@ -903,10 +903,10 @@ void Span::processSerialCommand(const char *c){ boolean foundInfo=false; if(acc==Accessories.begin() && (*acc)->aid!=1) - Serial.printf(" *** ERROR! AID of first Accessory must always be 1 ***\n",nErrors++); + Serial.printf(" *** ERROR #%d! AID of first Accessory must always be 1 ***\n",++nErrors); if(aidValues.find((*acc)->aid)!=aidValues.end()) - Serial.printf(" *** ERROR! AID already in use for another Accessory ***\n",nErrors++); + Serial.printf(" *** ERROR #%d! AID already in use for another Accessory ***\n",++nErrors); aidValues.insert((*acc)->aid); @@ -917,7 +917,7 @@ void Span::processSerialCommand(const char *c){ if(!strcmp((*svc)->type,"3E")){ foundInfo=true; if((*svc)->iid!=1) - Serial.printf(" *** ERROR! The Accessory Information Service must be defined before any other Services in an Accessory ***\n",nErrors++); + Serial.printf(" *** ERROR #%d! The Accessory Information Service must be defined before any other Services in an Accessory ***\n",++nErrors); } else if((*acc)->aid==1) // this is an Accessory with aid=1, but it has more than just AccessoryInfo. So... isBridge=false; // ...this is not a bridge device @@ -948,22 +948,22 @@ void Span::processSerialCommand(const char *c){ Serial.printf("\n"); if(!(*chr)->isCustom && !(*svc)->isCustom && (*svc)->req.find((*chr)->hapChar)==(*svc)->req.end() && (*svc)->opt.find((*chr)->hapChar)==(*svc)->opt.end()) - Serial.printf(" *** WARNING! Service does not support this Characteristic ***\n",nWarnings++); + Serial.printf(" *** WARNING #%d! Service does not support this Characteristic ***\n",++nWarnings); else if(invalidUUID((*chr)->type,(*chr)->isCustom)) - Serial.printf(" *** ERROR! Format of UUID is invalid ***\n",nErrors++); + Serial.printf(" *** ERROR #%d! Format of UUID is invalid ***\n",++nErrors); else if(hapChar.find((*chr)->hapChar)!=hapChar.end()) - Serial.printf(" *** ERROR! Characteristic already defined for this Service ***\n",nErrors++); + Serial.printf(" *** ERROR #%d! Characteristic already defined for this Service ***\n",++nErrors); if((*chr)->setRangeError) - Serial.printf(" *** WARNING! Attempt to set Custom Range for this Characteristic ignored ***\n",nWarnings++); + Serial.printf(" *** WARNING #%d! Attempt to set Custom Range for this Characteristic ignored ***\n",++nWarnings); if((*chr)->setValidValuesError) - Serial.printf(" *** WARNING! Attempt to set Custom Valid Values for this Characteristic ignored ***\n",nWarnings++); + Serial.printf(" *** WARNING #%d! Attempt to set Custom Valid Values for this Characteristic ignored ***\n",++nWarnings); if((*chr)->format!=STRING && ((*chr)->uvGet((*chr)->value) < (*chr)->uvGet((*chr)->minValue) || (*chr)->uvGet((*chr)->value) > (*chr)->uvGet((*chr)->maxValue))) - Serial.printf(" *** WARNING! Value of %llg is out of range [%llg,%llg] ***\n",(*chr)->uvGet((*chr)->value),(*chr)->uvGet((*chr)->minValue),(*chr)->uvGet((*chr)->maxValue),nWarnings++); + Serial.printf(" *** WARNING #%d! Value of %g is out of range [%g,%g] ***\n",++nWarnings,(*chr)->uvGet((*chr)->value),(*chr)->uvGet((*chr)->minValue),(*chr)->uvGet((*chr)->maxValue)); hapChar.insert((*chr)->hapChar); @@ -971,7 +971,7 @@ void Span::processSerialCommand(const char *c){ for(auto req=(*svc)->req.begin(); req!=(*svc)->req.end(); req++){ if(hapChar.find(*req)==hapChar.end()) - Serial.printf(" *** WARNING! Required '%s' Characteristic for this Service not found ***\n",(*req)->hapName,nWarnings++); + Serial.printf(" *** WARNING #%d! Required '%s' Characteristic for this Service not found ***\n",++nWarnings,(*req)->hapName); } for(auto button=PushButtons.begin(); button!=PushButtons.end(); button++){ @@ -990,14 +990,14 @@ void Span::processSerialCommand(const char *c){ Serial.printf("USER-DEFINED\n"); if((void(*)(int,int))((*svc)->*(&SpanService::button))==(void(*)(int,int))(&SpanService::button)) - Serial.printf(" *** WARNING! No button() method defined in this Service ***\n",nWarnings++); + Serial.printf(" *** WARNING #%d! No button() method defined in this Service ***\n",++nWarnings); } } } // Services if(!foundInfo) - Serial.printf(" *** ERROR! Required 'AccessoryInformation' Service not found ***\n",nErrors++); + Serial.printf(" *** ERROR #%d! Required 'AccessoryInformation' Service not found ***\n",++nErrors); } // Accessories @@ -1077,9 +1077,13 @@ void Span::processSerialCommand(const char *c){ uCom->second->userFunction1(c+1); else uCom->second->userFunction2(c+1,uCom->second->userArg); - break; + } else { + Serial.print("*** Undefined user command: '"); + Serial.print(c); + Serial.print("'. Type '?' for list of commands.\n"); } } + break; default: Serial.print("*** Unknown command: '"); @@ -1730,12 +1734,6 @@ int SpanService::sprintfAttributes(char *cBuf, int flags){ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){ - if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ - Serial.printf("\nFATAL ERROR! Can't create new Characteristic '%s' without a defined Service ***\n",hapName); - Serial.printf("\n=== PROGRAM HALTED ==="); - while(1); - } - type=hapChar->type; perms=hapChar->perms; hapName=hapChar->hapName; @@ -1744,6 +1742,12 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar, boolean isCustom){ this->isCustom=isCustom; this->hapChar=hapChar; + if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ + Serial.printf("\nFATAL ERROR! Can't create new Characteristic '%s' without a defined Service ***\n",hapName); + Serial.printf("\n=== PROGRAM HALTED ==="); + while(1); + } + homeSpan.Accessories.back()->Services.back()->Characteristics.push_back(this); iid=++(homeSpan.Accessories.back()->iidCount); service=homeSpan.Accessories.back()->Services.back(); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index ec02347..bf9e4bc 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -32,6 +32,7 @@ #endif #pragma GCC diagnostic ignored "-Wpmf-conversions" // eliminates warning messages from use of pointers to member functions to detect whether update() and loop() are overridden by user +#pragma GCC diagnostic ignored "-Wunused-result" // eliminates warning message regarded unused result from call to crypto_scalarmult_curve25519() #include #include @@ -390,7 +391,7 @@ class SpanService{ protected: - ~SpanService(); // destructor + virtual ~SpanService(); // destructor unordered_set req; // unordered set of pointers to all required HAP Characteristic Types for this Service unordered_set opt; // unordered set of pointers to all optional HAP Characteristic Types for this Service @@ -472,7 +473,7 @@ class SpanCharacteristic{ sprintf(c,"%llu",u.UINT64); return(String(c)); case FORMAT::FLOAT: - sprintf(c,"%llg",u.FLOAT); + sprintf(c,"%g",u.FLOAT); return(String(c)); case FORMAT::STRING: sprintf(c,"\"%s\"",u.STRING); @@ -516,6 +517,8 @@ class SpanCharacteristic{ case FORMAT::FLOAT: u.FLOAT=(double)val; break; + case FORMAT::STRING: + break; } // switch } @@ -536,6 +539,8 @@ class SpanCharacteristic{ return((T) u.UINT64); case FORMAT::FLOAT: return((T) u.FLOAT); + case FORMAT::STRING: + break; } return(0); // included to prevent compiler warnings } @@ -546,37 +551,32 @@ class SpanCharacteristic{ template void init(T val, boolean nvsStore, A min=0, B max=1){ - int nvsFlag=0; uvSet(value,val); if(nvsStore){ nvsKey=(char *)malloc(16); uint16_t t; - sscanf(type,"%x",&t); + sscanf(type,"%hx",&t); sprintf(nvsKey,"%04X%08X%03X",t,aid,iid&0xFFF); size_t len; if(format != FORMAT::STRING){ if(!nvs_get_blob(homeSpan.charNVS,nvsKey,NULL,&len)){ nvs_get_blob(homeSpan.charNVS,nvsKey,&value,&len); - nvsFlag=2; } else { nvs_set_blob(homeSpan.charNVS,nvsKey,&value,sizeof(UVal)); // store data nvs_commit(homeSpan.charNVS); // commit to NVS - nvsFlag=1; } } else { if(!nvs_get_str(homeSpan.charNVS,nvsKey,NULL,&len)){ char c[len]; nvs_get_str(homeSpan.charNVS,nvsKey,c,&len); uvSet(value,(const char *)c); - nvsFlag=2; } else { nvs_set_str(homeSpan.charNVS,nvsKey,value.STRING); // store string data nvs_commit(homeSpan.charNVS); // commit to NVS - nvsFlag=1; } } } diff --git a/src/src.ino b/src/src.ino index abf2d6b..40d7395 100644 --- a/src/src.ino +++ b/src/src.ino @@ -65,8 +65,6 @@ void setup() { homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); - - 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 @@ -92,7 +90,7 @@ void setup() { new Service::LightBulb(); new Characteristic::On(0,true); - (new Characteristic::Brightness(50,false))->setRange(10,100,5); + (new Characteristic::Brightness())->setRange(10,100,5); new Characteristic::Name("Light 2"); new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), which takes no arguments From 5daaf3d0cf5ede42b2f7a29981a8c57debe8493d Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 3 Dec 2022 11:12:30 -0600 Subject: [PATCH 02/41] Added #pragma once to extras header files --- src/extras/Blinker.h | 4 ++-- src/extras/Pixel.h | 3 ++- src/extras/PwmPin.h | 3 ++- src/extras/RFControl.h | 3 ++- src/extras/extras.ino | 1 + 5 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 src/extras/extras.ino diff --git a/src/extras/Blinker.h b/src/extras/Blinker.h index b54c4ce..fe89bef 100644 --- a/src/extras/Blinker.h +++ b/src/extras/Blinker.h @@ -25,6 +25,6 @@ * ********************************************************************************/ +#pragma once + #include "../src/extras/Blinker.h" - - diff --git a/src/extras/Pixel.h b/src/extras/Pixel.h index 3bcc8bd..34b699e 100644 --- a/src/extras/Pixel.h +++ b/src/extras/Pixel.h @@ -25,5 +25,6 @@ * ********************************************************************************/ -#include "../src/extras/Pixel.h" +#pragma once +#include "../src/extras/Pixel.h" diff --git a/src/extras/PwmPin.h b/src/extras/PwmPin.h index f012652..269f2a4 100644 --- a/src/extras/PwmPin.h +++ b/src/extras/PwmPin.h @@ -24,6 +24,7 @@ * SOFTWARE. * ********************************************************************************/ + +#pragma once #include "../src/extras/PwmPin.h" - diff --git a/src/extras/RFControl.h b/src/extras/RFControl.h index bfbcaea..bd955aa 100644 --- a/src/extras/RFControl.h +++ b/src/extras/RFControl.h @@ -25,5 +25,6 @@ * ********************************************************************************/ +#pragma once + #include "../src/extras/RFControl.h" - diff --git a/src/extras/extras.ino b/src/extras/extras.ino new file mode 100644 index 0000000..fd9911d --- /dev/null +++ b/src/extras/extras.ino @@ -0,0 +1 @@ +// This is a placeholder .ino file that allows for editing of top-level "extras" header files. From ea07da5ab0ab2b947ba2cbed963e6c390200b869 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 11 Dec 2022 14:19:37 -0600 Subject: [PATCH 03/41] Update HomeSpan.h Fixed another compiler warning --- src/HomeSpan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index bf9e4bc..97c6acc 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -651,7 +651,7 @@ class SpanCharacteristic{ } if(val < uvGet(minValue) || val > uvGet(maxValue)){ - Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s with setVal(%llg) is out of range [%llg,%llg]. This may cause device to become non-reponsive!\n\n", + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s with setVal(%g) is out of range [%g,%g]. This may cause device to become non-reponsive!\n\n", hapName,(double)val,uvGet(minValue),uvGet(maxValue)); } From 7939624bf78cb766b084cc03441544d638d39c57 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 23 Dec 2022 16:51:55 -0600 Subject: [PATCH 04/41] Added Service::TelevisionSpeaker Also updated Television Example. Volume buttons on remote now function as expected, though there does not seems to be a mute button --- Other Examples/Television/Television.ino | 6 ++++++ src/Characteristics.h | 2 +- src/HomeSpan.cpp | 2 +- src/Span.h | 8 ++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Other Examples/Television/Television.ino b/Other Examples/Television/Television.ino index fda3581..39a232b 100644 --- a/Other Examples/Television/Television.ino +++ b/Other Examples/Television/Television.ino @@ -189,6 +189,11 @@ void setup() { new Characteristic::CurrentVisibilityState(0); // ...and included in the Selection List... new Characteristic::TargetVisibilityState(0); // ...and a "checked" checkbox is provided on the Settings Screen that can be used to toggle CurrentVisibilityState() + SpanService *speaker = new Service::TelevisionSpeaker(); + new Characteristic::Mute(); + new Characteristic::VolumeSelector(); + new Characteristic::VolumeControlType(3); + (new HomeSpanTV("Test TV")) // Define a Television Service. Must link in InputSources! ->addLink(hdmi1) ->addLink(hdmi2) @@ -200,6 +205,7 @@ void setup() { ->addLink(hdmi8) ->addLink(hdmi9) ->addLink(hdmi10) + ->addLink(speaker) ; } diff --git a/src/Characteristics.h b/src/Characteristics.h index 5bce47c..e5d075f 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -192,7 +192,7 @@ struct HapCharacteristics { HAPCHAR( VOCDensity, C8, PR+EV, FLOAT, false ); HAPCHAR( Volume, 119, PW+PR+EV, UINT8, false ); HAPCHAR( VolumeControlType, E9, PR+EV, UINT8, true ); - HAPCHAR( VolumeSelector, EA, PR+EV, UINT8, true ); + HAPCHAR( VolumeSelector, EA, PW, UINT8, true ); HAPCHAR( WaterLevel, B5, PR+EV, FLOAT, false ); }; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index e5328ee..6d8718c 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -911,7 +911,7 @@ void Span::processSerialCommand(const char *c){ aidValues.insert((*acc)->aid); for(auto svc=(*acc)->Services.begin(); svc!=(*acc)->Services.end(); svc++){ - Serial.printf(" \u279f Service %s: IID=%d, %sUUIS=\"%s\"",(*svc)->hapName,(*svc)->iid,(*svc)->isCustom?"Custom-":"",(*svc)->type); + Serial.printf(" \u279f Service %s: IID=%d, %sUUID=\"%s\"",(*svc)->hapName,(*svc)->iid,(*svc)->isCustom?"Custom-":"",(*svc)->type); Serial.printf("\n"); if(!strcmp((*svc)->type,"3E")){ diff --git a/src/Span.h b/src/Span.h index 8bb10da..04747ba 100644 --- a/src/Span.h +++ b/src/Span.h @@ -335,6 +335,14 @@ namespace Service { OPT(PowerModeSelection); }}; + struct TelevisionSpeaker : SpanService { TelevisionSpeaker() : SpanService{"113","TelevisionSpeaker"}{ + REQ(Mute); + OPT(Active); + OPT(Volume); + OPT(VolumeControlType); + OPT(VolumeSelector); + }}; + struct TemperatureSensor : SpanService { TemperatureSensor() : SpanService{"8A","TemperatureSensor"}{ REQ(CurrentTemperature); OPT(Name); From 3fae9c24a9ccdd343ad43a6427f83eb6ffc4634c Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 23 Dec 2022 18:39:14 -0600 Subject: [PATCH 05/41] Updated Television Characteristics Removed Mute, Active, and Volume since they don't appear to do anything. --- Other Examples/Television/Television.ino | 1 - src/Span.h | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Other Examples/Television/Television.ino b/Other Examples/Television/Television.ino index 39a232b..412601b 100644 --- a/Other Examples/Television/Television.ino +++ b/Other Examples/Television/Television.ino @@ -190,7 +190,6 @@ void setup() { new Characteristic::TargetVisibilityState(0); // ...and a "checked" checkbox is provided on the Settings Screen that can be used to toggle CurrentVisibilityState() SpanService *speaker = new Service::TelevisionSpeaker(); - new Characteristic::Mute(); new Characteristic::VolumeSelector(); new Characteristic::VolumeControlType(3); diff --git a/src/Span.h b/src/Span.h index 04747ba..f751052 100644 --- a/src/Span.h +++ b/src/Span.h @@ -336,11 +336,8 @@ namespace Service { }}; struct TelevisionSpeaker : SpanService { TelevisionSpeaker() : SpanService{"113","TelevisionSpeaker"}{ - REQ(Mute); - OPT(Active); - OPT(Volume); - OPT(VolumeControlType); - OPT(VolumeSelector); + REQ(VolumeControlType); + REQ(VolumeSelector); }}; struct TemperatureSensor : SpanService { TemperatureSensor() : SpanService{"8A","TemperatureSensor"}{ From eecce34848d92d9ea0a9cd9e0bbfb1c30542a95d Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 27 Dec 2022 09:55:30 -0600 Subject: [PATCH 06/41] Added NVS storage for last channel used in SpanPoint Applicable only for remote devices (i.e. not a Hub device). Last channel stored is used as initial channel upon reboot, provided that this channel is allowed by the channel mask (if not, the first allowed channel is selected instead). --- src/HomeSpan.cpp | 17 ++++++++++++++++- src/HomeSpan.h | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 6d8718c..300c524 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -2247,6 +2247,16 @@ void SpanPoint::init(const char *password){ statusQueue = xQueueCreate(1,sizeof(esp_now_send_status_t)); // create statusQueue even if not needed setChannelMask(channelMask); // default channel mask at start-up uses channels 1-13 + uint8_t channel; + if(!isHub){ // this is not a hub + nvs_flash_init(); // initialize NVS + nvs_open("POINT",NVS_READWRITE,&pointNVS); // open SpanPoint data namespace in NVS + if(!nvs_get_u8(pointNVS,"CHANNEL",&channel)){ // if channel found in NVS... + if(channelMask & (1< SpanPoint::SpanPoints; uint16_t SpanPoint::channelMask=0x3FFE; QueueHandle_t SpanPoint::statusQueue; +nvs_handle SpanPoint::pointNVS; + /////////////////////////////// // MISC // diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 97c6acc..bb6efb1 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -799,8 +799,9 @@ class SpanPoint { static boolean initialized; static boolean isHub; static vector SpanPoints; - static uint16_t channelMask; // channel mask + static uint16_t channelMask; // channel mask (only used for remote devices) static QueueHandle_t statusQueue; // queue for communication between SpanPoint::dataSend and SpanPoint::send + static nvs_handle pointNVS; // NVS storage for channel number (only used for remote devices) static void dataReceived(const uint8_t *mac, const uint8_t *incomingData, int len); static void init(const char *password="HomeSpan"); From 9ecc355c84df29ddc1258f102922e1ec13023b34 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 27 Dec 2022 17:44:03 -0600 Subject: [PATCH 07/41] Moved "Other Examples" into "examples" folder Noticed that the Arduino IDE 2.0 interface was not displaying Other Examples. This is because Other Examples was not under the "examples" folder. Not sure why this was the case - I should have originally put it there (?) Regardless, once moved into the examples folder, Other Examples now properly shows up in both Arduino IDE version 1 and version 2. --- .../Other Examples}/CustomService/CustomService.ino | 0 {Other Examples => examples/Other Examples}/Pixel/Pixel.ino | 0 .../Other Examples}/ProgrammableHub/ProgrammableHub.ino | 0 .../Other Examples}/RemoteControl/RemoteControl.ino | 0 .../Other Examples}/RemoteSensors/MainDevice/MainDevice.ino | 0 .../Other Examples}/RemoteSensors/RemoteDevice/RemoteDevice.ino | 0 .../RemoteSensors/RemoteTempSensor/RemoteTempSensor.ino | 0 .../Other Examples}/ServoControl/DEV_DoorsWindows.h | 0 .../Other Examples}/ServoControl/ServoControl.ino | 0 .../Other Examples}/TableLamp/TableLamp.ino | 0 .../Other Examples}/Television/Television.ino | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename {Other Examples => examples/Other Examples}/CustomService/CustomService.ino (100%) rename {Other Examples => examples/Other Examples}/Pixel/Pixel.ino (100%) rename {Other Examples => examples/Other Examples}/ProgrammableHub/ProgrammableHub.ino (100%) rename {Other Examples => examples/Other Examples}/RemoteControl/RemoteControl.ino (100%) rename {Other Examples => examples/Other Examples}/RemoteSensors/MainDevice/MainDevice.ino (100%) rename {Other Examples => examples/Other Examples}/RemoteSensors/RemoteDevice/RemoteDevice.ino (100%) rename {Other Examples => examples/Other Examples}/RemoteSensors/RemoteTempSensor/RemoteTempSensor.ino (100%) rename {Other Examples => examples/Other Examples}/ServoControl/DEV_DoorsWindows.h (100%) rename {Other Examples => examples/Other Examples}/ServoControl/ServoControl.ino (100%) rename {Other Examples => examples/Other Examples}/TableLamp/TableLamp.ino (100%) rename {Other Examples => examples/Other Examples}/Television/Television.ino (100%) diff --git a/Other Examples/CustomService/CustomService.ino b/examples/Other Examples/CustomService/CustomService.ino similarity index 100% rename from Other Examples/CustomService/CustomService.ino rename to examples/Other Examples/CustomService/CustomService.ino diff --git a/Other Examples/Pixel/Pixel.ino b/examples/Other Examples/Pixel/Pixel.ino similarity index 100% rename from Other Examples/Pixel/Pixel.ino rename to examples/Other Examples/Pixel/Pixel.ino diff --git a/Other Examples/ProgrammableHub/ProgrammableHub.ino b/examples/Other Examples/ProgrammableHub/ProgrammableHub.ino similarity index 100% rename from Other Examples/ProgrammableHub/ProgrammableHub.ino rename to examples/Other Examples/ProgrammableHub/ProgrammableHub.ino diff --git a/Other Examples/RemoteControl/RemoteControl.ino b/examples/Other Examples/RemoteControl/RemoteControl.ino similarity index 100% rename from Other Examples/RemoteControl/RemoteControl.ino rename to examples/Other Examples/RemoteControl/RemoteControl.ino diff --git a/Other Examples/RemoteSensors/MainDevice/MainDevice.ino b/examples/Other Examples/RemoteSensors/MainDevice/MainDevice.ino similarity index 100% rename from Other Examples/RemoteSensors/MainDevice/MainDevice.ino rename to examples/Other Examples/RemoteSensors/MainDevice/MainDevice.ino diff --git a/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino similarity index 100% rename from Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino rename to examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino diff --git a/Other Examples/RemoteSensors/RemoteTempSensor/RemoteTempSensor.ino b/examples/Other Examples/RemoteSensors/RemoteTempSensor/RemoteTempSensor.ino similarity index 100% rename from Other Examples/RemoteSensors/RemoteTempSensor/RemoteTempSensor.ino rename to examples/Other Examples/RemoteSensors/RemoteTempSensor/RemoteTempSensor.ino diff --git a/Other Examples/ServoControl/DEV_DoorsWindows.h b/examples/Other Examples/ServoControl/DEV_DoorsWindows.h similarity index 100% rename from Other Examples/ServoControl/DEV_DoorsWindows.h rename to examples/Other Examples/ServoControl/DEV_DoorsWindows.h diff --git a/Other Examples/ServoControl/ServoControl.ino b/examples/Other Examples/ServoControl/ServoControl.ino similarity index 100% rename from Other Examples/ServoControl/ServoControl.ino rename to examples/Other Examples/ServoControl/ServoControl.ino diff --git a/Other Examples/TableLamp/TableLamp.ino b/examples/Other Examples/TableLamp/TableLamp.ino similarity index 100% rename from Other Examples/TableLamp/TableLamp.ino rename to examples/Other Examples/TableLamp/TableLamp.ino diff --git a/Other Examples/Television/Television.ino b/examples/Other Examples/Television/Television.ino similarity index 100% rename from Other Examples/Television/Television.ino rename to examples/Other Examples/Television/Television.ino From 1f7c86621c58190c04fbf7b17331e089aa67b295 Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 28 Dec 2022 17:18:59 -0600 Subject: [PATCH 08/41] Bumped version number to 1.7.1 --- src/Settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Settings.h b/src/Settings.h index 40d6bd8..2b25a1f 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -36,7 +36,7 @@ #define HS_MAJOR 1 #define HS_MINOR 7 -#define HS_PATCH 0 +#define HS_PATCH 1 #define STRINGIFY(x) _STR(x) #define _STR(x) #x From f3f2c5c4c83ec9f0a6ea6fac9740feb77c007dc1 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 29 Dec 2022 12:36:09 -0600 Subject: [PATCH 09/41] Update TVServices.md --- docs/TVServices.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/TVServices.md b/docs/TVServices.md index 8e37c04..3b35514 100644 --- a/docs/TVServices.md +++ b/docs/TVServices.md @@ -56,6 +56,14 @@ All of this is accomplished by using a combination of some, or all, of the follo * `Characteristic::CurrentVisibilityState()` and `Characteristic::TargetVisibilityState()` - these two Characteristics work in tandem much like any current-state/target-state pair. When these are defined for an Input Source, a checkbox toggle appears next to the name of the Input Source on the Settings page, provided `Characteristic::IsConfigured()` has also been defined. Clicking the checkbox causes the Home App to toggle the TargetVisibilityState between 0 to 1, where 0 ironically means the checkbox is *checked*, and 1 means it is *unchecked* (the reverse of what you might expect!). If you read this update in HomeSpan you can then use `setVal()` to change the CurrentVisibiltyState() to match the TargetVisibilityState(). Setting CurrentVisibilityState() to 0 means the Input Source appears as a choice in the Input Source Selector. Setting CurrentVisibilityState() to 1 means it does not appear as a selection. Note these features only operate if an ID has been set for the Input Source with `Characteristic::Identifier()`, and IsConfigured() has been defined and set to 1 +### `Service::TelevisionSpeaker()` + +This Service allows you to change the volume of a television using the iPhone's physical volume control buttons when operating the TV via the iPhone's Remote Control widget (found in the iPhone Control Center). Similar the Input Source Service above, the Television Speaker Service ***must*** be linked to a Television Service using `addLink()`. The Television Speaker Service requires the following two Characteristics: + +* `Characteristic::VolumeControlType()` - this read-only Characteristic seems to be required but there is uncertainty as to its purpose. In the example HomeSpan sketches I initialized this Characteristic with a value of 3 based on what others have done in scripts based on [HomeBridge](https://developers.homebridge.io/#/service/TelevisionSpeaker) + +* `Characteristic::VolumeSelector()` - this write-only Characterstic is updated whenever the user is operating the TV via the iPhone's Remote Control widget and the physical volume control buttons are pressed. The Home App sends a value of 0 when the up-volume button is pressed, and value of 1 when the down-volume button is pressed. These values can be read the usual way by creating an `update()` method for a class that is derived from the Television Speaker Service + ### Examples Please see [*File → Examples → HomeSpan → Other Examples → Television*](../Other%20Examples/Television) for a complete worked example demonstrating the effects of using different combinations of the above Characteristics. Also, don't forget to check out the [HomeSpan Projects](https://github.com/topics/homespan) page for some real-world examples of TV sketches and controllers. From 72b4ece64d764ac402665159535e90964f59af08 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 1 Jan 2023 11:33:50 -0600 Subject: [PATCH 10/41] Added DATA format Includes 3 new methods: getData(), getNewData(), and setData() --- src/Characteristics.h | 5 +- src/HomeSpan.cpp | 8 +- src/HomeSpan.h | 65 +++++++++++++++- src/Span.h | 2 + src/src.ino | 170 ++++++------------------------------------ 5 files changed, 94 insertions(+), 156 deletions(-) diff --git a/src/Characteristics.h b/src/Characteristics.h index e5d075f..5530d15 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -48,7 +48,8 @@ enum FORMAT { // HAP Table 6-5 UINT64=4, INT=5, FLOAT=6, - STRING=7 + STRING=7, + DATA=8 }; /////////////////////////////// @@ -195,6 +196,8 @@ struct HapCharacteristics { HAPCHAR( VolumeSelector, EA, PW, UINT8, true ); HAPCHAR( WaterLevel, B5, PR+EV, FLOAT, false ); + HAPCHAR( EveTest, 12345678-079E-48FF-8F27-9C2605A29F52, PW+PR+EV, DATA, false ); + }; extern HapCharacteristics hapChars; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 300c524..185dfda 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -934,7 +934,7 @@ void Span::processSerialCommand(const char *c){ Serial.printf("%s%s",(foundPerms++)?"+":"",pNames[i]); } - if((*chr)->format!=FORMAT::STRING && (*chr)->format!=FORMAT::BOOL){ + if((*chr)->format!=FORMAT::STRING && (*chr)->format!=FORMAT::BOOL && (*chr)->format!=FORMAT::DATA){ if((*chr)->validValues) Serial.printf(", Valid Values=%s",(*chr)->validValues); else if((*chr)->uvGet((*chr)->stepValue)>0) @@ -1378,7 +1378,7 @@ int Span::updateCharacteristics(char *buf, SpanBuf *pObj){ if(status==StatusCode::OK){ // if status is okay pObj[j].characteristic->uvSet(pObj[j].characteristic->value,pObj[j].characteristic->newValue); // update characteristic value with new value if(pObj[j].characteristic->nvsKey){ // if storage key found - if(pObj[j].characteristic->format != FORMAT::STRING) + if(pObj[j].characteristic->format!=FORMAT::STRING && pObj[j].characteristic->format!=FORMAT::DATA) nvs_set_blob(charNVS,pObj[j].characteristic->nvsKey,&(pObj[j].characteristic->value),sizeof(pObj[j].characteristic->value)); // store data else nvs_set_str(charNVS,pObj[j].characteristic->nvsKey,pObj[j].characteristic->value.STRING); // store data @@ -1771,7 +1771,7 @@ SpanCharacteristic::~SpanCharacteristic(){ free(validValues); free(nvsKey); - if(format==FORMAT::STRING){ + if(format==FORMAT::STRING || format==FORMAT::DATA){ free(value.STRING); free(newValue.STRING); } @@ -1786,7 +1786,7 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){ const char permCodes[][7]={"pr","pw","ev","aa","tw","hd","wr"}; - const char formatCodes[][8]={"bool","uint8","uint16","uint32","uint64","int","float","string"}; + const char formatCodes[][9]={"bool","uint8","uint16","uint32","uint64","int","float","string","data"}; nBytes+=snprintf(cBuf,cBuf?64:0,"{\"iid\":%d",iid); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index bb6efb1..7a34337 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -41,6 +41,7 @@ #include #include #include +#include #include "extras/Blinker.h" #include "extras/Pixel.h" @@ -476,6 +477,7 @@ class SpanCharacteristic{ sprintf(c,"%g",u.FLOAT); return(String(c)); case FORMAT::STRING: + case FORMAT::DATA: sprintf(c,"\"%s\"",u.STRING); return(String(c)); } // switch @@ -483,7 +485,7 @@ class SpanCharacteristic{ } void uvSet(UVal &dest, UVal &src){ - if(format==FORMAT::STRING) + if(format==FORMAT::STRING || format==FORMAT::DATA) uvSet(dest,(const char *)src.STRING); else dest=src; @@ -518,6 +520,7 @@ class SpanCharacteristic{ u.FLOAT=(double)val; break; case FORMAT::STRING: + case FORMAT::DATA: break; } // switch } @@ -540,6 +543,7 @@ class SpanCharacteristic{ case FORMAT::FLOAT: return((T) u.FLOAT); case FORMAT::STRING: + case FORMAT::DATA: break; } return(0); // included to prevent compiler warnings @@ -560,7 +564,7 @@ class SpanCharacteristic{ sprintf(nvsKey,"%04X%08X%03X",t,aid,iid&0xFFF); size_t len; - if(format != FORMAT::STRING){ + if(format!=FORMAT::STRING && format!=FORMAT::DATA){ if(!nvs_get_blob(homeSpan.charNVS,nvsKey,NULL,&len)){ nvs_get_blob(homeSpan.charNVS,nvsKey,&value,&len); } @@ -583,7 +587,7 @@ class SpanCharacteristic{ uvSet(newValue,value); - if(format != FORMAT::STRING) { + if(format!=FORMAT::STRING && format!=FORMAT::DATA) { uvSet(minValue,min); uvSet(maxValue,max); uvSet(stepValue,0); @@ -643,6 +647,61 @@ class SpanCharacteristic{ } // setString() + size_t getData(uint8_t *data, size_t len){ + if(format!=FORMAT::DATA) + return(0); + + size_t olen; + int ret=mbedtls_base64_decode(data,len,&olen,(uint8_t *)value.STRING,strlen(value.STRING)); + + if(data==NULL) + return(olen); + + if(ret==MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Destination buffer is too small (%d out of %d bytes needed)\n\n",hapName,len,olen); + else if(ret==MBEDTLS_ERR_BASE64_INVALID_CHARACTER) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Data is not in base-64 format\n\n",hapName); + + return(olen); + } + + size_t getNewData(uint8_t *data, size_t len){ + if(format!=FORMAT::DATA) + return(0); + + size_t olen; + int ret=mbedtls_base64_decode(data,len,&olen,(uint8_t *)newValue.STRING,strlen(newValue.STRING)); + + if(data==NULL) + return(olen); + + if(ret==MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Destination buffer is too small (%d out of %d bytes needed)\n\n",hapName,len,olen); + else if(ret==MBEDTLS_ERR_BASE64_INVALID_CHARACTER) + Serial.printf("\n*** WARNING: Can't decode Characteristic::%s with getData(). Data is not in base-64 format\n\n",hapName); + + return(olen); + } + + void setData(uint8_t *data, size_t len){ + + if((perms & EV) == 0){ + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. No NOTIFICATION permission on this characteristic\n\n",hapName); + return; + } + + if(len<1){ + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s with setData() ignored. Size of data buffer must be greater than zero\n\n",hapName); + return; + } + + size_t olen; + mbedtls_base64_encode(NULL,0,&olen,data,len); // get length of string buffer needed (mbedtls includes the trailing null in this size) + TempBuffer tBuf(olen); // create temporary string buffer, with room for trailing null + mbedtls_base64_encode((uint8_t*)tBuf.buf,olen,&olen,data,len ); // encode data into string buf + setString(tBuf.buf); // call setString to continue processing as if characteristic was a string + } + template void setVal(T val, boolean notify=true){ if((perms & EV) == 0){ diff --git a/src/Span.h b/src/Span.h index f751052..d7221be 100644 --- a/src/Span.h +++ b/src/Span.h @@ -526,6 +526,8 @@ namespace Characteristic { CREATE_CHAR(uint8_t,VolumeSelector,0,0,1); CREATE_CHAR(double,WaterLevel,0,0,100); + CREATE_CHAR(const char *,EveTest,"AAAA",0,1); + } //////////////////////////////////////////////////////// diff --git a/src/src.ino b/src/src.ino index 40d7395..b15dcb8 100644 --- a/src/src.ino +++ b/src/src.ino @@ -3,168 +3,42 @@ // as well as compile and test from this point. This file is ignored when the library is included in other sketches. #include "HomeSpan.h" -#include "FeatherPins.h" -#include "extras/Pixel.h" -#include "extras/RFControl.h" -#include "extras/Blinker.h" -#include "extras/PwmPin.h" - -#define STRING_t const char * // WORK-AROUND - -CUSTOM_CHAR(LightMode, AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA, PR, STRING, "ANY_VALUE", NULL, NULL, true); -CUSTOM_CHAR_STRING(DarkMode, AAAAAAAA-BBBB-AAAA-AAAA-AAAAAAAAAAAA, PR, "MY_VALUE"); - -SpanPoint *dev1; -SpanPoint *dev2; - -struct message_t { - char a[32]; - int b; - float c; - bool d; -} message; +Characteristic::EveTest *eveTest; void setup() { Serial.begin(115200); - -// homeSpan.setLogLevel(2); - homeSpan.setControlPin(F25); - homeSpan.setStatusPin(F26); -// homeSpan.setStatusPin(new LED(F26)); -// new Pixel(F27); + homeSpan.setLogLevel(2); + homeSpan.begin(Category::Lighting,"HomeSpan LightBulb"); - homeSpan.setHostNameSuffix("-lamp1"); - homeSpan.setPortNum(1201); -// homeSpan.setMaxConnections(6); -// homeSpan.setQRID("One1"); - homeSpan.enableOTA(); - homeSpan.setSketchVersion("OTA Test 8"); - homeSpan.setWifiCallback(wifiEstablished); - - homeSpan.setStatusCallback(statusUpdate); - - new SpanUserCommand('d',"- My Description",userCom1); - new SpanUserCommand('e',"- My second Description",userCom2); - -// homeSpan.enableAutoStartAP(); -// homeSpan.setApFunction(myWiFiAP); - - homeSpan.enableWebLog(10,"pool.ntp.org","UTC","myLog"); // creates a web log on the URL /HomeSpan-[DEVICE-ID].local:[TCP-PORT]/myLog - - SpanPoint::setChannelMask(1<<13); - - SpanPoint::setPassword("Hello Thert"); - - homeSpan.setLogLevel(1); - - dev2=new SpanPoint("7C:DF:A1:61:E4:A8",sizeof(int),sizeof(message_t)); - dev1=new SpanPoint("AC:67:B2:77:42:20",sizeof(int),0); - - homeSpan.begin(Category::Lighting,"HomeSpan Lamp Server","homespan"); - - 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 - new Characteristic::Name("HomeSpan Test"); // Name of the Accessory, which shows up on the HomeKit "tiles", and should be unique across Accessories - new Characteristic::Manufacturer("HomeSpan"); // Manufacturer of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::SerialNumber("HSL-123"); // Serial Number of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::Model("HSL Test"); // Model of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::FirmwareRevision(HOMESPAN_VERSION); // Firmware of the Accessory (arbitrary text string, and can be the same for every Accessory) - new Characteristic::Identify(); // Create the required Identify - - 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 SpanAccessory(); + new Service::AccessoryInformation(); + new Characteristic::Identify(); + new Service::LightBulb(); - new Characteristic::On(0); - new Characteristic::LightMode("HELLO"); - new Characteristic::DarkMode(); - new Characteristic::Brightness(50); - new Characteristic::Name("Light 1"); - new Characteristic::ColorTemperature(); - new Characteristic::Active(); + new Characteristic::On(); + new Characteristic::ConfiguredName(); + eveTest=new Characteristic::EveTest(); - - new Service::LightBulb(); - new Characteristic::On(0,true); - (new Characteristic::Brightness())->setRange(10,100,5); - new Characteristic::Name("Light 2"); + uint8_t x[]={0x01,0x26,0xFF,0x01,0x26,0xFF}; + eveTest->setData(x,6); + uint8_t y[6]={0}; + int n=eveTest->getData(y,10); + Serial.printf("%d:",n); + for(int i=0;isetRange(10,100,5); - new Characteristic::Name("Light 3"); - new Characteristic::TargetPosition(); - new Characteristic::OzoneDensity(); - (new Characteristic::OzoneDensity())->addPerms(PW|AA)->removePerms(EV|PR); - -} // end of setup() - -unsigned long alarmTime=0; +} ////////////////////////////////////// void loop(){ - homeSpan.poll(); -// if(dev1->get(&message)) -// Serial.printf("DEV1: '%s' %d %f %d\n",message.a,message.b,message.c,message.d); -// if(dev2->get(&message)) -// Serial.printf("DEV2: '%s' %d %f %d\n",message.a,message.b,message.c,message.d); -// -// if(millis()-alarmTime>5000){ -// alarmTime=millis(); -// boolean success = dev2->send(&alarmTime); -// Serial.printf("Success = %d\n",success); -// } - -} // end of loop() - -////////////////////////////////////// - -void myWiFiAP(){ - Serial.print("Calling My WIFI AP\n\n"); - homeSpan.setWifiCredentials("MY_NETWORK","MY_PASSWORD"); -} - -////////////////////////////////////// - -void wifiEstablished(){ - Serial.print("IN CALLBACK FUNCTION\n\n"); - Serial.printf("MODE = %d\n",WiFi.getMode()); - -} - -////////////////////////////////////// - -void userCom1(const char *v){ - Serial.printf("In User Command 1: '%s'\n\n",v); -} - -////////////////////////////////////// - -void userCom2(const char *v){ - Serial.printf("In User Command 2: '%s'\n\n",v); -} - -////////////////////////////////////// - -void statusUpdate(HS_STATUS status){ - Serial.printf("\n*** HOMESPAN STATUS CHANGE: %s\n",homeSpan.statusString(status)); + homeSpan.poll(); // run HomeSpan! + } From 3cb8d2734219bd4015dde39a6fdc91c0b356f4cc Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 1 Jan 2023 15:08:34 -0600 Subject: [PATCH 11/41] Added CUSTOM_CHAR_DATA() macro Similar to CUSTOM_CHAR_STRING() macro, but does not include a parameter to set the default value (since the user can type an invalid string). Instead, user setData after creating the Characteristic as needed. --- src/Characteristics.h | 2 -- src/Span.h | 6 ++++-- src/src.ino | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Characteristics.h b/src/Characteristics.h index 5530d15..2364e97 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -196,8 +196,6 @@ struct HapCharacteristics { HAPCHAR( VolumeSelector, EA, PW, UINT8, true ); HAPCHAR( WaterLevel, B5, PR+EV, FLOAT, false ); - HAPCHAR( EveTest, 12345678-079E-48FF-8F27-9C2605A29F52, PW+PR+EV, DATA, false ); - }; extern HapCharacteristics hapChars; diff --git a/src/Span.h b/src/Span.h index d7221be..382456c 100644 --- a/src/Span.h +++ b/src/Span.h @@ -526,8 +526,6 @@ namespace Characteristic { CREATE_CHAR(uint8_t,VolumeSelector,0,0,1); CREATE_CHAR(double,WaterLevel,0,0,100); - CREATE_CHAR(const char *,EveTest,"AAAA",0,1); - } //////////////////////////////////////////////////////// @@ -542,6 +540,10 @@ namespace Characteristic { HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),STRING,true}; \ namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val=DEFVAL, boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; } +#define CUSTOM_CHAR_DATA(NAME,UUID,PERMISISONS) \ + HapChar _CUSTOM_##NAME {#UUID,#NAME,(PERMS)(PERMISISONS),DATA,true}; \ + namespace Characteristic { struct NAME : SpanCharacteristic { NAME(const char * val="AA==", boolean nvsStore=false) : SpanCharacteristic {&_CUSTOM_##NAME,true} { init(val,nvsStore); } }; } + #define CUSTOM_SERV(NAME,UUID) \ namespace Service { struct NAME : SpanService { NAME() : SpanService{#UUID,#NAME,true}{} }; } diff --git a/src/src.ino b/src/src.ino index b15dcb8..6a9026f 100644 --- a/src/src.ino +++ b/src/src.ino @@ -4,7 +4,9 @@ #include "HomeSpan.h" -Characteristic::EveTest *eveTest; +CUSTOM_CHAR_DATA(DataTest, 87654321-079E-48FF-8F27-9C2605A29F52, PW+PR+EV); +Characteristic::DataTest *eveTest; + void setup() { @@ -21,16 +23,26 @@ void setup() { new Service::LightBulb(); new Characteristic::On(); new Characteristic::ConfiguredName(); - eveTest=new Characteristic::EveTest(); + eveTest=new Characteristic::DataTest(); uint8_t x[]={0x01,0x26,0xFF,0x01,0x26,0xFF}; eveTest->setData(x,6); uint8_t y[6]={0}; int n=eveTest->getData(y,10); Serial.printf("%d:",n); - for(int i=0;isetData(y,6); + n=eveTest->getData(x,10); + Serial.printf("%d:",n); + for(int i=0;i Date: Sun, 1 Jan 2023 15:22:12 -0600 Subject: [PATCH 12/41] Update Reference.md --- docs/Reference.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index 6ea8f8d..b82eebc 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -471,17 +471,18 @@ To create more than one user-defined command, simply create multiple instances o ### *CUSTOM_CHAR(name,uuid,perms,format,defaultValue,minValue,maxValue,staticRange)* ### *CUSTOM_CHAR_STRING(name,uuid,perms,defaultValue)* +### *CUSTOM_CHAR_DATA(name,uuid,perms)* -Creates a custom Characteristic that can be added to any Service. Custom Characteristics are generally ignored by the Home App but may be used by other third-party applications (such as *Eve for HomeKit*). The first form should be used create numerical Characterstics (e.g., UINT8, BOOL...). The second form is used to String-based Characteristics. Parameters are as follows (note that quotes should NOT be used in any of the macro parameters, except for *defaultValue* when applied to a STRING-based Characteristic): +Creates a custom Characteristic that can be added to any Service. Custom Characteristics are generally ignored by the Home App but may be used by other third-party applications (such as *Eve for HomeKit*). The first form should be used create numerical Characterstics (e.g., UINT8, BOOL...). The second form is used to String-based Characteristics. The third form is used for base-64 encoded DATA Characteristics. Parameters are as follows (note that quotes should NOT be used in any of the macro parameters, except for *defaultValue* when applied to a STRING-based Characteristic): * *name* - the name of the custom Characteristic. This will be added to the Characteristic namespace so that it is accessed the same as any HomeSpan Characteristic * *uuid* - the UUID of the Characteristic as defined by the manufacturer. Must be *exactly* 36 characters in the form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, where *X* represent a valid hexidecimal digit. Leading zeros are required if needed as described more fully in HAP-R2 Section 6.6.1 * *perms* - additive list of permissions as described in HAP-R2 Table 6-4. Valid values are PR, PW, EV, AA, TW, HD, and WR -* *format* - specifies the format of the Characteristic value, as described in HAP-R2 Table 6-5. Valid value are BOOL, UINT8, UINT16, UNIT32, UINT64, INT, and FLOAT (note that the HomeSpan does not presently support the TLV8 or DATA formats). Not applicable for Strings-based Characteristics -* *defaultValue* - specifies the default value of the Characteristic if not defined during instantiation -* *minValue* - specifies the default minimum range for a valid value, which may be able to be overriden by a call to `setRange()`. Not applicable for Strings-based Characteristics -* *minValue* - specifies the default minimum range for a valid value, which may be able to be overriden by a call to `setRange()`. Not applicable for Strings-based Characteristics -* *staticRange* - set to *true* if *minValue* and *maxValue* are static and cannot be overridden with a call to `setRange()`. Set to *false* if calls to `setRange()` are allowed. Not applicable for Strings-based Characteristics +* *format* - specifies the format of the Characteristic value, as described in HAP-R2 Table 6-5. Valid value are BOOL, UINT8, UINT16, UNIT32, UINT64, INT, and FLOAT (note that the HomeSpan does not presently support the TLV8 formats). Not applicable for the STRING or DATA Characteristic macros +* *defaultValue* - specifies the default value of the Characteristic if not defined during instantiation. Not applicable for the DATA Characteristic macro. +* *minValue* - specifies the default minimum range for a valid value, which may be able to be overriden by a call to `setRange()`. Not applicable for the STRING or DATA Characteristic macros +* *minValue* - specifies the default minimum range for a valid value, which may be able to be overriden by a call to `setRange()`. Not applicable for the STRING or DATA Characteristic macros +* *staticRange* - set to *true* if *minValue* and *maxValue* are static and cannot be overridden with a call to `setRange()`. Set to *false* if calls to `setRange()` are allowed. Not applicable for the STRING or DATA Characteristic macros As an example, the first line below creates a custom Characteristic named "Voltage" with a UUID code that is recognized by the *Eve for HomeKit* app. The parameters show that the Characteristic is read-only (PR) and notifications are enabled (EV). The default range of allowed values is 0-240, with a default of 120. The range *can* be overridden by subsequent calls to `setRange()`. The second line below creates a custom read-only String-based Characteristic: @@ -497,9 +498,11 @@ new Service::LightBulb(); new Characteristic::UserTag(); // adds UserTag Characteristic and retains default initial value of "Tag 123" ``` -Note that Custom Characteristics must be created prior to calling `homeSpan.begin()` +Note that Custom Characteristics must be created at the global level (i.e. not inside `setup()`) and prior to calling `homeSpan.begin()` -> Advanced Tip: When presented with an unrecognized Custom Characteristic, *Eve for HomeKit* helpfully displays a *generic control* allowing you to interact with any Custom Characteristic you create in HomeSpan. However, since Eve does not recognize the Characteristic, it will only render the generic control if the Characteristic includes a **description** field, which you can add to any Characteristic using the `setDescription()` method described above. You may also want to use `setUnit()` and `setRange()` so that the Eve App displays a control with appropriate ranges for your Custom Characteristic. +> Advanced Tip 1: When presented with an unrecognized Custom Characteristic, *Eve for HomeKit* helpfully displays a *generic control* allowing you to interact with any Custom Characteristic you create in HomeSpan. However, since Eve does not recognize the Characteristic, it will only render the generic control if the Characteristic includes a **description** field, which you can add to any Characteristic using the `setDescription()` method described above. You may also want to use `setUnit()` and `setRange()` so that the Eve App displays a control with appropriate ranges for your Custom Characteristic. + +> Advanced Tip 2: The DATA format is not currently used by any native Home App Characteristic, though it is part of the HAP-R2 specifications. This format is included in HomeSpan because other applications, such as *Eve for HomeKit* do use these types of Characteristics to create functionality beyond that of the Home App, and are thus provided for advanced users to experiment. ### *CUSTOM_SERV(name,uuid)* From e51dc8c76552bc8898c69ff62736624031b84c45 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 1 Jan 2023 16:52:19 -0600 Subject: [PATCH 13/41] Update Reference.md --- docs/Reference.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index b82eebc..c6c8b54 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -307,7 +307,7 @@ This is a **base class** from which all HomeSpan Characteristics are derived, an * example with template excluded : `int tilt = Characteristic::CurrentTiltAngle->getVal();` * `type T getNewVal()` - * a template method that returns the desired **new** value to which a HomeKit Controller has requested the Characteristic be updated. Same casting rules as for `getVal<>()`. Only applicable for numerical-based Characteristics + * a template method that returns the desired **new** value to which a HomeKit Controller has requested the Characteristic be updated. Same casting rules as for `getVal<>()` * `void setVal(value [,boolean notify])` * sets the value of a numerical-based Characteristic to *value*, and, if *notify* is set to true, notifies all HomeKit Controllers of the change. The *notify* flag is optional and will be set to true if not specified. Setting the *notify* flag to false allows you to update a Characateristic without notifying any HomeKit Controllers, which is useful for Characteristics that HomeKit automatically adjusts (such as a countdown timer) but will be requested from the Accessory if the Home App closes and is then re-opened @@ -343,6 +343,23 @@ This is a **base class** from which all HomeSpan Characteristics are derived, an * `void setString(const char *value)` * equivalent to `setVal(value)`, but used exclusively for string-characteristics (i.e. a null-terminated array of characters) + + #### The following methods are supported for "data" Characteristics (note the Home App does not currently use this format for any HAP-R2 Characteristics): + +* `size_t getData(uint8_t *data, size_t len)` + * similar to `getVal()`, but exclusively used for data-based Characteristics + * fills byte array *data*, of specified size *len*, with all bytes "encoded" as the current value of the Characteristic + * returns the total number of bytes encoded in the Characteristic + * if *len* is less than the total number of bytes encoded, no data is extracted (i.e. *data* is unmodified) and a warning message is thrown indicating that the size of the *data* array is insufficient to extract all the bytes encoded in the Characteristic + * setting *data* to NULL returns the total number of bytes encoded without extracting any data. This can be used to help create a *data* array of sufficient size in advance of extracting the data + +* `size_t getNewData(uint8_t *data, size_t len)` + * similar to `getData()`, but fills byte array *data*, of specified size *len*, with bytes based on the desired **new** value to which a HomeKit Controller has requested the Characteristic be updated + +* `void setData(uint8_t *data, size_t len)` + * similar to `setVal()`, but exclusively used for data-based Characteristics + * updates the Characteristic by "filling" it with *len* bytes from bytes array *data* + * note: data-based Characteristics are encoded and transmitted as base-64 strings. HomeSpan automatically peforms all encoding and decoding between this format and the specified byte arrays. But when output to the Serial Monitor, the value of data-based Characteristics are displayed in their base-64 format (as opposed to being shown as a byte array), since base-64 is the representation that is actually transmitted to and from HomeKit #### The following methods are supported for all Characteristics: From 56a46b5fdbe51f8f03b14318698a70bf6e4b2b1a Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 1 Jan 2023 17:10:08 -0600 Subject: [PATCH 14/41] Update Reference.md --- docs/Reference.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index c6c8b54..e0fd18e 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -344,10 +344,10 @@ This is a **base class** from which all HomeSpan Characteristics are derived, an * `void setString(const char *value)` * equivalent to `setVal(value)`, but used exclusively for string-characteristics (i.e. a null-terminated array of characters) - #### The following methods are supported for "data" Characteristics (note the Home App does not currently use this format for any HAP-R2 Characteristics): + #### The following methods are supported for DATA (i.e. byte-array) Characteristics: * `size_t getData(uint8_t *data, size_t len)` - * similar to `getVal()`, but exclusively used for data-based Characteristics + * similar to `getVal()`, but exclusively used for byte-array Characteristics * fills byte array *data*, of specified size *len*, with all bytes "encoded" as the current value of the Characteristic * returns the total number of bytes encoded in the Characteristic * if *len* is less than the total number of bytes encoded, no data is extracted (i.e. *data* is unmodified) and a warning message is thrown indicating that the size of the *data* array is insufficient to extract all the bytes encoded in the Characteristic @@ -357,9 +357,9 @@ This is a **base class** from which all HomeSpan Characteristics are derived, an * similar to `getData()`, but fills byte array *data*, of specified size *len*, with bytes based on the desired **new** value to which a HomeKit Controller has requested the Characteristic be updated * `void setData(uint8_t *data, size_t len)` - * similar to `setVal()`, but exclusively used for data-based Characteristics + * similar to `setVal()`, but exclusively used for byte-array Characteristics * updates the Characteristic by "filling" it with *len* bytes from bytes array *data* - * note: data-based Characteristics are encoded and transmitted as base-64 strings. HomeSpan automatically peforms all encoding and decoding between this format and the specified byte arrays. But when output to the Serial Monitor, the value of data-based Characteristics are displayed in their base-64 format (as opposed to being shown as a byte array), since base-64 is the representation that is actually transmitted to and from HomeKit + * note: byte-array Characteristics are encoded and transmitted as base-64 strings. HomeSpan automatically peforms all encoding and decoding between this format and the specified byte arrays. But when output to the Serial Monitor, the value of byte-array Characteristics are displayed in their base-64 format (as opposed to being shown as a byte array), since base-64 is the representation that is actually transmitted to and from HomeKit #### The following methods are supported for all Characteristics: @@ -490,7 +490,7 @@ To create more than one user-defined command, simply create multiple instances o ### *CUSTOM_CHAR_STRING(name,uuid,perms,defaultValue)* ### *CUSTOM_CHAR_DATA(name,uuid,perms)* -Creates a custom Characteristic that can be added to any Service. Custom Characteristics are generally ignored by the Home App but may be used by other third-party applications (such as *Eve for HomeKit*). The first form should be used create numerical Characterstics (e.g., UINT8, BOOL...). The second form is used to String-based Characteristics. The third form is used for base-64 encoded DATA Characteristics. Parameters are as follows (note that quotes should NOT be used in any of the macro parameters, except for *defaultValue* when applied to a STRING-based Characteristic): +Creates a custom Characteristic that can be added to any Service. Custom Characteristics are generally ignored by the Home App but may be used by other third-party applications (such as *Eve for HomeKit*). The first form should be used create numerical Characterstics (e.g., UINT8, BOOL...). The second form is used to STRING-based Characteristics. The third form is used for DATA-based (i.e. byte-array) Characteristics. Parameters are as follows (note that quotes should NOT be used in any of the macro parameters, except for *defaultValue* when applied to a STRING-based Characteristic): * *name* - the name of the custom Characteristic. This will be added to the Characteristic namespace so that it is accessed the same as any HomeSpan Characteristic * *uuid* - the UUID of the Characteristic as defined by the manufacturer. Must be *exactly* 36 characters in the form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, where *X* represent a valid hexidecimal digit. Leading zeros are required if needed as described more fully in HAP-R2 Section 6.6.1 From 9ef9a590dab5a31e6b6415398434587a15391d9f Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 7 Jan 2023 14:28:50 -0600 Subject: [PATCH 15/41] Added homeSpan.setStatusDevice() Allows any Blinkable class to be used as the Status LED --- src/HomeSpan.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 7a34337..5d76818 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -298,7 +298,9 @@ class Span{ void setStatusPixel(uint8_t pin,float h=0,float s=100,float v=100){ // sets Status Device to an RGB Pixel on specified pin statusDevice=((new Pixel(pin))->setOnColor(Pixel::HSV(h,s,v))); - } + } + + void setStatusDevice(Blinkable *sDev){statusDevice=sDev;} void setApSSID(const char *ssid){network.apSSID=ssid;} // sets Access Point SSID void setApPassword(const char *pwd){network.apPassword=pwd;} // sets Access Point Password From a8271c8724fb36c81b666919861f0baa98962171 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 7 Jan 2023 17:09:22 -0600 Subject: [PATCH 16/41] Added homeSpan.refreshStatusDevice() Provides for additional control over Status LED when a generic device has been used. If the color of the device is changed, the change will only take effect when the LED is next turned on. If the LED is blinking, the color changes upon the next blink. But if the LED is ON, there is no next blink and color will not change. This method check the status of the LED, and if it is ON, is calls the on() function again, which will result in an update of the color. The method does nothing if the LED is OFF or BLINKING. --- src/HomeSpan.h | 1 + src/src/extras/Blinker.cpp | 4 ++++ src/src/extras/Blinker.h | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 5d76818..40d3dc8 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -301,6 +301,7 @@ class Span{ } void setStatusDevice(Blinkable *sDev){statusDevice=sDev;} + void refreshStatusDevice(){if(statusLED)statusLED->refresh();} void setApSSID(const char *ssid){network.apSSID=ssid;} // sets Access Point SSID void setApPassword(const char *pwd){network.apPassword=pwd;} // sets Access Point Password diff --git a/src/src/extras/Blinker.cpp b/src/src/extras/Blinker.cpp index e97ee34..ede2a26 100644 --- a/src/src/extras/Blinker.cpp +++ b/src/src/extras/Blinker.cpp @@ -78,6 +78,7 @@ void Blinker::start(int period, float dutyCycle, int nBlinks, int delayTime){ pauseTime=millis(); isPaused=false; + status=STATUS::BLINKING; } ////////////////////////////////////// @@ -93,6 +94,7 @@ void Blinker::stop(){ } isPaused=true; + status=STATUS::OFF; } ////////////////////////////////////// @@ -107,6 +109,7 @@ void Blinker::on(){ pauseTime=millis(); isPaused=false; + status=STATUS::ON; } ////////////////////////////////////// @@ -118,6 +121,7 @@ void Blinker::off(){ stop(); led->off(); + status=STATUS::OFF; } ////////////////////////////////////// diff --git a/src/src/extras/Blinker.h b/src/src/extras/Blinker.h index 633bc19..1484a86 100644 --- a/src/src/extras/Blinker.h +++ b/src/src/extras/Blinker.h @@ -47,6 +47,8 @@ class Blinkable { //////////////////////////////// class Blinker { + + enum STATUS {OFF, BLINKING, ON}; TaskHandle_t blinkHandle = NULL; Blinkable *led; @@ -55,6 +57,7 @@ class Blinker { int onTime; int offTime; int delayTime; + STATUS status=STATUS::OFF; unsigned long pauseDuration; unsigned long pauseTime; @@ -102,6 +105,10 @@ class Blinker { // Stops current blinking pattern and turns off LED + void refresh(){if(status==STATUS::ON)on();} + +// Refreshes LED color by turning device ON if status=ON (if status=BLINKING, new color is automatically used at next blink) + void check(); // Optional check to see if LED output should be paused (check is bypassed if pauseDuration=0) From 6d18d5a3dc9bee79b93932991e7629ae37228708 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 7 Jan 2023 20:44:19 -0600 Subject: [PATCH 17/41] Added "invert" option to LedPin() If invert=true, PWM output will be phase-inverted. This is useful when creating a pair of PWM pins that need to be out of phase by 180 degrees (e.g driving a piezo-electric buzzer via two PWM pins). --- src/src/extras/PwmPin.cpp | 16 ++++++---------- src/src/extras/PwmPin.h | 6 +++--- src/src/extras/RFControl.cpp | 2 -- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/src/extras/PwmPin.cpp b/src/src/extras/PwmPin.cpp index 5359c4c..4031af7 100644 --- a/src/src/extras/PwmPin.cpp +++ b/src/src/extras/PwmPin.cpp @@ -29,7 +29,7 @@ /////////////////// -LedC::LedC(uint8_t pin, uint16_t freq){ +LedC::LedC(uint8_t pin, uint16_t freq, boolean invert){ if(freq==0) freq=DEFAULT_PWM_FREQ; @@ -44,10 +44,7 @@ LedC::LedC(uint8_t pin, uint16_t freq){ timerList[nTimer][nMode]->speed_mode=(ledc_mode_t)nMode; timerList[nTimer][nMode]->timer_num=(ledc_timer_t)nTimer; timerList[nTimer][nMode]->freq_hz=freq; - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) timerList[nTimer][nMode]->clk_cfg=LEDC_USE_APB_CLK; -#endif int res=LEDC_TIMER_BIT_MAX-1; // find the maximum possible resolution while(getApbFrequency()/(freq*pow(2,res))<1) @@ -68,9 +65,7 @@ LedC::LedC(uint8_t pin, uint16_t freq){ channelList[nChannel][nMode]->channel=(ledc_channel_t)nChannel; channelList[nChannel][nMode]->timer_sel=(ledc_timer_t)nTimer; channelList[nChannel][nMode]->intr_type=LEDC_INTR_DISABLE; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) - channelList[nChannel][nMode]->flags.output_invert=0; -#endif + channelList[nChannel][nMode]->flags.output_invert=invert; channelList[nChannel][nMode]->hpoint=0; channelList[nChannel][nMode]->gpio_num=pin; timer=timerList[nTimer][nMode]; @@ -85,18 +80,19 @@ LedC::LedC(uint8_t pin, uint16_t freq){ /////////////////// -LedPin::LedPin(uint8_t pin, float level, uint16_t freq) : LedC(pin, freq){ +LedPin::LedPin(uint8_t pin, float level, uint16_t freq, boolean invert) : LedC(pin, freq, invert){ if(!channel) Serial.printf("\n*** ERROR: Can't create LedPin(%d) - no open PWM channels and/or Timers ***\n\n",pin); else - Serial.printf("LedPin=%d: mode=%d channel=%d, timer=%d, freq=%d Hz, resolution=%d bits\n", + Serial.printf("LedPin=%d: mode=%d channel=%d, timer=%d, freq=%d Hz, resolution=%d bits %s\n", channel->gpio_num, channel->speed_mode, channel->channel, channel->timer_sel, timer->freq_hz, - timer->duty_resolution + timer->duty_resolution, + channel->flags.output_invert?"(inverted)":"" ); set(level); diff --git a/src/src/extras/PwmPin.h b/src/src/extras/PwmPin.h index d9506ec..b4c1bb5 100644 --- a/src/src/extras/PwmPin.h +++ b/src/src/extras/PwmPin.h @@ -59,7 +59,7 @@ class LedC { ledc_channel_config_t *channel=NULL; ledc_timer_config_t *timer; - LedC(uint8_t pin, uint16_t freq); + LedC(uint8_t pin, uint16_t freq, boolean invert=false); public: int getPin(){return(channel?channel->gpio_num:-1);} // returns the pin number @@ -75,8 +75,8 @@ class LedC { class LedPin : public LedC { public: - LedPin(uint8_t pin, float level=0, uint16_t freq=DEFAULT_PWM_FREQ); // assigns pin to be output of one of 16 PWM channels initial level and frequency - void set(float level); // sets the PWM duty to level (0-100) + LedPin(uint8_t pin, float level=0, uint16_t freq=DEFAULT_PWM_FREQ, boolean invert=false); // assigns pin to be output of one of 16 PWM channels initial level and frequency + void set(float level); // sets the PWM duty to level (0-100) static void HSVtoRGB(float h, float s, float v, float *r, float *g, float *b ); // converts Hue/Saturation/Brightness to R/G/B }; diff --git a/src/src/extras/RFControl.cpp b/src/src/extras/RFControl.cpp index 31e48c3..7eadebb 100644 --- a/src/src/extras/RFControl.cpp +++ b/src/src/extras/RFControl.cpp @@ -45,9 +45,7 @@ RFControl::RFControl(uint8_t pin, boolean refClock, boolean installDriver){ config->rmt_mode=RMT_MODE_TX; config->tx_config.carrier_en=false; config->channel=(rmt_channel_t)nChannels; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) config->flags=0; -#endif config->clk_div = 1; config->mem_block_num=1; config->gpio_num=(gpio_num_t)pin; From fa787a9c63df45e8f934a1d81e4102e2324146fa Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Fri, 13 Jan 2023 06:51:08 -0600 Subject: [PATCH 18/41] Update PWM.md --- docs/PWM.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/PWM.md b/docs/PWM.md index fdb238c..c8329af 100644 --- a/docs/PWM.md +++ b/docs/PWM.md @@ -4,13 +4,14 @@ The ESP32 has up to 16 PWM channels that can be used to drive a variety of devic `#include "extras/PwmPin.h"` -## *LedPin(uint8_t pin [,float level [,uint16_t frequency]])* +## *LedPin(uint8_t pin [,float level [,uint16_t frequency [,boolean invert]]])* Creating an instance of this **class** configures the specified *pin* to output a PWM signal suitable for a controlling dimmable LED. Arguments, along with their defaults if left unspecified, are as follows: * *pin* - the pin on which the PWM control signal will be output * *level* - sets the initial %duty-cycle of the PWM from from 0 (LED completely off) to 100 (LED fully on). Default=0 (LED initially off) * *frequency* - sets the PWM frequency, in Hz, from 1-65535 (ESP32 only) or 5-65535 (ESP32-S2 and ESP32-C3). Defaults to 5000 Hz if unspecified, or if set to 0 + * *boolean* - if true, the output of the PWM signal will be inverted. Default=false The following methods are supported: From 7eca1e776be5fc26e32f26ab3bdb4440973319b2 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 22 Jan 2023 18:05:59 -0600 Subject: [PATCH 19/41] Add option to SpanPoint to use softAP MAC Address instead of STA Needed to support ESP-NOW on ESP-8266 chips, which seem to only work if connecting into softAP MAC Address once HomeSpan is connected to WiFi network (prior to connection ESP-8266 will properly connect to normal STA address as well as softAP address). --- .../RemoteDevice/RemoteDevice.ino | 2 +- src/HomeSpan.cpp | 13 ++- src/HomeSpan.h | 2 +- src/src.ino | 99 ++++++++++++------- 4 files changed, 72 insertions(+), 44 deletions(-) diff --git a/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino index 04b9dca..9859362 100644 --- a/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino +++ b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino @@ -61,7 +61,7 @@ void setup() { // In the line below, replace the MAC Address with that of your MAIN HOMESPAN DEVICE - mainDevice=new SpanPoint("7C:DF:A1:61:E4:A8",sizeof(float),0); // create a SpanPoint with send size=sizeof(float) and receive size=0 + mainDevice=new SpanPoint("84:CC:A8:11:B4:84",sizeof(float),0); // create a SpanPoint with send size=sizeof(float) and receive size=0 homeSpan.setLogLevel(1); } diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 185dfda..c51ca4e 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -2187,7 +2187,7 @@ boolean SpanOTA::auth; // SpanPoint // /////////////////////////////// -SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth){ +SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth, boolean useAPaddress){ 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); @@ -2204,17 +2204,20 @@ SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int this->sendSize=sendSize; this->receiveSize=receiveSize; - Serial.printf("SpanPoint: Created link to device with MAC Address %02X:%02X:%02X:%02X:%02X:%02X. Send size=%d bytes, Receive size=%d bytes with queue depth=%d.\n", - peerInfo.peer_addr[0],peerInfo.peer_addr[1],peerInfo.peer_addr[2],peerInfo.peer_addr[3],peerInfo.peer_addr[4],peerInfo.peer_addr[5],sendSize,receiveSize,queueDepth); - if(receiveSize>0) WiFi.mode(WIFI_AP_STA); else if(WiFi.getMode()==WIFI_OFF) WiFi.mode(WIFI_STA); + + Serial.printf("SpanPoint: Created link from (%s) to (%02X:%02X:%02X:%02X:%02X:%02X). Send size=%d bytes, Receive size=%d bytes with queue depth=%d.\n", + useAPaddress?WiFi.softAPmacAddress().c_str():WiFi.macAddress().c_str(), + peerInfo.peer_addr[0],peerInfo.peer_addr[1],peerInfo.peer_addr[2],peerInfo.peer_addr[3],peerInfo.peer_addr[4],peerInfo.peer_addr[5],sendSize,receiveSize,queueDepth); init(); // initialize SpanPoint peerInfo.channel=0; // 0 = matches current WiFi channel - peerInfo.ifidx=WIFI_IF_STA; // must specify interface + + peerInfo.ifidx=useAPaddress?WIFI_IF_AP:WIFI_IF_STA; // specify interface as either STA or AP + 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 diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 40d3dc8..9c37a49 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -876,7 +876,7 @@ class SpanPoint { public: - SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth=1); + SpanPoint(const char *macAddress, int sendSize, int receiveSize, int queueDepth=1, boolean useAPaddress=false); static void setPassword(const char *pwd){init(pwd);}; static void setChannelMask(uint16_t mask); boolean get(void *dataBuf); diff --git a/src/src.ino b/src/src.ino index 6a9026f..b63e1df 100644 --- a/src/src.ino +++ b/src/src.ino @@ -1,56 +1,81 @@ // This is a placeholder .ino file that allows you to easily edit the contents of this library using the Arduino IDE, // as well as compile and test from this point. This file is ignored when the library is included in other sketches. - #include "HomeSpan.h" -CUSTOM_CHAR_DATA(DataTest, 87654321-079E-48FF-8F27-9C2605A29F52, PW+PR+EV); -Characteristic::DataTest *eveTest; +struct RemoteTempSensor : Service::TemperatureSensor { + SpanCharacteristic *temp; + SpanCharacteristic *fault; + SpanPoint *remoteTemp; + const char *name; + float temperature; + + RemoteTempSensor(const char *name, const char*macAddress, boolean is8266=false) : Service::TemperatureSensor(){ + + this->name=name; + + temp=new Characteristic::CurrentTemperature(-10.0); // set initial temperature + temp->setRange(-50,100); // expand temperature range to allow negative values + + fault=new Characteristic::StatusFault(1); // set initial state = fault + + remoteTemp=new SpanPoint(macAddress,0,sizeof(float),1,is8266); // create a SpanPoint with send size=0 and receive size=sizeof(float) + + } // end constructor + + void loop(){ + + if(remoteTemp->get(&temperature)){ // if there is data from the remote sensor + temp->setVal(temperature); // update temperature + fault->setVal(0); // clear fault + + LOG1("Sensor %s update: Temperature=%0.2f\n",name,temperature*9/5+32); + + } else if(remoteTemp->time()>60000 && !fault->getVal()){ // else if it has been a while since last update (60 seconds), and there is no current fault + fault->setVal(1); // set fault state + LOG1("Sensor %s update: FAULT\n",name); + } + + } // loop + +}; + +////////////////////////////////////// void setup() { - + Serial.begin(115200); - homeSpan.setLogLevel(2); - homeSpan.begin(Category::Lighting,"HomeSpan LightBulb"); - - new SpanAccessory(); + homeSpan.setLogLevel(1); - new Service::AccessoryInformation(); - new Characteristic::Identify(); + homeSpan.begin(Category::Bridges,"Sensor Hub"); + + new SpanAccessory(); + new Service::AccessoryInformation(); + new Characteristic::Identify(); - new Service::LightBulb(); - new Characteristic::On(); - new Characteristic::ConfiguredName(); - eveTest=new Characteristic::DataTest(); + new SpanAccessory(); + new Service::AccessoryInformation(); + new Characteristic::Identify(); + new Characteristic::Name("Indoor Temp"); + new RemoteTempSensor("Device 1","AC:67:B2:77:42:20"); // pass MAC Address of Remote Device - uint8_t x[]={0x01,0x26,0xFF,0x01,0x26,0xFF}; - eveTest->setData(x,6); - uint8_t y[6]={0}; - int n=eveTest->getData(y,10); - Serial.printf("%d:",n); - for(int i=0;isetData(y,6); - n=eveTest->getData(x,10); - Serial.printf("%d:",n); - for(int i=0;i Date: Mon, 23 Jan 2023 05:54:46 -0600 Subject: [PATCH 20/41] Update RemoteDevice.ino --- .../Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino index 9859362..04b9dca 100644 --- a/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino +++ b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino @@ -61,7 +61,7 @@ void setup() { // In the line below, replace the MAC Address with that of your MAIN HOMESPAN DEVICE - mainDevice=new SpanPoint("84:CC:A8:11:B4:84",sizeof(float),0); // create a SpanPoint with send size=sizeof(float) and receive size=0 + mainDevice=new SpanPoint("7C:DF:A1:61:E4:A8",sizeof(float),0); // create a SpanPoint with send size=sizeof(float) and receive size=0 homeSpan.setLogLevel(1); } From 49f6316df83e2e8a12f1b5a8bb1176c3c373c6b0 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Mon, 23 Jan 2023 06:15:51 -0600 Subject: [PATCH 21/41] Update NOW.md --- docs/NOW.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/NOW.md b/docs/NOW.md index 5d7d632..bbe2733 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -8,14 +8,15 @@ SpanPoint creates all the internal data queues needed to manage message flow, co SpanPoint is part of the main HomeSpan library and is accessible by adding `#include "HomeSpan.h"` near the top of your sketch. Detailed descriptions of the SpanPoint class and all of its methods are provided below. -## *SpanPoint(const char \*macAddress, int sendSize, int receiveSize, int queueDepth=1)* +## *SpanPoint(const char \*macAddress, int sendSize, int receiveSize [, int queueDepth=1 [, boolean useAPaddress=false]])* Creating an instance of this **class** enables the device to send messages to, and/or receive messages from, a "complementary" instance of *SpanPoint* on another ESP32 device. Arguments, along with their defaults if left unspecified, are as follows: * *macAddress* - the MAC Address of the *other* device to which you want to send data to, and/or receive data from, in the standard 6-byte format "XX:XX:XX:XX:XX:XX", where each XX represents a single 2-digit hexidecimal byte from 00 to FF * *sendSize* - the size, in bytes, of any messages that will be sent from this device to the *other* device. Allowed range is 0 to 200, where a value of 0 is used to indicate to SpanPoint that you will **not** be using `send()` to transmit any messages from this device to the *other* device * *receiveSize* - the size, in bytes, of any messages that will be received by this device from the *other* device. Allowed range is 0 to 200, where a value of 0 is used to indicate to SpanPoint that you will **not** be using `get()` to retreive any messages transmitted by the *other* device to this device - * *queueDepth* - the depth of the queue reserved to hold messages of *receiveSize* bytes that were received by this device from the *other* device, but not yet retreived using `get()`. Default=1 if left unspecified, which should be sufficient for most applications. See `get()` below for further details. + * *queueDepth* - the depth of the queue reserved to hold messages of *receiveSize* bytes that were received by this device from the *other* device, but not yet retreived using `get()`. Default=1 if left unspecified, which should be sufficient for most applications. See `get()` below for further details. + * *useAPaddress* - SpanPoint normally communicates via the ESP32's WiFi Station (STA) Interface using the STA MAC Address. Setting *useAPaddress* to *true* causes SpanPoint to instead communicate via the ESP32's WiFi Access Point (AP) Interface using the AP MAC Address. This is needed when using an ESP-8266 as a Remote Device (see below). Default=*false* if left unspecified. Note for each instance of SpanPoint, HomeSpan will display in the Serial Monitor during start up the specific MAC Address each Remote Device should use to connect back to the Main HomeSpan Device > SpanPoint objects created on two separate devices are considered "complementary" if the MAC Addresses specified in each SpanPoint object references each other's devices, and the *sendSize* and *receiveSize* of the SpanPoint object on one device matches, respectively, the *receiveSize* and *sendSize* of the SpanPoint object on the *other* device, with the exception that it is always okay to set either the *sendSize* or *receiveSize* to zero regardless of the value set on the *other* device. From 3ec999cd8de15fc8db91a2ca7fbdc08645badbe2 Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 23 Jan 2023 06:17:23 -0600 Subject: [PATCH 22/41] Create RemoteDevice8286.ino --- .../RemoteDevice8286/RemoteDevice8286.ino | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino diff --git a/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino b/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino new file mode 100644 index 0000000..0db15bb --- /dev/null +++ b/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino @@ -0,0 +1,51 @@ + +#include +#include +#include + +float temp=-10.0; + +uint8_t main_mac[6]={0x84,0xCC,0xA8,0x11,0xB4,0x85}; + +void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { + Serial.printf("Last Packet Send Status: %s\n",sendStatus==0?"Success":"Fail"); +} + +void setup() { + + Serial.begin(115200); + delay(1000); + Serial.printf("\nMAC Address: %s\n",WiFi.macAddress().c_str()); + + WiFi.mode(WIFI_STA); + wifi_set_channel(6); + + if (esp_now_init() != 0) { + Serial.println("Error initializing ESP-NOW"); + return; + } + + uint8_t hash[32]; + char password[]="HomeSpan"; + + experimental::crypto::SHA256::hash(password,strlen(password),hash); + + esp_now_register_send_cb(OnDataSent); + esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); + + esp_now_set_kok(hash+16,16); + + esp_now_add_peer(main_mac, ESP_NOW_ROLE_COMBO, 0, hash, 16); +} + +void loop() { + + Serial.printf("Sending Temperature: %f\n",temp); + esp_now_send(main_mac, (uint8_t *)&temp, sizeof(temp)); + + temp+=0.5; + if(temp>35.0) + temp=-10.0; + + delay(5000); +} From b1bdb55d07dad92bf3ee8d3221ef4df21ca572f5 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 24 Jan 2023 22:51:13 -0600 Subject: [PATCH 23/41] Update RemoteDevice8286.ino --- .../RemoteDevice8286/RemoteDevice8286.ino | 112 +++++++++++++++--- 1 file changed, 95 insertions(+), 17 deletions(-) diff --git a/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino b/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino index 0db15bb..7b3e998 100644 --- a/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino +++ b/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino @@ -1,51 +1,129 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2023 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 +#ifndef ARDUINO_ARCH_ESP8266 +#error ERROR: THIS SKETCH IS DESIGNED FOR ESP8266 MICROCONTROLLERS! +#endif + +// *** THIS SKETCH IS FOR AN ESP8266, NOT AN ESP32 *** // + +// This sketch is similar to HomeSpan's RemoteDevice.ino example (designed for an ESP32 running HomeSpan) in which we simulate +// a Remote Temperature Sensor using HomeSpan's SpanPoint class. However, since neither HomeSpan nor SpanPoint is designed to +// run on an ESP8266, we will implement the BASIC communication functionality of SpanPoint by directly calling the equivalent +// ESP-NOW commands that are supported by the ESP8266. This sketch does NOT seek to replicate all of SpanPoint's features, and +// does not include automatic channel calibration or queue management. + +// Start by including the following ESP8266 libraries + +#include #include -#include +#include // this library is needed to implement the hash-code process SpanPoint uses to generate ESP-NOW encryption keys -float temp=-10.0; +float temp=-10.0; // this global variable represents our "simulated" temperature (in degrees C) -uint8_t main_mac[6]={0x84,0xCC,0xA8,0x11,0xB4,0x85}; +// Below we encode the MAC Address of the Main ESP32 Device running HomeSpan to which this ESP8266 device will connect + +// IMPORTANT: ESP32 devices have TWO MAC Addresses. One is used when the ESP32 is operating in Station (STA) mode. It is the address returned +// by the WiFi.macAddress() function. The other is used when the ESP32 is operating in Access Point (AP) mode. This address is returned by the +// WiFi.softAPmacAddress() function. HomeSpan normally operates the ESP32 with both modes (STA+AP), so both MAC Addresses are active. + +// On ESP32 devices, ESP-NOW seems to work fine when each device sends data to other devices via their STA MAC Address. The same is true for ESP8266 +// devices sending data to an ESP32 device via ESP-NOW with one critical exception: Once the ESP32 connects (via STA mode) to a WiFi network, which it must +// do to run HomeSpan, for some reason ESP8266 devices can no longer send data via ESP-NOW to the ESP32 using its STA MAC Address. + +// The solution is to instead have the ESP8266 send data via ESP-NOW to the ESP32's AP MAC Address. This seems to work regardless of whether or not +// the ESP32 is connected to a central WiFi newtork. To support such use on the ESP32, the SpanPoint constructor includes a fifth, optional parameter +// called "useAPaddress". When creating SpanPoint links of the ESP32 using HomeSpan, set useAPaddress to TRUE if the Remote Device SpanPoint is connecting +// to is an ESP8266. Set "useAPaddress" to FALSE (or leave unspecified, since FALSE is the default) if the Remote Device is an ESP32. + +// When HomeSpan first starts, it will will output to the Serial Monitor details of each SpanPoint object you instantiated in your ESP32 sketch. This +// output includes the MAC Address at which SpanPoint will be listening for incoming data from Remote Devices. The MAC Address shown for the instance +// of SpanPoint corresponding to this Remote Deivce (i.e. this sketch) is the MAC Address you should use below. + +uint8_t main_mac[6]={0x84,0xCC,0xA8,0x11,0xB4,0x85}; // this is the **AP MAC Address** of the Main Device running HomeSpan on an ESP32 as reported in the HomeSpan Serial Monitor + +// Next we create a simple, standard ESP-NOW callback function to report on the status of each data transmission void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) { Serial.printf("Last Packet Send Status: %s\n",sendStatus==0?"Success":"Fail"); } +////////////////////// + void setup() { Serial.begin(115200); delay(1000); - Serial.printf("\nMAC Address: %s\n",WiFi.macAddress().c_str()); + Serial.printf("\nMAC Address: %s\n",WiFi.macAddress().c_str()); // enter this MAC address as the first argument of the matching SpanPoint object on the ESP32 running HomeSpan - WiFi.mode(WIFI_STA); - wifi_set_channel(6); + WiFi.mode(WIFI_STA); // set the mode to Station + wifi_set_channel(6); // you also need to manually set the channel to match whatever channel is used by the ESP32 after it connects to your WiFi network + + // Hint: As an alterntive, you can add code to this sketch to connect to the same WiFi network that HomeSpan uses. Though this sketch won't make any use of that WiFi network, + // by establishing the connection the ESP8266 automatically configures the channel, which will now match the ESP32. + + // Next, initialize ESP-NOW if (esp_now_init() != 0) { Serial.println("Error initializing ESP-NOW"); return; } - uint8_t hash[32]; - char password[]="HomeSpan"; + // SpanPoint uses ESP-NOW encryption for all communication. This encrpytion is based on two 16-byte keys: a local master key (LMK) and a primary master key (PMK). To generate + // these keys, SpanPoint takes a text-based password (the default is the word "HomeSpan"), creates a 32 byte (256 bit) hash of the text (using the SHA256 method), and uses + // the first 16 bytes as the LMK and the last 16 bytes as the PMK. This is easily replicated as follows: - experimental::crypto::SHA256::hash(password,strlen(password),hash); + uint8_t hash[32]; // create space to store as 32-byte hash code + char password[]="HomeSpan"; // specify the password - esp_now_register_send_cb(OnDataSent); - esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); + experimental::crypto::SHA256::hash(password,strlen(password),hash); // create the hash code to be used further below - esp_now_set_kok(hash+16,16); + esp_now_register_send_cb(OnDataSent); // register the callback function we defined above + esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); // set the role of this device to be a controller (i.e. it sends data to the ESP32) + + esp_now_set_kok(hash+16,16); // next we set the PMK. For some reason this is called KOK on the ESP8266. Note you must set the PMK BEFORE adding any peers - esp_now_add_peer(main_mac, ESP_NOW_ROLE_COMBO, 0, hash, 16); + esp_now_add_peer(main_mac, ESP_NOW_ROLE_COMBO, 0, hash, 16); // now we add in the peer, set its role, and specify the LMK + + // Hint: The third argument above is the WiFi Channel. However, this is only a reference number stored by ESP-NOW. ESP-NOW does NOT actually set the channel for you. + // We already set the WiFi channel above. To make things easier, ESP-NOW allows you to set the channel as zero, which means ESP-NOW should expect the channel to be whatever was + // already set for the WiFi controller. Recommend always setting this to zero to avoid having any mismatches if you instead specified a real channel. } +////////////////////// + void loop() { Serial.printf("Sending Temperature: %f\n",temp); - esp_now_send(main_mac, (uint8_t *)&temp, sizeof(temp)); + esp_now_send(main_mac, (uint8_t *)&temp, sizeof(temp)); // Send the Data to the Main Device! - temp+=0.5; + temp+=0.5; // increment the "temperature" by 0.5 C if(temp>35.0) temp=-10.0; - delay(5000); + delay(5000); // wait 5 seconds before sending another update } From 2bc8e7e89a0bfbc561421a280f352d7711681f69 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Wed, 25 Jan 2023 06:53:30 -0600 Subject: [PATCH 24/41] Update NOW.md --- docs/NOW.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/NOW.md b/docs/NOW.md index bbe2733..6d0c98c 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -73,12 +73,12 @@ Also note that regardless of whether or not the queue if full, if the size of a One of the primary reasons for using SpanPoint is to enable the deployement of battery-powered devices. Since HomeKit requires an always-on WiFi connection, wall-power is a must. But ESP-NOW does not require always-on connectivity to a central WiFi network, which makes it possible to power things like remote-sensor devices with just a battery. Such battery-powered "Remote Devices" can take periodic local measurements and transmit them via SpanPoint messages to a wall-powered "Main Device" that is running a full HomeSpan sketch connected to HomeKit via a central WiFi network. -Examples showing such a configuration can be found in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → RemoteSensors*](../Other%20Examples/RemoteSensors). This folder contains three sketches: +Examples showing such a configuration can be found in the Arduino IDE under [*File → Examples → HomeSpan → Other Examples → RemoteSensors*](../Other%20Examples/RemoteSensors). This folder contains the following sketches: * *MainDevice.ino* - a full HomeSpan sketch that implements two Temperature Sensor Accessories, but instead of taking its own temperature measurements, it uses SpanPoint to read messages containing temperature updates from other Remote Devices * *RemoteDevice.ino* - a lightweight sketch that simulates taking periodic temperature measurements, which are then transmitted to the Main Device via SpanPoint * *RemoteTempSensor.ino* - a lightweight sketch that is similar to *RemoteDevice.ino*, except that instead of simulating a temperature sensor, it implements an actual Adafruit ADT7410 I2C-based temperature sensor. This sketch also uses some power-management techniques to extend battery life, such as lowering the CPU frequency and entering into deep-sleep after each measurement is taken - +* *RemoteDevice8266.ino* - similar in function to *RemoteDevice.ino*, but implemented to run on an ESP8266 device using native ESP-NOW commands (since neither HomeSpan nor SpanPoint support the ESP8266). Note that the "complementary" SpanPoint object on the ESP32 that receives data from the ESP8266 must be configured to use the ESP32's *AP MAC Address* (instead of the *STA MAC Address*) by setting *useAPaddress* to *true* in the SpanPoint constructor --- [↩️](README.md) Back to the Welcome page From eb53e7f6e74d2214d2a08da5f5b579a64c8b2498 Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 25 Jan 2023 22:22:49 -0600 Subject: [PATCH 25/41] Moved SpanPoint initialization message to main Info 'i' output Created SpanPoint table within 'i' output --- src/HomeSpan.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index c51ca4e..3d4dbba 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1027,6 +1027,20 @@ void Span::processSerialCommand(const char *c){ Serial.print("\n"); } } + + if(SpanPoint::SpanPoints.size()>0){ + uint8_t channel; + wifi_second_chan_t channel2; + esp_wifi_get_channel(&channel,&channel2); + Serial.printf("\nSpanPoint Channel=%d:\n\n",channel); + Serial.printf("%-17s %18s %7s %7s %7s\n","Local MAC Address","Remote MAC Address","Send","Receive","Depth"); + Serial.printf("%.17s %.18s %.7s %.7s %.7s\n",d,d,d,d,d); + for(auto it=SpanPoint::SpanPoints.begin();it!=SpanPoint::SpanPoints.end();it++) + Serial.printf("%-18s %02X:%02X:%02X:%02X:%02X:%02X %7d %7d %7d\n",(*it)->peerInfo.ifidx==WIFI_IF_AP?WiFi.softAPmacAddress().c_str():WiFi.macAddress().c_str(), + (*it)->peerInfo.peer_addr[0],(*it)->peerInfo.peer_addr[1],(*it)->peerInfo.peer_addr[2],(*it)->peerInfo.peer_addr[3],(*it)->peerInfo.peer_addr[4],(*it)->peerInfo.peer_addr[5], + (*it)->sendSize,(*it)->receiveSize,uxQueueSpacesAvailable((*it)->receiveQueue)); + } + Serial.print("\n*** End Info ***\n\n"); } break; @@ -2203,16 +2217,12 @@ SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int this->sendSize=sendSize; this->receiveSize=receiveSize; - + if(receiveSize>0) WiFi.mode(WIFI_AP_STA); else if(WiFi.getMode()==WIFI_OFF) WiFi.mode(WIFI_STA); - Serial.printf("SpanPoint: Created link from (%s) to (%02X:%02X:%02X:%02X:%02X:%02X). Send size=%d bytes, Receive size=%d bytes with queue depth=%d.\n", - useAPaddress?WiFi.softAPmacAddress().c_str():WiFi.macAddress().c_str(), - peerInfo.peer_addr[0],peerInfo.peer_addr[1],peerInfo.peer_addr[2],peerInfo.peer_addr[3],peerInfo.peer_addr[4],peerInfo.peer_addr[5],sendSize,receiveSize,queueDepth); - init(); // initialize SpanPoint peerInfo.channel=0; // 0 = matches current WiFi channel From 86337e5bfe0b14e7056405d4a0bb4622a65df7c9 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Thu, 26 Jan 2023 20:10:31 -0600 Subject: [PATCH 26/41] Update NOW.md --- docs/NOW.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/NOW.md b/docs/NOW.md index 6d0c98c..9628193 100644 --- a/docs/NOW.md +++ b/docs/NOW.md @@ -15,10 +15,12 @@ Creating an instance of this **class** enables the device to send messages to, a * *macAddress* - the MAC Address of the *other* device to which you want to send data to, and/or receive data from, in the standard 6-byte format "XX:XX:XX:XX:XX:XX", where each XX represents a single 2-digit hexidecimal byte from 00 to FF * *sendSize* - the size, in bytes, of any messages that will be sent from this device to the *other* device. Allowed range is 0 to 200, where a value of 0 is used to indicate to SpanPoint that you will **not** be using `send()` to transmit any messages from this device to the *other* device * *receiveSize* - the size, in bytes, of any messages that will be received by this device from the *other* device. Allowed range is 0 to 200, where a value of 0 is used to indicate to SpanPoint that you will **not** be using `get()` to retreive any messages transmitted by the *other* device to this device - * *queueDepth* - the depth of the queue reserved to hold messages of *receiveSize* bytes that were received by this device from the *other* device, but not yet retreived using `get()`. Default=1 if left unspecified, which should be sufficient for most applications. See `get()` below for further details. - * *useAPaddress* - SpanPoint normally communicates via the ESP32's WiFi Station (STA) Interface using the STA MAC Address. Setting *useAPaddress* to *true* causes SpanPoint to instead communicate via the ESP32's WiFi Access Point (AP) Interface using the AP MAC Address. This is needed when using an ESP-8266 as a Remote Device (see below). Default=*false* if left unspecified. Note for each instance of SpanPoint, HomeSpan will display in the Serial Monitor during start up the specific MAC Address each Remote Device should use to connect back to the Main HomeSpan Device + * *queueDepth* - the depth of the queue reserved to hold messages of *receiveSize* bytes that were received by this device from the *other* device, but not yet retreived using `get()`. Default=1 if left unspecified, which should be sufficient for most applications. See `get()` below for further details + * *useAPaddress* - SpanPoint normally communicates via the ESP32's WiFi Station (STA) Interface using the STA MAC Address. Setting *useAPaddress* to *true* causes SpanPoint to instead communicate via the ESP32's WiFi Access Point (AP) Interface using the AP MAC Address. This is needed when using an ESP-8266 as a Remote Device (see below). Default=*false* if left unspecified -> SpanPoint objects created on two separate devices are considered "complementary" if the MAC Addresses specified in each SpanPoint object references each other's devices, and the *sendSize* and *receiveSize* of the SpanPoint object on one device matches, respectively, the *receiveSize* and *sendSize* of the SpanPoint object on the *other* device, with the exception that it is always okay to set either the *sendSize* or *receiveSize* to zero regardless of the value set on the *other* device. +A list of all SpanPoint objects instantiated in a sketch, their parameters as specified above, and the specific MAC Address each Remote Device should use to connect back to the Main HomeSpan Device, is displayed in the Serial Monitor by typing 'i' into the CLI + +> SpanPoint objects created on two separate devices are considered "complementary" if the MAC Addresses specified in each SpanPoint object references each other's devices, and the *sendSize* and *receiveSize* of the SpanPoint object on one device matches, respectively, the *receiveSize* and *sendSize* of the SpanPoint object on the *other* device, with the exception that it is always okay to set either the *sendSize* or *receiveSize* to zero regardless of the value set on the *other* device SpanPoint will throw a fatal error during instantiation and halt the sketch if: * the *macAddress* specified is ill-formed, or From d04677d051a4c6a12b157fb43871a495fefd6368 Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 26 Jan 2023 20:22:48 -0600 Subject: [PATCH 27/41] Update RemoteDevice8286.ino --- .../RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino b/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino index 7b3e998..7f66bed 100644 --- a/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino +++ b/examples/Other Examples/RemoteSensors/RemoteDevice8286/RemoteDevice8286.ino @@ -60,9 +60,9 @@ float temp=-10.0; // this global variable represents our "simulated" tem // called "useAPaddress". When creating SpanPoint links of the ESP32 using HomeSpan, set useAPaddress to TRUE if the Remote Device SpanPoint is connecting // to is an ESP8266. Set "useAPaddress" to FALSE (or leave unspecified, since FALSE is the default) if the Remote Device is an ESP32. -// When HomeSpan first starts, it will will output to the Serial Monitor details of each SpanPoint object you instantiated in your ESP32 sketch. This -// output includes the MAC Address at which SpanPoint will be listening for incoming data from Remote Devices. The MAC Address shown for the instance -// of SpanPoint corresponding to this Remote Deivce (i.e. this sketch) is the MAC Address you should use below. +// When HomeSpan first starts (and whenever you type 'i' into the CLI), the Serial Monitor will display the details of each SpanPoint object you instantiated +// in your ESP32 sketch. This output includes the MAC Address at which SpanPoint will be listening for incoming data from Remote Devices. The MAC Address +// shown for the instance of SpanPoint corresponding to this Remote Deivce (i.e. this sketch) is the MAC Address you should use below. uint8_t main_mac[6]={0x84,0xCC,0xA8,0x11,0xB4,0x85}; // this is the **AP MAC Address** of the Main Device running HomeSpan on an ESP32 as reported in the HomeSpan Serial Monitor From 03ba061b9b4ca791c9e8133c537ca2cfe3ed12ff Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 28 Jan 2023 18:05:59 -0600 Subject: [PATCH 28/41] Added logic to hide AP SSID from broadcasting when WIFI_AP_STA used for SpanPoint This does NOT effect the HomeSpan Access Point from being broadcast as usual when launched. --- .../RemoteSensors/RemoteDevice/RemoteDevice.ino | 2 +- src/HomeSpan.cpp | 10 ++++++++-- src/src.ino | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino index 04b9dca..9859362 100644 --- a/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino +++ b/examples/Other Examples/RemoteSensors/RemoteDevice/RemoteDevice.ino @@ -61,7 +61,7 @@ void setup() { // In the line below, replace the MAC Address with that of your MAIN HOMESPAN DEVICE - mainDevice=new SpanPoint("7C:DF:A1:61:E4:A8",sizeof(float),0); // create a SpanPoint with send size=sizeof(float) and receive size=0 + mainDevice=new SpanPoint("84:CC:A8:11:B4:84",sizeof(float),0); // create a SpanPoint with send size=sizeof(float) and receive size=0 homeSpan.setLogLevel(1); } diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 3d4dbba..2b20cf5 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1032,13 +1032,14 @@ void Span::processSerialCommand(const char *c){ uint8_t channel; wifi_second_chan_t channel2; esp_wifi_get_channel(&channel,&channel2); - Serial.printf("\nSpanPoint Channel=%d:\n\n",channel); + Serial.printf("\nFound %d SpanPoint Links:\n\n",SpanPoint::SpanPoints.size()); Serial.printf("%-17s %18s %7s %7s %7s\n","Local MAC Address","Remote MAC Address","Send","Receive","Depth"); Serial.printf("%.17s %.18s %.7s %.7s %.7s\n",d,d,d,d,d); for(auto it=SpanPoint::SpanPoints.begin();it!=SpanPoint::SpanPoints.end();it++) Serial.printf("%-18s %02X:%02X:%02X:%02X:%02X:%02X %7d %7d %7d\n",(*it)->peerInfo.ifidx==WIFI_IF_AP?WiFi.softAPmacAddress().c_str():WiFi.macAddress().c_str(), (*it)->peerInfo.peer_addr[0],(*it)->peerInfo.peer_addr[1],(*it)->peerInfo.peer_addr[2],(*it)->peerInfo.peer_addr[3],(*it)->peerInfo.peer_addr[4],(*it)->peerInfo.peer_addr[5], (*it)->sendSize,(*it)->receiveSize,uxQueueSpacesAvailable((*it)->receiveQueue)); + Serial.printf("\nSpanPoint using WiFi Channel %d%s\n",channel,WiFi.status()!=WL_CONNECTED?" (subject to change once WiFi connection established)":""); } Serial.print("\n*** End Info ***\n\n"); @@ -2221,7 +2222,7 @@ SpanPoint::SpanPoint(const char *macAddress, int sendSize, int receiveSize, int if(receiveSize>0) WiFi.mode(WIFI_AP_STA); else if(WiFi.getMode()==WIFI_OFF) - WiFi.mode(WIFI_STA); + WiFi.mode(WIFI_STA); init(); // initialize SpanPoint peerInfo.channel=0; // 0 = matches current WiFi channel @@ -2248,6 +2249,11 @@ void SpanPoint::init(const char *password){ if(WiFi.getMode()==WIFI_OFF) WiFi.mode(WIFI_STA); + wifi_config_t conf; // make sure AP is hidden (if WIFI_AP_STA is used), since it is just a "dummy" AP to keep WiFi alive for ESP-NOW + esp_wifi_get_config(WIFI_IF_AP,&conf); + conf.ap.ssid_hidden=1; + esp_wifi_set_config(WIFI_IF_AP,&conf); + uint8_t hash[32]; mbedtls_sha256_ret((const unsigned char *)password,strlen(password),hash,0); // produce 256-bit bit hash from password diff --git a/src/src.ino b/src/src.ino index b63e1df..0bf5dcd 100644 --- a/src/src.ino +++ b/src/src.ino @@ -1,6 +1,7 @@ // This is a placeholder .ino file that allows you to easily edit the contents of this library using the Arduino IDE, // as well as compile and test from this point. This file is ignored when the library is included in other sketches. + #include "HomeSpan.h" struct RemoteTempSensor : Service::TemperatureSensor { @@ -75,7 +76,7 @@ void setup() { void loop(){ homeSpan.poll(); - + } // end of loop() ////////////////////////////////////// From 1a3887b6cfad28ec93f5e65d5358375694e2184e Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 29 Jan 2023 18:30:25 -0600 Subject: [PATCH 29/41] Added switch toggle logic to PushButton Class Adds new method toggled() which is the analog of triggered(). Next step: Extend SpanButton to access this new logic. --- src/Utils.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/Utils.h | 9 +++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 4fd4c68..09e9dde 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -88,6 +88,7 @@ PushButton::PushButton(int pin, triggerType_t triggerType){ this->pin=pin; this->triggerType=triggerType; + status=0; doubleCheck=false; @@ -95,7 +96,7 @@ PushButton::PushButton(int pin, triggerType_t triggerType){ pinMode(pin, INPUT_PULLUP); else if(triggerType==TRIGGER_ON_HIGH) pinMode(pin, INPUT_PULLDOWN); - + #if SOC_TOUCH_SENSOR_NUM > 0 else if (triggerType==TRIGGER_ON_TOUCH && threshold==0){ for(int i=0;isingleAlarm){ // switch has been in "on" state for sufficient time + toggleStatus=2; + pressType=ON; + return(true); + } + break; + + case 2: + if(!triggerType(pin)){ // switch is toggled "off" after being in "on" state + toggleStatus=0; + pressType=OFF; + return(true); + } + break; + + } // switch + + return(false); +} + +////////////////////////////////////// + boolean PushButton::primed(){ if(millis()>singleAlarm && status==1){ diff --git a/src/Utils.h b/src/Utils.h index ecac65e..eab47b3 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -80,6 +80,7 @@ typedef uint16_t touch_value_t; class PushButton{ int status; + int toggleStatus; boolean doubleCheck; uint32_t singleAlarm; uint32_t doubleAlarm; @@ -101,7 +102,9 @@ class PushButton{ enum { SINGLE=0, DOUBLE=1, - LONG=2 + LONG=2, + ON=3, + OFF=4 }; static boolean TRIGGER_ON_LOW(int pin){return(!digitalRead(pin));} @@ -158,12 +161,14 @@ class PushButton{ int type(); -// Returns 0=Single Press, 1=Double Press, or 2=Long Press +// Returns 0=Single Press, 1=Double Press, or 2=Long Press void wait(); // Waits for button to be released. Use after Long Press if button release confirmation is desired + boolean toggled(uint16_t toggleTime); + int getPin(){return(pin);} // Returns pin number From 232362c807a3784ca768fb49575eacf2403330ba Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 30 Jan 2023 07:56:46 -0600 Subject: [PATCH 30/41] Update Utils.h Added comments for new toggled() functionality --- src/Utils.h | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/Utils.h b/src/Utils.h index eab47b3..87cc616 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -100,11 +100,11 @@ class PushButton{ public: enum { - SINGLE=0, - DOUBLE=1, - LONG=2, - ON=3, - OFF=4 + SINGLE=0, // applicable only for push button + DOUBLE=1, // applicable only for push button + LONG=2, // applicable only for push button + ON=3, // applicable only for toggle switch + OFF=4 // applicable only for toggle switch }; static boolean TRIGGER_ON_LOW(int pin){return(!digitalRead(pin));} @@ -120,27 +120,27 @@ class PushButton{ PushButton(int pin, triggerType_t triggerType=TRIGGER_ON_LOW); -// Creates pushbutton of specified type on specified pin +// Creates a push-button/toggle-switch of specified type on specified pin // // pin: pin number to which the button is connected // triggerType: a function of of the form 'boolean f(int)' that is passed // the parameter *pin* and returns TRUE if the button associated -// with *pin* is pressed, or FALSE if not. Can choose from 3 pre-specifed -// triggerType_t functions (TRIGGER_ON_LOW, TRIGGER_ON_HIGH, and TRIGGER_ON_TOUCH), or write your -// own custom handler +// with *pin* is pressed/on, or FALSE if not. Can choose from 3 pre-specifed +// triggerType_t functions (TRIGGER_ON_LOW, TRIGGER_ON_HIGH, and TRIGGER_ON_TOUCH), +// or write your own custom handler void reset(); // Resets state of PushButton. Should be called once before any loops that will -// repeatedly check the button for a trigger event. +// repeatedly check the button for a trigger() event. boolean triggered(uint16_t singleTime, uint16_t longTime, uint16_t doubleTime=0); // Returns true if button has been triggered by an press event based on the following parameters: -// singleTime: the minimum time required for the button to be pressed to trigger a Single Press -// doubleTime: the maximum time allowed between button presses to qualify as a Double Press -// longTime: the minimum time required for the button to be pressed and held to trigger a Long Press +// singleTime: the minimum time required for the button to be pressed to trigger a Single Press +// doubleTime: the maximum time allowed between button presses to qualify as a Double Press +// longTime: the minimum time required for the button to be pressed and held to trigger a Long Press // All times are in milliseconds (ms). Trigger Rules: @@ -161,7 +161,10 @@ class PushButton{ int type(); -// Returns 0=Single Press, 1=Double Press, or 2=Long Press +// Returns the press type based on the whether triggered() or toggled() is called: + +// * For a push button, returns the last trigger event: 0=Single Press, 1=Double Press, 2=Long Press +// * For a toggle switch, returns the current state of the switch: 4=ON, 5=OFF void wait(); @@ -169,6 +172,12 @@ class PushButton{ boolean toggled(uint16_t toggleTime); +// Returns true if switch has been toggled, where + +// toggleTime: the minimum time (in milliseconds) a switch needs to be ON to register a toggle event + +// Once toggled() returns true, if will subsequently return false until the switch is toggled again. + int getPin(){return(pin);} // Returns pin number @@ -179,15 +188,15 @@ class PushButton{ // Sets the measure time and sleep time touch cycles , and lower threshold that triggers a touch - used only when triggerType=PushButton::TRIGGER_ON_TOUCH -// measureTime: duration of measurement time of all touch sensors in number of clock cycles -// sleepTime: duration of sleep time (between measurements) of all touch sensors number of clock cycles +// measureTime: duration of measurement time of all touch sensors in number of clock cycles +// sleepTime: duration of sleep time (between measurements) of all touch sensors number of clock cycles static void setTouchThreshold(touch_value_t thresh){threshold=thresh;} // Sets the threshold that triggers a touch - used only when triggerType=TRIGGER_ON_TOUCH -// thresh: the read value of touch sensors, beyond which which sensors are considered touched (i.e. "pressed"). -// This is a class-level value applied to all touch sensor buttons. +// thresh: the read value of touch sensors, beyond which which sensors are considered touched (i.e. "pressed"). +// This is a class-level value applied to all touch sensor buttons. #endif From c3d0c98e04a888e11abb1ce390575baedd575928 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 31 Jan 2023 22:55:43 -0600 Subject: [PATCH 31/41] Created SpanToggle() Derived from SpanButton() --- src/HomeSpan.cpp | 7 ++++++- src/HomeSpan.h | 30 +++++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 2b20cf5..b07b858 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -976,7 +976,12 @@ void Span::processSerialCommand(const char *c){ for(auto button=PushButtons.begin(); button!=PushButtons.end(); button++){ if((*button)->service==(*svc)){ - Serial.printf(" \u25bc SpanButton: Pin=%d, Single=%ums, Double=%ums, Long=%ums, Type=",(*button)->pin,(*button)->singleTime,(*button)->doubleTime,(*button)->longTime); + + if((*button)->buttonType==SpanButton::BUTTON) + Serial.printf(" \u25bc SpanButton: Pin=%d, Single=%ums, Double=%ums, Long=%ums, Type=",(*button)->pin,(*button)->singleTime,(*button)->doubleTime,(*button)->longTime); + else + Serial.printf(" \u25bc SpanToggle: Pin=%d, Toggle=%ums, Type=",(*button)->pin,(*button)->longTime); + if((*button)->triggerType==PushButton::TRIGGER_ON_LOW) Serial.printf("TRIGGER_ON_LOW\n"); else if((*button)->triggerType==PushButton::TRIGGER_ON_HIGH) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 9c37a49..34438d9 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -794,24 +794,35 @@ struct [[deprecated("Please use Characteristic::setRange() method instead.")]] S /////////////////////////////// -class SpanButton : PushButton { +class SpanButton : public PushButton { friend class Span; friend class SpanService; - + uint16_t singleTime; // minimum time (in millis) required to register a single press uint16_t longTime; // minimum time (in millis) required to register a long press uint16_t doubleTime; // maximum time (in millis) between single presses to register a double press instead - SpanService *service; // Service to which this PushButton is attached + SpanService *service; // Service to which this PushButton is attached - void check(); // check PushButton and call button() if pressed + void check(); // check PushButton and call button() if "pressed" + protected: + + enum buttonType_t { + BUTTON, + TOGGLE + }; + + buttonType_t buttonType=BUTTON; // type of SpanButton + public: enum { SINGLE=0, DOUBLE=1, - LONG=2 + LONG=2, + ON=3, + OFF=4 }; static constexpr triggerType_t TRIGGER_ON_LOW=PushButton::TRIGGER_ON_LOW; @@ -830,6 +841,15 @@ class SpanButton : PushButton { /////////////////////////////// +class SpanToggle : SpanButton { + + public: + + SpanToggle(int pin, triggerType_t triggerType=TRIGGER_ON_LOW, uint16_t toggleTime=5) : SpanButton(pin,triggerType,toggleTime){buttonType=TOGGLE;}; +}; + +/////////////////////////////// + class SpanUserCommand { friend class Span; From e2678f5661d7f8cf331e4d56cb4cc4ef0f51c8f9 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 3 Feb 2023 23:09:08 -0600 Subject: [PATCH 32/41] Added position() method to SpanToggle() Created PushButton::OPEN and PushButton::CLOSED enums. This completes all SpanToggle() functionality. Will add a SpanToggle() to UnitTest. --- src/HomeSpan.cpp | 11 ++++++++--- src/HomeSpan.h | 9 +-------- src/Utils.cpp | 16 ++++++++-------- src/Utils.h | 6 +++--- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index b07b858..d2f2c29 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -2032,7 +2032,11 @@ SpanRange::SpanRange(int min, int max, int step){ SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime, triggerType_t triggerType) : PushButton(pin, triggerType){ if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ - Serial.printf("\nFATAL ERROR! Can't create new SpanButton(%d,%u,%u,%u) without a defined Service ***\n",pin,longTime,singleTime,doubleTime); + if(buttonType==BUTTON) + Serial.printf("\nFATAL ERROR! Can't create new SpanButton(%d,%u,%u,%u) without a defined Service ***\n",pin,longTime,singleTime,doubleTime); + else + Serial.printf("\nFATAL ERROR! Can't create new SpanToggle(%d,%u) without a defined Service ***\n",pin,longTime); + Serial.printf("\n=== PROGRAM HALTED ==="); while(1); } @@ -2049,8 +2053,9 @@ SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t void SpanButton::check(){ - if(triggered(singleTime,longTime,doubleTime)) // if the underlying PushButton is triggered - service->button(pin,type()); // call the Service's button() routine with pin and type as parameters + if( (buttonType==BUTTON && triggered(singleTime,longTime,doubleTime)) || + (buttonType==TOGGLE && toggled(longTime)) ) // if the underlying PushButton is triggered/toggled + service->button(pin,type()); // call the Service's button() routine with pin and type as parameters } /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 34438d9..3dbe3c3 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -817,14 +817,6 @@ class SpanButton : public PushButton { public: - enum { - SINGLE=0, - DOUBLE=1, - LONG=2, - ON=3, - OFF=4 - }; - static constexpr triggerType_t TRIGGER_ON_LOW=PushButton::TRIGGER_ON_LOW; static constexpr triggerType_t TRIGGER_ON_HIGH=PushButton::TRIGGER_ON_HIGH; @@ -846,6 +838,7 @@ class SpanToggle : SpanButton { public: SpanToggle(int pin, triggerType_t triggerType=TRIGGER_ON_LOW, uint16_t toggleTime=5) : SpanButton(pin,triggerType,toggleTime){buttonType=TOGGLE;}; + int position(){return(pressType);} }; /////////////////////////////// diff --git a/src/Utils.cpp b/src/Utils.cpp index 09e9dde..58aa74a 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -113,10 +113,10 @@ PushButton::PushButton(int pin, triggerType_t triggerType){ #endif if(triggerType(pin)){ - pressType=ON; + pressType=CLOSED; toggleStatus=2; } else { - pressType=OFF; + pressType=OPEN; toggleStatus=0; } @@ -208,28 +208,28 @@ boolean PushButton::toggled(uint16_t toggleTime){ switch(toggleStatus){ case 0: - if(triggerType(pin)){ // switch is toggled "on" + if(triggerType(pin)){ // switch is toggled CLOSED singleAlarm=cTime+toggleTime; toggleStatus=1; } break; case 1: - if(!triggerType(pin)){ // switch is toggled "off" too soon + if(!triggerType(pin)){ // switch is toggled back OPEN too soon toggleStatus=0; } - else if(cTime>singleAlarm){ // switch has been in "on" state for sufficient time + else if(cTime>singleAlarm){ // switch has been in CLOSED state for sufficient time toggleStatus=2; - pressType=ON; + pressType=CLOSED; return(true); } break; case 2: - if(!triggerType(pin)){ // switch is toggled "off" after being in "on" state + if(!triggerType(pin)){ // switch is toggled OPEN after being in CLOSED state toggleStatus=0; - pressType=OFF; + pressType=OPEN; return(true); } break; diff --git a/src/Utils.h b/src/Utils.h index 87cc616..1fef484 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -85,13 +85,13 @@ class PushButton{ uint32_t singleAlarm; uint32_t doubleAlarm; uint32_t longAlarm; - int pressType; static touch_value_t threshold; static const int calibCount=20; protected: + int pressType; typedef boolean (*triggerType_t)(int pin); int pin; @@ -103,8 +103,8 @@ class PushButton{ SINGLE=0, // applicable only for push button DOUBLE=1, // applicable only for push button LONG=2, // applicable only for push button - ON=3, // applicable only for toggle switch - OFF=4 // applicable only for toggle switch + CLOSED=3, // applicable only for toggle switch + OPEN=4 // applicable only for toggle switch }; static boolean TRIGGER_ON_LOW(int pin){return(!digitalRead(pin));} From f7e02ecf62d4e464eac7d7372a4f8e52118e2cb5 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 07:57:16 -0600 Subject: [PATCH 33/41] Update Reference.md --- docs/Reference.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Reference.md b/docs/Reference.md index e0fd18e..054d2b3 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -450,6 +450,8 @@ In addition, you can also override the ESP32's touch sensor timing parameters us * changes the measurement time and sleep time clock cycles to *measureTime* and *sleepTime*, respectively. This is simply a pass-though call to the Arduino-ESP32 library `touchSetCycles()` function * unless a specific threshold value has been set with `setTouchThreshold()`, `setTouchCycles()` must be called *before* instantiating the first SpanButton() of type `SpanButton::TRIGGER_ON_TOUCH` so that HomeSpan will calibrate the touch threshold based on the new timing parameters specified +### *SpanToggle(int pin, boolean (\*triggerType)(int)=PushButton::TRIGGER_ON_LOW, uint16_32 toggleTime=5)* + ### *SpanUserCommand(char c, const char \*desc, void (\*f)(const char \*buf [,void \*obj]) [,void \*userObject])* Creating an instance of this **class** adds a user-defined command to the HomeSpan Command-Line Interface (CLI), where: From a65c5853ae21e1c79b68cf93006bcfe069ec8415 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 10:09:10 -0600 Subject: [PATCH 34/41] Update Reference.md --- docs/Reference.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/Reference.md b/docs/Reference.md index 054d2b3..748f315 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -452,6 +452,20 @@ In addition, you can also override the ESP32's touch sensor timing parameters us ### *SpanToggle(int pin, boolean (\*triggerType)(int)=PushButton::TRIGGER_ON_LOW, uint16_32 toggleTime=5)* +Creating an instance of this **class** attaches a toggle-switch handler to the ESP32 *pin* specified. This is a child class of *SpanButton* and thus derives all of the same functionality. For example, you can set *triggerType* to PushButton::TRIGGER_ON_HIGH, create your own trigger function, etc. However, instead of HomeSpan calling `button(int pin, int pressType)` when a pushbutton is "pressed," HomeSpan calls the same `button()` method when the switch is "toggled" from one position to another. In this case the parameter *pressType* that is passed into `button()` has a different set of enumerations: + * 3=switch is closed (`SpanToggle::CLOSED`) + * 4=switch is open (`SpanToggle::OPEN`) + +Note there are no *singleTime*, *longTime*, or *doubleTime* paramaters in the constructor since you can't single-press, double-press, or long-press a toggle switch. Instead, the constructor supports the single parameter *toggleTime* (default=5ms if left unspecified) that sets the minimum time at which the switch needs to be moved to the closed position in order to trigger a call to the `button()` method. This effectively "debounces" the toggle switch. + +SpanToggle also supports the following additional method: + + * `int position()` + * returns the current position of the toggle switch (i.e. SpanToggle::CLOSED or SpanToggle::OPEN) + * is equivalent to the *pressType* parameter passed to the `button()` method, but can be called from anywhere in a sketch + * useful for reading the initial state of a contact switch upon start-up so that the initial value of Characteristic::ContactSensorState can be set accordingly + * example `sensorState=new Characteristic::ContactSensorState(toggleSwitch->position()==SpanToggle::OPEN);` + ### *SpanUserCommand(char c, const char \*desc, void (\*f)(const char \*buf [,void \*obj]) [,void \*userObject])* Creating an instance of this **class** adds a user-defined command to the HomeSpan Command-Line Interface (CLI), where: From 2f713b3749965c4265146508b6f8f83105ea8a25 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 4 Feb 2023 10:15:37 -0600 Subject: [PATCH 35/41] Update HomeSpan.h --- src/HomeSpan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 3dbe3c3..76ab8b3 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -833,7 +833,7 @@ class SpanButton : public PushButton { /////////////////////////////// -class SpanToggle : SpanButton { +class SpanToggle : public SpanButton { public: From 88897ee08558e689e060a802569665ea5897de50 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 4 Feb 2023 11:41:57 -0600 Subject: [PATCH 36/41] Updated copyright dates on source code --- src/Characteristics.h | 2 +- src/FeatherPins.h | 2 +- src/HAP.cpp | 2 +- src/HAP.h | 2 +- src/HAPConstants.h | 2 +- src/HKDF.cpp | 2 +- src/HKDF.h | 2 +- src/HapQR.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/Settings.h | 2 +- src/Span.h | 2 +- src/TLV.h | 2 +- src/Utils.cpp | 2 +- src/Utils.h | 2 +- src/src.ino | 26 ++++++++++++++++++++++++++ src/src/extras/Blinker.cpp | 2 +- src/src/extras/Blinker.h | 2 +- src/src/extras/Pixel.cpp | 2 +- src/src/extras/Pixel.h | 2 +- src/src/extras/PwmPin.cpp | 2 +- src/src/extras/PwmPin.h | 2 +- src/src/extras/RFControl.cpp | 2 +- src/src/extras/RFControl.h | 2 +- src/src/extras/extras.ino | 27 +++++++++++++++++++++++++++ 29 files changed, 80 insertions(+), 27 deletions(-) diff --git a/src/Characteristics.h b/src/Characteristics.h index 2364e97..65aac71 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/FeatherPins.h b/src/FeatherPins.h index b41aa7e..562f5ad 100644 --- a/src/FeatherPins.h +++ b/src/FeatherPins.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HAP.cpp b/src/HAP.cpp index 29f9f6e..a922826 100644 --- a/src/HAP.cpp +++ b/src/HAP.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HAP.h b/src/HAP.h index 8ed6db1..49c8944 100644 --- a/src/HAP.h +++ b/src/HAP.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HAPConstants.h b/src/HAPConstants.h index 0b42451..5ed6ab3 100644 --- a/src/HAPConstants.h +++ b/src/HAPConstants.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HKDF.cpp b/src/HKDF.cpp index bf5f529..5194ad7 100644 --- a/src/HKDF.cpp +++ b/src/HKDF.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HKDF.h b/src/HKDF.h index 787ef05..46933ed 100644 --- a/src/HKDF.h +++ b/src/HKDF.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HapQR.h b/src/HapQR.h index 737d04c..d97e9ad 100644 --- a/src/HapQR.h +++ b/src/HapQR.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index d2f2c29..bb8a013 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 76ab8b3..a7db2d4 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Network.cpp b/src/Network.cpp index 7cbaae1..a5f452f 100644 --- a/src/Network.cpp +++ b/src/Network.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Network.h b/src/Network.h index 8f43653..679ecfe 100644 --- a/src/Network.h +++ b/src/Network.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/SRP.cpp b/src/SRP.cpp index 66a3611..bc03cd7 100644 --- a/src/SRP.cpp +++ b/src/SRP.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/SRP.h b/src/SRP.h index d8bca6e..da5023b 100644 --- a/src/SRP.h +++ b/src/SRP.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Settings.h b/src/Settings.h index 2b25a1f..f170d04 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Span.h b/src/Span.h index 382456c..23ec984 100644 --- a/src/Span.h +++ b/src/Span.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/TLV.h b/src/TLV.h index 40d9eff..4b7ae96 100644 --- a/src/TLV.h +++ b/src/TLV.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Utils.cpp b/src/Utils.cpp index 58aa74a..94dd131 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/Utils.h b/src/Utils.h index 1fef484..0a06462 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src.ino b/src/src.ino index 0bf5dcd..3585673 100644 --- a/src/src.ino +++ b/src/src.ino @@ -1,3 +1,29 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2020-2023 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. + * + ********************************************************************************/ // This is a placeholder .ino file that allows you to easily edit the contents of this library using the Arduino IDE, // as well as compile and test from this point. This file is ignored when the library is included in other sketches. diff --git a/src/src/extras/Blinker.cpp b/src/src/extras/Blinker.cpp index ede2a26..1bf30d4 100644 --- a/src/src/extras/Blinker.cpp +++ b/src/src/extras/Blinker.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/Blinker.h b/src/src/extras/Blinker.h index 1484a86..c0f6087 100644 --- a/src/src/extras/Blinker.h +++ b/src/src/extras/Blinker.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/Pixel.cpp b/src/src/extras/Pixel.cpp index 1e87187..3386e7f 100644 --- a/src/src/extras/Pixel.cpp +++ b/src/src/extras/Pixel.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/Pixel.h b/src/src/extras/Pixel.h index e781129..6cf4945 100644 --- a/src/src/extras/Pixel.h +++ b/src/src/extras/Pixel.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/PwmPin.cpp b/src/src/extras/PwmPin.cpp index 4031af7..8ba7123 100644 --- a/src/src/extras/PwmPin.cpp +++ b/src/src/extras/PwmPin.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/PwmPin.h b/src/src/extras/PwmPin.h index b4c1bb5..53e409e 100644 --- a/src/src/extras/PwmPin.h +++ b/src/src/extras/PwmPin.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/RFControl.cpp b/src/src/extras/RFControl.cpp index 7eadebb..f00d4b5 100644 --- a/src/src/extras/RFControl.cpp +++ b/src/src/extras/RFControl.cpp @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/RFControl.h b/src/src/extras/RFControl.h index 34cceb2..47e5d45 100644 --- a/src/src/extras/RFControl.h +++ b/src/src/extras/RFControl.h @@ -1,7 +1,7 @@ /********************************************************************************* * MIT License * - * Copyright (c) 2020-2022 Gregg E. Berman + * Copyright (c) 2020-2023 Gregg E. Berman * * https://github.com/HomeSpan/HomeSpan * diff --git a/src/src/extras/extras.ino b/src/src/extras/extras.ino index b179ae1..0097f00 100644 --- a/src/src/extras/extras.ino +++ b/src/src/extras/extras.ino @@ -1,3 +1,30 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2020-2023 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. + * + ********************************************************************************/ + // This is a placeholder .ino file that allows you to easily edit the contents of this files using the Arduino IDE, // as well as compile and test from this point. This file is ignored when the library is included in other sketches. From 86944152e7892a607d2a9e91dbb8de2ba35d87a9 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 18:19:49 -0600 Subject: [PATCH 37/41] Update README.md --- docs/README.md | 55 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/docs/README.md b/docs/README.md index ddf7579..f40ce7c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,7 +26,7 @@ HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](ht * Dedicated classes that utilize the ESP32's 16-channel PWM peripheral for easy control of: * LED Brightness * Servo Motors -* Integrated Push Button functionality supporting single, double, and long presses of: +* Integrated Push Button and Toggle Switch functionality supporting single, double, and long presses of: * Physical pushbuttons that connect an ESP32 pin to either ground or VCC * Touch pads/sensors connected to an ESP32 pin (for ESP32 devices that support touch pads) * Integrated access to the ESP32's on-chip Remote Control peripheral for easy generation of IR and RF signals @@ -48,29 +48,40 @@ HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](ht * Launch the WiFi Access Point * A standalone, detailed End-User Guide -## ❗Latest Update - HomeSpan 1.7.0 (11/11/2022) +## ❗Latest Update - HomeSpan 1.7.1 (2/4/2023) -* **ESP-NOW is now fully integrated into HomeSpan!** - * New dedicated class, **SpanPoint**, that facilitates bi-directional device-to-device communication between multiple ESP32 devices - * Provides automatic calibration of WiFi channels to ensure compatibility with HomeSpan's normal WiFi connectivity - * Includes detailed [Example Sketches](../Other%20Examples/RemoteSensors) demonstrating how SpanPoint can be used to implement a battery-powered Remote Sensor - * See the dedicated [SpanPoint Tutorial Page](NOW.md) for full details - -* **NeoPixels can now be used as a Status LED** - * Adds`homeSpan.setStatusPixel()` method - * Works well with ESP32 boards that have a built-in NeoPixel LED - * See the [API Reference](Reference.md) for details +* **SpanPoint support for the ESP8266!** + * Use ESP-NOW on an ESP8266 to connect to HomeSpan running on an ESP32 + * See the [SpanPoint Tutorial Page](NOW.md) for more info as well as a detailed ESP8266 example + +* **SpanPoint WiFi channel scanning upgrade** + * SpanPoint now saves the last WiFi channel successfully used for transmission in non-volatile storage + * Avoids the need for SpanPoint to restart a full scan of all channels upon reboot + * Dramatically extends battery life when used in conjunction with deep-sleep functionality + +* **New SpanToggle class** + * Similar to SpanButton, but designed for toggle switches + * Integrated de-bounce logic prevents false triggers + * Ideal for use with Contact Sensors + * See the [API Reference](API.md) for details + +* **Added Television Speaker Service** + * Control the volume of a Television from Apple's Remote App + * See the [Television Services Page](TVServices.md) for details and examples + +* **Added support for byte-array ("DATA") Characteristics** + * Useful for experimentation with other HomeKit applications, such as *Eve for HomeKit* + * Includes three new Characteristic methods: `setData()`, `getData()`, and `getNewData()` + * Includes new macro `CUSTOM_CHAR_DATA()` to easily create custom byte-array Characteristics + * See the [API Reference](API.md) for details + +* **LedPin upgrade** + * New option to invert the PWM signal + * Useful for generating two, separate out-of-phase PWM signals (one inverted, one not) to drive certain two-pin devices in a push/pull manner, such as a piezo-electric buzzer + * See the [PWM Page](PWM.md) for details -* **New functionality to track HomeSpan run-time status** - * Adds `homeSpan.setStatusCallback()` method providing users with a callback function whenever the internal state of HomeSpan changes, such as from *WiFi Needed* to *WiFi Connecting...* - * Tracks changes to the run-time state of HomeSpan that would normally trigger a change in the blinking pattern of the (optional) Status LED - * See the [API Reference](Reference.md) for details - -* **Important Bug Fixes** - - * Fixed bug in controller-update logic associated with changes to the way Apple now handles HomeKit Hubs that was producing *ERROR: Device not yet paired!* messages - - * Fixed bug in touch sensor logic that would cause compile failure when using Arduino-ESP32 versions 2.0.0-2.0.2 +* **Bug Fixes** + * Added logic to prevent the extraneous broadcasting of an Access Point SSID when SpanPoint is being used See [Releases](https://github.com/HomeSpan/HomeSpan/releases) for details on all changes and bug fixes included in this update. From 2e88e5a0939713270f4ae45e1c8069ed2d7043bb Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 18:23:37 -0600 Subject: [PATCH 38/41] Update README.md --- docs/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index f40ce7c..9b5f450 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ Welcome to HomeSpan - a robust and extremely easy-to-use Arduino library for cre HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit Accessory Protocol Specification Release R2 (HAP-R2)](https://developer.apple.com/homekit/specification/) designed specifically for the Espressif ESP32 microcontroller running within the Arduino IDE. HomeSpan pairs directly to HomeKit via your home WiFi network without the need for any external bridges or components. With HomeSpan you can use the full power of the ESP32's I/O functionality to create custom control software and/or hardware to automatically operate external devices from the Home App on your iPhone, iPad, or Mac, or with Siri. -HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](https://github.com/espressif/arduino-esp32), and has been tested up through version 2.0.5 (recommended). HomeSpan can be run on the original ESP32 as well as Espressif's ESP32-S2, ESP32-C3, and ESP32-S3 chips. +HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](https://github.com/espressif/arduino-esp32), and has been tested up through version 2.0.6 (recommended). HomeSpan can be run on the original ESP32 as well as Espressif's ESP32-S2, ESP32-C3, and ESP32-S3 chips. ### HomeSpan Highlights @@ -12,7 +12,7 @@ HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](ht * Utilizes a unique *Service-Centric* approach to creating HomeKit devices * Takes full advantage of the widely-popular Arduino IDE * 100% HAP-R2 compliance -* 38 integrated HomeKit Services +* 41 integrated HomeKit Services * Operates in either Accessory or Bridge mode * Supports pairing with Setup Codes or QR Codes @@ -63,7 +63,7 @@ HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](ht * Similar to SpanButton, but designed for toggle switches * Integrated de-bounce logic prevents false triggers * Ideal for use with Contact Sensors - * See the [API Reference](API.md) for details + * See the [API Reference](Reference.md) for details * **Added Television Speaker Service** * Control the volume of a Television from Apple's Remote App @@ -73,7 +73,7 @@ HomeSpan requires version 2.0.0 or later of the [Arduino-ESP32 Board Manager](ht * Useful for experimentation with other HomeKit applications, such as *Eve for HomeKit* * Includes three new Characteristic methods: `setData()`, `getData()`, and `getNewData()` * Includes new macro `CUSTOM_CHAR_DATA()` to easily create custom byte-array Characteristics - * See the [API Reference](API.md) for details + * See the [API Reference](Reference.md) for details * **LedPin upgrade** * New option to invert the PWM signal From 1b3e901a6383189705efbf478586a13c700d863e Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 18:49:18 -0600 Subject: [PATCH 39/41] Update README.md --- docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/README.md b/docs/README.md index 9b5f450..a102980 100644 --- a/docs/README.md +++ b/docs/README.md @@ -121,3 +121,9 @@ You ***do not*** need to read the entire document. The whole point of HomeSpan ### Feedback or Questions? Please consider adding to the [HomeSpan Discussion Board](https://github.com/HomeSpan/HomeSpan/discussions), or email me directly at [homespan@icloud.com](mailto:homespan@icloud.com). + +### About the Author + +HomeSpan was developed and continues to be maintained and supported by Gregg Berman. It was originally conceived to solve the pesky problem of not being able to operate an RF-controlled kitchen vent hood with Siri. I hope you find it useful as well as fun to use. + +This is my second large-scale open-source project --- my first was the design of an open-source sytem for operating model railroads using nothing more than an Arduino Uno and Arduino Motor Shield to generate digital command and control (DCC) signals. Though I have not been involved with the model railroading hobby for many years, videos showcasing my original system (dubbed DCC++), along with detailed tutorials of how it works, are still available on the [DCC++ YouTube Channel](https://www.youtube.com/@dcc2840/videos). From 83d994f32177f3588745a5f943b692c0c507ab9e Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 18:51:08 -0600 Subject: [PATCH 40/41] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 9dc7fbd..27bcd43 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HomeSpan -version=1.7.0 +version=1.7.1 author=Gregg maintainer=Gregg sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE. From 8114798cae549cdf64db9cdc3f8e175f4c3caad8 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 4 Feb 2023 18:52:19 -0600 Subject: [PATCH 41/41] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index d53f0b0..6f23de4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020, 2021 Gregg E. Berman +Copyright (c) 2020-2023 Gregg E. Berman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal