commit
6aba1a28e5
|
|
@ -37,9 +37,9 @@ HomeSpan provides a microcontroller-focused implementation of [Apple's HomeKit A
|
||||||
* Launch the WiFi Access Point
|
* Launch the WiFi Access Point
|
||||||
* A standalone, detailed End-User Guide
|
* 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 included in this update.
|
||||||
|
|
||||||
# HomeSpan Resources
|
# HomeSpan Resources
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
* 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
|
* 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);`
|
* example: `new Characteristic::Brightness(50);`
|
||||||
|
|
||||||
The following methods are supported:
|
The following methods are supported:
|
||||||
|
|
@ -167,18 +168,23 @@ 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<>()`
|
* 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)`
|
* `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*, 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()`
|
* `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)
|
* 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)
|
||||||
|
|
||||||
## *SpanRange(int min, int max, int step)*
|
* `SpanCharacteristic *setRange(min, max, step)`
|
||||||
|
* overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* parameters specified
|
||||||
Creating an instance of this **class** overrides the default HAP range for a Characteristic with the *min*, *max*, and *step* values 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)
|
||||||
* instantiated Ranges are added to the HomeSpan HAP Database and associated with the last Characteristic instantiated
|
* an error is thrown if:
|
||||||
* instantiating a Range without first instantiating a Characteristic throws an error during initialization
|
* called on a Characteristic that does not suport range changes, or
|
||||||
* example: `new Characteristic::Brightness(50); new SpanRange(10,100,5);`
|
* 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)*
|
## *SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime)*
|
||||||
|
|
||||||
|
|
@ -213,6 +219,17 @@ If REQUIRED is defined in the main sketch prior to including the HomeSpan librar
|
||||||
```C++
|
```C++
|
||||||
#define REQUIRED VERISON(2,1,3) // throws a compile-time error unless HomeSpan library used is version 2.1.3 or later
|
#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**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ Additionally, when first starting up, HomeSpan begins by validating the device's
|
||||||
|TargetHumidifierDehumidifierState|uint8_t|0|
|
|TargetHumidifierDehumidifierState|uint8_t|0|
|
||||||
|TargetPosition|uint8_t|0|
|
|TargetPosition|uint8_t|0|
|
||||||
|TargetDoorState|uint8_t|1|
|
|TargetDoorState|uint8_t|1|
|
||||||
|
|TargetHeaterCoolerState|uint8_t|0|
|
||||||
|TargetHeatingCoolingState|uint8_t|0|
|
|TargetHeatingCoolingState|uint8_t|0|
|
||||||
|TargetRelativeHumidity|double|0|
|
|TargetRelativeHumidity|double|0|
|
||||||
|TargetTemperature|double|16|
|
|TargetTemperature|double|16|
|
||||||
|
|
|
||||||
|
|
@ -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 - 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:
|
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 - 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:
|
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:
|
||||||
|
|
|
||||||
|
|
@ -61,31 +61,40 @@ void setup() {
|
||||||
new Characteristic::Version("1.1.0");
|
new Characteristic::Version("1.1.0");
|
||||||
|
|
||||||
new Service::LightBulb();
|
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::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)
|
// 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 Service::Fan();
|
||||||
new Characteristic::Active();
|
new Characteristic::Active();
|
||||||
new Characteristic::RotationDirection(); // NEW: This allows control of the Rotation Direction of the Fan
|
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 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%
|
||||||
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%
|
|
||||||
|
|
||||||
|
|
||||||
// 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.
|
// 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,
|
// 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
|
// 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.
|
// 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
|
// 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%. SpanRange(min,max,step) can be used to over-ride this default. SpanRange is generic and can be used wih other Characteristics
|
// 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
|
||||||
// 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
|
|
||||||
// HomeKit experience. This is because the LightBulb power is controlled by the On Characteristic, and allowing Brightness to be as low as 0%
|
// 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
|
// 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.
|
// some Brightness value whenever the LightBulb is turned on.
|
||||||
|
|
||||||
} // end of setup()
|
} // end of setup()
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
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)
|
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->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.
|
this->pwmPin=new PwmPin(channel, ledPin); // NEW! Configures the PWM channel and attach the specified ledPin. pinMode() does NOT need to be called.
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
power=new Characteristic::On();
|
||||||
|
|
||||||
level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50%
|
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->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.
|
this->pwmPin=new PwmPin(channel, ledPin); // configure the PWM channel and attach the specified ledPin. pinMode() does NOT need to be called.
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
power=new Characteristic::On();
|
||||||
|
|
||||||
level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50%
|
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->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.
|
this->pwmPin=new PwmPin(channel, ledPin); // configure the PWM channel and attach the specified ledPin. pinMode() does NOT need to be called.
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
power=new Characteristic::On();
|
||||||
|
|
||||||
level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50%
|
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->channel=channel; // save the channel number (from 0-15)
|
||||||
this->ledPin=ledPin; // LED pin number <- NEW!!
|
this->ledPin=ledPin; // LED pin number <- NEW!!
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
power=new Characteristic::On();
|
||||||
|
|
||||||
level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50%
|
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->channel=channel; // save the channel number (from 0-15)
|
||||||
this->ledPin=ledPin; // save LED pin number
|
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
|
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%
|
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%
|
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->redChannel=redChannel; // save the channel number (from 0-15)
|
||||||
this->greenChannel=greenChannel;
|
this->greenChannel=greenChannel;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
power=new Characteristic::On();
|
||||||
|
|
||||||
level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50%
|
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->channel=channel; // save the channel number (from 0-15)
|
||||||
this->ledPin=ledPin; // save LED pin number
|
this->ledPin=ledPin; // save LED pin number
|
||||||
|
|
|
||||||
|
|
@ -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
|
// 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.
|
// 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(-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
|
Serial.print("Configuring Temperature Sensor"); // initialization message
|
||||||
Serial.print("\n");
|
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
|
if(temp->timeVal()>5000){ // check time elapsed since last update and proceed only if greater than 5 seconds
|
||||||
float temperature=temp->getVal<float>()+0.5; // "simulate" a half-degree temperature change...
|
float temperature=temp->getVal<float>()+0.5; // "simulate" a half-degree temperature change...
|
||||||
if(temperature>35.0) // ...but cap the maximum at 35C before starting over at 10C
|
if(temperature>35.0) // ...but cap the maximum at 35C before starting over at -30C
|
||||||
temperature=10.0;
|
temperature=-30.0;
|
||||||
|
|
||||||
temp->setVal(temperature); // set the new temperature; this generates an Event Notification and also resets the elapsed time
|
temp->setVal(temperature); // set the new temperature; this generates an Event Notification and also resets the elapsed time
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,11 +71,10 @@ struct DEV_WindowShade : Service::WindowCovering { // A motorized Window Sha
|
||||||
|
|
||||||
DEV_WindowShade() : Service::WindowCovering(){ // constructor() method
|
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)
|
current=new Characteristic::CurrentPosition(0); // Window 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
|
|
||||||
|
|
||||||
target=new Characteristic::TargetPosition(0); // Windows Shades have positions that range from 0 (fully lowered) to 100 (fully raised)
|
target=new Characteristic::TargetPosition(0); // Window 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->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("Configuring Motorized Window Shade"); // initialization message
|
||||||
Serial.print("\n");
|
Serial.print("\n");
|
||||||
|
|
@ -106,20 +105,21 @@ struct DEV_WindowShade : Service::WindowCovering { // A motorized Window Sha
|
||||||
|
|
||||||
void loop(){ // loop() method
|
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->timeVal()>5000){ // if 5 seconds have elapsed since the target-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(target->getVal()); // ...set the current position to equal the target position
|
||||||
current->setVal(current->getVal()+10);
|
|
||||||
} else
|
|
||||||
if(target->getVal()<current->getVal()){ // else decrease the current-position by 10 if the target-position is less than the current-position
|
|
||||||
current->setVal(current->getVal()-10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note we do NOTHING if target-positon and current-position is the same - HomeKit will detect this and adjust its tile icon accordingly.
|
// Note there is no reason to send continuous updates of the current position to the HomeKit. HomeKit does NOT display the
|
||||||
// Unlike the Garage Door Service above, we do not need to set any Characteristic telling HomeKit the shade is actually raising, lowering, or stopped.
|
// current position. Rather, it simply compares the value of the current position to the value of target positon as set by the
|
||||||
// HomeKit figures this out automatically, which is very good, though unfortunately inconsistent with the HAP Documentation.
|
// 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
|
} // loop
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
|
||||||
power=new Characteristic::On();
|
power=new Characteristic::On();
|
||||||
|
|
||||||
level=new Characteristic::Brightness(favoriteLevel); // Brightness Characteristic with an initial value equal to the favorite level
|
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
|
// 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
|
// 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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name=HomeSpan
|
name=HomeSpan
|
||||||
version=1.2.0
|
version=1.2.1
|
||||||
author=Gregg <homespan@icloud.com>
|
author=Gregg <homespan@icloud.com>
|
||||||
maintainer=Gregg <homespan@icloud.com>
|
maintainer=Gregg <homespan@icloud.com>
|
||||||
sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE.
|
sentence=A robust and extremely easy-to-use HomeKit implementation for the Espressif ESP32 running on the Arduino IDE.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*********************************************************************************
|
||||||
|
* 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=0,
|
||||||
|
UINT8=1,
|
||||||
|
UINT16=2,
|
||||||
|
UINT32=3,
|
||||||
|
UINT64=4,
|
||||||
|
INT=5,
|
||||||
|
FLOAT=6,
|
||||||
|
STRING=7
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
struct HapChar {
|
||||||
|
const char *type;
|
||||||
|
const char *hapName;
|
||||||
|
PERMS perms;
|
||||||
|
FORMAT format;
|
||||||
|
boolean staticRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
#define HAPCHAR(hapName,type,perms,format,staticRange) HapChar hapName {#type,#hapName,(PERMS)(perms),format,staticRange}
|
||||||
|
|
||||||
|
struct HapCharacteristics {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
@ -86,130 +86,3 @@ enum class StatusCode {
|
||||||
InvalidValue=-70410,
|
InvalidValue=-70410,
|
||||||
TBD=-1 // status To-Be-Determined (TBD) once service.update() called - internal use only
|
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}
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HapCharList {
|
|
||||||
|
|
||||||
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 );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
|
||||||
281
src/HomeSpan.cpp
281
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)
|
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)
|
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 //
|
// Span //
|
||||||
|
|
@ -120,6 +121,10 @@ void Span::poll() {
|
||||||
homeSpan.Accessories.back()->validate();
|
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
|
processSerialCommand("i"); // print homeSpan configuration info
|
||||||
|
|
||||||
if(nFatalErrors>0){
|
if(nFatalErrors>0){
|
||||||
|
|
@ -500,7 +505,7 @@ void Span::checkConnect(){
|
||||||
Serial.print("\nAuthorization Password: ");
|
Serial.print("\nAuthorization Password: ");
|
||||||
Serial.print(otaAuth?"Enabled\n\n":"DISABLED!\n\n");
|
Serial.print(otaAuth?"Enabled\n\n":"DISABLED!\n\n");
|
||||||
} else {
|
} 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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -841,7 +846,7 @@ void Span::processSerialCommand(const char *c){
|
||||||
Serial.print("\n\n");
|
Serial.print("\n\n");
|
||||||
|
|
||||||
char d[]="------------------------------";
|
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);
|
Serial.printf("%.30s %.4s %.10s %.3s %.6s %.4s %.6s %.15s\n",d,d,d,d,d,d,d,d);
|
||||||
for(int i=0;i<Accessories.size();i++){ // identify all services with over-ridden loop() methods
|
for(int i=0;i<Accessories.size();i++){ // identify all services with over-ridden loop() methods
|
||||||
for(int j=0;j<Accessories[i]->Services.size();j++){
|
for(int j=0;j<Accessories[i]->Services.size();j++){
|
||||||
|
|
@ -1203,10 +1208,10 @@ int Span::sprintfAttributes(char **ids, int numIDs, int flags, char *cBuf){
|
||||||
|
|
||||||
for(int i=0;i<numIDs;i++){ // PASS 1: loop over all ids requested to check status codes - only errors are if characteristic not found, or not readable
|
for(int i=0;i<numIDs;i++){ // PASS 1: loop over all ids requested to check status codes - only errors are if characteristic not found, or not readable
|
||||||
sscanf(ids[i],"%u.%d",&aid,&iid); // parse aid and iid
|
sscanf(ids[i],"%u.%d",&aid,&iid); // parse aid and iid
|
||||||
Characteristics[i]=find(aid,iid); // find matching chararacteristic
|
Characteristics[i]=find(aid,iid); // find matching chararacteristic
|
||||||
|
|
||||||
if(Characteristics[i]){ // if found
|
if(Characteristics[i]){ // if found
|
||||||
if(Characteristics[i]->perms&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)
|
status[i]=StatusCode::OK; // always set status to OK (since no actual reading of device is needed)
|
||||||
} else {
|
} else {
|
||||||
Characteristics[i]=NULL;
|
Characteristics[i]=NULL;
|
||||||
|
|
@ -1276,7 +1281,7 @@ SpanAccessory::SpanAccessory(uint32_t aid){
|
||||||
this->aid=aid;
|
this->aid=aid;
|
||||||
}
|
}
|
||||||
|
|
||||||
homeSpan.configLog+="+Accessory-" + String(this->aid);
|
homeSpan.configLog+="\u27a4 Accessory: AID=" + String(this->aid);
|
||||||
|
|
||||||
for(int i=0;i<homeSpan.Accessories.size()-1;i++){
|
for(int i=0;i<homeSpan.Accessories.size()-1;i++){
|
||||||
if(this->aid==homeSpan.Accessories[i]->aid){
|
if(this->aid==homeSpan.Accessories[i]->aid){
|
||||||
|
|
@ -1309,16 +1314,28 @@ void SpanAccessory::validate(){
|
||||||
foundProtocol=true;
|
foundProtocol=true;
|
||||||
else if(aid==1) // this is an Accessory with aid=1, but it has more than just AccessoryInfo and HAPProtocolInformation. So...
|
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
|
homeSpan.isBridge=false; // ...this is not a bridge device
|
||||||
|
|
||||||
|
for(int j=0;j<Services[i]->Characteristics.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<double>(chr->value) < chr->uvGet<double>(chr->minValue) || chr->uvGet<double>(chr->value) > chr->uvGet<double>(chr->maxValue))){
|
||||||
|
char c[256];
|
||||||
|
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<double>(chr->value),chr->uvGet<double>(chr->minValue),chr->uvGet<double>(chr->maxValue));
|
||||||
|
homeSpan.configLog+=c;
|
||||||
|
homeSpan.nWarnings++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!foundInfo){
|
if(!foundInfo){
|
||||||
homeSpan.configLog+=" !Service AccessoryInformation";
|
homeSpan.configLog+=" \u2718 Service AccessoryInformation";
|
||||||
homeSpan.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n";
|
homeSpan.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n";
|
||||||
homeSpan.nFatalErrors++;
|
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)
|
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.configLog+=" *** ERROR! Required Service for this Accessory not found. ***\n";
|
||||||
homeSpan.nFatalErrors++;
|
homeSpan.nFatalErrors++;
|
||||||
}
|
}
|
||||||
|
|
@ -1354,7 +1371,7 @@ SpanService::SpanService(const char *type, const char *hapName){
|
||||||
this->type=type;
|
this->type=type;
|
||||||
this->hapName=hapName;
|
this->hapName=hapName;
|
||||||
|
|
||||||
homeSpan.configLog+="-->Service " + String(hapName);
|
homeSpan.configLog+=" \u279f Service " + String(hapName);
|
||||||
|
|
||||||
if(homeSpan.Accessories.empty()){
|
if(homeSpan.Accessories.empty()){
|
||||||
homeSpan.configLog+=" *** ERROR! Can't create new Service without a defined Accessory! ***\n";
|
homeSpan.configLog+=" *** ERROR! Can't create new Service without a defined Accessory! ***\n";
|
||||||
|
|
@ -1365,7 +1382,7 @@ SpanService::SpanService(const char *type, const char *hapName){
|
||||||
homeSpan.Accessories.back()->Services.push_back(this);
|
homeSpan.Accessories.back()->Services.push_back(this);
|
||||||
iid=++(homeSpan.Accessories.back()->iidCount);
|
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){
|
if(!strcmp(this->type,"3E") && iid!=1){
|
||||||
homeSpan.configLog+=" *** ERROR! The AccessoryInformation Service must be defined before any other Services in an Accessory. ***";
|
homeSpan.configLog+=" *** ERROR! The AccessoryInformation Service must be defined before any other Services in an Accessory. ***";
|
||||||
|
|
@ -1440,26 +1457,31 @@ void SpanService::validate(){
|
||||||
for(int i=0;i<req.size();i++){
|
for(int i=0;i<req.size();i++){
|
||||||
boolean valid=false;
|
boolean valid=false;
|
||||||
for(int j=0;!valid && j<Characteristics.size();j++)
|
for(int j=0;!valid && j<Characteristics.size();j++)
|
||||||
valid=!strcmp(req[i]->id,Characteristics[j]->type);
|
valid=!strcmp(req[i]->type,Characteristics[j]->type);
|
||||||
|
|
||||||
if(!valid){
|
if(!valid){
|
||||||
homeSpan.configLog+=" !Characteristic " + String(req[i]->name);
|
homeSpan.configLog+=" \u2718 Characteristic " + String(req[i]->hapName);
|
||||||
homeSpan.configLog+=" *** ERROR! Required Characteristic for this Service not found. ***\n";
|
homeSpan.configLog+=" *** WARNING! Required Characteristic for this Service not found. ***\n";
|
||||||
homeSpan.nFatalErrors++;
|
homeSpan.nWarnings++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<HapChar *>().swap(opt);
|
||||||
|
vector<HapChar *>().swap(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
// SpanCharacteristic //
|
// SpanCharacteristic //
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, const char *hapName){
|
SpanCharacteristic::SpanCharacteristic(HapChar *hapChar){
|
||||||
this->type=type;
|
type=hapChar->type;
|
||||||
this->perms=perms;
|
perms=hapChar->perms;
|
||||||
this->hapName=hapName;
|
hapName=hapChar->hapName;
|
||||||
|
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()){
|
if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){
|
||||||
homeSpan.configLog+=" *** ERROR! Can't create new Characteristic without a defined Service! ***\n";
|
homeSpan.configLog+=" *** ERROR! Can't create new Characteristic without a defined Service! ***\n";
|
||||||
|
|
@ -1472,92 +1494,6 @@ SpanCharacteristic::SpanCharacteristic(const char *type, uint8_t perms, const ch
|
||||||
aid=homeSpan.Accessories.back()->aid;
|
aid=homeSpan.Accessories.back()->aid;
|
||||||
|
|
||||||
ev=(boolean *)calloc(homeSpan.maxConnections,sizeof(boolean));
|
ev=(boolean *)calloc(homeSpan.maxConnections,sizeof(boolean));
|
||||||
|
|
||||||
homeSpan.configLog+="-" + String(iid) + String(" (") + String(type) + String(") ");
|
|
||||||
|
|
||||||
boolean valid=false;
|
|
||||||
|
|
||||||
for(int i=0; !valid && i<homeSpan.Accessories.back()->Services.back()->req.size(); i++)
|
|
||||||
valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->id);
|
|
||||||
|
|
||||||
for(int i=0; !valid && i<homeSpan.Accessories.back()->Services.back()->opt.size(); i++)
|
|
||||||
valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->opt[i]->id);
|
|
||||||
|
|
||||||
if(!valid){
|
|
||||||
homeSpan.configLog+=" *** ERROR! Service does not support this Characteristic. ***";
|
|
||||||
homeSpan.nFatalErrors++;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean repeated=false;
|
|
||||||
|
|
||||||
for(int i=0; !repeated && i<homeSpan.Accessories.back()->Services.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";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
@ -1575,53 +1511,21 @@ int SpanCharacteristic::sprintfAttributes(char *cBuf, int flags){
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"type\":\"%s\"",type);
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"type\":\"%s\"",type);
|
||||||
|
|
||||||
if(perms&PR){
|
if(perms&PR){
|
||||||
|
if(perms&NV && !(flags&GET_NV))
|
||||||
if(perms&NV && !(flags&GET_NV)){
|
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":null");
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":null");
|
||||||
} else {
|
else
|
||||||
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":%s",uvPrint(value).c_str());
|
||||||
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);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STRING:
|
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"value\":\"%s\"",value.STRING);
|
|
||||||
break;
|
|
||||||
|
|
||||||
} // switch
|
|
||||||
} // print Characteristic value
|
|
||||||
} // permissions=PR
|
|
||||||
|
|
||||||
if(flags&GET_META){
|
if(flags&GET_META){
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"format\":\"%s\"",formatCodes[format]);
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",\"format\":\"%s\"",formatCodes[format]);
|
||||||
|
|
||||||
if(range && (flags&GET_META))
|
if(customRange && (flags&GET_META)){
|
||||||
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minValue\":%d,\"maxValue\":%d,\"minStep\":%d",range->min,range->max,range->step);
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minValue\":%s,\"maxValue\":%s",uvPrint(minValue).c_str(),uvPrint(maxValue).c_str());
|
||||||
|
|
||||||
|
if(uvGet<float>(stepValue)>0)
|
||||||
|
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?128:0,",\"minStep\":%s",uvPrint(stepValue).c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(desc && (flags&GET_DESC)){
|
if(desc && (flags&GET_DESC)){
|
||||||
|
|
@ -1737,72 +1641,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;
|
|
||||||
|
|
||||||
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(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(){
|
unsigned long SpanCharacteristic::timeVal(){
|
||||||
|
|
||||||
return(homeSpan.snapTime-updateTime);
|
return(homeSpan.snapTime-updateTime);
|
||||||
|
|
@ -1813,20 +1651,13 @@ unsigned long SpanCharacteristic::timeVal(){
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
SpanRange::SpanRange(int min, int max, int step){
|
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() ){
|
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+=" \u2718 SpanRange: *** ERROR! Can't create new Range without a defined Characteristic! ***\n";
|
||||||
homeSpan.nFatalErrors++;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
@ -1835,7 +1666,7 @@ SpanRange::SpanRange(int min, int max, int step){
|
||||||
|
|
||||||
SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t doubleTime){
|
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()){
|
if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty()){
|
||||||
homeSpan.configLog+=" *** ERROR! Can't create new PushButton without a defined Service! ***\n";
|
homeSpan.configLog+=" *** ERROR! Can't create new PushButton without a defined Service! ***\n";
|
||||||
|
|
@ -1853,8 +1684,10 @@ SpanButton::SpanButton(int pin, uint16_t longTime, uint16_t singleTime, uint16_t
|
||||||
this->doubleTime=doubleTime;
|
this->doubleTime=doubleTime;
|
||||||
service=homeSpan.Accessories.back()->Services.back();
|
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.configLog+=" *** WARNING: No button() method defined for this PushButton! ***";
|
||||||
|
homeSpan.nWarnings++;
|
||||||
|
}
|
||||||
|
|
||||||
pushButton=new PushButton(pin); // create underlying PushButton
|
pushButton=new PushButton(pin); // create underlying PushButton
|
||||||
|
|
||||||
|
|
|
||||||
297
src/HomeSpan.h
297
src/HomeSpan.h
|
|
@ -39,6 +39,7 @@
|
||||||
#include "Network.h"
|
#include "Network.h"
|
||||||
#include "HAPConstants.h"
|
#include "HAPConstants.h"
|
||||||
#include "HapQR.h"
|
#include "HapQR.h"
|
||||||
|
#include "Characteristics.h"
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::unordered_map;
|
using std::unordered_map;
|
||||||
|
|
@ -54,6 +55,8 @@ enum {
|
||||||
GET_ALL=255
|
GET_ALL=255
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
// Forward-Declarations
|
// Forward-Declarations
|
||||||
|
|
||||||
struct Span;
|
struct Span;
|
||||||
|
|
@ -64,6 +67,8 @@ struct SpanRange;
|
||||||
struct SpanBuf;
|
struct SpanBuf;
|
||||||
struct SpanButton;
|
struct SpanButton;
|
||||||
|
|
||||||
|
extern Span homeSpan;
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
struct SpanConfig {
|
struct SpanConfig {
|
||||||
|
|
@ -73,6 +78,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{
|
struct Span{
|
||||||
|
|
||||||
const char *displayName; // display name for this device - broadcast as part of Bonjour MDNS
|
const char *displayName; // display name for this device - broadcast as part of Bonjour MDNS
|
||||||
|
|
@ -84,6 +100,7 @@ struct Span{
|
||||||
unsigned long snapTime; // current time (in millis) snapped before entering Service loops() or updates()
|
unsigned long snapTime; // current time (in millis) snapped before entering Service loops() or updates()
|
||||||
boolean isInitialized=false; // flag indicating HomeSpan has been initialized
|
boolean isInitialized=false; // flag indicating HomeSpan has been initialized
|
||||||
int nFatalErrors=0; // number of fatal errors in user-defined configuration
|
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
|
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)
|
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
|
HapQR qrCode; // optional QR Code to use for pairing
|
||||||
|
|
@ -118,8 +135,6 @@ struct Span{
|
||||||
vector<SpanButton *> PushButtons; // vector of pointer to all PushButtons
|
vector<SpanButton *> PushButtons; // vector of pointer to all PushButtons
|
||||||
unordered_map<uint64_t, uint32_t> TimedWrites; // map of timed-write PIDs and Alarm Times (based on TTLs)
|
unordered_map<uint64_t, uint32_t> 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,
|
void begin(Category catID=DEFAULT_CATEGORY,
|
||||||
const char *displayName=DEFAULT_DISPLAY_NAME,
|
const char *displayName=DEFAULT_DISPLAY_NAME,
|
||||||
const char *hostNameBase=DEFAULT_HOST_NAME,
|
const char *hostNameBase=DEFAULT_HOST_NAME,
|
||||||
|
|
@ -185,15 +200,15 @@ struct SpanService{
|
||||||
boolean hidden=false; // optional property indicating service is hidden
|
boolean hidden=false; // optional property indicating service is hidden
|
||||||
boolean primary=false; // optional property indicating service is primary
|
boolean primary=false; // optional property indicating service is primary
|
||||||
vector<SpanCharacteristic *> Characteristics; // vector of pointers to all Characteristics in this Service
|
vector<SpanCharacteristic *> Characteristics; // vector of pointers to all Characteristics in this Service
|
||||||
vector<HapCharType *> req; // vector of pointers to all required HAP Characteristic Types for this Service
|
vector<HapChar *> req; // vector of pointers to all required HAP Characteristic Types for this Service
|
||||||
vector<HapCharType *> opt; // vector of pointers to all optional HAP Characteristic Types for this Service
|
vector<HapChar *> opt; // vector of pointers to all optional HAP Characteristic Types for this Service
|
||||||
vector<SpanService *> linkedServices; // vector of pointers to any optional linked Services
|
vector<SpanService *> linkedServices; // vector of pointers to any optional linked Services
|
||||||
|
|
||||||
SpanService(const char *type, const char *hapName);
|
SpanService(const char *type, const char *hapName);
|
||||||
|
|
||||||
SpanService *setPrimary(); // sets the Service Type to be primary and returns pointer to self
|
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 *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
|
int sprintfAttributes(char *cBuf); // prints Service JSON records into buf; return number of characters printed, excluding null terminator
|
||||||
void validate(); // error-checks Service
|
void validate(); // error-checks Service
|
||||||
|
|
@ -207,27 +222,6 @@ struct SpanService{
|
||||||
|
|
||||||
struct SpanCharacteristic{
|
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
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FORMAT { // HAP Table 6-5
|
|
||||||
BOOL=0,
|
|
||||||
UINT8=1,
|
|
||||||
UINT16=2,
|
|
||||||
UINT32=3,
|
|
||||||
UINT64=4,
|
|
||||||
INT=5,
|
|
||||||
FLOAT=6,
|
|
||||||
STRING=7
|
|
||||||
};
|
|
||||||
|
|
||||||
union UVal {
|
union UVal {
|
||||||
boolean BOOL;
|
boolean BOOL;
|
||||||
|
|
@ -247,7 +241,11 @@ struct SpanCharacteristic{
|
||||||
uint8_t perms; // Characteristic Permissions
|
uint8_t perms; // Characteristic Permissions
|
||||||
FORMAT format; // Characteristic Format
|
FORMAT format; // Characteristic Format
|
||||||
char *desc=NULL; // Characteristic Description (optional)
|
char *desc=NULL; // Characteristic Description (optional)
|
||||||
SpanRange *range=NULL; // Characteristic min/max/step; NULL = default values (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 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)
|
boolean *ev; // Characteristic Event Notify Enable (per-connection)
|
||||||
|
|
||||||
uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic
|
uint32_t aid=0; // Accessory ID - passed through from Service containing this Characteristic
|
||||||
|
|
@ -256,80 +254,207 @@ struct SpanCharacteristic{
|
||||||
UVal newValue; // the updated value requested by PUT /characteristic
|
UVal newValue; // the updated value requested by PUT /characteristic
|
||||||
SpanService *service=NULL; // pointer to Service containing this Characteristic
|
SpanService *service=NULL; // pointer to Service containing this Characteristic
|
||||||
|
|
||||||
SpanCharacteristic(const char *type, uint8_t perms, const char *hapName);
|
SpanCharacteristic(HapChar *hapChar); // contructor
|
||||||
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);
|
|
||||||
|
|
||||||
int sprintfAttributes(char *cBuf, int flags); // prints Characteristic JSON records into buf, according to flags mask; return number of characters printed, excluding null terminator
|
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.)
|
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.)
|
||||||
|
|
||||||
template <class T=int> T getVal(){return(getValue<T>(value));} // returns UVal value
|
boolean updated(){return(isUpdated);} // returns isUpdated
|
||||||
template <class T=int> T getNewVal(){return(getValue<T>(newValue));} // returns UVal newValue
|
unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated
|
||||||
template <class T> T getValue(UVal v); // returns UVal v
|
|
||||||
|
|
||||||
void setVal(int value); // sets value of UVal value for all integer-based Characterstic types
|
String uvPrint(UVal &u){
|
||||||
void setVal(double value); // sets value of UVal value for FLOAT Characteristic type
|
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:
|
||||||
|
sprintf(c,"\"%s\"",u.STRING);
|
||||||
|
return(String(c));
|
||||||
|
} // switch
|
||||||
|
} // str()
|
||||||
|
|
||||||
boolean updated(){return(isUpdated);} // returns isUpdated
|
void uvSet(UVal &u, const char *val){
|
||||||
unsigned long timeVal(); // returns time elapsed (in millis) since value was last updated
|
u.STRING=val;
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
template <class T> 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 <typename T> 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 <class T> 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 <typename A, typename B, typename S=int> SpanCharacteristic *setRange(A min, B max, S step=0){
|
||||||
|
|
||||||
|
char c[256];
|
||||||
|
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");
|
||||||
|
homeSpan.nFatalErrors++;
|
||||||
|
} else
|
||||||
|
|
||||||
|
if(staticRange){
|
||||||
|
sprintf(c," *** ERROR! Can't change range for this Characteristic! ***\n");
|
||||||
|
homeSpan.nFatalErrors++;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
uvSet(minValue,min);
|
||||||
|
uvSet(maxValue,max);
|
||||||
|
uvSet(stepValue,step);
|
||||||
|
customRange=true;
|
||||||
|
|
||||||
|
if(uvGet<double>(stepValue)>0)
|
||||||
|
sprintf(c,": Min=%s, Max=%s, Step=%s\n",uvPrint(minValue),uvPrint(maxValue),uvPrint(stepValue));
|
||||||
|
else
|
||||||
|
sprintf(c,": Min=%s, Max=%s\n",uvPrint(minValue),uvPrint(maxValue));
|
||||||
|
}
|
||||||
|
homeSpan.configLog+=c;
|
||||||
|
return(this);
|
||||||
|
|
||||||
|
} // setRange()
|
||||||
|
|
||||||
|
template <typename T, typename A=boolean, typename B=boolean> 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);
|
||||||
|
|
||||||
|
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 && i<homeSpan.Accessories.back()->Services.back()->req.size(); i++)
|
||||||
|
valid=!strcmp(type,homeSpan.Accessories.back()->Services.back()->req[i]->type);
|
||||||
|
|
||||||
|
for(int i=0; !valid && i<homeSpan.Accessories.back()->Services.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 && i<homeSpan.Accessories.back()->Services.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 <class T=int> T getVal(){
|
||||||
|
return(uvGet<T>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T=int> T getNewVal(){
|
||||||
|
return(uvGet<T>(newValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(val < uvGet<T>(minValue) || val > uvGet<T>(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,uvGet<double>(minValue),uvGet<double>(maxValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
uvSet(value,val);
|
||||||
|
uvSet(newValue,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
|
||||||
|
|
||||||
|
} // setVal()
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
struct SpanRange{
|
struct SpanRange{
|
||||||
int min;
|
|
||||||
int max;
|
|
||||||
int step;
|
|
||||||
|
|
||||||
SpanRange(int min, int max, int step);
|
SpanRange(int min, int max, int step);
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
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{
|
struct SpanButton{
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -350,10 +475,6 @@ struct SpanButton{
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/////////////////////////////////////////////////
|
||||||
// Extern Variables
|
|
||||||
|
|
||||||
extern Span homeSpan;
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
#include "Span.h"
|
||||||
|
|
||||||
#include "Services.h"
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#define HS_MAJOR 1
|
#define HS_MAJOR 1
|
||||||
#define HS_MINOR 2
|
#define HS_MINOR 2
|
||||||
#define HS_PATCH 0
|
#define HS_PATCH 1
|
||||||
|
|
||||||
#define STRINGIFY(x) _STR(x)
|
#define STRINGIFY(x) _STR(x)
|
||||||
#define _STR(x) #x
|
#define _STR(x) #x
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@
|
||||||
|
|
||||||
// Macros to define vectors of required and optional characteristics for each Span Service structure
|
// Macros to define vectors of required and optional characteristics for each Span Service structure
|
||||||
|
|
||||||
#define REQ(name) req.push_back(&homeSpan.chr.name)
|
#define REQ(HAPCHAR) req.push_back(&hapChars.HAPCHAR)
|
||||||
#define OPT(name) opt.push_back(&homeSpan.chr.name)
|
#define OPT(HAPCHAR) opt.push_back(&hapChars.HAPCHAR)
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
|
||||||
|
|
@ -365,7 +365,7 @@ namespace Service {
|
||||||
struct WindowCovering : SpanService { WindowCovering() : SpanService{"8C","WindowCovering"}{
|
struct WindowCovering : SpanService { WindowCovering() : SpanService{"8C","WindowCovering"}{
|
||||||
REQ(TargetPosition);
|
REQ(TargetPosition);
|
||||||
REQ(CurrentPosition);
|
REQ(CurrentPosition);
|
||||||
OPT(PositionState);
|
REQ(PositionState);
|
||||||
OPT(Name);
|
OPT(Name);
|
||||||
OPT(HoldPosition);
|
OPT(HoldPosition);
|
||||||
OPT(CurrentHorizontalTiltAngle);
|
OPT(CurrentHorizontalTiltAngle);
|
||||||
|
|
@ -381,109 +381,111 @@ namespace Service {
|
||||||
// SPAN CHARACTERISTICS (HAP Chapter 9) //
|
// 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 or BOOL which default to min=0, max=1)
|
||||||
|
|
||||||
#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(TYPE,HAPCHAR,DEFVAL,MINVAL,MAXVAL) \
|
||||||
|
struct HAPCHAR : SpanCharacteristic { HAPCHAR(TYPE val=DEFVAL) : SpanCharacteristic {&hapChars.HAPCHAR} { init(val,(TYPE)MINVAL,(TYPE)MAXVAL); } };
|
||||||
|
|
||||||
namespace Characteristic {
|
namespace Characteristic {
|
||||||
|
|
||||||
CREATE_CHAR(Active,uint8_t,0);
|
CREATE_CHAR(uint8_t,Active,0,0,1);
|
||||||
CREATE_CHAR(AirQuality,uint8_t,0);
|
CREATE_CHAR(uint8_t,AirQuality,0,0,5);
|
||||||
CREATE_CHAR(BatteryLevel,uint8_t,0);
|
CREATE_CHAR(uint8_t,BatteryLevel,0,0,100);
|
||||||
CREATE_CHAR(Brightness,int,0);
|
CREATE_CHAR(int,Brightness,0,0,100);
|
||||||
CREATE_CHAR(CarbonMonoxideLevel,double,0);
|
CREATE_CHAR(double,CarbonMonoxideLevel,0,0,100);
|
||||||
CREATE_CHAR(CarbonMonoxidePeakLevel,double,0);
|
CREATE_CHAR(double,CarbonMonoxidePeakLevel,0,0,100);
|
||||||
CREATE_CHAR(CarbonMonoxideDetected,uint8_t,0);
|
CREATE_CHAR(uint8_t,CarbonMonoxideDetected,0,0,1);
|
||||||
CREATE_CHAR(CarbonDioxideLevel,double,0);
|
CREATE_CHAR(double,CarbonDioxideLevel,0,0,100000);
|
||||||
CREATE_CHAR(CarbonDioxidePeakLevel,double,0);
|
CREATE_CHAR(double,CarbonDioxidePeakLevel,0,0,100000);
|
||||||
CREATE_CHAR(CarbonDioxideDetected,uint8_t,0);
|
CREATE_CHAR(uint8_t,CarbonDioxideDetected,0,0,1);
|
||||||
CREATE_CHAR(ChargingState,uint8_t,0);
|
CREATE_CHAR(uint8_t,ChargingState,0,0,2);
|
||||||
CREATE_CHAR(CoolingThresholdTemperature,double,10);
|
CREATE_CHAR(double,CoolingThresholdTemperature,10,10,35);
|
||||||
CREATE_CHAR(ColorTemperature,uint32_t,50);
|
CREATE_CHAR(uint32_t,ColorTemperature,200,140,500);
|
||||||
CREATE_CHAR(ContactSensorState,uint8_t,1);
|
CREATE_CHAR(uint8_t,ContactSensorState,1,0,1);
|
||||||
CREATE_CHAR(CurrentAmbientLightLevel,double,1);
|
CREATE_CHAR(double,CurrentAmbientLightLevel,1,0.0001,100000);
|
||||||
CREATE_CHAR(CurrentHorizontalTiltAngle,int,0);
|
CREATE_CHAR(int,CurrentHorizontalTiltAngle,0,-90,90);
|
||||||
CREATE_CHAR(CurrentAirPurifierState,uint8_t,1);
|
CREATE_CHAR(uint8_t,CurrentAirPurifierState,1,0,2);
|
||||||
CREATE_CHAR(CurrentSlatState,uint8_t,0);
|
CREATE_CHAR(uint8_t,CurrentSlatState,0,0,2);
|
||||||
CREATE_CHAR(CurrentPosition,uint8_t,0);
|
CREATE_CHAR(uint8_t,CurrentPosition,0,0,100);
|
||||||
CREATE_CHAR(CurrentVerticalTiltAngle,int,0);
|
CREATE_CHAR(int,CurrentVerticalTiltAngle,0,-90,90);
|
||||||
CREATE_CHAR(CurrentHumidifierDehumidifierState,uint8_t,1);
|
CREATE_CHAR(uint8_t,CurrentHumidifierDehumidifierState,1,0,3);
|
||||||
CREATE_CHAR(CurrentDoorState,uint8_t,1);
|
CREATE_CHAR(uint8_t,CurrentDoorState,1,0,4);
|
||||||
CREATE_CHAR(CurrentFanState,uint8_t,1);
|
CREATE_CHAR(uint8_t,CurrentFanState,1,0,2);
|
||||||
CREATE_CHAR(CurrentHeatingCoolingState,uint8_t,0);
|
CREATE_CHAR(uint8_t,CurrentHeatingCoolingState,0,0,2);
|
||||||
CREATE_CHAR(CurrentHeaterCoolerState,uint8_t,1);
|
CREATE_CHAR(uint8_t,CurrentHeaterCoolerState,1,0,3);
|
||||||
CREATE_CHAR(CurrentRelativeHumidity,double,0);
|
CREATE_CHAR(double,CurrentRelativeHumidity,0,0,100);
|
||||||
CREATE_CHAR(CurrentTemperature,double,0);
|
CREATE_CHAR(double,CurrentTemperature,0,0,100);
|
||||||
CREATE_CHAR(CurrentTiltAngle,int,0);
|
CREATE_CHAR(int,CurrentTiltAngle,0,-90,90);
|
||||||
CREATE_CHAR(FilterLifeLevel,double,0);
|
CREATE_CHAR(double,FilterLifeLevel,0,0,100);
|
||||||
CREATE_CHAR(FilterChangeIndication,uint8_t,0);
|
CREATE_CHAR(uint8_t,FilterChangeIndication,0,0,1);
|
||||||
CREATE_CHAR(FirmwareRevision,const char *,"1.0.0");
|
CREATE_CHAR(const char *,FirmwareRevision,"1.0.0",0,1);
|
||||||
CREATE_CHAR(HardwareRevision,const char *,"1.0.0");
|
CREATE_CHAR(const char *,HardwareRevision,"1.0.0",0,1);
|
||||||
CREATE_CHAR(HeatingThresholdTemperature,double,16);
|
CREATE_CHAR(double,HeatingThresholdTemperature,16,0,25);
|
||||||
CREATE_CHAR(HoldPosition,boolean,false);
|
CREATE_CHAR(boolean,HoldPosition,false,0,1);
|
||||||
CREATE_CHAR(Hue,double,0);
|
CREATE_CHAR(double,Hue,0,0,360);
|
||||||
CREATE_CHAR(Identify,boolean,false);
|
CREATE_CHAR(boolean,Identify,false,0,1);
|
||||||
CREATE_CHAR(InUse,uint8_t,0);
|
CREATE_CHAR(uint8_t,InUse,0,0,1);
|
||||||
CREATE_CHAR(IsConfigured,uint8_t,0);
|
CREATE_CHAR(uint8_t,IsConfigured,0,0,1);
|
||||||
CREATE_CHAR(LeakDetected,uint8_t,0);
|
CREATE_CHAR(uint8_t,LeakDetected,0,0,1);
|
||||||
CREATE_CHAR(LockCurrentState,uint8_t,0);
|
CREATE_CHAR(uint8_t,LockCurrentState,0,0,3);
|
||||||
CREATE_CHAR(LockPhysicalControls,uint8_t,0);
|
CREATE_CHAR(uint8_t,LockPhysicalControls,0,0,1);
|
||||||
CREATE_CHAR(LockTargetState,uint8_t,0);
|
CREATE_CHAR(uint8_t,LockTargetState,0,0,1);
|
||||||
CREATE_CHAR(Manufacturer,const char *,"HomeSpan");
|
CREATE_CHAR(const char *,Manufacturer,"HomeSpan",0,1);
|
||||||
CREATE_CHAR(Model,const char *,"HomeSpan-ESP32");
|
CREATE_CHAR(const char *,Model,"HomeSpan-ESP32",0,1);
|
||||||
CREATE_CHAR(MotionDetected,boolean,false);
|
CREATE_CHAR(boolean,MotionDetected,false,0,1);
|
||||||
CREATE_CHAR(Mute,boolean,false);
|
CREATE_CHAR(boolean,Mute,false,0,1);
|
||||||
CREATE_CHAR(Name,const char *,"unnamed");
|
CREATE_CHAR(const char *,Name,"unnamed",0,1);
|
||||||
CREATE_CHAR(NitrogenDioxideDensity,double,0);
|
CREATE_CHAR(double,NitrogenDioxideDensity,0,0,1000);
|
||||||
CREATE_CHAR(ObstructionDetected,boolean,false);
|
CREATE_CHAR(boolean,ObstructionDetected,false,0,1);
|
||||||
CREATE_CHAR(PM25Density,double,0);
|
CREATE_CHAR(double,PM25Density,0,0,1000);
|
||||||
CREATE_CHAR(OccupancyDetected,uint8_t,0);
|
CREATE_CHAR(uint8_t,OccupancyDetected,0,0,1);
|
||||||
CREATE_CHAR(OutletInUse,boolean,false);
|
CREATE_CHAR(boolean,OutletInUse,false,0,1);
|
||||||
CREATE_CHAR(On,boolean,false);
|
CREATE_CHAR(boolean,On,false,0,1);
|
||||||
CREATE_CHAR(OzoneDensity,double,0);
|
CREATE_CHAR(double,OzoneDensity,0,0,1000);
|
||||||
CREATE_CHAR(PM10Density,double,0);
|
CREATE_CHAR(double,PM10Density,0,0,1000);
|
||||||
CREATE_CHAR(PositionState,uint8_t,2);
|
CREATE_CHAR(uint8_t,PositionState,2,0,2);
|
||||||
CREATE_CHAR(ProgramMode,uint8_t,0);
|
CREATE_CHAR(uint8_t,ProgramMode,0,0,2);
|
||||||
CREATE_CHAR(ProgrammableSwitchEvent,uint8_t,0);
|
CREATE_CHAR(uint8_t,ProgrammableSwitchEvent,0,0,2);
|
||||||
CREATE_CHAR(RelativeHumidityDehumidifierThreshold,double,50);
|
CREATE_CHAR(double,RelativeHumidityDehumidifierThreshold,50,0,100);
|
||||||
CREATE_CHAR(RelativeHumidityHumidifierThreshold,double,50);
|
CREATE_CHAR(double,RelativeHumidityHumidifierThreshold,50,0,100);
|
||||||
CREATE_CHAR(RemainingDuration,uint32_t,60);
|
CREATE_CHAR(uint32_t,RemainingDuration,60,0,3600);
|
||||||
CREATE_CHAR(ResetFilterIndication,uint8_t,0);
|
CREATE_CHAR(uint8_t,ResetFilterIndication,0,1,1);
|
||||||
CREATE_CHAR(RotationDirection,int,0);
|
CREATE_CHAR(int,RotationDirection,0,0,1);
|
||||||
CREATE_CHAR(RotationSpeed,double,0);
|
CREATE_CHAR(double,RotationSpeed,0,0,100);
|
||||||
CREATE_CHAR(Saturation,double,0);
|
CREATE_CHAR(double,Saturation,0,0,100);
|
||||||
CREATE_CHAR(SecuritySystemAlarmType,uint8_t,0);
|
CREATE_CHAR(uint8_t,SecuritySystemAlarmType,0,0,1);
|
||||||
CREATE_CHAR(SecuritySystemCurrentState,uint8_t,3);
|
CREATE_CHAR(uint8_t,SecuritySystemCurrentState,3,0,4);
|
||||||
CREATE_CHAR(SecuritySystemTargetState,uint8_t,3);
|
CREATE_CHAR(uint8_t,SecuritySystemTargetState,3,0,3);
|
||||||
CREATE_CHAR(SerialNumber,const char *,"HS-12345");
|
CREATE_CHAR(const char *,SerialNumber,"HS-12345",0,1);
|
||||||
CREATE_CHAR(ServiceLabelIndex,uint8_t,1);
|
CREATE_CHAR(uint8_t,ServiceLabelIndex,1,1,255);
|
||||||
CREATE_CHAR(ServiceLabelNamespace,uint8_t,1);
|
CREATE_CHAR(uint8_t,ServiceLabelNamespace,1,0,1);
|
||||||
CREATE_CHAR(SlatType,uint8_t,0);
|
CREATE_CHAR(uint8_t,SlatType,0,0,1);
|
||||||
CREATE_CHAR(SmokeDetected,uint8_t,0);
|
CREATE_CHAR(uint8_t,SmokeDetected,0,0,1);
|
||||||
CREATE_CHAR(StatusActive,boolean,true);
|
CREATE_CHAR(boolean,StatusActive,true,0,1);
|
||||||
CREATE_CHAR(StatusFault,uint8_t,0);
|
CREATE_CHAR(uint8_t,StatusFault,0,0,1);
|
||||||
CREATE_CHAR(StatusJammed,uint8_t,0);
|
CREATE_CHAR(uint8_t,StatusJammed,0,0,1);
|
||||||
CREATE_CHAR(StatusLowBattery,uint8_t,0);
|
CREATE_CHAR(uint8_t,StatusLowBattery,0,0,1);
|
||||||
CREATE_CHAR(StatusTampered,uint8_t,0);
|
CREATE_CHAR(uint8_t,StatusTampered,0,0,1);
|
||||||
CREATE_CHAR(SulphurDioxideDensity,double,0);
|
CREATE_CHAR(double,SulphurDioxideDensity,0,0,1000);
|
||||||
CREATE_CHAR(SwingMode,uint8_t,0);
|
CREATE_CHAR(uint8_t,SwingMode,0,0,1);
|
||||||
CREATE_CHAR(TargetAirPurifierState,uint8_t,1);
|
CREATE_CHAR(uint8_t,TargetAirPurifierState,1,0,1);
|
||||||
CREATE_CHAR(TargetFanState,uint8_t,1);
|
CREATE_CHAR(uint8_t,TargetFanState,1,0,1);
|
||||||
CREATE_CHAR(TargetTiltAngle,int,0);
|
CREATE_CHAR(int,TargetTiltAngle,0,-90,90);
|
||||||
CREATE_CHAR(SetDuration,uint32_t,60);
|
CREATE_CHAR(uint8_t,TargetHeaterCoolerState,0,0,2);
|
||||||
CREATE_CHAR(TargetHorizontalTiltAngle,int,0);
|
CREATE_CHAR(uint32_t,SetDuration,60,0,3600);
|
||||||
CREATE_CHAR(TargetHumidifierDehumidifierState,uint8_t,0);
|
CREATE_CHAR(int,TargetHorizontalTiltAngle,0,-90,90);
|
||||||
CREATE_CHAR(TargetPosition,uint8_t,0);
|
CREATE_CHAR(uint8_t,TargetHumidifierDehumidifierState,0,0,2);
|
||||||
CREATE_CHAR(TargetDoorState,uint8_t,1);
|
CREATE_CHAR(uint8_t,TargetPosition,0,0,100);
|
||||||
CREATE_CHAR(TargetHeatingCoolingState,uint8_t,0);
|
CREATE_CHAR(uint8_t,TargetDoorState,1,0,1);
|
||||||
CREATE_CHAR(TargetRelativeHumidity,double,0);
|
CREATE_CHAR(uint8_t,TargetHeatingCoolingState,0,0,3);
|
||||||
CREATE_CHAR(TargetTemperature,double,16);
|
CREATE_CHAR(double,TargetRelativeHumidity,0,0,100);
|
||||||
CREATE_CHAR(TemperatureDisplayUnits,uint8_t,0);
|
CREATE_CHAR(double,TargetTemperature,16,10,38);
|
||||||
CREATE_CHAR(TargetVerticalTiltAngle,int,0);
|
CREATE_CHAR(uint8_t,TemperatureDisplayUnits,0,0,1);
|
||||||
CREATE_CHAR(ValveType,uint8_t,0);
|
CREATE_CHAR(int,TargetVerticalTiltAngle,0,-90,90);
|
||||||
CREATE_CHAR(Version,const char *,"1.0.0");
|
CREATE_CHAR(uint8_t,ValveType,0,0,3);
|
||||||
CREATE_CHAR(VOCDensity,double,0);
|
CREATE_CHAR(const char *,Version,"1.0.0",0,1);
|
||||||
CREATE_CHAR(Volume,uint8_t,0);
|
CREATE_CHAR(double,VOCDensity,0,0,1000);
|
||||||
CREATE_CHAR(WaterLevel,double,0);
|
CREATE_CHAR(uint8_t,Volume,0,0,100);
|
||||||
|
CREATE_CHAR(double,WaterLevel,0,0,100);
|
||||||
|
|
||||||
}
|
}
|
||||||
11
src/src.ino
11
src/src.ino
|
|
@ -14,7 +14,7 @@ void setup() {
|
||||||
homeSpan.setPortNum(1201);
|
homeSpan.setPortNum(1201);
|
||||||
// homeSpan.setMaxConnections(6);
|
// homeSpan.setMaxConnections(6);
|
||||||
// homeSpan.setQRID("One1");
|
// homeSpan.setQRID("One1");
|
||||||
homeSpan.enableOTA();
|
// homeSpan.enableOTA();
|
||||||
homeSpan.setSketchVersion("Test 1.3.1");
|
homeSpan.setSketchVersion("Test 1.3.1");
|
||||||
homeSpan.setWifiCallback(wifiEstablished);
|
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::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 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 Characteristic::Version("1.1.0"); // Set the Version Characteristic to "1.1.0" as required by HAP
|
||||||
|
|
||||||
new Service::LightBulb();
|
new Service::LightBulb();
|
||||||
new Characteristic::On();
|
// new Characteristic::On();
|
||||||
new Characteristic::Brightness();
|
new Characteristic::Brightness();
|
||||||
new Characteristic::Name("Light 1");
|
new Characteristic::Name("Light 1");
|
||||||
new Service::LightBulb();
|
new Service::LightBulb();
|
||||||
new Characteristic::On();
|
new Characteristic::On(2);
|
||||||
new Characteristic::Brightness();
|
(new Characteristic::Brightness(150))->setRange(0,140,5);
|
||||||
new Characteristic::Name("Light 2");
|
new Characteristic::Name("Light 2");
|
||||||
(new Service::Switch())->setPrimary();
|
(new Service::Switch())->setPrimary();
|
||||||
new Characteristic::On();
|
new Characteristic::On();
|
||||||
new Characteristic::Name("Switch 3");
|
new Characteristic::Name("Switch 3");
|
||||||
|
new SpanButton(17);
|
||||||
|
|
||||||
} // end of setup()
|
} // end of setup()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue