From b2790386d69df7a19c48c28693f6f3d02bad1af0 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 20 Feb 2021 15:43:35 -0600 Subject: [PATCH 01/32] Update Services.h HAP documentation is INCORRECT! Actual range for ColorTemperature is 140-500. Change default to 200. --- src/Services.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services.h b/src/Services.h index ed3bb5f..8b19cc0 100644 --- a/src/Services.h +++ b/src/Services.h @@ -399,7 +399,7 @@ namespace Characteristic { CREATE_CHAR(CarbonDioxideDetected,uint8_t,0); CREATE_CHAR(ChargingState,uint8_t,0); CREATE_CHAR(CoolingThresholdTemperature,double,10); - CREATE_CHAR(ColorTemperature,uint32_t,50); + CREATE_CHAR(ColorTemperature,uint32_t,200); CREATE_CHAR(ContactSensorState,uint8_t,1); CREATE_CHAR(CurrentAmbientLightLevel,double,1); CREATE_CHAR(CurrentHorizontalTiltAngle,int,0); From 3edc30222f5882652340318fcd9d87717fabab43 Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 22 Feb 2021 20:27:42 -0600 Subject: [PATCH 02/32] Updated Example 12 to demonstrate negative temperatures Use SpanRange() to change HAP default range of 0-100 to -50 to 100. Change starting temp +30 and have it reset to -30 after hitting +35. --- examples/12-ServiceLoops/DEV_Sensors.h | 7 ++++--- src/HAPConstants.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index f32520d..a47acb6 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -15,7 +15,8 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera // Though the HAP documentation includes a Characteristic that appears to allow the device to over-ride this setting by specifying a display // of Celsius or Fahrenheit for each Service, it does not appear to work as advertised. - temp=new Characteristic::CurrentTemperature(20.0); // instantiate the Current Temperature Characteristic + temp=new Characteristic::CurrentTemperature(30.0); // instantiate the Current Temperature Characteristic + new SpanRange(-50,100,1); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures Serial.print("Configuring Temperature Sensor"); // initialization message Serial.print("\n"); @@ -39,8 +40,8 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera if(temp->timeVal()>5000){ // check time elapsed since last update and proceed only if greater than 5 seconds float temperature=temp->getVal()+0.5; // "simulate" a half-degree temperature change... - if(temperature>35.0) // ...but cap the maximum at 35C before starting over at 10C - temperature=10.0; + if(temperature>35.0) // ...but cap the maximum at 35C before starting over at -30C + temperature=-30.0; temp->setVal(temperature); // set the new temperature; this generates an Event Notification and also resets the elapsed time diff --git a/src/HAPConstants.h b/src/HAPConstants.h index fdef845..3e23ffc 100644 --- a/src/HAPConstants.h +++ b/src/HAPConstants.h @@ -99,6 +99,8 @@ struct HapCharType { #define HAPCHAR(name,id,perms) HapCharType name {#id,#name,perms} +struct HapCharList { + enum { // create bitflags based on HAP Table 6-4 PR=1, PW=2, @@ -109,8 +111,6 @@ struct HapCharType { WR=64, NV=128 }; - -struct HapCharList { HAPCHAR( Active, B0, PW+PR+EV ); HAPCHAR( AirQuality, 95, PR+EV ); From 396e3322a9fcb65a63e7279a0249f71a246ec47a Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 23 Feb 2021 06:43:41 -0600 Subject: [PATCH 03/32] Update DEV_Sensors.h --- examples/12-ServiceLoops/DEV_Sensors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index a47acb6..59eb3ca 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -16,7 +16,7 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera // of Celsius or Fahrenheit for each Service, it does not appear to work as advertised. temp=new Characteristic::CurrentTemperature(30.0); // instantiate the Current Temperature Characteristic - new SpanRange(-50,100,1); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures + new SpanRange(-50,100,0.5); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures Serial.print("Configuring Temperature Sensor"); // initialization message Serial.print("\n"); From 6f589af43af6ef52a47c8038600a4854c8bfe69d Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 23 Feb 2021 09:56:45 -0600 Subject: [PATCH 04/32] Update DEV_Sensors.h --- examples/12-ServiceLoops/DEV_Sensors.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index 59eb3ca..f7f012c 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -16,7 +16,7 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera // of Celsius or Fahrenheit for each Service, it does not appear to work as advertised. temp=new Characteristic::CurrentTemperature(30.0); // instantiate the Current Temperature Characteristic - new SpanRange(-50,100,0.5); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures + new SpanRange(-50,100,1); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures Serial.print("Configuring Temperature Sensor"); // initialization message Serial.print("\n"); @@ -39,7 +39,7 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera void loop(){ if(temp->timeVal()>5000){ // check time elapsed since last update and proceed only if greater than 5 seconds - float temperature=temp->getVal()+0.5; // "simulate" a half-degree temperature change... + float temperature=temp->getVal()+0.5; // "simulate" a half-degree temperature change (it's okay that we set step size in SpanRange to 1)... if(temperature>35.0) // ...but cap the maximum at 35C before starting over at -30C temperature=-30.0; From f536db83aae358e93c4d64d15b107280ce7438d6 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 23 Feb 2021 19:35:38 -0600 Subject: [PATCH 05/32] Update FAQ.md --- docs/FAQ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 9c83140..83334a0 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -6,7 +6,7 @@ * In the spirit of promoting good security practices, HomeSpan does not allow you to embed your WiFi SSID and Password (collectively known as WiFi Credentials) into your sketch. This eliminates the possibility of accidentally disclosing this information should you share your sketch with others. -* Instead, HomeSpan stores your WiFi Credentials in a dedicated non-volatile storage (NVS) partition of the ESP32. There are two ways of entering this information. If you are developing a sketch within the Arduino IDE, simply use the HomeSpan Command Line Interface and type 'W' into the Serial Monitor. HomeSpan will prompt you to input your WiFi SSID and Password (see [CLI](CLI.md) for details). As an alternative, if your HomeSpan device is not connected to a computer, you can launch HomeSpan's Temporary WiFi Setup Network and input your WiFi Credentials directly into the web forms served by your device (see the [User Guide](https://github.com/HomeSpan/HomeSpan/blob/master/docs/UserGuide.md#setting-homespans-wifi-credentials-and-setup-code) for details). +* Instead, HomeSpan stores your WiFi Credentials in a dedicated non-volatile storage (NVS) partition of the ESP32. There are two ways of entering this information. If you are developing a sketch within the Arduino IDE, simply use the HomeSpan Command Line Interface and type 'W' into the Serial Monitor. HomeSpan will prompt you to input your WiFi SSID and Password (see [CLI](CLI.md) for details). As an alternative, if your HomeSpan device is not connected to a computer, you can launch HomeSpan's Temporary WiFi Setup Network and input your WiFi Credentials directly into the web forms served by your device (see the [User Guide](UserGuide.md#setting-homespans-wifi-credentials-and-setup-code) for details). #### Does HomeSpan support video and audio streams? From 433e1cd59a3088d4781387d0c4282f37cac36ea5 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 26 Feb 2021 07:53:33 -0600 Subject: [PATCH 06/32] Updated setVal() logic Updated setVal() logic to ensure that every possible combination of parameter type and Characteristic type is handled properly, and without generating a compile-time error related to ambiguous parameters. --- src/HomeSpan.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/HomeSpan.h | 6 ++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index c9463a2..a05214e 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1771,6 +1771,11 @@ void SpanCharacteristic::setVal(int val){ newValue.UINT64=(uint64_t)val; break; + case FLOAT: + value.FLOAT=(double)val; + newValue.FLOAT=(double)val; + break; + default: break; } @@ -1787,6 +1792,38 @@ void SpanCharacteristic::setVal(int val){ /////////////////////////////// +void SpanCharacteristic::setVal(uint32_t val){ + + value.UINT32=(uint32_t)val; + newValue.UINT32=(uint32_t)val; + updateTime=homeSpan.snapTime; + + SpanBuf sb; // create SpanBuf object + sb.characteristic=this; // set characteristic + sb.status=StatusCode::OK; // set status + char dummy[]=""; + sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" + homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector +} + +/////////////////////////////// + +void SpanCharacteristic::setVal(uint64_t val){ + + value.UINT64=(uint64_t)val; + newValue.UINT64=(uint64_t)val; + updateTime=homeSpan.snapTime; + + SpanBuf sb; // create SpanBuf object + sb.characteristic=this; // set characteristic + sb.status=StatusCode::OK; // set status + char dummy[]=""; + sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" + homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector +} + +/////////////////////////////// + void SpanCharacteristic::setVal(double val){ value.FLOAT=(double)val; diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 1b9953c..f28e1ff 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -273,8 +273,10 @@ struct SpanCharacteristic{ template T getNewVal(){return(getValue(newValue));} // returns UVal newValue template T getValue(UVal v); // returns UVal v - void setVal(int value); // sets value of UVal value for all integer-based Characterstic types - void setVal(double value); // sets value of UVal value for FLOAT Characteristic type + void setVal(uint64_t value); // sets value of UVal value for UINT64 Characteristic when parameter type is uint64_t + void setVal(uint32_t value); // sets value of UVal value for UINT32 Characteristic when parameter type is uint32_t + void setVal(double value); // sets value of UVal value for FLOAT Characteristic when parameter type is float or double + void setVal(int value); // sets value of UVal value for ANY Characteristic (except char *) when parameter type does not exactly match uint64_t, uint32_t, double, or float boolean updated(){return(isUpdated);} // returns isUpdated unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated From f591735debc67013af3067ce68b7796661fd54b2 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 27 Feb 2021 12:36:50 -0600 Subject: [PATCH 07/32] Refactored setVal() to use a template Ensures robustness and is fully backwards compatible. User does NOT have to specify a template parameter, as the compiler determines this from the setVal() argument itself. Allows for any numeric type to be properly mapped to correct HAP format for the Characteristic. This change is also needed to prepare for the refactoring of SpanRange, the addition of UVals to store HAP min/max, and new error-checking of min/max limits within setVal. --- src/HomeSpan.cpp | 103 -------------------------- src/HomeSpan.h | 185 +++++++++++++++++++++++++++++------------------ 2 files changed, 114 insertions(+), 174 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index a05214e..4e01328 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1737,109 +1737,6 @@ StatusCode SpanCharacteristic::loadUpdate(char *val, char *ev){ /////////////////////////////// -void SpanCharacteristic::setVal(int val){ - - switch(format){ - - case BOOL: - value.BOOL=(boolean)val; - newValue.BOOL=(boolean)val; - break; - - case INT: - value.INT=(int)val; - newValue.INT=(int)val; - break; - - case UINT8: - value.UINT8=(uint8_t)val; - newValue.INT=(int)val; - break; - - case UINT16: - value.UINT16=(uint16_t)val; - newValue.UINT16=(uint16_t)val; - break; - - case UINT32: - value.UINT32=(uint32_t)val; - newValue.UINT32=(uint32_t)val; - break; - - case UINT64: - value.UINT64=(uint64_t)val; - newValue.UINT64=(uint64_t)val; - break; - - case FLOAT: - value.FLOAT=(double)val; - newValue.FLOAT=(double)val; - break; - - default: - break; - } - - updateTime=homeSpan.snapTime; - - SpanBuf sb; // create SpanBuf object - sb.characteristic=this; // set characteristic - sb.status=StatusCode::OK; // set status - char dummy[]=""; - sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" - homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector -} - -/////////////////////////////// - -void SpanCharacteristic::setVal(uint32_t val){ - - value.UINT32=(uint32_t)val; - newValue.UINT32=(uint32_t)val; - updateTime=homeSpan.snapTime; - - SpanBuf sb; // create SpanBuf object - sb.characteristic=this; // set characteristic - sb.status=StatusCode::OK; // set status - char dummy[]=""; - sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" - homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector -} - -/////////////////////////////// - -void SpanCharacteristic::setVal(uint64_t val){ - - value.UINT64=(uint64_t)val; - newValue.UINT64=(uint64_t)val; - updateTime=homeSpan.snapTime; - - SpanBuf sb; // create SpanBuf object - sb.characteristic=this; // set characteristic - sb.status=StatusCode::OK; // set status - char dummy[]=""; - sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" - homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector -} - -/////////////////////////////// - -void SpanCharacteristic::setVal(double val){ - - value.FLOAT=(double)val; - newValue.FLOAT=(double)val; - updateTime=homeSpan.snapTime; - - SpanBuf sb; // create SpanBuf object - sb.characteristic=this; // set characteristic - sb.status=StatusCode::OK; // set status - char dummy[]=""; - sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" - homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector -} - -/////////////////////////////// - unsigned long SpanCharacteristic::timeVal(){ return(homeSpan.snapTime-updateTime); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index f28e1ff..1d52edc 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -54,6 +54,64 @@ enum { GET_ALL=255 }; +enum FORMAT { // HAP Table 6-5 + BOOL, + UINT8, + UINT16, + UINT32, + UINT64, + INT, + FLOAT, + STRING +}; + +union UVal { + boolean BOOL; + uint8_t UINT8; + uint16_t UINT16; + uint32_t UINT32; + uint64_t UINT64; + int32_t INT; + double FLOAT; + const char *STRING; + + template void set(FORMAT fmt, T val){ + + switch(fmt){ + + case FORMAT::BOOL: + BOOL=(boolean)val; + break; + + case FORMAT::INT: + INT=(int)val; + break; + + case FORMAT::UINT8: + UINT8=(uint8_t)val; + break; + + case FORMAT::UINT16: + UINT16=(uint16_t)val; + break; + + case FORMAT::UINT32: + UINT32=(uint32_t)val; + break; + + case FORMAT::UINT64: + UINT64=(uint64_t)val; + break; + + case FORMAT::FLOAT: + FLOAT=(double)val; + break; + } + } +}; + +/////////////////////////////// + // Forward-Declarations struct Span; @@ -64,6 +122,8 @@ struct SpanRange; struct SpanBuf; struct SpanButton; +extern Span homeSpan; + /////////////////////////////// struct SpanConfig { @@ -73,6 +133,17 @@ struct SpanConfig { /////////////////////////////// +struct SpanBuf{ // temporary storage buffer for use with putCharacteristicsURL() and checkTimedResets() + uint32_t aid=0; // updated aid + int iid=0; // updated iid + char *val=NULL; // updated value (optional, though either at least 'val' or 'ev' must be specified) + char *ev=NULL; // updated event notification flag (optional, though either at least 'val' or 'ev' must be specified) + StatusCode status; // return status (HAP Table 6-11) + SpanCharacteristic *characteristic=NULL; // Characteristic to update (NULL if not found) +}; + +/////////////////////////////// + struct Span{ const char *displayName; // display name for this device - broadcast as part of Bonjour MDNS @@ -217,28 +288,6 @@ struct SpanCharacteristic{ WR=64, NV=128 }; - - enum FORMAT { // HAP Table 6-5 - BOOL=0, - UINT8=1, - UINT16=2, - UINT32=3, - UINT64=4, - INT=5, - FLOAT=6, - STRING=7 - }; - - union UVal { - boolean BOOL; - uint8_t UINT8; - uint16_t UINT16; - uint32_t UINT32; - uint64_t UINT64; - int32_t INT; - double FLOAT; - const char *STRING; - }; int iid=0; // Instance ID (HAP Table 6-3) const char *type; // Characteristic Type @@ -269,44 +318,53 @@ struct SpanCharacteristic{ int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intiial HAP status code (checks to see if characteristic is found, is writable, etc.) + boolean updated(){return(isUpdated);} // returns isUpdated + unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated + template T getVal(){return(getValue(value));} // returns UVal value template T getNewVal(){return(getValue(newValue));} // returns UVal newValue - template T getValue(UVal v); // returns UVal v - - void setVal(uint64_t value); // sets value of UVal value for UINT64 Characteristic when parameter type is uint64_t - void setVal(uint32_t value); // sets value of UVal value for UINT32 Characteristic when parameter type is uint32_t - void setVal(double value); // sets value of UVal value for FLOAT Characteristic when parameter type is float or double - void setVal(int value); // sets value of UVal value for ANY Characteristic (except char *) when parameter type does not exactly match uint64_t, uint32_t, double, or float - - boolean updated(){return(isUpdated);} // returns isUpdated - unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated -}; - -/////////////////////////////// - -template T SpanCharacteristic::getValue(UVal v){ - - switch(format){ - case BOOL: - return((T) v.BOOL); - case INT: - return((T) v.INT); - case UINT8: - return((T) v.UINT8); - case UINT16: - return((T) v.UINT16); - case UINT32: - return((T) v.UINT32); - case UINT64: - return((T) v.UINT64); - case FLOAT: - return((T) v.FLOAT); - case STRING: - Serial.print("*** ERROR: Can't use getVal() or getNewVal() for string Characteristics.\n\n"); - return(0); - } + template T getValue(UVal v){ + + switch(format){ + case BOOL: + return((T) v.BOOL); + case INT: + return((T) v.INT); + case UINT8: + return((T) v.UINT8); + case UINT16: + return((T) v.UINT16); + case UINT32: + return((T) v.UINT32); + case UINT64: + return((T) v.UINT64); + case FLOAT: + return((T) v.FLOAT); + case STRING: + Serial.print("*** ERROR: Can't use getVal() or getNewVal() for string Characteristics.\n\n"); + return(0); + + } // switch + + } // getValue + + template void setVal(T val){ + value.set(format, val); + newValue.set(format, val); + + updateTime=homeSpan.snapTime; + + SpanBuf sb; // create SpanBuf object + sb.characteristic=this; // set characteristic + sb.status=StatusCode::OK; // set status + char dummy[]=""; + sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" + homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector + + } // setValue + }; /////////////////////////////// @@ -321,17 +379,6 @@ struct SpanRange{ /////////////////////////////// -struct SpanBuf{ // temporary storage buffer for use with putCharacteristicsURL() and checkTimedResets() - uint32_t aid=0; // updated aid - int iid=0; // updated iid - char *val=NULL; // updated value (optional, though either at least 'val' or 'ev' must be specified) - char *ev=NULL; // updated event notification flag (optional, though either at least 'val' or 'ev' must be specified) - StatusCode status; // return status (HAP Table 6-11) - SpanCharacteristic *characteristic=NULL; // Characteristic to update (NULL if not found) -}; - -/////////////////////////////// - struct SpanButton{ enum { @@ -352,10 +399,6 @@ struct SpanButton{ }; ///////////////////////////////////////////////// -// Extern Variables -extern Span homeSpan; - -///////////////////////////////////////////////// #include "Services.h" From 064d881e9cf8782ddc233ddcceb6e16a3b32afdc Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 27 Feb 2021 12:54:32 -0600 Subject: [PATCH 08/32] Refactored getVal() and getNewVal() Functionality is identical, but template has been moved into UVal structure along with setVal, which simplifies code and allows for other uses if needed. --- src/HomeSpan.h | 66 ++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 1d52edc..7e23842 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -107,7 +107,40 @@ union UVal { FLOAT=(double)val; break; } - } + } // set() + + template T get(FORMAT fmt){ + + switch(fmt){ + + case FORMAT::BOOL: + return((T) BOOL); + + case FORMAT::INT: + return((T) INT); + + case FORMAT::UINT8: + return((T) UINT8); + + case FORMAT::UINT16: + return((T) UINT16); + + case FORMAT::UINT32: + return((T) UINT32); + + case FORMAT::UINT64: + return((T) UINT64); + + case FORMAT::FLOAT: + return((T) FLOAT); + + case FORMAT::STRING: + Serial.print("*** ERROR: Can't use getVal() or getNewVal() for string Characteristics.\n\n"); + return(0); + } + + } // get() + }; /////////////////////////////// @@ -321,34 +354,9 @@ struct SpanCharacteristic{ boolean updated(){return(isUpdated);} // returns isUpdated unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated - template T getVal(){return(getValue(value));} // returns UVal value - template T getNewVal(){return(getValue(newValue));} // returns UVal newValue - - template T getValue(UVal v){ - - switch(format){ - case BOOL: - return((T) v.BOOL); - case INT: - return((T) v.INT); - case UINT8: - return((T) v.UINT8); - case UINT16: - return((T) v.UINT16); - case UINT32: - return((T) v.UINT32); - case UINT64: - return((T) v.UINT64); - case FLOAT: - return((T) v.FLOAT); - case STRING: - Serial.print("*** ERROR: Can't use getVal() or getNewVal() for string Characteristics.\n\n"); - return(0); - - } // switch - - } // getValue - + template T getVal(){return(value.get(format));} // returns UVal value + template T getNewVal(){return(newValue.get(format));} // returns UVal newValue + template void setVal(T val){ value.set(format, val); From 7930e3a0d9356836302f7b89ee8e3a1e657c7a7c Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 28 Feb 2021 10:49:17 -0600 Subject: [PATCH 09/32] Re-Factored SpanCharacteristic Constructor and Services.h Added Characteristics.h file that defines all static data for HAP Characteristics. Changed macros in Services.h to use this new HapChar structure. Code is now more streamlined and ready for mix/max range-checking to be added. --- src/Characteristics.h | 170 +++++++++++++++++++++++++++++++++ src/HAPConstants.h | 127 ------------------------- src/HomeSpan.cpp | 81 +++------------- src/HomeSpan.h | 43 ++------- src/Services.h | 215 ++++++++++++++++++++++-------------------- 5 files changed, 302 insertions(+), 334 deletions(-) create mode 100644 src/Characteristics.h diff --git a/src/Characteristics.h b/src/Characteristics.h new file mode 100644 index 0000000..38625fb --- /dev/null +++ b/src/Characteristics.h @@ -0,0 +1,170 @@ +/********************************************************************************* + * MIT License + * + * Copyright (c) 2020-2021 Gregg E. Berman + * + * https://github.com/HomeSpan/HomeSpan + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + ********************************************************************************/ + +////////////////////////////////////////// +// HAP CHARACTERISTICS (HAP Chapter 9) // +////////////////////////////////////////// + +enum PERMS{ // create bitflags based on HAP Table 6-4 + PR=1, + PW=2, + EV=4, + AA=8, + TW=16, + HD=32, + WR=64, + NV=128 // this is a non-HAP flag used to specify that no value should be provided (should be a HAP flag!) +}; + +enum FORMAT { // HAP Table 6-5 + BOOL, + UINT8, + UINT16, + UINT32, + UINT64, + INT, + FLOAT, + STRING +}; + +/////////////////////////////// + +struct HapChar { + const char *type; + const char *hapName; + PERMS perms; + FORMAT format; +}; + +/////////////////////////////// + +#define HAPCHAR(hapName,type,perms,format) HapChar hapName {#type,#hapName,(PERMS)(perms),format} + +struct HapCharacteristics { + + HAPCHAR( Active, B0, PW+PR+EV, UINT8 ); + HAPCHAR( AirQuality, 95, PR+EV, UINT8 ); + HAPCHAR( BatteryLevel, 68, PR+EV, UINT8 ); + HAPCHAR( Brightness, 8, PR+PW+EV, INT ); + HAPCHAR( CarbonMonoxideLevel, 90, PR+EV, FLOAT ); + HAPCHAR( CarbonMonoxidePeakLevel, 91, PR+EV, FLOAT ); + HAPCHAR( CarbonDioxideDetected, 92, PR+EV, UINT8 ); + HAPCHAR( CarbonDioxideLevel, 93, PR+EV, FLOAT ); + HAPCHAR( CarbonDioxidePeakLevel, 94, PR+EV, FLOAT ); + HAPCHAR( CarbonMonoxideDetected, 69, PR+EV, UINT8 ); + HAPCHAR( ChargingState, 8F, PR+EV, UINT8 ); + HAPCHAR( CoolingThresholdTemperature, D, PR+PW+EV, FLOAT ); + HAPCHAR( ColorTemperature, CE, PR+PW+EV, UINT32 ); + HAPCHAR( ContactSensorState, 6A, PR+EV, UINT8 ); + HAPCHAR( CurrentAmbientLightLevel, 6B, PR+EV, FLOAT ); + HAPCHAR( CurrentHorizontalTiltAngle, 6C, PR+EV, INT ); + HAPCHAR( CurrentAirPurifierState, A9, PR+EV, UINT8 ); + HAPCHAR( CurrentSlatState, AA, PR+EV, UINT8 ); + HAPCHAR( CurrentPosition, 6D, PR+EV, UINT8 ); + HAPCHAR( CurrentVerticalTiltAngle, 6E, PR+EV, INT ); + HAPCHAR( CurrentHumidifierDehumidifierState, B3, PR+EV, UINT8 ); + HAPCHAR( CurrentDoorState, E, PR+EV, UINT8 ); + HAPCHAR( CurrentFanState, AF, PR+EV, UINT8 ); + HAPCHAR( CurrentHeatingCoolingState, F, PR+EV, UINT8 ); + HAPCHAR( CurrentHeaterCoolerState, B1, PR+EV, UINT8 ); + HAPCHAR( CurrentRelativeHumidity, 10, PR+EV, FLOAT ); + HAPCHAR( CurrentTemperature, 11, PR+EV, FLOAT ); + HAPCHAR( CurrentTiltAngle, C1, PR+EV, INT ); + HAPCHAR( FilterLifeLevel, AB, PR+EV, FLOAT ); + HAPCHAR( FilterChangeIndication, AC, PR+EV, UINT8 ); + HAPCHAR( FirmwareRevision, 52, PR, STRING ); + HAPCHAR( HardwareRevision, 53, PR, STRING ); + HAPCHAR( HeatingThresholdTemperature, 12, PR+PW+EV, FLOAT ); + HAPCHAR( HoldPosition, 6F, PW, BOOL ); + HAPCHAR( Hue, 13, PR+PW+EV, FLOAT ); + HAPCHAR( Identify, 14, PW, BOOL ); + HAPCHAR( InUse, D2, PR+EV, UINT8 ); + HAPCHAR( IsConfigured, D6, PR+EV, UINT8 ); + HAPCHAR( LeakDetected, 70, PR+EV, UINT8 ); + HAPCHAR( LockCurrentState, 1D, PR+EV, UINT8 ); + HAPCHAR( LockPhysicalControls, A7, PW+PR+EV, UINT8 ); + HAPCHAR( LockTargetState, 1E, PW+PR+EV, UINT8 ); + HAPCHAR( Manufacturer, 20, PR, STRING ); + HAPCHAR( Model, 21, PR, STRING ); + HAPCHAR( MotionDetected, 22, PR+EV, BOOL ); + HAPCHAR( Mute, 11A, PW+PR+EV, BOOL ); + HAPCHAR( Name, 23, PR, STRING ); + HAPCHAR( NitrogenDioxideDensity, C4, PR+EV, FLOAT ); + HAPCHAR( ObstructionDetected, 24, PR+EV, BOOL ); + HAPCHAR( PM25Density, C6, PR+EV, FLOAT ); + HAPCHAR( OccupancyDetected, 71, PR+EV, UINT8 ); + HAPCHAR( OutletInUse, 26, PR+EV, BOOL ); + HAPCHAR( On, 25, PR+PW+EV, BOOL ); + HAPCHAR( OzoneDensity, C3, PR+EV, FLOAT ); + HAPCHAR( PM10Density, C7, PR+EV, FLOAT ); + HAPCHAR( PositionState, 72, PR+EV, UINT8 ); + HAPCHAR( ProgramMode, D1, PR+EV, UINT8 ); + HAPCHAR( ProgrammableSwitchEvent, 73, PR+EV+NV, UINT8 ); + HAPCHAR( RelativeHumidityDehumidifierThreshold, C9, PR+PW+EV, FLOAT ); + HAPCHAR( RelativeHumidityHumidifierThreshold, CA, PR+PW+EV, FLOAT ); + HAPCHAR( RemainingDuration, D4, PR+EV, UINT32 ); + HAPCHAR( ResetFilterIndication, AD, PW, UINT8 ); + HAPCHAR( RotationDirection, 28, PR+PW+EV, INT ); + HAPCHAR( RotationSpeed, 29, PR+PW+EV, FLOAT ); + HAPCHAR( Saturation, 2F, PR+PW+EV, FLOAT ); + HAPCHAR( SecuritySystemAlarmType, 8E, PR+EV, UINT8 ); + HAPCHAR( SecuritySystemCurrentState, 66, PR+EV, UINT8 ); + HAPCHAR( SecuritySystemTargetState, 67, PW+PR+EV, UINT8 ); + HAPCHAR( SerialNumber, 30, PR, STRING ); + HAPCHAR( ServiceLabelIndex, CB, PR, UINT8 ); + HAPCHAR( ServiceLabelNamespace, CD, PR, UINT8 ); + HAPCHAR( SlatType, C0, PR, UINT8 ); + HAPCHAR( SmokeDetected, 76, PR+EV, UINT8 ); + HAPCHAR( StatusActive, 75, PR+EV, BOOL ); + HAPCHAR( StatusFault, 77, PR+EV, UINT8 ); + HAPCHAR( StatusJammed, 78, PR+EV, UINT8 ); + HAPCHAR( StatusLowBattery, 79, PR+EV, UINT8 ); + HAPCHAR( StatusTampered, 7A, PR+EV, UINT8 ); + HAPCHAR( SulphurDioxideDensity, C5, PR+EV, FLOAT ); + HAPCHAR( SwingMode, B6, PR+EV+PW, UINT8 ); + HAPCHAR( TargetAirPurifierState, A8, PW+PR+EV, UINT8 ); + HAPCHAR( TargetFanState, BF, PW+PR+EV, UINT8 ); + HAPCHAR( TargetTiltAngle, C2, PW+PR+EV, INT ); + HAPCHAR( TargetHeaterCoolerState, B2, PW+PR+EV, UINT8 ); + HAPCHAR( SetDuration, D3, PW+PR+EV, UINT32 ); + HAPCHAR( TargetHorizontalTiltAngle, 7B, PW+PR+EV, INT ); + HAPCHAR( TargetHumidifierDehumidifierState, B4, PW+PR+EV, UINT8 ); + HAPCHAR( TargetPosition, 7C, PW+PR+EV, UINT8 ); + HAPCHAR( TargetDoorState, 32, PW+PR+EV, UINT8 ); + HAPCHAR( TargetHeatingCoolingState, 33, PW+PR+EV, UINT8 ); + HAPCHAR( TargetRelativeHumidity, 34, PW+PR+EV, FLOAT ); + HAPCHAR( TargetTemperature, 35, PW+PR+EV, FLOAT ); + HAPCHAR( TemperatureDisplayUnits, 36, PW+PR+EV, UINT8 ); + HAPCHAR( TargetVerticalTiltAngle, 7D, PW+PR+EV, INT ); + HAPCHAR( ValveType, D5, PR+EV, UINT8 ); + HAPCHAR( Version, 37, PR, STRING ); + HAPCHAR( VOCDensity, C8, PR+EV, FLOAT ); + HAPCHAR( Volume, 119, PW+PR+EV, UINT8 ); + HAPCHAR( WaterLevel, B5, PR+EV, FLOAT ); +}; + +extern HapCharacteristics hapChars; diff --git a/src/HAPConstants.h b/src/HAPConstants.h index 3e23ffc..77bd183 100644 --- a/src/HAPConstants.h +++ b/src/HAPConstants.h @@ -86,130 +86,3 @@ enum class StatusCode { InvalidValue=-70410, TBD=-1 // status To-Be-Determined (TBD) once service.update() called - internal use only }; - -/////////////////////////////// - -struct HapCharType { - const char *id; - const char *name; - uint8_t perms; -}; - -/////////////////////////////// - -#define HAPCHAR(name,id,perms) HapCharType name {#id,#name,perms} - -struct HapCharList { - - enum { // create bitflags based on HAP Table 6-4 - PR=1, - PW=2, - EV=4, - AA=8, - TW=16, - HD=32, - WR=64, - NV=128 - }; - - HAPCHAR( Active, B0, PW+PR+EV ); - HAPCHAR( AirQuality, 95, PR+EV ); - HAPCHAR( BatteryLevel, 68, PR+EV ); - HAPCHAR( Brightness, 8, PR+PW+EV ); - HAPCHAR( CarbonMonoxideLevel, 90, PR+EV ); - HAPCHAR( CarbonMonoxidePeakLevel, 91, PR+EV ); - HAPCHAR( CarbonDioxideDetected, 92, PR+EV ); - HAPCHAR( CarbonDioxideLevel, 93, PR+EV ); - HAPCHAR( CarbonDioxidePeakLevel, 94, PR+EV ); - HAPCHAR( CarbonMonoxideDetected, 69, PR+EV ); - HAPCHAR( ChargingState, 8F, PR+EV ); - HAPCHAR( CoolingThresholdTemperature, D, PR+PW+EV ); - HAPCHAR( ColorTemperature, CE, PR+PW+EV ); - HAPCHAR( ContactSensorState, 6A, PR+EV ); - HAPCHAR( CurrentAmbientLightLevel, 6B, PR+EV ); - HAPCHAR( CurrentHorizontalTiltAngle, 6C, PR+EV ); - HAPCHAR( CurrentAirPurifierState, A9, PR+EV ); - HAPCHAR( CurrentSlatState, AA, PR+EV ); - HAPCHAR( CurrentPosition, 6D, PR+EV ); - HAPCHAR( CurrentVerticalTiltAngle, 6E, PR+EV ); - HAPCHAR( CurrentHumidifierDehumidifierState, B3, PR+EV ); - HAPCHAR( CurrentDoorState, E, PR+EV ); - HAPCHAR( CurrentFanState, AF, PR+EV ); - HAPCHAR( CurrentHeatingCoolingState, F, PR+EV ); - HAPCHAR( CurrentHeaterCoolerState, B1, PR+EV ); - HAPCHAR( CurrentRelativeHumidity, 10, PR+EV ); - HAPCHAR( CurrentTemperature, 11, PR+EV ); - HAPCHAR( CurrentTiltAngle, C1, PR+EV ); - HAPCHAR( FilterLifeLevel, AB, PR+EV ); - HAPCHAR( FilterChangeIndication, AC, PR+EV ); - HAPCHAR( FirmwareRevision, 52, PR ); - HAPCHAR( HardwareRevision, 53, PR ); - HAPCHAR( HeatingThresholdTemperature, 12, PR+PW+EV ); - HAPCHAR( HoldPosition, 6F, PW ); - HAPCHAR( Hue, 13, PR+PW+EV ); - HAPCHAR( Identify, 14, PW ); - HAPCHAR( InUse, D2, PR+EV ); - HAPCHAR( IsConfigured, D6, PR+EV ); - HAPCHAR( LeakDetected, 70, PR+EV ); - HAPCHAR( LockCurrentState, 1D, PR+EV ); - HAPCHAR( LockPhysicalControls, A7, PW+PR+EV ); - HAPCHAR( LockTargetState, 1E, PW+PR+EV ); - HAPCHAR( Manufacturer, 20, PR ); - HAPCHAR( Model, 21, PR ); - HAPCHAR( MotionDetected, 22, PR+EV ); - HAPCHAR( Mute, 11A, PW+PR+EV ); - HAPCHAR( Name, 23, PR ); - HAPCHAR( NitrogenDioxideDensity, C4, PR+EV ); - HAPCHAR( ObstructionDetected, 24, PR+EV ); - HAPCHAR( PM25Density, C6, PR+EV ); - HAPCHAR( OccupancyDetected, 71, PR+EV ); - HAPCHAR( OutletInUse, 26, PR+EV ); - HAPCHAR( On, 25, PR+PW+EV ); - HAPCHAR( OzoneDensity, C3, PR+EV ); - HAPCHAR( PM10Density, C7, PR+EV ); - HAPCHAR( PositionState, 72, PR+EV ); - HAPCHAR( ProgramMode, D1, PR+EV ); - HAPCHAR( ProgrammableSwitchEvent, 73, PR+EV+NV ); // NV = flag to indicate that HomeSpan should always return a null value, as required by HAP for this Characteristic - HAPCHAR( RelativeHumidityDehumidifierThreshold, C9, PR+PW+EV ); - HAPCHAR( RelativeHumidityHumidifierThreshold, CA, PR+PW+EV ); - HAPCHAR( RemainingDuration, D4, PR+EV ); - HAPCHAR( ResetFilterIndication, AD, PW ); - HAPCHAR( RotationDirection, 28, PR+PW+EV ); - HAPCHAR( RotationSpeed, 29, PR+PW+EV ); - HAPCHAR( Saturation , 2F, PR+PW+EV ); - HAPCHAR( SecuritySystemAlarmType , 8E, PR+EV ); - HAPCHAR( SecuritySystemCurrentState , 66, PR+EV ); - HAPCHAR( SecuritySystemTargetState , 67, PW+PR+EV ); - HAPCHAR( SerialNumber, 30, PR ); - HAPCHAR( ServiceLabelIndex, CB, PR ); - HAPCHAR( ServiceLabelNamespace, CD, PR ); - HAPCHAR( SlatType, C0, PR ); - HAPCHAR( SmokeDetected, 76, PR+EV ); - HAPCHAR( StatusActive, 75, PR+EV ); - HAPCHAR( StatusFault, 77, PR+EV ); - HAPCHAR( StatusJammed, 78, PR+EV ); - HAPCHAR( StatusLowBattery, 79, PR+EV ); - HAPCHAR( StatusTampered, 7A, PR+EV ); - HAPCHAR( SulphurDioxideDensity, C5, PR+EV ); - HAPCHAR( SwingMode, B6, PR+EV+PW ); - HAPCHAR( TargetAirPurifierState, A8, PW+PR+EV ); - HAPCHAR( TargetFanState, BF, PW+PR+EV ); - HAPCHAR( TargetTiltAngle, C2, PW+PR+EV ); - HAPCHAR( TargetHeaterCoolerState, B2, PW+PR+EV ); - HAPCHAR( SetDuration, D3, PW+PR+EV ); - HAPCHAR( TargetHorizontalTiltAngle, 7B, PW+PR+EV ); - HAPCHAR( TargetHumidifierDehumidifierState, B4, PW+PR+EV ); - HAPCHAR( TargetPosition, 7C, PW+PR+EV ); - HAPCHAR( TargetDoorState, 32, PW+PR+EV ); - HAPCHAR( TargetHeatingCoolingState, 33, PW+PR+EV ); - HAPCHAR( TargetRelativeHumidity, 34, PW+PR+EV ); - HAPCHAR( TargetTemperature, 35, PW+PR+EV ); - HAPCHAR( TemperatureDisplayUnits, 36, PW+PR+EV ); - HAPCHAR( TargetVerticalTiltAngle, 7D, PW+PR+EV ); - HAPCHAR( ValveType, D5, PR+EV ); - HAPCHAR( Version, 37, PR ); - HAPCHAR( VOCDensity, C8, PR+EV ); - HAPCHAR( Volume, 119, PW+PR+EV ); - HAPCHAR( WaterLevel, B5, PR+EV ); - -}; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 4e01328..cdab560 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -39,6 +39,7 @@ using namespace Utils; HAPClient **hap; // HAP Client structure containing HTTP client connections, parsing routines, and state variables (global-scoped variable) Span homeSpan; // HAP Attributes database and all related control functions for this Accessory (global-scoped variable) +HapCharacteristics hapChars; // Instantiation of all HAP Characteristics (used to create SpanCharacteristics) /////////////////////////////// // Span // @@ -1203,10 +1204,10 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){ for(int i=0;iperms&SpanCharacteristic::PR){ // if permissions allow reading + if(Characteristics[i]->perms&PERMS::PR){ // if permissions allow reading status[i]=StatusCode::OK; // always set status to OK (since no actual reading of device is needed) } else { Characteristics[i]=NULL; @@ -1440,10 +1441,10 @@ void SpanService::validate(){ for(int i=0;iid,Characteristics[j]->type); + valid=!strcmp(req[i]->type,Characteristics[j]->type); if(!valid){ - homeSpan.configLog+=" !Characteristic " + String(req[i]->name); + homeSpan.configLog+=" !Characteristic " + String(req[i]->hapName); homeSpan.configLog+=" *** ERROR! Required Characteristic for this Service not found. ***\n"; homeSpan.nFatalErrors++; } @@ -1454,10 +1455,11 @@ void SpanService::validate(){ // SpanCharacteristic // /////////////////////////////// -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, const char *hapName){ - this->type=type; - this->perms=perms; - this->hapName=hapName; +SpanCharacteristic::SpanCharacteristic(HapChar *hapChar){ + type=hapChar->type; + perms=hapChar->perms; + hapName=hapChar->hapName; + format=hapChar->format; homeSpan.configLog+="---->Characteristic " + String(hapName); @@ -1478,10 +1480,10 @@ SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, const ch boolean valid=false; for(int i=0; !valid && iServices.back()->req.size(); i++) - valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->id); + valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type); for(int i=0; !valid && iServices.back()->opt.size(); i++) - valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->opt[i]->id); + valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->opt[i]->type); if(!valid){ homeSpan.configLog+=" *** ERROR! Service does not support this Characteristic. ***"; @@ -1500,64 +1502,7 @@ SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, const ch homeSpan.Accessories.back()->Services.back()->Characteristics.push_back(this); - homeSpan.configLog+="\n"; - -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, boolean value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=BOOL; - this->value.BOOL=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, int32_t value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=INT; - this->value.INT=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, uint8_t value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=UINT8; - this->value.UINT8=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, uint16_t value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=UINT16; - this->value.UINT16=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, uint32_t value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=UINT32; - this->value.UINT32=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, uint64_t value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=UINT64; - this->value.UINT64=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, double value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=FLOAT; - this->value.FLOAT=value; -} - -/////////////////////////////// - -SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, const char* value, const char *hapName) : SpanCharacteristic(type, perms, hapName) { - this->format=STRING; - this->value.STRING=value; + homeSpan.configLog+="\n"; } /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 7e23842..fefbfb9 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -39,6 +39,7 @@ #include "Network.h" #include "HAPConstants.h" #include "HapQR.h" +#include "Characteristics.h" using std::vector; using std::unordered_map; @@ -54,17 +55,6 @@ enum { GET_ALL=255 }; -enum FORMAT { // HAP Table 6-5 - BOOL, - UINT8, - UINT16, - UINT32, - UINT64, - INT, - FLOAT, - STRING -}; - union UVal { boolean BOOL; uint8_t UINT8; @@ -222,8 +212,6 @@ struct Span{ vector PushButtons; // vector of pointer to all PushButtons unordered_map TimedWrites; // map of timed-write PIDs and Alarm Times (based on TTLs) - HapCharList chr; // list of all HAP Characteristics - void begin(Category catID=DEFAULT_CATEGORY, const char *displayName=DEFAULT_DISPLAY_NAME, const char *hostNameBase=DEFAULT_HOST_NAME, @@ -289,8 +277,8 @@ struct SpanService{ boolean hidden=false; // optional property indicating service is hidden boolean primary=false; // optional property indicating service is primary vector Characteristics; // vector of pointers to all Characteristics in this Service - vector req; // vector of pointers to all required HAP Characteristic Types for this Service - vector opt; // vector of pointers to all optional HAP Characteristic Types for this Service + vector req; // vector of pointers to all required HAP Characteristic Types for this Service + vector opt; // vector of pointers to all optional HAP Characteristic Types for this Service vector linkedServices; // vector of pointers to any optional linked Services SpanService(const char *type, const char *hapName); @@ -311,17 +299,6 @@ struct SpanService{ struct SpanCharacteristic{ - enum { // create bitflags based on HAP Table 6-4 - PR=1, - PW=2, - EV=4, - AA=8, - TW=16, - HD=32, - WR=64, - NV=128 - }; - int iid=0; // Instance ID (HAP Table 6-3) const char *type; // Characteristic Type const char *hapName; // HAP Name @@ -338,15 +315,11 @@ struct SpanCharacteristic{ UVal newValue; // the updated value requested by PUT /characteristic SpanService *service=NULL; // pointer to Service containing this Characteristic - SpanCharacteristic(const char *type, uint8_t perms, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, boolean value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, uint8_t value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, uint16_t value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, uint32_t value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, uint64_t value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, int32_t value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, double value, const char *hapName); - SpanCharacteristic(const char *type, uint8_t perms, const char* value, const char *hapName); + SpanCharacteristic(HapChar *hapChar); // contructor + + template void init(T val){ + value.set(format,val); + } int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intiial HAP status code (checks to see if characteristic is found, is writable, etc.) diff --git a/src/Services.h b/src/Services.h index 8b19cc0..f28516e 100644 --- a/src/Services.h +++ b/src/Services.h @@ -24,15 +24,15 @@ * SOFTWARE. * ********************************************************************************/ - + /////////////////////////////////// // SPAN SERVICES (HAP Chapter 8) // /////////////////////////////////// // Macros to define vectors of required and optional characteristics for each Span Service structure -#define REQ(name) req.push_back(&homeSpan.chr.name) -#define OPT(name) opt.push_back(&homeSpan.chr.name) +#define REQ(HAPCHAR) req.push_back(&hapChars.HAPCHAR) +#define OPT(HAPCHAR) opt.push_back(&hapChars.HAPCHAR) namespace Service { @@ -381,109 +381,116 @@ namespace Service { // SPAN CHARACTERISTICS (HAP Chapter 9) // ////////////////////////////////////////// -// Macro to define Span Characteristic structures based on name of HAP Characteristic (see HAPConstants.h), its type (e.g. int, double) and its default value +// Macro to define Span Characteristic structures based on name of HAP Characteristic, default value, and mix/max value (not applicable for STRING) -#define CREATE_CHAR(CHR,TYPE,DEFVAL) struct CHR : SpanCharacteristic { CHR(TYPE value=DEFVAL) : SpanCharacteristic{homeSpan.chr.CHR.id, homeSpan.chr.CHR.perms,(TYPE)value, homeSpan.chr.CHR.name}{} } +#define CREATE_CHAR_FLOAT(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(double val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_INT(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(int val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_UINT8(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint8_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_UINT16(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint16_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_UINT32(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint32_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_UINT64(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint64_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_BOOL(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(boolean val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_STRING(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(const char *val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { value.STRING=val; } }; namespace Characteristic { - - CREATE_CHAR(Active,uint8_t,0); - CREATE_CHAR(AirQuality,uint8_t,0); - CREATE_CHAR(BatteryLevel,uint8_t,0); - CREATE_CHAR(Brightness,int,0); - CREATE_CHAR(CarbonMonoxideLevel,double,0); - CREATE_CHAR(CarbonMonoxidePeakLevel,double,0); - CREATE_CHAR(CarbonMonoxideDetected,uint8_t,0); - CREATE_CHAR(CarbonDioxideLevel,double,0); - CREATE_CHAR(CarbonDioxidePeakLevel,double,0); - CREATE_CHAR(CarbonDioxideDetected,uint8_t,0); - CREATE_CHAR(ChargingState,uint8_t,0); - CREATE_CHAR(CoolingThresholdTemperature,double,10); - CREATE_CHAR(ColorTemperature,uint32_t,200); - CREATE_CHAR(ContactSensorState,uint8_t,1); - CREATE_CHAR(CurrentAmbientLightLevel,double,1); - CREATE_CHAR(CurrentHorizontalTiltAngle,int,0); - CREATE_CHAR(CurrentAirPurifierState,uint8_t,1); - CREATE_CHAR(CurrentSlatState,uint8_t,0); - CREATE_CHAR(CurrentPosition,uint8_t,0); - CREATE_CHAR(CurrentVerticalTiltAngle,int,0); - CREATE_CHAR(CurrentHumidifierDehumidifierState,uint8_t,1); - CREATE_CHAR(CurrentDoorState,uint8_t,1); - CREATE_CHAR(CurrentFanState,uint8_t,1); - CREATE_CHAR(CurrentHeatingCoolingState,uint8_t,0); - CREATE_CHAR(CurrentHeaterCoolerState,uint8_t,1); - CREATE_CHAR(CurrentRelativeHumidity,double,0); - CREATE_CHAR(CurrentTemperature,double,0); - CREATE_CHAR(CurrentTiltAngle,int,0); - CREATE_CHAR(FilterLifeLevel,double,0); - CREATE_CHAR(FilterChangeIndication,uint8_t,0); - CREATE_CHAR(FirmwareRevision,const char *,"1.0.0"); - CREATE_CHAR(HardwareRevision,const char *,"1.0.0"); - CREATE_CHAR(HeatingThresholdTemperature,double,16); - CREATE_CHAR(HoldPosition,boolean,false); - CREATE_CHAR(Hue,double,0); - CREATE_CHAR(Identify,boolean,false); - CREATE_CHAR(InUse,uint8_t,0); - CREATE_CHAR(IsConfigured,uint8_t,0); - CREATE_CHAR(LeakDetected,uint8_t,0); - CREATE_CHAR(LockCurrentState,uint8_t,0); - CREATE_CHAR(LockPhysicalControls,uint8_t,0); - CREATE_CHAR(LockTargetState,uint8_t,0); - CREATE_CHAR(Manufacturer,const char *,"HomeSpan"); - CREATE_CHAR(Model,const char *,"HomeSpan-ESP32"); - CREATE_CHAR(MotionDetected,boolean,false); - CREATE_CHAR(Mute,boolean,false); - CREATE_CHAR(Name,const char *,"unnamed"); - CREATE_CHAR(NitrogenDioxideDensity,double,0); - CREATE_CHAR(ObstructionDetected,boolean,false); - CREATE_CHAR(PM25Density,double,0); - CREATE_CHAR(OccupancyDetected,uint8_t,0); - CREATE_CHAR(OutletInUse,boolean,false); - CREATE_CHAR(On,boolean,false); - CREATE_CHAR(OzoneDensity,double,0); - CREATE_CHAR(PM10Density,double,0); - CREATE_CHAR(PositionState,uint8_t,2); - CREATE_CHAR(ProgramMode,uint8_t,0); - CREATE_CHAR(ProgrammableSwitchEvent,uint8_t,0); - CREATE_CHAR(RelativeHumidityDehumidifierThreshold,double,50); - CREATE_CHAR(RelativeHumidityHumidifierThreshold,double,50); - CREATE_CHAR(RemainingDuration,uint32_t,60); - CREATE_CHAR(ResetFilterIndication,uint8_t,0); - CREATE_CHAR(RotationDirection,int,0); - CREATE_CHAR(RotationSpeed,double,0); - CREATE_CHAR(Saturation,double,0); - CREATE_CHAR(SecuritySystemAlarmType,uint8_t,0); - CREATE_CHAR(SecuritySystemCurrentState,uint8_t,3); - CREATE_CHAR(SecuritySystemTargetState,uint8_t,3); - CREATE_CHAR(SerialNumber,const char *,"HS-12345"); - CREATE_CHAR(ServiceLabelIndex,uint8_t,1); - CREATE_CHAR(ServiceLabelNamespace,uint8_t,1); - CREATE_CHAR(SlatType,uint8_t,0); - CREATE_CHAR(SmokeDetected,uint8_t,0); - CREATE_CHAR(StatusActive,boolean,true); - CREATE_CHAR(StatusFault,uint8_t,0); - CREATE_CHAR(StatusJammed,uint8_t,0); - CREATE_CHAR(StatusLowBattery,uint8_t,0); - CREATE_CHAR(StatusTampered,uint8_t,0); - CREATE_CHAR(SulphurDioxideDensity,double,0); - CREATE_CHAR(SwingMode,uint8_t,0); - CREATE_CHAR(TargetAirPurifierState,uint8_t,1); - CREATE_CHAR(TargetFanState,uint8_t,1); - CREATE_CHAR(TargetTiltAngle,int,0); - CREATE_CHAR(SetDuration,uint32_t,60); - CREATE_CHAR(TargetHorizontalTiltAngle,int,0); - CREATE_CHAR(TargetHumidifierDehumidifierState,uint8_t,0); - CREATE_CHAR(TargetPosition,uint8_t,0); - CREATE_CHAR(TargetDoorState,uint8_t,1); - CREATE_CHAR(TargetHeatingCoolingState,uint8_t,0); - CREATE_CHAR(TargetRelativeHumidity,double,0); - CREATE_CHAR(TargetTemperature,double,16); - CREATE_CHAR(TemperatureDisplayUnits,uint8_t,0); - CREATE_CHAR(TargetVerticalTiltAngle,int,0); - CREATE_CHAR(ValveType,uint8_t,0); - CREATE_CHAR(Version,const char *,"1.0.0"); - CREATE_CHAR(VOCDensity,double,0); - CREATE_CHAR(Volume,uint8_t,0); - CREATE_CHAR(WaterLevel,double,0); + CREATE_CHAR_UINT8(Active,0); + CREATE_CHAR_UINT8(AirQuality,0); + CREATE_CHAR_UINT8(BatteryLevel,0); + CREATE_CHAR_INT(Brightness,0); + CREATE_CHAR_FLOAT(CarbonMonoxideLevel,0); + CREATE_CHAR_FLOAT(CarbonMonoxidePeakLevel,0); + CREATE_CHAR_UINT8(CarbonMonoxideDetected,0); + CREATE_CHAR_FLOAT(CarbonDioxideLevel,0); + CREATE_CHAR_FLOAT(CarbonDioxidePeakLevel,0); + CREATE_CHAR_UINT8(CarbonDioxideDetected,0); + CREATE_CHAR_UINT8(ChargingState,0); + CREATE_CHAR_FLOAT(CoolingThresholdTemperature,10); + CREATE_CHAR_UINT32(ColorTemperature,200); + CREATE_CHAR_UINT8(ContactSensorState,1); + CREATE_CHAR_FLOAT(CurrentAmbientLightLevel,1); + CREATE_CHAR_INT(CurrentHorizontalTiltAngle,0); + CREATE_CHAR_UINT8(CurrentAirPurifierState,1); + CREATE_CHAR_UINT8(CurrentSlatState,0); + CREATE_CHAR_UINT8(CurrentPosition,0); + CREATE_CHAR_INT(CurrentVerticalTiltAngle,0); + CREATE_CHAR_UINT8(CurrentHumidifierDehumidifierState,1); + CREATE_CHAR_UINT8(CurrentDoorState,1); + CREATE_CHAR_UINT8(CurrentFanState,1); + CREATE_CHAR_UINT8(CurrentHeatingCoolingState,0); + CREATE_CHAR_UINT8(CurrentHeaterCoolerState,1); + CREATE_CHAR_FLOAT(CurrentRelativeHumidity,0); + CREATE_CHAR_FLOAT(CurrentTemperature,0); + CREATE_CHAR_INT(CurrentTiltAngle,0); + CREATE_CHAR_FLOAT(FilterLifeLevel,0); + CREATE_CHAR_UINT8(FilterChangeIndication,0); + CREATE_CHAR_STRING(FirmwareRevision,"1.0.0"); + CREATE_CHAR_STRING(HardwareRevision,"1.0.0"); + CREATE_CHAR_FLOAT(HeatingThresholdTemperature,16); + CREATE_CHAR_BOOL(HoldPosition,false); + CREATE_CHAR_FLOAT(Hue,0); + CREATE_CHAR_BOOL(Identify,false); + CREATE_CHAR_UINT8(InUse,0); + CREATE_CHAR_UINT8(IsConfigured,0); + CREATE_CHAR_UINT8(LeakDetected,0); + CREATE_CHAR_UINT8(LockCurrentState,0); + CREATE_CHAR_UINT8(LockPhysicalControls,0); + CREATE_CHAR_UINT8(LockTargetState,0); + CREATE_CHAR_STRING(Manufacturer,"HomeSpan"); + CREATE_CHAR_STRING(Model,"HomeSpan-ESP32"); + CREATE_CHAR_BOOL(MotionDetected,false); + CREATE_CHAR_BOOL(Mute,false); + CREATE_CHAR_STRING(Name,"unnamed"); + CREATE_CHAR_FLOAT(NitrogenDioxideDensity,0); + CREATE_CHAR_BOOL(ObstructionDetected,false); + CREATE_CHAR_FLOAT(PM25Density,0); + CREATE_CHAR_UINT8(OccupancyDetected,0); + CREATE_CHAR_BOOL(OutletInUse,false); + CREATE_CHAR_BOOL(On,false); + CREATE_CHAR_FLOAT(OzoneDensity,0); + CREATE_CHAR_FLOAT(PM10Density,0); + CREATE_CHAR_UINT8(PositionState,2); + CREATE_CHAR_UINT8(ProgramMode,0); + CREATE_CHAR_UINT8(ProgrammableSwitchEvent,0); + CREATE_CHAR_FLOAT(RelativeHumidityDehumidifierThreshold,50); + CREATE_CHAR_FLOAT(RelativeHumidityHumidifierThreshold,50); + CREATE_CHAR_UINT32(RemainingDuration,60); + CREATE_CHAR_UINT8(ResetFilterIndication,0); + CREATE_CHAR_INT(RotationDirection,0); + CREATE_CHAR_FLOAT(RotationSpeed,0); + CREATE_CHAR_FLOAT(Saturation,0); + CREATE_CHAR_UINT8(SecuritySystemAlarmType,0); + CREATE_CHAR_UINT8(SecuritySystemCurrentState,3); + CREATE_CHAR_UINT8(SecuritySystemTargetState,3); + CREATE_CHAR_STRING(SerialNumber,"HS-12345"); + CREATE_CHAR_UINT8(ServiceLabelIndex,1); + CREATE_CHAR_UINT8(ServiceLabelNamespace,1); + CREATE_CHAR_UINT8(SlatType,0); + CREATE_CHAR_UINT8(SmokeDetected,0); + CREATE_CHAR_BOOL(StatusActive,true); + CREATE_CHAR_UINT8(StatusFault,0); + CREATE_CHAR_UINT8(StatusJammed,0); + CREATE_CHAR_UINT8(StatusLowBattery,0); + CREATE_CHAR_UINT8(StatusTampered,0); + CREATE_CHAR_FLOAT(SulphurDioxideDensity,0); + CREATE_CHAR_UINT8(SwingMode,0); + CREATE_CHAR_UINT8(TargetAirPurifierState,1); + CREATE_CHAR_UINT8(TargetFanState,1); + CREATE_CHAR_INT(TargetTiltAngle,0); + CREATE_CHAR_UINT32(SetDuration,60); + CREATE_CHAR_INT(TargetHorizontalTiltAngle,0); + CREATE_CHAR_UINT8(TargetHumidifierDehumidifierState,0); + CREATE_CHAR_UINT8(TargetPosition,0); + CREATE_CHAR_UINT8(TargetDoorState,1); + CREATE_CHAR_UINT8(TargetHeatingCoolingState,0); + CREATE_CHAR_FLOAT(TargetRelativeHumidity,0); + CREATE_CHAR_FLOAT(TargetTemperature,16); + CREATE_CHAR_UINT8(TemperatureDisplayUnits,0); + CREATE_CHAR_INT(TargetVerticalTiltAngle,0); + CREATE_CHAR_UINT8(ValveType,0); + CREATE_CHAR_STRING(Version,"1.0.0"); + CREATE_CHAR_FLOAT(VOCDensity,0); + CREATE_CHAR_UINT8(Volume,0); + CREATE_CHAR_FLOAT(WaterLevel,0); + } From c8a2770253d6af17052c1796e0f7045ec45dfb1b Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 28 Feb 2021 17:48:34 -0600 Subject: [PATCH 10/32] Renamed Services.h to Span.h Also, made it possible to use UVAL.set() for STRING Characteristic (upon initialization) but setVal() is NOT allowed. --- src/HomeSpan.h | 15 ++++++++++++--- src/{Services.h => Span.h} | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) rename src/{Services.h => Span.h} (99%) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index fefbfb9..00c559e 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -65,6 +65,10 @@ union UVal { double FLOAT; const char *STRING; + void set(FORMAT fmt, const char *val){ + STRING=val; + }; + template void set(FORMAT fmt, T val){ switch(fmt){ @@ -98,7 +102,7 @@ union UVal { break; } } // set() - + template T get(FORMAT fmt){ switch(fmt){ @@ -125,7 +129,7 @@ union UVal { return((T) FLOAT); case FORMAT::STRING: - Serial.print("*** ERROR: Can't use getVal() or getNewVal() for string Characteristics.\n\n"); + Serial.print("\n*** WARNING: Can't use getVal() or getNewVal() with string Characteristics.\n\n"); return(0); } @@ -331,6 +335,11 @@ struct SpanCharacteristic{ template T getNewVal(){return(newValue.get(format));} // returns UVal newValue template void setVal(T val){ + + if(format==STRING){ + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s(\"%s\") with setVal() ignored. Can't update string characteristics once they are initialized!\n\n",hapName,value.STRING); + return; + } value.set(format, val); newValue.set(format, val); @@ -382,4 +391,4 @@ struct SpanButton{ ///////////////////////////////////////////////// -#include "Services.h" +#include "Span.h" diff --git a/src/Services.h b/src/Span.h similarity index 99% rename from src/Services.h rename to src/Span.h index f28516e..563babd 100644 --- a/src/Services.h +++ b/src/Span.h @@ -390,7 +390,7 @@ namespace Service { #define CREATE_CHAR_UINT32(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint32_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; #define CREATE_CHAR_UINT64(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint64_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; #define CREATE_CHAR_BOOL(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(boolean val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_STRING(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(const char *val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { value.STRING=val; } }; +#define CREATE_CHAR_STRING(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(const char *val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; namespace Characteristic { From 5ca0bdc907651f629f7455b804a795319eb6d68b Mon Sep 17 00:00:00 2001 From: Gregg Date: Mon, 1 Mar 2021 09:09:24 -0600 Subject: [PATCH 11/32] Added error checks to setVal() Warning will be thrown if setVal() request is outside of mix/max range for the Characteristic, though min/max range not yet modified by SpanRange(). TO DO: Create new Characteristic methods setRange(typename T_MIN, typename T_MAX) and setRange(typename T_MIN, typename T_MAX, typename T_STEP) that will reset min/max, or min/max/step, and trigger required output in database. Add in checks to ensure setRange is NOT used to STRING or BOOLEAN. Also add check to ensure STEP is always>0. Add new UVAL for STEP that is normally zero, which indicates NO step size has been set (and does not need to be reported to database). Then, set warnings about SpanRange being deprecated at some point in the future. --- src/HomeSpan.h | 15 ++++++++++++--- src/Span.h | 50 +++++++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 00c559e..5fe7ae8 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -310,6 +310,8 @@ struct SpanCharacteristic{ uint8_t perms; // Characteristic Permissions FORMAT format; // Characteristic Format char *desc=NULL; // Characteristic Description (optional) + UVal minValue; // Characteristic minimum (not applicable for STRING) + UVal maxValue; // Characteristic maximum (not applicable for STRING) SpanRange *range=NULL; // Characteristic min/max/step; NULL = default values (optional) boolean *ev; // Characteristic Event Notify Enable (per-connection) @@ -321,8 +323,10 @@ struct SpanCharacteristic{ SpanCharacteristic(HapChar *hapChar); // contructor - template void init(T val){ + template void init(T val, A min=0, B max=1){ value.set(format,val); + minValue.set(format,min); + maxValue.set(format,max); } int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator @@ -337,10 +341,15 @@ struct SpanCharacteristic{ template void setVal(T val){ if(format==STRING){ - Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s(\"%s\") with setVal() ignored. Can't update string characteristics once they are initialized!\n\n",hapName,value.STRING); + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s(\"%s\") with setVal() ignored. Can't update string Characteristics once they are initialized!\n\n",hapName,value.STRING); return; } - + + if(val(format) || val>maxValue.get(format)){ + 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", + hapName,(double)val,minValue.get(format),maxValue.get(format)); + } + value.set(format, val); newValue.set(format, val); diff --git a/src/Span.h b/src/Span.h index 563babd..7e95597 100644 --- a/src/Span.h +++ b/src/Span.h @@ -383,7 +383,7 @@ namespace Service { // Macro to define Span Characteristic structures based on name of HAP Characteristic, default value, and mix/max value (not applicable for STRING) -#define CREATE_CHAR_FLOAT(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(double val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR_FLOAT(HAPCHAR,DEFVAL,MINVAL,MAXVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(double val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val,(double)MINVAL,(double)MAXVAL); } }; #define CREATE_CHAR_INT(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(int val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; #define CREATE_CHAR_UINT8(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint8_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; #define CREATE_CHAR_UINT16(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint16_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; @@ -398,17 +398,17 @@ namespace Characteristic { CREATE_CHAR_UINT8(AirQuality,0); CREATE_CHAR_UINT8(BatteryLevel,0); CREATE_CHAR_INT(Brightness,0); - CREATE_CHAR_FLOAT(CarbonMonoxideLevel,0); - CREATE_CHAR_FLOAT(CarbonMonoxidePeakLevel,0); + CREATE_CHAR_FLOAT(CarbonMonoxideLevel,0,0,100); + CREATE_CHAR_FLOAT(CarbonMonoxidePeakLevel,0,0,100); CREATE_CHAR_UINT8(CarbonMonoxideDetected,0); - CREATE_CHAR_FLOAT(CarbonDioxideLevel,0); - CREATE_CHAR_FLOAT(CarbonDioxidePeakLevel,0); + CREATE_CHAR_FLOAT(CarbonDioxideLevel,0,0,100000); + CREATE_CHAR_FLOAT(CarbonDioxidePeakLevel,0,0,100000); CREATE_CHAR_UINT8(CarbonDioxideDetected,0); CREATE_CHAR_UINT8(ChargingState,0); - CREATE_CHAR_FLOAT(CoolingThresholdTemperature,10); + CREATE_CHAR_FLOAT(CoolingThresholdTemperature,10,10,35); CREATE_CHAR_UINT32(ColorTemperature,200); CREATE_CHAR_UINT8(ContactSensorState,1); - CREATE_CHAR_FLOAT(CurrentAmbientLightLevel,1); + CREATE_CHAR_FLOAT(CurrentAmbientLightLevel,1,0.0001,100000); CREATE_CHAR_INT(CurrentHorizontalTiltAngle,0); CREATE_CHAR_UINT8(CurrentAirPurifierState,1); CREATE_CHAR_UINT8(CurrentSlatState,0); @@ -419,16 +419,16 @@ namespace Characteristic { CREATE_CHAR_UINT8(CurrentFanState,1); CREATE_CHAR_UINT8(CurrentHeatingCoolingState,0); CREATE_CHAR_UINT8(CurrentHeaterCoolerState,1); - CREATE_CHAR_FLOAT(CurrentRelativeHumidity,0); - CREATE_CHAR_FLOAT(CurrentTemperature,0); + CREATE_CHAR_FLOAT(CurrentRelativeHumidity,0,0,100); + CREATE_CHAR_FLOAT(CurrentTemperature,0,0,100); CREATE_CHAR_INT(CurrentTiltAngle,0); - CREATE_CHAR_FLOAT(FilterLifeLevel,0); + CREATE_CHAR_FLOAT(FilterLifeLevel,0,0,100); CREATE_CHAR_UINT8(FilterChangeIndication,0); CREATE_CHAR_STRING(FirmwareRevision,"1.0.0"); CREATE_CHAR_STRING(HardwareRevision,"1.0.0"); - CREATE_CHAR_FLOAT(HeatingThresholdTemperature,16); + CREATE_CHAR_FLOAT(HeatingThresholdTemperature,16,0,25); CREATE_CHAR_BOOL(HoldPosition,false); - CREATE_CHAR_FLOAT(Hue,0); + CREATE_CHAR_FLOAT(Hue,0,0,360); CREATE_CHAR_BOOL(Identify,false); CREATE_CHAR_UINT8(InUse,0); CREATE_CHAR_UINT8(IsConfigured,0); @@ -441,24 +441,24 @@ namespace Characteristic { CREATE_CHAR_BOOL(MotionDetected,false); CREATE_CHAR_BOOL(Mute,false); CREATE_CHAR_STRING(Name,"unnamed"); - CREATE_CHAR_FLOAT(NitrogenDioxideDensity,0); + CREATE_CHAR_FLOAT(NitrogenDioxideDensity,0,0,1000); CREATE_CHAR_BOOL(ObstructionDetected,false); - CREATE_CHAR_FLOAT(PM25Density,0); + CREATE_CHAR_FLOAT(PM25Density,0,0,1000); CREATE_CHAR_UINT8(OccupancyDetected,0); CREATE_CHAR_BOOL(OutletInUse,false); CREATE_CHAR_BOOL(On,false); - CREATE_CHAR_FLOAT(OzoneDensity,0); - CREATE_CHAR_FLOAT(PM10Density,0); + CREATE_CHAR_FLOAT(OzoneDensity,0,0,1000); + CREATE_CHAR_FLOAT(PM10Density,0,0,1000); CREATE_CHAR_UINT8(PositionState,2); CREATE_CHAR_UINT8(ProgramMode,0); CREATE_CHAR_UINT8(ProgrammableSwitchEvent,0); - CREATE_CHAR_FLOAT(RelativeHumidityDehumidifierThreshold,50); - CREATE_CHAR_FLOAT(RelativeHumidityHumidifierThreshold,50); + CREATE_CHAR_FLOAT(RelativeHumidityDehumidifierThreshold,50,0,100); + CREATE_CHAR_FLOAT(RelativeHumidityHumidifierThreshold,50,0,100); CREATE_CHAR_UINT32(RemainingDuration,60); CREATE_CHAR_UINT8(ResetFilterIndication,0); CREATE_CHAR_INT(RotationDirection,0); - CREATE_CHAR_FLOAT(RotationSpeed,0); - CREATE_CHAR_FLOAT(Saturation,0); + CREATE_CHAR_FLOAT(RotationSpeed,0,0,100); + CREATE_CHAR_FLOAT(Saturation,0,0,100); CREATE_CHAR_UINT8(SecuritySystemAlarmType,0); CREATE_CHAR_UINT8(SecuritySystemCurrentState,3); CREATE_CHAR_UINT8(SecuritySystemTargetState,3); @@ -472,7 +472,7 @@ namespace Characteristic { CREATE_CHAR_UINT8(StatusJammed,0); CREATE_CHAR_UINT8(StatusLowBattery,0); CREATE_CHAR_UINT8(StatusTampered,0); - CREATE_CHAR_FLOAT(SulphurDioxideDensity,0); + CREATE_CHAR_FLOAT(SulphurDioxideDensity,0,0,1000); CREATE_CHAR_UINT8(SwingMode,0); CREATE_CHAR_UINT8(TargetAirPurifierState,1); CREATE_CHAR_UINT8(TargetFanState,1); @@ -483,14 +483,14 @@ namespace Characteristic { CREATE_CHAR_UINT8(TargetPosition,0); CREATE_CHAR_UINT8(TargetDoorState,1); CREATE_CHAR_UINT8(TargetHeatingCoolingState,0); - CREATE_CHAR_FLOAT(TargetRelativeHumidity,0); - CREATE_CHAR_FLOAT(TargetTemperature,16); + CREATE_CHAR_FLOAT(TargetRelativeHumidity,0,0,100); + CREATE_CHAR_FLOAT(TargetTemperature,16,10,38); CREATE_CHAR_UINT8(TemperatureDisplayUnits,0); CREATE_CHAR_INT(TargetVerticalTiltAngle,0); CREATE_CHAR_UINT8(ValveType,0); CREATE_CHAR_STRING(Version,"1.0.0"); - CREATE_CHAR_FLOAT(VOCDensity,0); + CREATE_CHAR_FLOAT(VOCDensity,0,0,1000); CREATE_CHAR_UINT8(Volume,0); - CREATE_CHAR_FLOAT(WaterLevel,0); + CREATE_CHAR_FLOAT(WaterLevel,0,0,100); } From 5c5361be7b2cb5e4b33f1a0a12cfeb0e40f3f8de Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 3 Mar 2021 19:53:13 -0600 Subject: [PATCH 12/32] Moved UVal back into SpanCharacteristics --- examples/12-ServiceLoops/DEV_Sensors.h | 3 +- src/Characteristics.h | 16 +- src/HomeSpan.cpp | 7 + src/HomeSpan.h | 221 ++++++++++++++----------- 4 files changed, 139 insertions(+), 108 deletions(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index f7f012c..b172eb6 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -16,7 +16,8 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera // of Celsius or Fahrenheit for each Service, it does not appear to work as advertised. temp=new Characteristic::CurrentTemperature(30.0); // instantiate the Current Temperature Characteristic - new SpanRange(-50,100,1); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures + //new SpanRange(-50,100,1); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures + temp->setRange(-50,100,5.5); Serial.print("Configuring Temperature Sensor"); // initialization message Serial.print("\n"); diff --git a/src/Characteristics.h b/src/Characteristics.h index 38625fb..a05a1c6 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -41,14 +41,14 @@ enum PERMS{ // create bitflags based on HAP Table 6-4 }; enum FORMAT { // HAP Table 6-5 - BOOL, - UINT8, - UINT16, - UINT32, - UINT64, - INT, - FLOAT, - STRING + BOOL=0, + UINT8=1, + UINT16=2, + UINT32=3, + UINT64=4, + INT=5, + FLOAT=6, + STRING=7 }; /////////////////////////////// diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index cdab560..6ce917b 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1552,6 +1552,11 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){ case FLOAT: nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%lg",value.FLOAT); + if(customRange && (flags&GET_META)){ + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minValue\":%lg,\"maxValue\":%lg",minValue.FLOAT,maxValue.FLOAT); + if(stepValue.FLOAT>0) + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minStep\":%lg",stepValue.FLOAT); + } break; case STRING: @@ -1562,6 +1567,8 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){ } // print Characteristic value } // permissions=PR + + if(flags&GET_META){ nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"format\":\"%s\"",formatCodes[format]); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 5fe7ae8..a050b18 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -55,88 +55,6 @@ enum { GET_ALL=255 }; -union UVal { - boolean BOOL; - uint8_t UINT8; - uint16_t UINT16; - uint32_t UINT32; - uint64_t UINT64; - int32_t INT; - double FLOAT; - const char *STRING; - - void set(FORMAT fmt, const char *val){ - STRING=val; - }; - - template void set(FORMAT fmt, T val){ - - switch(fmt){ - - case FORMAT::BOOL: - BOOL=(boolean)val; - break; - - case FORMAT::INT: - INT=(int)val; - break; - - case FORMAT::UINT8: - UINT8=(uint8_t)val; - break; - - case FORMAT::UINT16: - UINT16=(uint16_t)val; - break; - - case FORMAT::UINT32: - UINT32=(uint32_t)val; - break; - - case FORMAT::UINT64: - UINT64=(uint64_t)val; - break; - - case FORMAT::FLOAT: - FLOAT=(double)val; - break; - } - } // set() - - template T get(FORMAT fmt){ - - switch(fmt){ - - case FORMAT::BOOL: - return((T) BOOL); - - case FORMAT::INT: - return((T) INT); - - case FORMAT::UINT8: - return((T) UINT8); - - case FORMAT::UINT16: - return((T) UINT16); - - case FORMAT::UINT32: - return((T) UINT32); - - case FORMAT::UINT64: - return((T) UINT64); - - case FORMAT::FLOAT: - return((T) FLOAT); - - case FORMAT::STRING: - Serial.print("\n*** WARNING: Can't use getVal() or getNewVal() with string Characteristics.\n\n"); - return(0); - } - - } // get() - -}; - /////////////////////////////// // Forward-Declarations @@ -289,7 +207,7 @@ struct SpanService{ SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self SpanService *setHidden(); // sets the Service Type to be hidden and returns pointer to self - SpanService *addLink(SpanService *svc); // adds svc as a Linked Service + SpanService *addLink(SpanService *svc); // adds svc as a Linked Service and returns pointer to self int sprintfAttributes(char *cBuf); // prints Service JSON records into buf; return number of characters printed, excluding null terminator void validate(); // error-checks Service @@ -303,6 +221,18 @@ struct SpanService{ struct SpanCharacteristic{ + + union UVal { + boolean BOOL; + uint8_t UINT8; + uint16_t UINT16; + uint32_t UINT32; + uint64_t UINT64; + int32_t INT; + double FLOAT; + const char *STRING; + }; + int iid=0; // Instance ID (HAP Table 6-3) const char *type; // Characteristic Type const char *hapName; // HAP Name @@ -312,6 +242,8 @@ struct SpanCharacteristic{ char *desc=NULL; // Characteristic Description (optional) UVal minValue; // Characteristic minimum (not applicable for STRING) UVal maxValue; // Characteristic maximum (not applicable for STRING) + UVal stepValue; // Characteristic step size (not applicable for STRING) + boolean customRange=false; // Flag for custom ranges SpanRange *range=NULL; // Characteristic min/max/step; NULL = default values (optional) boolean *ev; // Characteristic Event Notify Enable (per-connection) @@ -321,22 +253,113 @@ struct SpanCharacteristic{ UVal newValue; // the updated value requested by PUT /characteristic SpanService *service=NULL; // pointer to Service containing this Characteristic - SpanCharacteristic(HapChar *hapChar); // contructor - - template void init(T val, A min=0, B max=1){ - value.set(format,val); - minValue.set(format,min); - maxValue.set(format,max); - } - + SpanCharacteristic(HapChar *hapChar); // contructor + int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator StatusCode loadUpdate(char *val, char *ev); // load updated val/ev from PUT /characteristic JSON request. Return intiial HAP status code (checks to see if characteristic is found, is writable, etc.) - boolean updated(){return(isUpdated);} // returns isUpdated - unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated + boolean updated(){return(isUpdated);} // returns isUpdated + unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated + + String uvPrint(UVal &u){ + char c[64]; + switch(format){ + case FORMAT::BOOL: + return(String(u.BOOL)); + case FORMAT::INT: + return(String(u.INT)); + case FORMAT::UINT8: + return(String(u.UINT8)); + case FORMAT::UINT16: + return(String(u.UINT16)); + case FORMAT::UINT32: + return(String(u.UINT32)); + case FORMAT::UINT64: + sprintf(c,"%llu",u.UINT64); + return(String(c)); + case FORMAT::FLOAT: + sprintf(c,"%llg",u.FLOAT); + return(String(c)); + case FORMAT::STRING: + return(String(u.STRING)); + } // switch + } // str() - template T getVal(){return(value.get(format));} // returns UVal value - template T getNewVal(){return(newValue.get(format));} // returns UVal newValue + void uvSet(UVal &u, const char *val){ + u.STRING=val; + } + + template void uvSet(UVal &u, T val){ + switch(format){ + case FORMAT::BOOL: + u.BOOL=(boolean)val; + break; + case FORMAT::INT: + u.INT=(int)val; + break; + case FORMAT::UINT8: + u.UINT8=(uint8_t)val; + break; + case FORMAT::UINT16: + u.UINT16=(uint16_t)val; + break; + case FORMAT::UINT32: + u.UINT32=(uint32_t)val; + break; + case FORMAT::UINT64: + u.UINT64=(uint64_t)val; + break; + case FORMAT::FLOAT: + u.FLOAT=(double)val; + break; + } // switch + } // set() + + template T uvGet(UVal &u){ + + switch(format){ + case FORMAT::BOOL: + return((T) u.BOOL); + case FORMAT::INT: + return((T) u.INT); + case FORMAT::UINT8: + return((T) u.UINT8); + case FORMAT::UINT16: + return((T) u.UINT16); + case FORMAT::UINT32: + return((T) u.UINT32); + case FORMAT::UINT64: + return((T) u.UINT64); + case FORMAT::FLOAT: + return((T) u.FLOAT); + case FORMAT::STRING: + Serial.print("\n*** WARNING: Can't use getVal() or getNewVal() with string Characteristics.\n\n"); + return(0); + } + } // get() + + template SpanCharacteristic *setRange(A min, B max, S step=0){ + uvSet(minValue,min); + uvSet(maxValue,max); + uvSet(stepValue,step); + customRange=true; + } + + template void init(T val, A min=0, B max=1){ + uvSet(value,val); + uvSet(newValue,val); + uvSet(minValue,min); + uvSet(maxValue,max); + uvSet(stepValue,0); + } + + template T getVal(){ + return(uvGet(value)); + } + + template T getNewVal(){ + return(uvGet(newValue)); + } template void setVal(T val){ @@ -345,13 +368,13 @@ struct SpanCharacteristic{ return; } - if(val(format) || val>maxValue.get(format)){ + 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", - hapName,(double)val,minValue.get(format),maxValue.get(format)); + hapName,(double)val,uvGet(minValue),uvGet(maxValue)); } - value.set(format, val); - newValue.set(format, val); + uvSet(value,val); + uvSet(newValue,val); updateTime=homeSpan.snapTime; From 26a38b68ccaeb98577007c537e89409af9dba104 Mon Sep 17 00:00:00 2001 From: Gregg Date: Thu, 4 Mar 2021 07:18:13 -0600 Subject: [PATCH 13/32] Completed full implementation of setRange() and deprecation of SpanRange() Next TO DO: Complete entry of default min/max into all Characteristics (except BOOL and STRING) defined Span.h so that setRange() error checking works for all Characteristics. --- examples/12-ServiceLoops/DEV_Sensors.h | 7 ++- src/HomeSpan.cpp | 74 +++++--------------------- src/HomeSpan.h | 43 ++++++++++----- 3 files changed, 46 insertions(+), 78 deletions(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index b172eb6..86f0cff 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -16,9 +16,8 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera // of Celsius or Fahrenheit for each Service, it does not appear to work as advertised. temp=new Characteristic::CurrentTemperature(30.0); // instantiate the Current Temperature Characteristic - //new SpanRange(-50,100,1); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures - temp->setRange(-50,100,5.5); - + temp->setRange(-50,100); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures + Serial.print("Configuring Temperature Sensor"); // initialization message Serial.print("\n"); @@ -40,7 +39,7 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera void loop(){ if(temp->timeVal()>5000){ // check time elapsed since last update and proceed only if greater than 5 seconds - float temperature=temp->getVal()+0.5; // "simulate" a half-degree temperature change (it's okay that we set step size in SpanRange to 1)... + float temperature=temp->getVal()+0.5; // "simulate" a half-degree temperature change... if(temperature>35.0) // ...but cap the maximum at 35C before starting over at -30C temperature=-30.0; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 6ce917b..da10762 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1519,61 +1519,22 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){ if(flags&GET_TYPE) nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"type\":\"%s\"",type); - if(perms&PR){ - - if(perms&NV && !(flags&GET_NV)){ + if(perms&PR){ + if(perms&NV && !(flags&GET_NV)) nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":null"); - } else { - - switch(format){ - case BOOL: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%s",value.BOOL?"true":"false"); - break; - - case INT: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%d",value.INT); - break; - - case UINT8: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%u",value.UINT8); - break; - - case UINT16: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%u",value.UINT16); - break; - - case UINT32: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%u",value.UINT32); - break; - - case UINT64: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%llu",value.UINT64); - break; - - case FLOAT: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%lg",value.FLOAT); - if(customRange && (flags&GET_META)){ - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minValue\":%lg,\"maxValue\":%lg",minValue.FLOAT,maxValue.FLOAT); - if(stepValue.FLOAT>0) - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minStep\":%lg",stepValue.FLOAT); - } - break; - - case STRING: - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":\"%s\"",value.STRING); - break; - - } // switch - } // print Characteristic value - } // permissions=PR - - + else + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%s",uvPrint(value).c_str()); + } if(flags&GET_META){ nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"format\":\"%s\"",formatCodes[format]); - if(range && (flags&GET_META)) - nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minValue\":%d,\"maxValue\":%d,\"minStep\":%d",range->min,range->max,range->step); + if(customRange && (flags&GET_META)){ + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minValue\":%s,\"maxValue\":%s",uvPrint(minValue).c_str(),uvPrint(maxValue).c_str()); + + if(uvGet(stepValue)>0) + nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minStep\":%s",uvPrint(stepValue).c_str()); + } } if(desc && (flags&GET_DESC)){ @@ -1699,20 +1660,13 @@ unsigned long SpanCharacteristic::timeVal(){ /////////////////////////////// SpanRange::SpanRange(int min, int max, int step){ - this->min=min; - this->max=max; - this->step=step; - - homeSpan.configLog+="------>SpanRange: " + String(min) + "/" + String(max) + "/" + String(step); if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty() || homeSpan.Accessories.back()->Services.back()->Characteristics.empty() ){ - homeSpan.configLog+=" *** ERROR! Can't create new Range without a defined Characteristic! ***\n"; + homeSpan.configLog+="------>SpanRange: *** ERROR! Can't create new Range without a defined Characteristic! ***\n"; homeSpan.nFatalErrors++; - return; + } else { + homeSpan.Accessories.back()->Services.back()->Characteristics.back()->setRange(min,max,step); } - - homeSpan.configLog+="\n"; - homeSpan.Accessories.back()->Services.back()->Characteristics.back()->range=this; } /////////////////////////////// diff --git a/src/HomeSpan.h b/src/HomeSpan.h index a050b18..f1951c8 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -244,7 +244,6 @@ struct SpanCharacteristic{ UVal maxValue; // Characteristic maximum (not applicable for STRING) UVal stepValue; // Characteristic step size (not applicable for STRING) boolean customRange=false; // Flag for custom ranges - SpanRange *range=NULL; // Characteristic min/max/step; NULL = default values (optional) boolean *ev; // Characteristic Event Notify Enable (per-connection) uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic @@ -281,7 +280,8 @@ struct SpanCharacteristic{ sprintf(c,"%llg",u.FLOAT); return(String(c)); case FORMAT::STRING: - return(String(u.STRING)); + sprintf(c,"\"%s\"",u.STRING); + return(String(c)); } // switch } // str() @@ -339,19 +339,38 @@ struct SpanCharacteristic{ } // get() template SpanCharacteristic *setRange(A min, B max, S step=0){ - uvSet(minValue,min); - uvSet(maxValue,max); - uvSet(stepValue,step); - customRange=true; - } + char c[256]; + homeSpan.configLog+="------>Range: "; + + if(format==BOOL || format==STRING){ + sprintf(c,"*** ERROR! Can't change range for STRING or BOOL Characteristics! ***\n",hapName); + homeSpan.nFatalErrors++; + } else { + + uvSet(minValue,min); + uvSet(maxValue,max); + uvSet(stepValue,step); + customRange=true; + + if(step>0) + sprintf(c,"%s/%s/%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue)); + else + sprintf(c,"%s/%s\n",uvPrint(minValue),uvPrint(maxValue)); + } + homeSpan.configLog+=c; + return(this); + + } // setRange() + template void init(T val, A min=0, B max=1){ uvSet(value,val); uvSet(newValue,val); uvSet(minValue,min); uvSet(maxValue,max); uvSet(stepValue,0); - } + + } // init() template T getVal(){ return(uvGet(value)); @@ -364,7 +383,7 @@ struct SpanCharacteristic{ template void setVal(T val){ if(format==STRING){ - Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s(\"%s\") with setVal() ignored. Can't update string Characteristics once they are initialized!\n\n",hapName,value.STRING); + Serial.printf("\n*** WARNING: Attempt to update Characteristic::%s(\"%s\") with setVal() ignored. Can't update STRING Characteristics once they are initialized!\n\n",hapName,value.STRING); return; } @@ -385,17 +404,13 @@ struct SpanCharacteristic{ sb.val=dummy; // set dummy "val" so that sprintfNotify knows to consider this "update" homeSpan.Notifications.push_back(sb); // store SpanBuf in Notifications vector - } // setValue + } // setVal() }; /////////////////////////////// struct SpanRange{ - int min; - int max; - int step; - SpanRange(int min, int max, int step); }; From 7e3d982ee53f5d0b4cc0b8e8f82495081ec4b7c6 Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 5 Mar 2021 22:34:55 -0600 Subject: [PATCH 14/32] Added min/max Range defaults for all Characteristics Also added new flag "staticRange" for all Characteristics that indicates whether the min/max range can be changed. An ERROR will be thrown if setRange is attempted for a Characteristic having staticRange=true. --- src/Characteristics.h | 201 ++++++++++++++++++++-------------------- src/HomeSpan.cpp | 1 + src/HomeSpan.h | 12 ++- src/Span.h | 209 +++++++++++++++++++++--------------------- 4 files changed, 211 insertions(+), 212 deletions(-) diff --git a/src/Characteristics.h b/src/Characteristics.h index a05a1c6..5bfa525 100644 --- a/src/Characteristics.h +++ b/src/Characteristics.h @@ -58,113 +58,114 @@ struct HapChar { const char *hapName; PERMS perms; FORMAT format; + boolean staticRange; }; /////////////////////////////// -#define HAPCHAR(hapName,type,perms,format) HapChar hapName {#type,#hapName,(PERMS)(perms),format} +#define HAPCHAR(hapName,type,perms,format,staticRange) HapChar hapName {#type,#hapName,(PERMS)(perms),format,staticRange} struct HapCharacteristics { - HAPCHAR( Active, B0, PW+PR+EV, UINT8 ); - HAPCHAR( AirQuality, 95, PR+EV, UINT8 ); - HAPCHAR( BatteryLevel, 68, PR+EV, UINT8 ); - HAPCHAR( Brightness, 8, PR+PW+EV, INT ); - HAPCHAR( CarbonMonoxideLevel, 90, PR+EV, FLOAT ); - HAPCHAR( CarbonMonoxidePeakLevel, 91, PR+EV, FLOAT ); - HAPCHAR( CarbonDioxideDetected, 92, PR+EV, UINT8 ); - HAPCHAR( CarbonDioxideLevel, 93, PR+EV, FLOAT ); - HAPCHAR( CarbonDioxidePeakLevel, 94, PR+EV, FLOAT ); - HAPCHAR( CarbonMonoxideDetected, 69, PR+EV, UINT8 ); - HAPCHAR( ChargingState, 8F, PR+EV, UINT8 ); - HAPCHAR( CoolingThresholdTemperature, D, PR+PW+EV, FLOAT ); - HAPCHAR( ColorTemperature, CE, PR+PW+EV, UINT32 ); - HAPCHAR( ContactSensorState, 6A, PR+EV, UINT8 ); - HAPCHAR( CurrentAmbientLightLevel, 6B, PR+EV, FLOAT ); - HAPCHAR( CurrentHorizontalTiltAngle, 6C, PR+EV, INT ); - HAPCHAR( CurrentAirPurifierState, A9, PR+EV, UINT8 ); - HAPCHAR( CurrentSlatState, AA, PR+EV, UINT8 ); - HAPCHAR( CurrentPosition, 6D, PR+EV, UINT8 ); - HAPCHAR( CurrentVerticalTiltAngle, 6E, PR+EV, INT ); - HAPCHAR( CurrentHumidifierDehumidifierState, B3, PR+EV, UINT8 ); - HAPCHAR( CurrentDoorState, E, PR+EV, UINT8 ); - HAPCHAR( CurrentFanState, AF, PR+EV, UINT8 ); - HAPCHAR( CurrentHeatingCoolingState, F, PR+EV, UINT8 ); - HAPCHAR( CurrentHeaterCoolerState, B1, PR+EV, UINT8 ); - HAPCHAR( CurrentRelativeHumidity, 10, PR+EV, FLOAT ); - HAPCHAR( CurrentTemperature, 11, PR+EV, FLOAT ); - HAPCHAR( CurrentTiltAngle, C1, PR+EV, INT ); - HAPCHAR( FilterLifeLevel, AB, PR+EV, FLOAT ); - HAPCHAR( FilterChangeIndication, AC, PR+EV, UINT8 ); - HAPCHAR( FirmwareRevision, 52, PR, STRING ); - HAPCHAR( HardwareRevision, 53, PR, STRING ); - HAPCHAR( HeatingThresholdTemperature, 12, PR+PW+EV, FLOAT ); - HAPCHAR( HoldPosition, 6F, PW, BOOL ); - HAPCHAR( Hue, 13, PR+PW+EV, FLOAT ); - HAPCHAR( Identify, 14, PW, BOOL ); - HAPCHAR( InUse, D2, PR+EV, UINT8 ); - HAPCHAR( IsConfigured, D6, PR+EV, UINT8 ); - HAPCHAR( LeakDetected, 70, PR+EV, UINT8 ); - HAPCHAR( LockCurrentState, 1D, PR+EV, UINT8 ); - HAPCHAR( LockPhysicalControls, A7, PW+PR+EV, UINT8 ); - HAPCHAR( LockTargetState, 1E, PW+PR+EV, UINT8 ); - HAPCHAR( Manufacturer, 20, PR, STRING ); - HAPCHAR( Model, 21, PR, STRING ); - HAPCHAR( MotionDetected, 22, PR+EV, BOOL ); - HAPCHAR( Mute, 11A, PW+PR+EV, BOOL ); - HAPCHAR( Name, 23, PR, STRING ); - HAPCHAR( NitrogenDioxideDensity, C4, PR+EV, FLOAT ); - HAPCHAR( ObstructionDetected, 24, PR+EV, BOOL ); - HAPCHAR( PM25Density, C6, PR+EV, FLOAT ); - HAPCHAR( OccupancyDetected, 71, PR+EV, UINT8 ); - HAPCHAR( OutletInUse, 26, PR+EV, BOOL ); - HAPCHAR( On, 25, PR+PW+EV, BOOL ); - HAPCHAR( OzoneDensity, C3, PR+EV, FLOAT ); - HAPCHAR( PM10Density, C7, PR+EV, FLOAT ); - HAPCHAR( PositionState, 72, PR+EV, UINT8 ); - HAPCHAR( ProgramMode, D1, PR+EV, UINT8 ); - HAPCHAR( ProgrammableSwitchEvent, 73, PR+EV+NV, UINT8 ); - HAPCHAR( RelativeHumidityDehumidifierThreshold, C9, PR+PW+EV, FLOAT ); - HAPCHAR( RelativeHumidityHumidifierThreshold, CA, PR+PW+EV, FLOAT ); - HAPCHAR( RemainingDuration, D4, PR+EV, UINT32 ); - HAPCHAR( ResetFilterIndication, AD, PW, UINT8 ); - HAPCHAR( RotationDirection, 28, PR+PW+EV, INT ); - HAPCHAR( RotationSpeed, 29, PR+PW+EV, FLOAT ); - HAPCHAR( Saturation, 2F, PR+PW+EV, FLOAT ); - HAPCHAR( SecuritySystemAlarmType, 8E, PR+EV, UINT8 ); - HAPCHAR( SecuritySystemCurrentState, 66, PR+EV, UINT8 ); - HAPCHAR( SecuritySystemTargetState, 67, PW+PR+EV, UINT8 ); - HAPCHAR( SerialNumber, 30, PR, STRING ); - HAPCHAR( ServiceLabelIndex, CB, PR, UINT8 ); - HAPCHAR( ServiceLabelNamespace, CD, PR, UINT8 ); - HAPCHAR( SlatType, C0, PR, UINT8 ); - HAPCHAR( SmokeDetected, 76, PR+EV, UINT8 ); - HAPCHAR( StatusActive, 75, PR+EV, BOOL ); - HAPCHAR( StatusFault, 77, PR+EV, UINT8 ); - HAPCHAR( StatusJammed, 78, PR+EV, UINT8 ); - HAPCHAR( StatusLowBattery, 79, PR+EV, UINT8 ); - HAPCHAR( StatusTampered, 7A, PR+EV, UINT8 ); - HAPCHAR( SulphurDioxideDensity, C5, PR+EV, FLOAT ); - HAPCHAR( SwingMode, B6, PR+EV+PW, UINT8 ); - HAPCHAR( TargetAirPurifierState, A8, PW+PR+EV, UINT8 ); - HAPCHAR( TargetFanState, BF, PW+PR+EV, UINT8 ); - HAPCHAR( TargetTiltAngle, C2, PW+PR+EV, INT ); - HAPCHAR( TargetHeaterCoolerState, B2, PW+PR+EV, UINT8 ); - HAPCHAR( SetDuration, D3, PW+PR+EV, UINT32 ); - HAPCHAR( TargetHorizontalTiltAngle, 7B, PW+PR+EV, INT ); - HAPCHAR( TargetHumidifierDehumidifierState, B4, PW+PR+EV, UINT8 ); - HAPCHAR( TargetPosition, 7C, PW+PR+EV, UINT8 ); - HAPCHAR( TargetDoorState, 32, PW+PR+EV, UINT8 ); - HAPCHAR( TargetHeatingCoolingState, 33, PW+PR+EV, UINT8 ); - HAPCHAR( TargetRelativeHumidity, 34, PW+PR+EV, FLOAT ); - HAPCHAR( TargetTemperature, 35, PW+PR+EV, FLOAT ); - HAPCHAR( TemperatureDisplayUnits, 36, PW+PR+EV, UINT8 ); - HAPCHAR( TargetVerticalTiltAngle, 7D, PW+PR+EV, INT ); - HAPCHAR( ValveType, D5, PR+EV, UINT8 ); - HAPCHAR( Version, 37, PR, STRING ); - HAPCHAR( VOCDensity, C8, PR+EV, FLOAT ); - HAPCHAR( Volume, 119, PW+PR+EV, UINT8 ); - HAPCHAR( WaterLevel, B5, PR+EV, FLOAT ); + HAPCHAR( Active, B0, PW+PR+EV, UINT8, true ); + HAPCHAR( AirQuality, 95, PR+EV, UINT8, true ); + HAPCHAR( BatteryLevel, 68, PR+EV, UINT8, false ); + HAPCHAR( Brightness, 8, PR+PW+EV, INT, false ); + HAPCHAR( CarbonMonoxideLevel, 90, PR+EV, FLOAT, false ); + HAPCHAR( CarbonMonoxidePeakLevel, 91, PR+EV, FLOAT, false ); + HAPCHAR( CarbonDioxideDetected, 92, PR+EV, UINT8, true ); + HAPCHAR( CarbonDioxideLevel, 93, PR+EV, FLOAT, false ); + HAPCHAR( CarbonDioxidePeakLevel, 94, PR+EV, FLOAT, false ); + HAPCHAR( CarbonMonoxideDetected, 69, PR+EV, UINT8, true ); + HAPCHAR( ChargingState, 8F, PR+EV, UINT8, true ); + HAPCHAR( CoolingThresholdTemperature, D, PR+PW+EV, FLOAT, false ); + HAPCHAR( ColorTemperature, CE, PR+PW+EV, UINT32, false ); + HAPCHAR( ContactSensorState, 6A, PR+EV, UINT8, true ); + HAPCHAR( CurrentAmbientLightLevel, 6B, PR+EV, FLOAT, false ); + HAPCHAR( CurrentHorizontalTiltAngle, 6C, PR+EV, INT, false ); + HAPCHAR( CurrentAirPurifierState, A9, PR+EV, UINT8, true ); + HAPCHAR( CurrentSlatState, AA, PR+EV, UINT8, true ); + HAPCHAR( CurrentPosition, 6D, PR+EV, UINT8, false ); + HAPCHAR( CurrentVerticalTiltAngle, 6E, PR+EV, INT, false ); + HAPCHAR( CurrentHumidifierDehumidifierState, B3, PR+EV, UINT8, true ); + HAPCHAR( CurrentDoorState, E, PR+EV, UINT8, true ); + HAPCHAR( CurrentFanState, AF, PR+EV, UINT8, true ); + HAPCHAR( CurrentHeatingCoolingState, F, PR+EV, UINT8, true ); + HAPCHAR( CurrentHeaterCoolerState, B1, PR+EV, UINT8, true ); + HAPCHAR( CurrentRelativeHumidity, 10, PR+EV, FLOAT, false ); + HAPCHAR( CurrentTemperature, 11, PR+EV, FLOAT, false ); + HAPCHAR( CurrentTiltAngle, C1, PR+EV, INT, false ); + HAPCHAR( FilterLifeLevel, AB, PR+EV, FLOAT, false ); + HAPCHAR( FilterChangeIndication, AC, PR+EV, UINT8, true ); + HAPCHAR( FirmwareRevision, 52, PR, STRING, true ); + HAPCHAR( HardwareRevision, 53, PR, STRING, true ); + HAPCHAR( HeatingThresholdTemperature, 12, PR+PW+EV, FLOAT, false ); + HAPCHAR( HoldPosition, 6F, PW, BOOL, true ); + HAPCHAR( Hue, 13, PR+PW+EV, FLOAT, false ); + HAPCHAR( Identify, 14, PW, BOOL, true ); + HAPCHAR( InUse, D2, PR+EV, UINT8, true ); + HAPCHAR( IsConfigured, D6, PR+EV, UINT8, true ); + HAPCHAR( LeakDetected, 70, PR+EV, UINT8, true ); + HAPCHAR( LockCurrentState, 1D, PR+EV, UINT8, true ); + HAPCHAR( LockPhysicalControls, A7, PW+PR+EV, UINT8, true ); + HAPCHAR( LockTargetState, 1E, PW+PR+EV, UINT8, true ); + HAPCHAR( Manufacturer, 20, PR, STRING, true ); + HAPCHAR( Model, 21, PR, STRING, true ); + HAPCHAR( MotionDetected, 22, PR+EV, BOOL, true ); + HAPCHAR( Mute, 11A, PW+PR+EV, BOOL, true ); + HAPCHAR( Name, 23, PR, STRING, true ); + HAPCHAR( NitrogenDioxideDensity, C4, PR+EV, FLOAT, false ); + HAPCHAR( ObstructionDetected, 24, PR+EV, BOOL, true ); + HAPCHAR( PM25Density, C6, PR+EV, FLOAT, false ); + HAPCHAR( OccupancyDetected, 71, PR+EV, UINT8, true ); + HAPCHAR( OutletInUse, 26, PR+EV, BOOL, true ); + HAPCHAR( On, 25, PR+PW+EV, BOOL, true ); + HAPCHAR( OzoneDensity, C3, PR+EV, FLOAT, false ); + HAPCHAR( PM10Density, C7, PR+EV, FLOAT, false ); + HAPCHAR( PositionState, 72, PR+EV, UINT8, true ); + HAPCHAR( ProgramMode, D1, PR+EV, UINT8, true ); + HAPCHAR( ProgrammableSwitchEvent, 73, PR+EV+NV, UINT8, true ); + HAPCHAR( RelativeHumidityDehumidifierThreshold, C9, PR+PW+EV, FLOAT, false ); + HAPCHAR( RelativeHumidityHumidifierThreshold, CA, PR+PW+EV, FLOAT, false ); + HAPCHAR( RemainingDuration, D4, PR+EV, UINT32, false ); + HAPCHAR( ResetFilterIndication, AD, PW, UINT8, true ); + HAPCHAR( RotationDirection, 28, PR+PW+EV, INT, true ); + HAPCHAR( RotationSpeed, 29, PR+PW+EV, FLOAT, false ); + HAPCHAR( Saturation, 2F, PR+PW+EV, FLOAT, false ); + HAPCHAR( SecuritySystemAlarmType, 8E, PR+EV, UINT8, true ); + HAPCHAR( SecuritySystemCurrentState, 66, PR+EV, UINT8, true ); + HAPCHAR( SecuritySystemTargetState, 67, PW+PR+EV, UINT8, true ); + HAPCHAR( SerialNumber, 30, PR, STRING, true ); + HAPCHAR( ServiceLabelIndex, CB, PR, UINT8, true ); + HAPCHAR( ServiceLabelNamespace, CD, PR, UINT8, true ); + HAPCHAR( SlatType, C0, PR, UINT8, true ); + HAPCHAR( SmokeDetected, 76, PR+EV, UINT8, true ); + HAPCHAR( StatusActive, 75, PR+EV, BOOL, true ); + HAPCHAR( StatusFault, 77, PR+EV, UINT8, true ); + HAPCHAR( StatusJammed, 78, PR+EV, UINT8, true ); + HAPCHAR( StatusLowBattery, 79, PR+EV, UINT8, true ); + HAPCHAR( StatusTampered, 7A, PR+EV, UINT8, true ); + HAPCHAR( SulphurDioxideDensity, C5, PR+EV, FLOAT, false ); + HAPCHAR( SwingMode, B6, PR+EV+PW, UINT8, true ); + HAPCHAR( TargetAirPurifierState, A8, PW+PR+EV, UINT8, true ); + HAPCHAR( TargetFanState, BF, PW+PR+EV, UINT8, true ); + HAPCHAR( TargetTiltAngle, C2, PW+PR+EV, INT, false ); + HAPCHAR( TargetHeaterCoolerState, B2, PW+PR+EV, UINT8, true ); + HAPCHAR( SetDuration, D3, PW+PR+EV, UINT32, false ); + HAPCHAR( TargetHorizontalTiltAngle, 7B, PW+PR+EV, INT, false ); + HAPCHAR( TargetHumidifierDehumidifierState, B4, PW+PR+EV, UINT8, true ); + HAPCHAR( TargetPosition, 7C, PW+PR+EV, UINT8, false ); + HAPCHAR( TargetDoorState, 32, PW+PR+EV, UINT8, true ); + HAPCHAR( TargetHeatingCoolingState, 33, PW+PR+EV, UINT8, true ); + HAPCHAR( TargetRelativeHumidity, 34, PW+PR+EV, FLOAT, false ); + HAPCHAR( TargetTemperature, 35, PW+PR+EV, FLOAT, false ); + HAPCHAR( TemperatureDisplayUnits, 36, PW+PR+EV, UINT8, true ); + HAPCHAR( TargetVerticalTiltAngle, 7D, PW+PR+EV, INT, false ); + HAPCHAR( ValveType, D5, PR+EV, UINT8, true ); + HAPCHAR( Version, 37, PR, STRING, true ); + HAPCHAR( VOCDensity, C8, PR+EV, FLOAT, false ); + HAPCHAR( Volume, 119, PW+PR+EV, UINT8, false ); + HAPCHAR( WaterLevel, B5, PR+EV, FLOAT, false ); }; extern HapCharacteristics hapChars; diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index da10762..9a18457 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1460,6 +1460,7 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar){ perms=hapChar->perms; hapName=hapChar->hapName; format=hapChar->format; + staticRange=hapChar->staticRange; homeSpan.configLog+="---->Characteristic " + String(hapName); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index f1951c8..50801b4 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -243,6 +243,7 @@ struct SpanCharacteristic{ UVal minValue; // Characteristic minimum (not applicable for STRING) UVal maxValue; // Characteristic maximum (not applicable for STRING) UVal stepValue; // Characteristic step size (not applicable for STRING) + boolean staticRange; // Flag that indiates whether Range is static and cannot be changed with setRange() boolean customRange=false; // Flag for custom ranges boolean *ev; // Characteristic Event Notify Enable (per-connection) @@ -341,10 +342,10 @@ struct SpanCharacteristic{ template SpanCharacteristic *setRange(A min, B max, S step=0){ char c[256]; - homeSpan.configLog+="------>Range: "; + homeSpan.configLog+=String("------>Set Range for ") + String(hapName) + "-" + String(iid); - if(format==BOOL || format==STRING){ - sprintf(c,"*** ERROR! Can't change range for STRING or BOOL Characteristics! ***\n",hapName); + if(staticRange){ + sprintf(c," *** ERROR! Can't change range for this Characteristic! ***\n"); homeSpan.nFatalErrors++; } else { @@ -354,9 +355,9 @@ struct SpanCharacteristic{ customRange=true; if(step>0) - sprintf(c,"%s/%s/%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue)); + sprintf(c,": %s/%s/%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue)); else - sprintf(c,"%s/%s\n",uvPrint(minValue),uvPrint(maxValue)); + sprintf(c,": %s/%s\n",uvPrint(minValue),uvPrint(maxValue)); } homeSpan.configLog+=c; return(this); @@ -364,6 +365,7 @@ struct SpanCharacteristic{ } // setRange() template void init(T val, A min=0, B max=1){ + uvSet(value,val); uvSet(newValue,val); uvSet(minValue,min); diff --git a/src/Span.h b/src/Span.h index 7e95597..7069572 100644 --- a/src/Span.h +++ b/src/Span.h @@ -381,116 +381,111 @@ namespace Service { // SPAN CHARACTERISTICS (HAP Chapter 9) // ////////////////////////////////////////// -// Macro to define Span Characteristic structures based on name of HAP Characteristic, default value, and mix/max value (not applicable for STRING) +// Macro to define Span Characteristic structures based on name of HAP Characteristic, default value, and mix/max value (not applicable for STRING or BOOL which default to min=0, max=1) -#define CREATE_CHAR_FLOAT(HAPCHAR,DEFVAL,MINVAL,MAXVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(double val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val,(double)MINVAL,(double)MAXVAL); } }; -#define CREATE_CHAR_INT(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(int val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_UINT8(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint8_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_UINT16(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint16_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_UINT32(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint32_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_UINT64(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(uint64_t val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_BOOL(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(boolean val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; -#define CREATE_CHAR_STRING(HAPCHAR,DEFVAL) struct HAPCHAR : SpanCharacteristic { HAPCHAR(const char *val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val); } }; +#define CREATE_CHAR(TYPE,HAPCHAR,DEFVAL,MINVAL,MAXVAL) \ + struct HAPCHAR : SpanCharacteristic { HAPCHAR(TYPE val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val,(TYPE)MINVAL,(TYPE)MAXVAL); } }; namespace Characteristic { - CREATE_CHAR_UINT8(Active,0); - CREATE_CHAR_UINT8(AirQuality,0); - CREATE_CHAR_UINT8(BatteryLevel,0); - CREATE_CHAR_INT(Brightness,0); - CREATE_CHAR_FLOAT(CarbonMonoxideLevel,0,0,100); - CREATE_CHAR_FLOAT(CarbonMonoxidePeakLevel,0,0,100); - CREATE_CHAR_UINT8(CarbonMonoxideDetected,0); - CREATE_CHAR_FLOAT(CarbonDioxideLevel,0,0,100000); - CREATE_CHAR_FLOAT(CarbonDioxidePeakLevel,0,0,100000); - CREATE_CHAR_UINT8(CarbonDioxideDetected,0); - CREATE_CHAR_UINT8(ChargingState,0); - CREATE_CHAR_FLOAT(CoolingThresholdTemperature,10,10,35); - CREATE_CHAR_UINT32(ColorTemperature,200); - CREATE_CHAR_UINT8(ContactSensorState,1); - CREATE_CHAR_FLOAT(CurrentAmbientLightLevel,1,0.0001,100000); - CREATE_CHAR_INT(CurrentHorizontalTiltAngle,0); - CREATE_CHAR_UINT8(CurrentAirPurifierState,1); - CREATE_CHAR_UINT8(CurrentSlatState,0); - CREATE_CHAR_UINT8(CurrentPosition,0); - CREATE_CHAR_INT(CurrentVerticalTiltAngle,0); - CREATE_CHAR_UINT8(CurrentHumidifierDehumidifierState,1); - CREATE_CHAR_UINT8(CurrentDoorState,1); - CREATE_CHAR_UINT8(CurrentFanState,1); - CREATE_CHAR_UINT8(CurrentHeatingCoolingState,0); - CREATE_CHAR_UINT8(CurrentHeaterCoolerState,1); - CREATE_CHAR_FLOAT(CurrentRelativeHumidity,0,0,100); - CREATE_CHAR_FLOAT(CurrentTemperature,0,0,100); - CREATE_CHAR_INT(CurrentTiltAngle,0); - CREATE_CHAR_FLOAT(FilterLifeLevel,0,0,100); - CREATE_CHAR_UINT8(FilterChangeIndication,0); - CREATE_CHAR_STRING(FirmwareRevision,"1.0.0"); - CREATE_CHAR_STRING(HardwareRevision,"1.0.0"); - CREATE_CHAR_FLOAT(HeatingThresholdTemperature,16,0,25); - CREATE_CHAR_BOOL(HoldPosition,false); - CREATE_CHAR_FLOAT(Hue,0,0,360); - CREATE_CHAR_BOOL(Identify,false); - CREATE_CHAR_UINT8(InUse,0); - CREATE_CHAR_UINT8(IsConfigured,0); - CREATE_CHAR_UINT8(LeakDetected,0); - CREATE_CHAR_UINT8(LockCurrentState,0); - CREATE_CHAR_UINT8(LockPhysicalControls,0); - CREATE_CHAR_UINT8(LockTargetState,0); - CREATE_CHAR_STRING(Manufacturer,"HomeSpan"); - CREATE_CHAR_STRING(Model,"HomeSpan-ESP32"); - CREATE_CHAR_BOOL(MotionDetected,false); - CREATE_CHAR_BOOL(Mute,false); - CREATE_CHAR_STRING(Name,"unnamed"); - CREATE_CHAR_FLOAT(NitrogenDioxideDensity,0,0,1000); - CREATE_CHAR_BOOL(ObstructionDetected,false); - CREATE_CHAR_FLOAT(PM25Density,0,0,1000); - CREATE_CHAR_UINT8(OccupancyDetected,0); - CREATE_CHAR_BOOL(OutletInUse,false); - CREATE_CHAR_BOOL(On,false); - CREATE_CHAR_FLOAT(OzoneDensity,0,0,1000); - CREATE_CHAR_FLOAT(PM10Density,0,0,1000); - CREATE_CHAR_UINT8(PositionState,2); - CREATE_CHAR_UINT8(ProgramMode,0); - CREATE_CHAR_UINT8(ProgrammableSwitchEvent,0); - CREATE_CHAR_FLOAT(RelativeHumidityDehumidifierThreshold,50,0,100); - CREATE_CHAR_FLOAT(RelativeHumidityHumidifierThreshold,50,0,100); - CREATE_CHAR_UINT32(RemainingDuration,60); - CREATE_CHAR_UINT8(ResetFilterIndication,0); - CREATE_CHAR_INT(RotationDirection,0); - CREATE_CHAR_FLOAT(RotationSpeed,0,0,100); - CREATE_CHAR_FLOAT(Saturation,0,0,100); - CREATE_CHAR_UINT8(SecuritySystemAlarmType,0); - CREATE_CHAR_UINT8(SecuritySystemCurrentState,3); - CREATE_CHAR_UINT8(SecuritySystemTargetState,3); - CREATE_CHAR_STRING(SerialNumber,"HS-12345"); - CREATE_CHAR_UINT8(ServiceLabelIndex,1); - CREATE_CHAR_UINT8(ServiceLabelNamespace,1); - CREATE_CHAR_UINT8(SlatType,0); - CREATE_CHAR_UINT8(SmokeDetected,0); - CREATE_CHAR_BOOL(StatusActive,true); - CREATE_CHAR_UINT8(StatusFault,0); - CREATE_CHAR_UINT8(StatusJammed,0); - CREATE_CHAR_UINT8(StatusLowBattery,0); - CREATE_CHAR_UINT8(StatusTampered,0); - CREATE_CHAR_FLOAT(SulphurDioxideDensity,0,0,1000); - CREATE_CHAR_UINT8(SwingMode,0); - CREATE_CHAR_UINT8(TargetAirPurifierState,1); - CREATE_CHAR_UINT8(TargetFanState,1); - CREATE_CHAR_INT(TargetTiltAngle,0); - CREATE_CHAR_UINT32(SetDuration,60); - CREATE_CHAR_INT(TargetHorizontalTiltAngle,0); - CREATE_CHAR_UINT8(TargetHumidifierDehumidifierState,0); - CREATE_CHAR_UINT8(TargetPosition,0); - CREATE_CHAR_UINT8(TargetDoorState,1); - CREATE_CHAR_UINT8(TargetHeatingCoolingState,0); - CREATE_CHAR_FLOAT(TargetRelativeHumidity,0,0,100); - CREATE_CHAR_FLOAT(TargetTemperature,16,10,38); - CREATE_CHAR_UINT8(TemperatureDisplayUnits,0); - CREATE_CHAR_INT(TargetVerticalTiltAngle,0); - CREATE_CHAR_UINT8(ValveType,0); - CREATE_CHAR_STRING(Version,"1.0.0"); - CREATE_CHAR_FLOAT(VOCDensity,0,0,1000); - CREATE_CHAR_UINT8(Volume,0); - CREATE_CHAR_FLOAT(WaterLevel,0,0,100); + CREATE_CHAR(uint8_t,Active,0,0,1); + CREATE_CHAR(uint8_t,AirQuality,0,0,5); + CREATE_CHAR(uint8_t,BatteryLevel,0,0,100); + CREATE_CHAR(int,Brightness,0,0,100); + CREATE_CHAR(double,CarbonMonoxideLevel,0,0,100); + CREATE_CHAR(double,CarbonMonoxidePeakLevel,0,0,100); + CREATE_CHAR(uint8_t,CarbonMonoxideDetected,0,0,1); + CREATE_CHAR(double,CarbonDioxideLevel,0,0,100000); + CREATE_CHAR(double,CarbonDioxidePeakLevel,0,0,100000); + CREATE_CHAR(uint8_t,CarbonDioxideDetected,0,0,1); + CREATE_CHAR(uint8_t,ChargingState,0,0,2); + CREATE_CHAR(double,CoolingThresholdTemperature,10,10,35); + CREATE_CHAR(uint32_t,ColorTemperature,200,140,500); + CREATE_CHAR(uint8_t,ContactSensorState,1,0,1); + CREATE_CHAR(double,CurrentAmbientLightLevel,1,0.0001,100000); + CREATE_CHAR(int,CurrentHorizontalTiltAngle,0,-90,90); + CREATE_CHAR(uint8_t,CurrentAirPurifierState,1,0,2); + CREATE_CHAR(uint8_t,CurrentSlatState,0,0,2); + CREATE_CHAR(uint8_t,CurrentPosition,0,0,100); + CREATE_CHAR(int,CurrentVerticalTiltAngle,0,-90,90); + CREATE_CHAR(uint8_t,CurrentHumidifierDehumidifierState,1,0,3); + CREATE_CHAR(uint8_t,CurrentDoorState,1,0,4); + CREATE_CHAR(uint8_t,CurrentFanState,1,0,2); + CREATE_CHAR(uint8_t,CurrentHeatingCoolingState,0,0,2); + CREATE_CHAR(uint8_t,CurrentHeaterCoolerState,1,0,3); + CREATE_CHAR(double,CurrentRelativeHumidity,0,0,100); + CREATE_CHAR(double,CurrentTemperature,0,0,100); + CREATE_CHAR(int,CurrentTiltAngle,0,-90,90); + CREATE_CHAR(double,FilterLifeLevel,0,0,100); + CREATE_CHAR(uint8_t,FilterChangeIndication,0,0,1); + CREATE_CHAR(const char *,FirmwareRevision,"1.0.0",0,1); + CREATE_CHAR(const char *,HardwareRevision,"1.0.0",0,1); + CREATE_CHAR(double,HeatingThresholdTemperature,16,0,25); + CREATE_CHAR(boolean,HoldPosition,false,0,1); + CREATE_CHAR(double,Hue,0,0,360); + CREATE_CHAR(boolean,Identify,false,0,1); + CREATE_CHAR(uint8_t,InUse,0,0,1); + CREATE_CHAR(uint8_t,IsConfigured,0,0,1); + CREATE_CHAR(uint8_t,LeakDetected,0,0,1); + CREATE_CHAR(uint8_t,LockCurrentState,0,0,3); + CREATE_CHAR(uint8_t,LockPhysicalControls,0,0,1); + CREATE_CHAR(uint8_t,LockTargetState,0,0,1); + CREATE_CHAR(const char *,Manufacturer,"HomeSpan",0,1); + CREATE_CHAR(const char *,Model,"HomeSpan-ESP32",0,1); + CREATE_CHAR(boolean,MotionDetected,false,0,1); + CREATE_CHAR(boolean,Mute,false,0,1); + CREATE_CHAR(const char *,Name,"unnamed",0,1); + CREATE_CHAR(double,NitrogenDioxideDensity,0,0,1000); + CREATE_CHAR(boolean,ObstructionDetected,false,0,1); + CREATE_CHAR(double,PM25Density,0,0,1000); + CREATE_CHAR(uint8_t,OccupancyDetected,0,0,1); + CREATE_CHAR(boolean,OutletInUse,false,0,1); + CREATE_CHAR(boolean,On,false,0,1); + CREATE_CHAR(double,OzoneDensity,0,0,1000); + CREATE_CHAR(double,PM10Density,0,0,1000); + CREATE_CHAR(uint8_t,PositionState,2,0,2); + CREATE_CHAR(uint8_t,ProgramMode,0,0,2); + CREATE_CHAR(uint8_t,ProgrammableSwitchEvent,0,0,2); + CREATE_CHAR(double,RelativeHumidityDehumidifierThreshold,50,0,100); + CREATE_CHAR(double,RelativeHumidityHumidifierThreshold,50,0,100); + CREATE_CHAR(uint32_t,RemainingDuration,60,0,3600); + CREATE_CHAR(uint8_t,ResetFilterIndication,0,1,1); + CREATE_CHAR(int,RotationDirection,0,0,1); + CREATE_CHAR(double,RotationSpeed,0,0,100); + CREATE_CHAR(double,Saturation,0,0,100); + CREATE_CHAR(uint8_t,SecuritySystemAlarmType,0,0,1); + CREATE_CHAR(uint8_t,SecuritySystemCurrentState,3,0,4); + CREATE_CHAR(uint8_t,SecuritySystemTargetState,3,0,3); + CREATE_CHAR(const char *,SerialNumber,"HS-12345",0,1); + CREATE_CHAR(uint8_t,ServiceLabelIndex,1,1,255); + CREATE_CHAR(uint8_t,ServiceLabelNamespace,1,0,1); + CREATE_CHAR(uint8_t,SlatType,0,0,1); + CREATE_CHAR(uint8_t,SmokeDetected,0,0,1); + CREATE_CHAR(boolean,StatusActive,true,0,1); + CREATE_CHAR(uint8_t,StatusFault,0,0,1); + CREATE_CHAR(uint8_t,StatusJammed,0,0,1); + CREATE_CHAR(uint8_t,StatusLowBattery,0,0,1); + CREATE_CHAR(uint8_t,StatusTampered,0,0,1); + CREATE_CHAR(double,SulphurDioxideDensity,0,0,1000); + CREATE_CHAR(uint8_t,SwingMode,0,0,1); + CREATE_CHAR(uint8_t,TargetAirPurifierState,1,0,1); + CREATE_CHAR(uint8_t,TargetFanState,1,0,1); + CREATE_CHAR(int,TargetTiltAngle,0,-90,90); + CREATE_CHAR(uint8_t,TargetHeaterCoolerState,0,0,2); + CREATE_CHAR(uint32_t,SetDuration,60,0,3600); + CREATE_CHAR(int,TargetHorizontalTiltAngle,0,-90,90); + CREATE_CHAR(uint8_t,TargetHumidifierDehumidifierState,0,0,2); + CREATE_CHAR(uint8_t,TargetPosition,0,0,100); + CREATE_CHAR(uint8_t,TargetDoorState,1,0,1); + CREATE_CHAR(uint8_t,TargetHeatingCoolingState,0,0,3); + CREATE_CHAR(double,TargetRelativeHumidity,0,0,100); + CREATE_CHAR(double,TargetTemperature,16,10,38); + CREATE_CHAR(uint8_t,TemperatureDisplayUnits,0,0,1); + CREATE_CHAR(int,TargetVerticalTiltAngle,0,-90,90); + CREATE_CHAR(uint8_t,ValveType,0,0,3); + CREATE_CHAR(const char *,Version,"1.0.0",0,1); + CREATE_CHAR(double,VOCDensity,0,0,1000); + CREATE_CHAR(uint8_t,Volume,0,0,100); + CREATE_CHAR(double,WaterLevel,0,0,100); } From 3b40aeec74ca6e6043536bae8d114fc4ec2ec0f5 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 6 Mar 2021 08:30:09 -0600 Subject: [PATCH 15/32] Added check to throw error is setRange is called twice on same Characteristic --- examples/12-ServiceLoops/DEV_Sensors.h | 2 ++ src/HomeSpan.h | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index 86f0cff..f33b2e1 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -70,6 +70,8 @@ struct DEV_AirQualitySensor : Service::AirQualitySensor { // A standalone Ai airQuality=new Characteristic::AirQuality(1); // instantiate the Air Quality Characteristic and set initial value to 1 o3Density=new Characteristic::OzoneDensity(300.0); // instantiate the Ozone Density Characteristic and set initial value to 300.0 no2Density=new Characteristic::NitrogenDioxideDensity(700.0); // instantiate the Nitrogen Dioxide Density Characteristic and set initial value to 700.0 + new SpanRange(300,500,2); + Serial.print("Configuring Air Quality Sensor"); // initialization message Serial.print("\n"); diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 50801b4..d2d1fb7 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -342,7 +342,12 @@ struct SpanCharacteristic{ template SpanCharacteristic *setRange(A min, B max, S step=0){ char c[256]; - homeSpan.configLog+=String("------>Set Range for ") + String(hapName) + "-" + String(iid); + homeSpan.configLog+=String("------>Set Range for ") + String(hapName) + "-" + String(iid); + + if(customRange){ + sprintf(c," *** ERROR! Range already set for this Characteristic! ***\n"); + homeSpan.nFatalErrors++; + } else if(staticRange){ sprintf(c," *** ERROR! Can't change range for this Characteristic! ***\n"); From ff0dfefc47b045674877b1ffd1f7e20c35a9bd43 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 6 Mar 2021 09:08:57 -0600 Subject: [PATCH 16/32] Added check to ensure initial value of Characteristic is in allowable Range Check is not applied to STRING Characteristics. Check is performed at end of each Accessory definition so will account for any changes to min/max as a result of calls to setRange(). If initial value is outside allowable range, a WARNING (not an ERROR) is thrown. --- examples/12-ServiceLoops/DEV_Sensors.h | 4 +--- src/HomeSpan.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/12-ServiceLoops/DEV_Sensors.h b/examples/12-ServiceLoops/DEV_Sensors.h index f33b2e1..01331aa 100644 --- a/examples/12-ServiceLoops/DEV_Sensors.h +++ b/examples/12-ServiceLoops/DEV_Sensors.h @@ -15,7 +15,7 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera // Though the HAP documentation includes a Characteristic that appears to allow the device to over-ride this setting by specifying a display // of Celsius or Fahrenheit for each Service, it does not appear to work as advertised. - temp=new Characteristic::CurrentTemperature(30.0); // instantiate the Current Temperature Characteristic + temp=new Characteristic::CurrentTemperature(-10.0); // instantiate the Current Temperature Characteristic temp->setRange(-50,100); // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures Serial.print("Configuring Temperature Sensor"); // initialization message @@ -70,8 +70,6 @@ struct DEV_AirQualitySensor : Service::AirQualitySensor { // A standalone Ai airQuality=new Characteristic::AirQuality(1); // instantiate the Air Quality Characteristic and set initial value to 1 o3Density=new Characteristic::OzoneDensity(300.0); // instantiate the Ozone Density Characteristic and set initial value to 300.0 no2Density=new Characteristic::NitrogenDioxideDensity(700.0); // instantiate the Nitrogen Dioxide Density Characteristic and set initial value to 700.0 - new SpanRange(300,500,2); - Serial.print("Configuring Air Quality Sensor"); // initialization message Serial.print("\n"); diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 9a18457..ccea28d 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1310,6 +1310,17 @@ void SpanAccessory::validate(){ foundProtocol=true; else if(aid==1) // this is an Accessory with aid=1, but it has more than just AccessoryInfo and HAPProtocolInformation. So... homeSpan.isBridge=false; // ...this is not a bridge device + + for(int j=0;jCharacteristics.size();j++){ // check that initial values are all in range of mix/max (which may have been modified by setRange) + SpanCharacteristic *chr=Services[i]->Characteristics[j]; + + if(chr->format!=STRING && (chr->uvGet(chr->value) < chr->uvGet(chr->minValue) || chr->uvGet(chr->value) > chr->uvGet(chr->maxValue))){ + char c[256]; + sprintf(c," !Warning: Initial value of %lg for %s-%d is out of range [%llg,%llg]. This may cause device to be non-reponsive!\n", + chr->uvGet(chr->value),chr->hapName,chr->iid,chr->uvGet(chr->minValue),chr->uvGet(chr->maxValue)); + homeSpan.configLog+=c; + } + } } if(!foundInfo){ From 2f8cd511ddb227de535aadf9e04ae2c3c9e85376 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Mar 2021 08:45:24 -0600 Subject: [PATCH 17/32] Update Reference.md --- docs/Reference.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index aeb2a9f..718192f 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -171,15 +171,16 @@ The following methods are supported: * `int timeVal()` * returns time elapsed (in millis) since value of the Characteristic was last updated (whether by `setVal()` or as the result of a successful update request from a HomeKit Controller) + +* `SpanCharacteristic *setRange(min, max, step)` + * overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* values specified + * only applicable for Characteristics that support value ranges, else error is thrown + * can only set set once per Characteristic. Calling setRange twice for the same Characteristic throws an error + * works with any integer or floating-based parameters, though HomeSpan will recast the values into the appropriate format for the Characteristic, which means if you specify *step*=0.5 for a UINT8 Characteristic, *step* will be truncated to zero + * *step* is an optional parameter. If unspecified, or set to zero or a negative number, the default HAP step size remains unchanged + * Returns a pointer to the Characteristic itself so that the method can be chained during instantiation + * example: `(new Characteristic::Brightness(50))->setRange(10,100,5);` -## *SpanRange(int min, int max, int step)* - -Creating an instance of this **class** overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* values specified. - -* instantiated Ranges are added to the HomeSpan HAP Database and associated with the last Characteristic instantiated -* instantiating a Range without first instantiating a Characteristic throws an error during initialization -* example: `new Characteristic::Brightness(50); new SpanRange(10,100,5);` - ## *SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime)* Creating an instance of this **class** attaches a pushbutton handler to the ESP32 *pin* specified. @@ -213,6 +214,15 @@ If REQUIRED is defined in the main sketch prior to including the HomeSpan librar ```C++ #define REQUIRED VERISON(2,1,3) // throws a compile-time error unless HomeSpan library used is version 2.1.3 or later ``` +### *SpanRange(int min, int max, int step)* + +Creating an instance of this **class** overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* values specified. + +* instantiated Ranges are added to the HomeSpan HAP Database and associated with the last Characteristic instantiated +* instantiating a Range without first instantiating a Characteristic throws an error during initialization +* example: `new Characteristic::Brightness(50); new SpanRange(10,100,5);` +* **this is a legacy function that is limited to integer-based parameters, and has been re-coded to simply call the more generic `setRange(min, max, step)` method** +* **please use setRange(min, max, step) for all new sketches** --- From 9e124ab7719f3b7adbe2adc084fc31de08370304 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Mar 2021 08:46:46 -0600 Subject: [PATCH 18/32] Update Reference.md --- docs/Reference.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index 718192f..85fb1da 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -214,14 +214,16 @@ If REQUIRED is defined in the main sketch prior to including the HomeSpan librar ```C++ #define REQUIRED VERISON(2,1,3) // throws a compile-time error unless HomeSpan library used is version 2.1.3 or later ``` -### *SpanRange(int min, int max, int step)* +--- + +## *SpanRange(int min, int max, int step)* Creating an instance of this **class** overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* values specified. * instantiated Ranges are added to the HomeSpan HAP Database and associated with the last Characteristic instantiated * instantiating a Range without first instantiating a Characteristic throws an error during initialization * example: `new Characteristic::Brightness(50); new SpanRange(10,100,5);` -* **this is a legacy function that is limited to integer-based parameters, and has been re-coded to simply call the more generic `setRange(min, max, step)` method** +* this is a legacy function that is limited to integer-based parameters, and has been re-coded to simply call the more generic `setRange(min, max, step)` method * **please use setRange(min, max, step) for all new sketches** --- From 209836c1704d1ac39f9afea6b54efd798be848d4 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Mar 2021 08:52:18 -0600 Subject: [PATCH 19/32] Update Reference.md --- docs/Reference.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index 85fb1da..8dcf86c 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -151,6 +151,7 @@ This is a **base class** from which all HomeSpan Characteristics are derived, an * instantiated Characteristics are added to the HomeSpan HAP Database and associated with the last Service instantiated * instantiating a Characteristic without first instantiating a Service throws an error during initialization * a single, optional argument is used to set the initial value of the Characteristic at startup +* throws a runtime warning if value is outside of the min/max range for the Characteristic, where min/max is either the HAP default, or any new values set via a call to `setRange()` * example: `new Characteristic::Brightness(50);` The following methods are supported: @@ -167,7 +168,8 @@ The following methods are supported: * returns *true* if a HomeKit Controller has requested an update to the value of the Characteristic, otherwise *false*. The requested value itself can retrieved with `getNewVal<>()` * `void setVal(value)` - * sets the value of the Characteristic to *value*, and notifies all HomeKit Controllers of the change. Works with any integer, boolean, or floating-based numerical value. + * sets the value of the Characteristic to *value*, and notifies all HomeKit Controllers of the change. Works with any integer, boolean, or floating-based numerical value + * throws a runtime warning if value is outside of the min/max range for the Characteristic, where min/max is either the HAP default, or any new values set via a prior call to `setRange()` * `int timeVal()` * returns time elapsed (in millis) since value of the Characteristic was last updated (whether by `setVal()` or as the result of a successful update request from a HomeKit Controller) From 53268127bed24d6e767211cc24c267e167fb7ddf Mon Sep 17 00:00:00 2001 From: Gregg Date: Sun, 7 Mar 2021 17:39:42 -0600 Subject: [PATCH 20/32] Updated Examples to use `setRange()` instead of `new SpanRange()` setRange() is preferred method. SpanRange() is legacy only --- .../04-AdvancedCeilingFan.ino | 37 ++++++++++++------- examples/06-DimmableLED/DEV_LED.h | 2 +- examples/07-IdentifyRoutines/DEV_LED.h | 2 +- examples/08-Bridges/DEV_LED.h | 2 +- examples/09-MessageLogging/DEV_LED.h | 2 +- examples/10-RGB_LED/DEV_LED.h | 4 +- examples/11-ServiceOptions/DEV_LED.h | 2 +- examples/13-TargetStates/DEV_DoorsWindows.h | 8 ++-- examples/15-RealPushButtons/DEV_LED.h | 2 +- src/HomeSpan.h | 2 +- 10 files changed, 36 insertions(+), 27 deletions(-) diff --git a/examples/04-AdvancedCeilingFan/04-AdvancedCeilingFan.ino b/examples/04-AdvancedCeilingFan/04-AdvancedCeilingFan.ino index 0f09f51..f849b2b 100644 --- a/examples/04-AdvancedCeilingFan/04-AdvancedCeilingFan.ino +++ b/examples/04-AdvancedCeilingFan/04-AdvancedCeilingFan.ino @@ -61,31 +61,40 @@ void setup() { new Characteristic::Version("1.1.0"); new Service::LightBulb(); - new Characteristic::On(true); // NEW: Providing an argument sets its initial value. In this case it means the LightBulb will be turned on at start-up - new Characteristic::Brightness(50); // NEW: This allows control of the Brightness of the LightBulb, with an initial value of 50% upon start-up (Note 1) - new SpanRange(20,100,5); // NEW: This sets the range of the Brightness to be from a min of 20%, to a max of 100%, in steps of 5% (Note 2) + new Characteristic::On(true); // NEW: Providing an argument sets its initial value. In this case it means the LightBulb will be turned on at start-up + + // In addition to setting the initial value of a Characteristic, it is also possible to override the default min/max/step range specified by HAP. + // We do this with the setRange() method: + + // setRange(min, max, step), where + // + // min = minimum allowed value + // max = maximum allowed value + // step = step size (can be left blank, in which case the HAP default is retained) + + // The setRange() method can be called on any numerical-based Characteristic that supports range overrides. The easiest way to apply to method is to call it right + // after instantiating a new Characteristic. Don't forget to surround the "new" command in parentheses when chaining a method in this fashion. + + // Here we create a Brightness Characteristic to set the brightness of the LightBulb with an initial value of 50% and an allowable range + // from 20-100% in steps of 5%. See Notes 1 and 2 below for more details: + + (new Characteristic::Brightness(50))->setRange(20,100,5); new Service::Fan(); new Characteristic::Active(); - new Characteristic::RotationDirection(); // NEW: This allows control of the Rotation Direction of the Fan - new Characteristic::RotationSpeed(25); // NEW: This allows control of the Rotation Speed of the Fan, with an initial value of 25% upon start-up (Note 1) - new SpanRange(0,100,25); // NEW: This sets the range of the Rotation Speed to be from a min of 0%, to a max of 100%, in steps of 25% - + new Characteristic::RotationDirection(); // NEW: This allows control of the Rotation Direction of the Fan + (new Characteristic::RotationSpeed(50))->setRange(0,100,25); // NEW: This allows control of the Rotation Speed of the Fan, with an initial value of 50% and a range from 0-100 in steps of 25% // NOTE 1: Setting the initial value of the Brightness Characteristic to 50% does not by itself cause HomeKit to turn the light on to 50% upon start-up. // Rather, this is governed by the initial value of the On Characteristic, which in this case happens to be set to true. If it were set to false, // or left unspecified (default is false) then the LightBulb will be off at start-up. However, it will jump to 50% brightness as soon as turned on // for the first time. This same logic applies to the Active and RotationSpeed Characteristics for a Fan. - // NOTE 2: The default range for Characteristics that support a range of values is specified in the HAP Section 9. For Brightness, the range defaults - // to min=0%, max=100%, step=1%. SpanRange(min,max,step) can be used to over-ride this default. SpanRange is generic and can be used wih other Characteristics - // that support a range of values, such as RotationSpeed. Whenever a new SpanRange is defined it is applied to the most recently defined Characteristic. - // It only has an effect if that Characteristic utilizes ranges. - - // RECOMMENDATION: Using SpanRange to change the minimum Brightness from 0% (the default) to 20% (or any non-zero value) provides for a better + // NOTE 2: The default range for Characteristics that support a range of values is specified in HAP Section 9. For Brightness, the range defaults + // to min=0%, max=100%, step=1%. Using setRange() to change the minimum Brightness from 0% to 20% (or any non-zero value) provides for a better // HomeKit experience. This is because the LightBulb power is controlled by the On Characteristic, and allowing Brightness to be as low as 0% // sometimes results in HomeKit turning on the LightBulb but with Brightness=0%, which is not very intuitive. This can occur when asking Siri - // to lower the Brightness all the way, and turnign on the LightBulb. By setting a minumum value of 20%, HomeKit always ensures that there is + // to lower the Brightness all the way, and then turning on the LightBulb. By setting a minumum value of 20%, HomeKit always ensures that there is // some Brightness value whenever the LightBulb is turned on. } // end of setup() diff --git a/examples/06-DimmableLED/DEV_LED.h b/examples/06-DimmableLED/DEV_LED.h index 6f24a9c..ba6f9e2 100644 --- a/examples/06-DimmableLED/DEV_LED.h +++ b/examples/06-DimmableLED/DEV_LED.h @@ -43,7 +43,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(50); // NEW! Instantiate the Brightness Characteristic with an initial value of 50% (same as we did in Example 4) - new SpanRange(5,100,1); // NEW! This sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% (different from Example 4 values) + level->setRange(5,100,1); // NEW! This sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% (different from Example 4 values) this->channel=channel; // NEW! Save the channel number (from 0-15) this->pwmPin=new PwmPin(channel, ledPin); // NEW! Configures the PWM channel and attach the specified ledPin. pinMode() does NOT need to be called. diff --git a/examples/07-IdentifyRoutines/DEV_LED.h b/examples/07-IdentifyRoutines/DEV_LED.h index 0f3f027..0598e22 100644 --- a/examples/07-IdentifyRoutines/DEV_LED.h +++ b/examples/07-IdentifyRoutines/DEV_LED.h @@ -41,7 +41,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50% - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + level->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% this->channel=channel; // save the channel number (from 0-15) this->pwmPin=new PwmPin(channel, ledPin); // configure the PWM channel and attach the specified ledPin. pinMode() does NOT need to be called. diff --git a/examples/08-Bridges/DEV_LED.h b/examples/08-Bridges/DEV_LED.h index 0f3f027..0598e22 100644 --- a/examples/08-Bridges/DEV_LED.h +++ b/examples/08-Bridges/DEV_LED.h @@ -41,7 +41,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50% - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + level->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% this->channel=channel; // save the channel number (from 0-15) this->pwmPin=new PwmPin(channel, ledPin); // configure the PWM channel and attach the specified ledPin. pinMode() does NOT need to be called. diff --git a/examples/09-MessageLogging/DEV_LED.h b/examples/09-MessageLogging/DEV_LED.h index c639ca5..dc8e0ce 100644 --- a/examples/09-MessageLogging/DEV_LED.h +++ b/examples/09-MessageLogging/DEV_LED.h @@ -64,7 +64,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50% - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + level->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% this->channel=channel; // save the channel number (from 0-15) this->ledPin=ledPin; // LED pin number <- NEW!! diff --git a/examples/10-RGB_LED/DEV_LED.h b/examples/10-RGB_LED/DEV_LED.h index f8c0cf4..d571420 100644 --- a/examples/10-RGB_LED/DEV_LED.h +++ b/examples/10-RGB_LED/DEV_LED.h @@ -56,7 +56,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50% - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + level->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% this->channel=channel; // save the channel number (from 0-15) this->ledPin=ledPin; // save LED pin number @@ -116,7 +116,7 @@ struct DEV_RgbLED : Service::LightBulb { // RGB LED (Command Cathode) H=new Characteristic::Hue(0); // instantiate the Hue Characteristic with an initial value of 0 out of 360 S=new Characteristic::Saturation(0); // instantiate the Saturation Characteristic with an initial value of 0% V=new Characteristic::Brightness(100); // instantiate the Brightness Characteristic with an initial value of 100% - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + V->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% this->redChannel=redChannel; // save the channel number (from 0-15) this->greenChannel=greenChannel; diff --git a/examples/11-ServiceOptions/DEV_LED.h b/examples/11-ServiceOptions/DEV_LED.h index 77e6f67..1a9924c 100644 --- a/examples/11-ServiceOptions/DEV_LED.h +++ b/examples/11-ServiceOptions/DEV_LED.h @@ -56,7 +56,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50% - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + level->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% this->channel=channel; // save the channel number (from 0-15) this->ledPin=ledPin; // save LED pin number diff --git a/examples/13-TargetStates/DEV_DoorsWindows.h b/examples/13-TargetStates/DEV_DoorsWindows.h index c9a3dfb..672e450 100644 --- a/examples/13-TargetStates/DEV_DoorsWindows.h +++ b/examples/13-TargetStates/DEV_DoorsWindows.h @@ -71,11 +71,11 @@ struct DEV_WindowShade : Service::WindowCovering { // A motorized Window Sha DEV_WindowShade() : Service::WindowCovering(){ // constructor() method - current=new Characteristic::CurrentPosition(0); // Windows Shades have positions that range from 0 (fully lowered) to 100 (fully raised) - new SpanRange(0,100,10); // set the allowable current-position range to 0-100 IN STEPS of 10 + current=new Characteristic::CurrentPosition(0); // Window Shades have positions that range from 0 (fully lowered) to 100 (fully raised) + current->setRange(0,100,10); // set the allowable current-position range to 0-100 IN STEPS of 10 - target=new Characteristic::TargetPosition(0); // Windows Shades have positions that range from 0 (fully lowered) to 100 (fully raised) - new SpanRange(0,100,10); // set the allowable target-position range to 0-100 IN STEPS of 10 + target=new Characteristic::TargetPosition(0); // Window Shades have positions that range from 0 (fully lowered) to 100 (fully raised) + target->setRange(0,100,10); // set the allowable target-position range to 0-100 IN STEPS of 10 Serial.print("Configuring Motorized Window Shade"); // initialization message Serial.print("\n"); diff --git a/examples/15-RealPushButtons/DEV_LED.h b/examples/15-RealPushButtons/DEV_LED.h index f454f11..2b22f05 100644 --- a/examples/15-RealPushButtons/DEV_LED.h +++ b/examples/15-RealPushButtons/DEV_LED.h @@ -33,7 +33,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED power=new Characteristic::On(); level=new Characteristic::Brightness(favoriteLevel); // Brightness Characteristic with an initial value equal to the favorite level - new SpanRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% + level->setRange(5,100,1); // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1% // NEW! Below we create three SpanButton() objects. In the first we specify the pin number, as required, but allow SpanButton() to use // its default values for a LONG press (2000 ms), a SINGLE press (5 ms), and a DOUBLE press (200 ms). In the second and third we change the diff --git a/src/HomeSpan.h b/src/HomeSpan.h index d2d1fb7..6744bd7 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -359,7 +359,7 @@ struct SpanCharacteristic{ uvSet(stepValue,step); customRange=true; - if(step>0) + if(uvGet(stepValue)>0) sprintf(c,": %s/%s/%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue)); else sprintf(c,": %s/%s\n",uvPrint(minValue),uvPrint(maxValue)); From c64c31f4cff22ee8d2a53f614965557d08592e6c Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sun, 7 Mar 2021 17:41:41 -0600 Subject: [PATCH 21/32] Update Reference.md --- docs/Reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Reference.md b/docs/Reference.md index 8dcf86c..f45f84d 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -226,7 +226,7 @@ Creating an instance of this **class** overrides the default HAP range for a Cha * instantiating a Range without first instantiating a Characteristic throws an error during initialization * example: `new Characteristic::Brightness(50); new SpanRange(10,100,5);` * this is a legacy function that is limited to integer-based parameters, and has been re-coded to simply call the more generic `setRange(min, max, step)` method -* **please use setRange(min, max, step) for all new sketches** +* **please use** `setRange(min, max, step)` **for all new sketches** --- From c6946891bb720e3b9f6f39605682d259c109b3cb Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 9 Mar 2021 08:03:06 -0600 Subject: [PATCH 22/32] Update Tutorials.md --- docs/Tutorials.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Tutorials.md b/docs/Tutorials.md index 05780d4..1d7eaf3 100644 --- a/docs/Tutorials.md +++ b/docs/Tutorials.md @@ -21,7 +21,7 @@ Example 3 shows how adding multiple Services to a single Accessory allows us to ### [Example 4 - AdvancedCeilingFan](../examples/04-AdvancedCeilingFan) Example 4 expands on Example 3 by adding Characteristics to set fan speed, fan rotation direction, and light brightness. New HomeSpan API topics covered in this example include: -* using `SpanRange()` to set the allowable range and increment values for a Characteristic +* using `setRange()` to set the allowable range and increment values for a Characteristic ### [Example 5 - WorkingLED](../examples/05-WorkingLED) Example 5 expands on Example 2 by adding in the code needed to actually control LEDs connected to the ESP32 from HomeKit. In Example 2 we built out all the functionality to create a "Tile" Acessories inside HomeKit that displayed an on/off light, but these control did not actually operate anything on the ESP32. To operate actual devices HomeSpan needs to be programmed to respond to "update" requests from HomeKit by performing some form of operation. New HomeSpan API topics covered in this example include: From a0e220356de65957cdb46d40d4a79d90b7f6cd4a Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 9 Mar 2021 08:08:39 -0600 Subject: [PATCH 23/32] Update ServiceList.md --- docs/ServiceList.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/ServiceList.md b/docs/ServiceList.md index 361e99f..73feb65 100644 --- a/docs/ServiceList.md +++ b/docs/ServiceList.md @@ -155,6 +155,7 @@ Additionally, when first starting up, HomeSpan begins by validating the device's |TargetHumidifierDehumidifierState|uint8_t|0| |TargetPosition|uint8_t|0| |TargetDoorState|uint8_t|1| +|TargetHeaterCoolerState|uint8_t|0| |TargetHeatingCoolingState|uint8_t|0| |TargetRelativeHumidity|double|0| |TargetTemperature|double|16| From da74066c70cbe7590015be362221cd9524fd4711 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Tue, 9 Mar 2021 08:25:13 -0600 Subject: [PATCH 24/32] Update Reference.md --- docs/Reference.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index f45f84d..b9af9d3 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -168,8 +168,9 @@ The following methods are supported: * returns *true* if a HomeKit Controller has requested an update to the value of the Characteristic, otherwise *false*. The requested value itself can retrieved with `getNewVal<>()` * `void setVal(value)` - * sets the value of the Characteristic to *value*, and notifies all HomeKit Controllers of the change. Works with any integer, boolean, or floating-based numerical value - * throws a runtime warning if value is outside of the min/max range for the Characteristic, where min/max is either the HAP default, or any new values set via a prior call to `setRange()` + * sets the value of the Characteristic to *value*, and notifies all HomeKit Controllers of the change. Works with any integer, boolean, or floating-based numerical *value*, though HomeSpan will convert *value* into the appropriate type for each Characteristic (e.g. value=5.5 is converted to 5 if used with an integer-based Characteristic) + * throws a runtime warning if *value* is outside of the min/max range for the Characteristic, where min/max is either the HAP default, or any new values set via a prior call to `setRange()` + * accepts any *value* within the allowed min/max range regardless of the setting of step size. Step size is only used by the Home App to limit the increments of adjustment for sliders, and will use a rounded version of *value* for display purposes of the slider while retaining the actual numerical value internally * `int timeVal()` * returns time elapsed (in millis) since value of the Characteristic was last updated (whether by `setVal()` or as the result of a successful update request from a HomeKit Controller) From 8121146c6b7c2f269b3474d3bec07c49f6205db4 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 9 Mar 2021 20:33:54 -0600 Subject: [PATCH 25/32] Changed ERROR to WARNING when a required Characteristic is missing Only throw a non-fatal warning instead of a fatal error if a Service is missing a required Characteristic. This allows for user flexibility in leaving out required Characteristics for Services that don't seem to need them (contrary to the HAP docs). Also, changed PositionState Characteristic back to Required (instead of Optional) in WindowCovering Service (as specified by HAP). If PositionState is not included this will only throw an error instead of a warning as a result of the above change. To Do: Update Example 13 to properly incorporate PositionState Characteristic. --- src/HomeSpan.cpp | 7 +++---- src/Span.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index ccea28d..c7f6d77 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -501,7 +501,7 @@ void Span::checkConnect(){ Serial.print("\nAuthorization Password: "); Serial.print(otaAuth?"Enabled\n\n":"DISABLED!\n\n"); } else { - Serial.print("\n*** Warning: Can't start OTA Server - Partition table used to compile this sketch is not configured for OTA.\n\n"); + Serial.print("\n*** WARNING: Can't start OTA Server - Partition table used to compile this sketch is not configured for OTA.\n\n"); } } @@ -1316,7 +1316,7 @@ void SpanAccessory::validate(){ if(chr->format!=STRING && (chr->uvGet(chr->value) < chr->uvGet(chr->minValue) || chr->uvGet(chr->value) > chr->uvGet(chr->maxValue))){ char c[256]; - sprintf(c," !Warning: Initial value of %lg for %s-%d is out of range [%llg,%llg]. This may cause device to be non-reponsive!\n", + sprintf(c," !WARNING: Initial value of %lg for %s-%d is out of range [%llg,%llg]. This may cause device to be non-reponsive!\n", chr->uvGet(chr->value),chr->hapName,chr->iid,chr->uvGet(chr->minValue),chr->uvGet(chr->maxValue)); homeSpan.configLog+=c; } @@ -1456,8 +1456,7 @@ void SpanService::validate(){ if(!valid){ homeSpan.configLog+=" !Characteristic " + String(req[i]->hapName); - homeSpan.configLog+=" *** ERROR! Required Characteristic for this Service not found. ***\n"; - homeSpan.nFatalErrors++; + homeSpan.configLog+=" *** WARNING! Required Characteristic for this Service not found. ***\n"; } } } diff --git a/src/Span.h b/src/Span.h index 7069572..f8eb3ce 100644 --- a/src/Span.h +++ b/src/Span.h @@ -365,7 +365,7 @@ namespace Service { struct WindowCovering : SpanService { WindowCovering() : SpanService{"8C","WindowCovering"}{ REQ(TargetPosition); REQ(CurrentPosition); - OPT(PositionState); + REQ(PositionState); OPT(Name); OPT(HoldPosition); OPT(CurrentHorizontalTiltAngle); From d2a7030640bd598c03a1904a94106c39bafc1eb1 Mon Sep 17 00:00:00 2001 From: Gregg Date: Tue, 9 Mar 2021 21:47:52 -0600 Subject: [PATCH 26/32] Reclaimed memory from REQ and OPT vectors after they are no longer needed. Lots more memory optimization to perform! --- src/HomeSpan.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index c7f6d77..1d0aba7 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -1459,6 +1459,9 @@ void SpanService::validate(){ homeSpan.configLog+=" *** WARNING! Required Characteristic for this Service not found. ***\n"; } } + + vector().swap(opt); + vector().swap(req); } /////////////////////////////// From 16aff0e8554a180b9f30b3e0247aa43ba8088fb3 Mon Sep 17 00:00:00 2001 From: Gregg Date: Wed, 10 Mar 2021 22:44:59 -0600 Subject: [PATCH 27/32] Updated formatting of Accessory Database output to Serial Monitor Used unicode arrows and symbols, and included more detailed information about each Service and Characteristic. --- src/HomeSpan.cpp | 63 ++++++++++++++++-------------------------------- src/HomeSpan.h | 40 +++++++++++++++++++++++++++--- src/src.ino | 11 +++++---- 3 files changed, 63 insertions(+), 51 deletions(-) diff --git a/src/HomeSpan.cpp b/src/HomeSpan.cpp index 1d0aba7..c6faa3c 100644 --- a/src/HomeSpan.cpp +++ b/src/HomeSpan.cpp @@ -121,6 +121,10 @@ void Span::poll() { homeSpan.Accessories.back()->validate(); } + if(nWarnings>0){ + configLog+="\n*** CAUTION: There " + String((nWarnings>1?"are ":"is ")) + String(nWarnings) + " WARNING" + (nWarnings>1?"S":"") + " associated with this configuration that may lead to the device becoming non-responsive, or operating in an unexpected manner. ***\n"; + } + processSerialCommand("i"); // print homeSpan configuration info if(nFatalErrors>0){ @@ -842,7 +846,7 @@ void Span::processSerialCommand(const char *c){ Serial.print("\n\n"); char d[]="------------------------------"; - Serial.printf("%-30s %s %10s %s %s %s %s %s\n","Service","Type","AID","IID","Update","Loop","Button","Linked Services"); + Serial.printf("%-30s %s %10s %s %s %s %s %s\n","Service","UUID","AID","IID","Update","Loop","Button","Linked Services"); Serial.printf("%.30s %.4s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d); for(int i=0;iServices.size();j++){ @@ -1277,7 +1281,7 @@ SpanAccessory::SpanAccessory(uint32_t aid){ this->aid=aid; } - homeSpan.configLog+="+Accessory-" + String(this->aid); + homeSpan.configLog+="\u27a4 Accessory: AID=" + String(this->aid); for(int i=0;iaid==homeSpan.Accessories[i]->aid){ @@ -1316,21 +1320,22 @@ void SpanAccessory::validate(){ if(chr->format!=STRING && (chr->uvGet(chr->value) < chr->uvGet(chr->minValue) || chr->uvGet(chr->value) > chr->uvGet(chr->maxValue))){ char c[256]; - sprintf(c," !WARNING: Initial value of %lg for %s-%d is out of range [%llg,%llg]. This may cause device to be non-reponsive!\n", - chr->uvGet(chr->value),chr->hapName,chr->iid,chr->uvGet(chr->minValue),chr->uvGet(chr->maxValue)); + sprintf(c," \u2718 Characteristic %s with IID=%d *** WARNING: Initial value of %lg is out of range [%llg,%llg]. ***\n", + chr->hapName,chr->iid,chr->uvGet(chr->value),chr->uvGet(chr->minValue),chr->uvGet(chr->maxValue)); homeSpan.configLog+=c; + homeSpan.nWarnings++; } } } if(!foundInfo){ - homeSpan.configLog+=" !Service AccessoryInformation"; + homeSpan.configLog+=" \u2718 Service AccessoryInformation"; homeSpan.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n"; homeSpan.nFatalErrors++; } if(!foundProtocol && (aid==1 || !homeSpan.isBridge)){ // HAPProtocolInformation must always be present in Accessory if aid=1, and any other Accessory if the device is not a bridge) - homeSpan.configLog+=" !Service HAPProtocolInformation"; + homeSpan.configLog+=" \u2718 Service HAPProtocolInformation"; homeSpan.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n"; homeSpan.nFatalErrors++; } @@ -1366,7 +1371,7 @@ SpanService::SpanService(const char *type, const char *hapName){ this->type=type; this->hapName=hapName; - homeSpan.configLog+="-->Service " + String(hapName); + homeSpan.configLog+=" \u279f Service " + String(hapName); if(homeSpan.Accessories.empty()){ homeSpan.configLog+=" *** ERROR! Can't create new Service without a defined Accessory! ***\n"; @@ -1377,7 +1382,7 @@ SpanService::SpanService(const char *type, const char *hapName){ homeSpan.Accessories.back()->Services.push_back(this); iid=++(homeSpan.Accessories.back()->iidCount); - homeSpan.configLog+="-" + String(iid) + String(" (") + String(type) + String(") "); + homeSpan.configLog+=": IID=" + String(iid) + ", UUID=0x" + String(type); if(!strcmp(this->type,"3E") && iid!=1){ homeSpan.configLog+=" *** ERROR! The AccessoryInformation Service must be defined before any other Services in an Accessory. ***"; @@ -1455,8 +1460,9 @@ void SpanService::validate(){ valid=!strcmp(req[i]->type,Characteristics[j]->type); if(!valid){ - homeSpan.configLog+=" !Characteristic " + String(req[i]->hapName); + homeSpan.configLog+=" \u2718 Characteristic " + String(req[i]->hapName); homeSpan.configLog+=" *** WARNING! Required Characteristic for this Service not found. ***\n"; + homeSpan.nWarnings++; } } @@ -1475,7 +1481,7 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar){ format=hapChar->format; staticRange=hapChar->staticRange; - homeSpan.configLog+="---->Characteristic " + String(hapName); + homeSpan.configLog+=" \u21e8 Characteristic " + String(hapName); if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ homeSpan.configLog+=" *** ERROR! Can't create new Characteristic without a defined Service! ***\n"; @@ -1488,35 +1494,6 @@ SpanCharacteristic::SpanCharacteristic(HapChar *hapChar){ aid=homeSpan.Accessories.back()->aid; ev=(boolean *)calloc(homeSpan.maxConnections,sizeof(boolean)); - - homeSpan.configLog+="-" + String(iid) + String(" (") + String(type) + String(") "); - - boolean valid=false; - - for(int i=0; !valid && iServices.back()->req.size(); i++) - valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type); - - for(int i=0; !valid && iServices.back()->opt.size(); i++) - valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->opt[i]->type); - - if(!valid){ - homeSpan.configLog+=" *** ERROR! Service does not support this Characteristic. ***"; - homeSpan.nFatalErrors++; - } - - boolean repeated=false; - - for(int i=0; !repeated && iServices.back()->Characteristics.size(); i++) - repeated=!strcmp(type,homeSpan.Accessories.back()->Services.back()->Characteristics[i]->type); - - if(valid && repeated){ - homeSpan.configLog+=" *** ERROR! Characteristic already defined for this Service. ***"; - homeSpan.nFatalErrors++; - } - - homeSpan.Accessories.back()->Services.back()->Characteristics.push_back(this); - - homeSpan.configLog+="\n"; } /////////////////////////////// @@ -1676,7 +1653,7 @@ unsigned long SpanCharacteristic::timeVal(){ SpanRange::SpanRange(int min, int max, int step){ if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty() || homeSpan.Accessories.back()->Services.back()->Characteristics.empty() ){ - homeSpan.configLog+="------>SpanRange: *** ERROR! Can't create new Range without a defined Characteristic! ***\n"; + homeSpan.configLog+=" \u2718 SpanRange: *** ERROR! Can't create new Range without a defined Characteristic! ***\n"; homeSpan.nFatalErrors++; } else { homeSpan.Accessories.back()->Services.back()->Characteristics.back()->setRange(min,max,step); @@ -1689,7 +1666,7 @@ SpanRange::SpanRange(int min, int max, int step){ SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime){ - homeSpan.configLog+="---->SpanButton: Pin=" + String(pin) + " Long/Single/Double=" + String(longTime) + "/" + String(singleTime) + "/" + String(doubleTime) + " ms"; + homeSpan.configLog+=" \u25bc SpanButton: Pin=" + String(pin) + ", Single=" + String(singleTime) + "ms, Double=" + String(doubleTime) + "ms, Long=" + String(longTime) + "ms"; if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){ homeSpan.configLog+=" *** ERROR! Can't create new PushButton without a defined Service! ***\n"; @@ -1707,8 +1684,10 @@ SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t this->doubleTime=doubleTime; service=homeSpan.Accessories.back()->Services.back(); - if((void(*)(int,int))(service->*(&SpanService::button))==(void(*)(int,int))(&SpanService::button)) + if((void(*)(int,int))(service->*(&SpanService::button))==(void(*)(int,int))(&SpanService::button)){ homeSpan.configLog+=" *** WARNING: No button() method defined for this PushButton! ***"; + homeSpan.nWarnings++; + } pushButton=new PushButton(pin); // create underlying PushButton diff --git a/src/HomeSpan.h b/src/HomeSpan.h index 6744bd7..fbf2cde 100644 --- a/src/HomeSpan.h +++ b/src/HomeSpan.h @@ -100,6 +100,7 @@ struct Span{ unsigned long snapTime; // current time (in millis) snapped before entering Service loops() or updates() boolean isInitialized=false; // flag indicating HomeSpan has been initialized int nFatalErrors=0; // number of fatal errors in user-defined configuration + int nWarnings=0; // number of warnings errors in user-defined configuration String configLog; // log of configuration process, including any errors boolean isBridge=true; // flag indicating whether device is configured as a bridge (i.e. first Accessory contains nothing but AccessoryInformation and HAPProtocolInformation) HapQR qrCode; // optional QR Code to use for pairing @@ -342,7 +343,7 @@ struct SpanCharacteristic{ template SpanCharacteristic *setRange(A min, B max, S step=0){ char c[256]; - homeSpan.configLog+=String("------>Set Range for ") + String(hapName) + "-" + String(iid); + homeSpan.configLog+=String(" \u2b0c Set Range for ") + String(hapName) + " with IID=" + String(iid); if(customRange){ sprintf(c," *** ERROR! Range already set for this Characteristic! ***\n"); @@ -360,9 +361,9 @@ struct SpanCharacteristic{ customRange=true; if(uvGet(stepValue)>0) - sprintf(c,": %s/%s/%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue)); + sprintf(c,": Min=%s, Max=%s, Step=%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue)); else - sprintf(c,": %s/%s\n",uvPrint(minValue),uvPrint(maxValue)); + sprintf(c,": Min=%s, Max=%s\n",uvPrint(minValue),uvPrint(maxValue)); } homeSpan.configLog+=c; return(this); @@ -376,7 +377,38 @@ struct SpanCharacteristic{ uvSet(minValue,min); uvSet(maxValue,max); uvSet(stepValue,0); - + + homeSpan.configLog+="(" + uvPrint(value) + ")" + ": IID=" + String(iid) + ", UUID=0x" + String(type); + if(format!=STRING && format!=BOOL) + homeSpan.configLog+= " Range=[" + String(uvPrint(minValue)) + "," + String(uvPrint(maxValue)) + "]"; + + boolean valid=false; + + for(int i=0; !valid && iServices.back()->req.size(); i++) + valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type); + + for(int i=0; !valid && iServices.back()->opt.size(); i++) + valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->opt[i]->type); + + if(!valid){ + homeSpan.configLog+=" *** ERROR! Service does not support this Characteristic. ***"; + homeSpan.nFatalErrors++; + } + + boolean repeated=false; + + for(int i=0; !repeated && iServices.back()->Characteristics.size(); i++) + repeated=!strcmp(type,homeSpan.Accessories.back()->Services.back()->Characteristics[i]->type); + + if(valid && repeated){ + homeSpan.configLog+=" *** ERROR! Characteristic already defined for this Service. ***"; + homeSpan.nFatalErrors++; + } + + homeSpan.Accessories.back()->Services.back()->Characteristics.push_back(this); + + homeSpan.configLog+="\n"; + } // init() template T getVal(){ diff --git a/src/src.ino b/src/src.ino index eff4b47..3becb91 100644 --- a/src/src.ino +++ b/src/src.ino @@ -14,7 +14,7 @@ void setup() { homeSpan.setPortNum(1201); // homeSpan.setMaxConnections(6); // homeSpan.setQRID("One1"); - homeSpan.enableOTA(); +// homeSpan.enableOTA(); homeSpan.setSketchVersion("Test 1.3.1"); homeSpan.setWifiCallback(wifiEstablished); @@ -30,20 +30,21 @@ void setup() { 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 Service::HAPProtocolInformation(); // Create the HAP Protcol Information Service new Characteristic::Version("1.1.0"); // Set the Version Characteristic to "1.1.0" as required by HAP new Service::LightBulb(); - new Characteristic::On(); +// new Characteristic::On(); new Characteristic::Brightness(); new Characteristic::Name("Light 1"); new Service::LightBulb(); - new Characteristic::On(); - new Characteristic::Brightness(); + new Characteristic::On(2); + (new Characteristic::Brightness(150))->setRange(0,140,5); new Characteristic::Name("Light 2"); (new Service::Switch())->setPrimary(); new Characteristic::On(); new Characteristic::Name("Switch 3"); + new SpanButton(17); } // end of setup() From a89ddf37487b0a77f68fb402f36f10d5311098ee Mon Sep 17 00:00:00 2001 From: Gregg Date: Fri, 12 Mar 2021 09:45:50 -0600 Subject: [PATCH 28/32] Updated Example 13 - Window Shade to show proper use of Characteristic Current Position Also added discussion of why Characteristic Position State is not needed even though it is required. --- examples/13-TargetStates/DEV_DoorsWindows.h | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/13-TargetStates/DEV_DoorsWindows.h b/examples/13-TargetStates/DEV_DoorsWindows.h index 672e450..c4c7a54 100644 --- a/examples/13-TargetStates/DEV_DoorsWindows.h +++ b/examples/13-TargetStates/DEV_DoorsWindows.h @@ -72,7 +72,6 @@ struct DEV_WindowShade : Service::WindowCovering { // A motorized Window Sha DEV_WindowShade() : Service::WindowCovering(){ // constructor() method current=new Characteristic::CurrentPosition(0); // Window Shades have positions that range from 0 (fully lowered) to 100 (fully raised) - current->setRange(0,100,10); // set the allowable current-position range to 0-100 IN STEPS of 10 target=new Characteristic::TargetPosition(0); // Window Shades have positions that range from 0 (fully lowered) to 100 (fully raised) target->setRange(0,100,10); // set the allowable target-position range to 0-100 IN STEPS of 10 @@ -106,20 +105,21 @@ struct DEV_WindowShade : Service::WindowCovering { // A motorized Window Sha void loop(){ // loop() method - // Here we simulate a window shade that moves 10% higher or lower every 1 second as it seeks to reach its target-position + // Here we simulate a window shade that takes 5 seconds to move to its new target posiiton - if(current->timeVal()>1000){ // if 1 second has elapsed since the current-position was last modified - if(target->getVal()>current->getVal()){ // increase the current-position by 10 if the target-position is greater than the current-position - current->setVal(current->getVal()+10); - } else - if(target->getVal()getVal()){ // else decrease the current-position by 10 if the target-position is less than the current-position - current->setVal(current->getVal()-10); - } + if(target->timeVal()>5000){ // if 5 seconds have elapsed since the target-position was last modified... + current->setVal(target->getVal()); // ...set the current position to equal the target position } - // Note we do NOTHING if target-positon and current-position is the same - HomeKit will detect this and adjust its tile icon accordingly. - // Unlike the Garage Door Service above, we do not need to set any Characteristic telling HomeKit the shade is actually raising, lowering, or stopped. - // HomeKit figures this out automatically, which is very good, though unfortunately inconsistent with the HAP Documentation. + // Note there is no reason to send continuous updates of the current position to the HomeKit. HomeKit does NOT display the + // current position. Rather, it simply compares the value of the current position to the value of target positon as set by the + // the user in the Home App. If it finds current and target positions are the same, it knows the shade is stopped. Otherwise + // it will report the shade is raising or lowering depending on whether the specified target state is greater or less than + // the current state. + + // According to HAP, the Characteristic Position State is also required. However, this seems duplicative and is NOT needed + // at all given the way HomeKit uses current position. HomeSpan will warn you if Position State is not defined (since it + // is technically required) but this works fine without it. } // loop From b90f173a6ff883dbba45cb98dd4fa5ae26d5a412 Mon Sep 17 00:00:00 2001 From: Gregg Date: Sat, 13 Mar 2021 06:31:18 -0600 Subject: [PATCH 29/32] Set version number to 1.2.1 in preparation for release --- library.properties | 2 +- src/Settings.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 3972eb8..162b33d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=HomeSpan -version=1.2.0 +version=1.2.1 author=Gregg maintainer=Gregg sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE. diff --git a/src/Settings.h b/src/Settings.h index a7a445b..f171e7f 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -34,7 +34,7 @@ #define HS_MAJOR 1 #define HS_MINOR 2 -#define HS_PATCH 0 +#define HS_PATCH 1 #define STRINGIFY(x) _STR(x) #define _STR(x) #x From 48127a338015871d405978440eade8cd51295636 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 13 Mar 2021 07:03:18 -0600 Subject: [PATCH 30/32] Update Reference.md --- docs/Reference.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/Reference.md b/docs/Reference.md index b9af9d3..9f73bcf 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -168,20 +168,22 @@ The following methods are supported: * returns *true* if a HomeKit Controller has requested an update to the value of the Characteristic, otherwise *false*. The requested value itself can retrieved with `getNewVal<>()` * `void setVal(value)` - * sets the value of the Characteristic to *value*, and notifies all HomeKit Controllers of the change. Works with any integer, boolean, or floating-based numerical *value*, though HomeSpan will convert *value* into the appropriate type for each Characteristic (e.g. value=5.5 is converted to 5 if used with an integer-based Characteristic) - * throws a runtime warning if *value* is outside of the min/max range for the Characteristic, where min/max is either the HAP default, or any new values set via a prior call to `setRange()` - * accepts any *value* within the allowed min/max range regardless of the setting of step size. Step size is only used by the Home App to limit the increments of adjustment for sliders, and will use a rounded version of *value* for display purposes of the slider while retaining the actual numerical value internally + * sets the value of the Characteristic to *value*, and notifies all HomeKit Controllers of the change + * works with any integer, boolean, or floating-based numerical *value*, though HomeSpan will convert *value* into the appropriate type for each Characteristic (e.g. calling `setValue(5.5)` on an integer-based Characteristic results in *value*=5) + * throws a runtime warning if *value* is outside of the min/max range for the Characteristic, where min/max is either the HAP default, or any new min/max range set via a prior call to `setRange()` + * *value* is **not** restricted to being an increment of the step size; for example it is perfectly valid to call `setVal(43.5)` after calling `setRange(0,100,5)` on a floating-based Characteristic even though 43.5 does does not align with the step size specified. The Home App will properly retain the value as 43.5, though it will round to the nearest step size increment (in this case 45) when used in a slider graphic (such as setting the temperature of a thermostat) * `int timeVal()` * returns time elapsed (in millis) since value of the Characteristic was last updated (whether by `setVal()` or as the result of a successful update request from a HomeKit Controller) * `SpanCharacteristic *setRange(min, max, step)` - * overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* values specified - * only applicable for Characteristics that support value ranges, else error is thrown - * can only set set once per Characteristic. Calling setRange twice for the same Characteristic throws an error - * works with any integer or floating-based parameters, though HomeSpan will recast the values into the appropriate format for the Characteristic, which means if you specify *step*=0.5 for a UINT8 Characteristic, *step* will be truncated to zero - * *step* is an optional parameter. If unspecified, or set to zero or a negative number, the default HAP step size remains unchanged - * Returns a pointer to the Characteristic itself so that the method can be chained during instantiation + * overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* parameters specified + * *step* is optional; if unspecified (or set to a non-positive number), the default HAP step size remains unchanged + * works with any integer or floating-based parameters, though HomeSpan will recast the parameters into the appropriate type for each Characteristic (e.g. calling `setRange(50.5,70.3,0.5)` on an integer-based Characteristic results in *min*=50, *max*=70, and *step*=0) + * an error is thrown if: + * called on a Characteristic that does not suport range changes, or + * called more than once on the same Characteristic + * returns a pointer to the Characteristic itself so that the method can be chained during instantiation * example: `(new Characteristic::Brightness(50))->setRange(10,100,5);` ## *SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime)* From 6df48a32ddaceaab68813043a72a701c0837c7ca Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 13 Mar 2021 07:22:58 -0600 Subject: [PATCH 31/32] Update README.md --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index fbe9dd9..19d5273 100644 --- a/docs/README.md +++ b/docs/README.md @@ -37,9 +37,9 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A * Launch the WiFi Access Point * A standalone, detailed End-User Guide -## Latest Update (2/18/2021) +## Latest Update (3/13/2021) -* HomeSpan 1.2.0 - HomeSpan now suports Over-the-Air ([OTA](https://github.com/HomeSpan/HomeSpan/blob/master/docs/OTA.md)) updates directly from the Arduino IDE (no serial connection needed)! This release also adds support for Linked Services and includes a new [tutorial example](https://github.com/HomeSpan/HomeSpan/blob/master/docs/Tutorials.md#example-17---linkedservices) demonstrating how Linked Services can be used to implement a multi-headed spa shower. Other new features include the ability to set the version number of your sketch (helpful when using OTA updates), and a method for specifying a user-defined function to callback after WiFi connectivity is established. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details. +* HomeSpan 1.2.1 - This update adds run-time range-checking for all Characteristics and will warn you if the initial value you set for a Characteristic, or any subsequent changes you make to that value, are outside the Characteristic's allowable min/max range. This helps diagnosis "No Response" errors in the Home App. This update also introduces `setRange(min,max,step)` as a new and more robust method for changing a Characteristic's range. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details on all changes includes in this update. # HomeSpan Resources From 01ae18e133ee3c78d4f9bfcecfa82a205e71e7c6 Mon Sep 17 00:00:00 2001 From: HomeSpan Date: Sat, 13 Mar 2021 07:23:39 -0600 Subject: [PATCH 32/32] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 19d5273..8a65e98 100644 --- a/docs/README.md +++ b/docs/README.md @@ -39,7 +39,7 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A ## Latest Update (3/13/2021) -* HomeSpan 1.2.1 - This update adds run-time range-checking for all Characteristics and will warn you if the initial value you set for a Characteristic, or any subsequent changes you make to that value, are outside the Characteristic's allowable min/max range. This helps diagnosis "No Response" errors in the Home App. This update also introduces `setRange(min,max,step)` as a new and more robust method for changing a Characteristic's range. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details on all changes includes in this update. +* HomeSpan 1.2.1 - This update adds run-time range-checking for all Characteristics and will warn you if the initial value you set for a Characteristic, or any subsequent changes you make to that value, are outside the Characteristic's allowable min/max range. This helps diagnosis "No Response" errors in the Home App. This update also introduces `setRange(min,max,step)` as a new and more robust method for changing a Characteristic's range. See [Release](https://github.com/HomeSpan/HomeSpan/releases) for details on all changes included in this update. # HomeSpan Resources