Updated Example 13
Completed new framework for using loop() methods and deleted all code related to new SpanEvent() and event() loops. Re-worked Example 13 to utilize new framework and validated it functions as expected.
This commit is contained in:
parent
1efeb2880b
commit
9cecc0a31a
|
|
@ -1,93 +0,0 @@
|
|||
|
||||
////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// HomeSpan: A HomeKit implementation for the ESP32 //
|
||||
// ------------------------------------------------ //
|
||||
// //
|
||||
// Example 13: Event Notifications //
|
||||
// * implementing a Temperature Sensor //
|
||||
// * implementing an Air Quality Sensor //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HomeSpan.h"
|
||||
#include "DEV_Identify.h"
|
||||
#include "DEV_Sensors.h"
|
||||
|
||||
void setup() {
|
||||
|
||||
// HomeKit is designed for two-way communication: HomeSpan devices not only receive and act on operational instructions from HomeKit Controllers, but
|
||||
// HomeSpan can also send HomeKit unsolicited messages regarding changes to the state of the device. Though it may not be apparent, this has already been
|
||||
// ocurring in the background in all prior examples. This is because when a HomeKit Controller sends an operational request to any HomeKit device, it expects
|
||||
// to receive a status message back indicating whether the request was successful or not. This is the purpose of returning StatusCode:OK in custom update()
|
||||
// methods. With this information returned, HomeKit can update its own status and properly reflect a change in the device, such as by showing a light is now
|
||||
// turned on instead of off. However, HomeKit unfortunately does NOT inform any other HomeKit Controllers of this new information. So if you have two iPhones
|
||||
// and use one to turn on a light, the other first iPhone does not relay a message to the second iPhone that a light has been turned on. This is the case even
|
||||
// if you are using an AppleTV or HomePod as a central hub for HomeKit.
|
||||
|
||||
// Normally this does not matter much, since the second iPhone will naturally update itself as to the status of all HomeKit devices as soon as the HomeKit
|
||||
// application is launched on that iPhone. It does this by sending every HomeKit device a message asking for a status update. In this fashion the second
|
||||
// iPhone quickly synchronizes itself as soon as the HomeKit app is opened, but ONLY when it is first opened (or re-opened if you first close it). But if you
|
||||
// have two iPhones BOTH opened to the HomeKit app (or one iPhone and one Mac opened to the HomeKit app) and you use one Controller app to turn on a light, the
|
||||
// resulting change in status of that light will NOT be reflected in the second Controller app, unless you close tha app and re-open (at which point it goes
|
||||
// through the request procedure discussed above). This is very annoying and counterintuitive.
|
||||
|
||||
// Fortunately, HomeKit provides a solution to this in the form of an Event Notification protcol. This protcol allows a device to send unsoliciated messages
|
||||
// to all Controllers that have previously registered themselves with the device indicating the Characteristics for which they would like to receive an event
|
||||
// message from the device whenever there is a change in the status of one or more of those Characteristics.
|
||||
|
||||
// The good news is that HomeSpan takes care of this automatically. To see this for yourself, use two iPhones (or an iPhone and Mac) with any of the previous examples
|
||||
// and open the HomeKit app on both. Any changes you make to the device using one of the Controllers, such as turning on an LED, is immediately reflected
|
||||
// in the other Controller. Not quite magic, but close.
|
||||
|
||||
// A different use of Event Notifications was also working behind in the scenes in Example 10 - Timed Resets. In this case, HomeSpan sent an unsolited Event message
|
||||
// to all registered Controllers letting them know that a device that was previously turned on, is now in fact turned off.
|
||||
|
||||
// In this Example 13 we explore the explicit use of Event Notifications to support Services that require constants updates from the device to all HomeKit Controllers.
|
||||
// The two Services we will use below are a Temperature Sensor and an Air Quality Sensor. Neither of these Services have any operational controls. They cannot be
|
||||
// turn on or off, or operated in any way. As such, they do not need to implement an update() method, since HomeKit Controllers will never ask them to change
|
||||
// any of their Characteristics.
|
||||
|
||||
// Rather, HomeKit is expecting to get periodic Event Notification messages from such Services so that the HomeKit Controllers can accurately reflect the status
|
||||
// and values of the Characteristics for those Services, such as the temperature, in the HomeKit Controller.
|
||||
|
||||
// There are two steps to accomplishing this. The first is to implement an event() method for each Service that uses a setVal() function to change the values
|
||||
// for one or more Characteristics for that Service. The second step is to instantiate a new SpanEvent() object for each Service that you want HomeSpan to invoke your
|
||||
// event() method. The SpanEvent object take only one argument - the number of milliseconds to wait between calls to a Service's event() method.
|
||||
|
||||
// As usual, all of the logic for this is encapsulated in new standalone derived Services. You'll find fully-commented definitions for the DEV_TempSensor() and
|
||||
// the DEV_AirQualitySensor() Services instantiated below, in the DEV_Sensors.h file. Note that this example is for instructional purposes only -- we do not actually
|
||||
// connect a Temperature Sensor or Air Quality Sensor to our ESP32 device. As such, we did not define the Services to take any arguments to specify pin numbers or any
|
||||
// other information needed to implement an actual sensor. Instead, in order to see how real a device would work, we will send Event messages by manufacturing simulated
|
||||
// updates. See DEV_Sensors.h for complete details.
|
||||
|
||||
// Once you understand these examples, you should be able to use Event Notifications for any combination of HomeKit Services with Characteristics that require your device to
|
||||
// send periodic update messages to HomeKit Controllers, ranging from Smoke Alarms to Door Sensors.
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
homeSpan.begin(Category::Bridges,"HomeSpan Bridge");
|
||||
|
||||
|
||||
new SpanAccessory();
|
||||
new DEV_Identify("Bridge #1","HomeSpan","123-ABC","HS Bridge","0.9",3);
|
||||
new Service::HAPProtocolInformation();
|
||||
new Characteristic::Version("1.1.0");
|
||||
|
||||
new SpanAccessory();
|
||||
new DEV_Identify("Temp Sensor","HomeSpan","123-ABC","Sensor","0.9",0);
|
||||
new DEV_TempSensor(); // Create a Temperature Sensor (see DEV_Sensors.h for definition)
|
||||
|
||||
new SpanAccessory();
|
||||
new DEV_Identify("Air Quality","HomeSpan","123-ABC","Sensor","0.9",0);
|
||||
new DEV_AirQualitySensor(); // Create an Air Quality Sensor (see DEV_Sensors.h for definition)
|
||||
|
||||
} // end of setup()
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void loop(){
|
||||
|
||||
homeSpan.poll();
|
||||
|
||||
} // end of loop()
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// HomeSpan: A HomeKit implementation for the ESP32 //
|
||||
// ------------------------------------------------ //
|
||||
// //
|
||||
// Example 13: Service Loops (and Event Notifications) //
|
||||
// * implementing a Temperature Sensor //
|
||||
// * implementing an Air Quality Sensor //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#include "HomeSpan.h"
|
||||
#include "DEV_Identify.h"
|
||||
#include "DEV_Sensors.h"
|
||||
|
||||
void setup() {
|
||||
|
||||
// So far we've seen that HomeSpan allows you to create derived Services with their own constructors and update() methods. For many applications, this
|
||||
// will be all that is needed. However, for many other types of applications you may need to take action or perform some background operations without
|
||||
// any prompting or requests from HomeKit.
|
||||
|
||||
// To perform background operations and actions, every Service implements a loop() method. The default loop() method is to do nothing, which has been
|
||||
// fine for all our prior examples. But if you need to perform some continuous background action, all you need to do is implement a loop() method for
|
||||
// your derived Service. At the end of each HomeSpan polling cycle, the loop() method is called for each Service that implements its own code.
|
||||
// In this fashion, the loop() method is similar to the main loop() method in the Arduino IDE itself - except it can be customized for each Service.
|
||||
|
||||
// In this Example 13 we explore the use of loop() methods to implement two new accessories - a Temperature Sensor and an Air Quality Sensor. Of course
|
||||
// we won't actually have these physical devices attached to the ESP32 for the purpoe of this example, but we will simulate "reading" their properties.
|
||||
// This is one of the main purposes of implementing a loop() method. It allows you to read a sensor or perform some sort of repetitive, Service-specific
|
||||
// action.
|
||||
|
||||
// Once you read (or simulate reading) a sensor's values in a loop() method, you need to somehow communicate this back to HomeKit so the new values can be
|
||||
// reflected in the HomeKit Controller. This may be strictly for information purposes (such as a temperature sensor) or could be used by HomeKit itself
|
||||
// to trigger other devices (as might occur if implementing a Door Sensor).
|
||||
|
||||
// Fortunately, HomeSpan makes communicating the values of Characteristics back to HomeKit easy. In prior examples we saw how getVal() and getNewVal()
|
||||
// are used to read current and updated Characteristic values requested by HomeKit. To perform the reverse, we simply use a method called setVal().
|
||||
// Setting the value of a Characteristic with this function does two things. First, it causes HomeSpan to send an Event Notification message back to HomeKit
|
||||
// letting HomeKit know the new value of the Characteristic. Since messages create network traffic, HomeSpan keeps track of all setVal() changes across
|
||||
// all Services and creates one a single Event Notification message reporting all the changes togther at the end of each polling cycle.
|
||||
|
||||
// The second thing that HomeSpan does when you change the value of a Characteristic with setVal() is to reset an internal timer for that Characteristic that
|
||||
// keeps track of how long it's been since the last modification, whether from a previous setVal() instruction, or by HomeKit itself via a call to update().
|
||||
// You can query the time since the last modificaton using the method timeVal() which returns the elapsed time in milliseconds. By calling this function from
|
||||
// within loop() you can determine when it's time for a new sensor read, or when to perform some other action.
|
||||
|
||||
// NOTE: It it NOT recommended to continuously change Characteristic values using setVal() as this will generate a lot of network traffic since HomeSpan
|
||||
// sends Event Notifications bck to all registered HomeKit Controllers. It's fine to perform internal calculations, generate signals on different pins,
|
||||
// and perform any other internal actions you may need as frequently as you require. But limit the use of setVal() to a reasonable frequency, such as maybe
|
||||
// one per minute for a temperature sensor. Do not use setVal() unless the value of the Characteristic changes, but do use it to immediately inform HomeKit of
|
||||
// something time-sensitive, such as a door opening, or a smoke alarm triggering.
|
||||
|
||||
// As usual, all of the logic for this example are encapsulated in new standalone derived Services. You'll find fully-commented definitions for the DEV_TempSensor() and
|
||||
// the DEV_AirQualitySensor() Services instantiated below, in the DEV_Sensors.h file. As noted, this example is for instructional purposes only -- we do not actually
|
||||
// connect a Temperature Sensor or Air Quality Sensor to our ESP32 device. As such, we did not define the Services to take any arguments to specify pin numbers or any
|
||||
// other information needed to implement an actual sensor. Instead, in order to see how real a device would work, we simulate periodic changes by modifying Characteristic
|
||||
// values using setVal() with either a sequence of repeating values, or random values. See DEV_Sensors.h for complete details.
|
||||
|
||||
// Once you understand these examples, you should be able to use implement your own loop() method and utilize setVal() along with timeVal() for any combination of
|
||||
// HomeKit Services with Characteristics that require your device to send periodic update messages to HomeKit Controllers, ranging from Smoke Alarms to Door Sensors.
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
homeSpan.begin(Category::Bridges,"HomeSpan Bridge");
|
||||
|
||||
new SpanAccessory();
|
||||
new DEV_Identify("Bridge #1","HomeSpan","123-ABC","HS Bridge","0.9",3);
|
||||
new Service::HAPProtocolInformation();
|
||||
new Characteristic::Version("1.1.0");
|
||||
|
||||
new SpanAccessory();
|
||||
new DEV_Identify("Temp Sensor","HomeSpan","123-ABC","Sensor","0.9",0);
|
||||
new DEV_TempSensor(); // Create a Temperature Sensor (see DEV_Sensors.h for definition)
|
||||
|
||||
new SpanAccessory();
|
||||
new DEV_Identify("Air Quality","HomeSpan","123-ABC","Sensor","0.9",0);
|
||||
new DEV_AirQualitySensor(); // Create an Air Quality Sensor (see DEV_Sensors.h for definition)
|
||||
|
||||
} // end of setup()
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void loop(){
|
||||
|
||||
homeSpan.poll();
|
||||
|
||||
} // end of loop()
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
|
||||
// Additional Technical Notes about Event Notifications in HomeKit
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// HomeKit is designed for two-way communication: HomeSpan devices not only receive and act on operational instructions from HomeKit Controllers, but
|
||||
// HomeSpan can also send HomeKit unsolicited messages regarding changes to the state of the device. Though it may not be apparent, this has already been
|
||||
// ocurring in the background in all prior examples. This is because when a HomeKit Controller sends an operational request to any HomeKit device, it expects
|
||||
// to receive a status message back indicating whether the request was successful or not. This is the purpose of returning StatusCode:OK in custom update()
|
||||
// methods. With this information returned, HomeKit can update its own status and properly reflect a change in the device, such as by showing a light is now
|
||||
// turned on instead of off. However, HomeKit unfortunately does NOT inform any other HomeKit Controllers of this new information. So if you have two iPhones
|
||||
// and use one to turn on a light, this iPhone does not relay a message to the second iPhone that a light has been turned on. This is the case even
|
||||
// if you are using an AppleTV or HomePod as a central hub for HomeKit.
|
||||
|
||||
// Normally this does not matter much, since the second iPhone will automatically update itself as to the status of all HomeKit devices as soon as the HomeKit
|
||||
// application is launched on that iPhone. It does this by sending every HomeKit device a message asking for a status update. In this fashion the second
|
||||
// iPhone quickly synchronizes itself as soon as its HomeKit app is opened, but ONLY when it is first opened (or re-opened if you first close it). However, if you
|
||||
// have two iPhones BOTH opened to the HomeKit app (or one iPhone and one Mac opened to the HomeKit app) and you use one Controller app to turn on a light, the
|
||||
// resulting change in status of that light will NOT be reflected in the second Controller app, unless you close tha app and re-open (at which point it goes
|
||||
// through the request procedure discussed above). This can be very annoying and counterintuitive.
|
||||
|
||||
// Fortunately, HomeKit provides a solution to this in the form of an Event Notification protcol. This protcol allows a device to send unsoliciated messages
|
||||
// to all Controllers that have previously registered themselves with the device indicating the Characteristics for which they would like to receive an event
|
||||
// message from the device whenever there is a change in the status of one or more of those Characteristics.
|
||||
|
||||
// HomeSpan takes care of this automatically, and has being doing so in the background in all prior examples. To see this for yourself, use two iPhones
|
||||
// (or an iPhone and Mac) with any of the previous examples and open the HomeKit app on both. Any changes you make to the device using one of the Controllers,
|
||||
// such as turning on an LED, is immediately reflected in the other Controller. Not quite magic, but close.
|
||||
|
||||
// As described above, and fully explored in this example, HomeSpan automatically generates Event Notification messages and transmis them to all registered
|
||||
// Controllers every time you change the value of a Characteristic using the setVal() function from within a derived Service's loop() method.
|
||||
|
|
@ -8,16 +8,8 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera
|
|||
SpanCharacteristic *temp; // reference to the Current Temperature Characteristic
|
||||
|
||||
DEV_TempSensor(ServiceType sType=ServiceType::Regular) : Service::TemperatureSensor(sType){ // constructor() method
|
||||
|
||||
// We begin by defining a new SpanEvent. This instructs HomeSpan to call the Service's event() method (defined below) periodically.
|
||||
// The argument to SpanEvent() defines the periodicity, in milliseconds. In this case we are instructing HomeSpan to check this Service for
|
||||
// updates every 5 seconds. Checking takes time, and updates use network traffic, so choose your periodicity wisely. In practice you could
|
||||
// probably set the periodicity for a temperature sensor to 60 seconds or more. But for illustrative purposes we are specifying more frequent
|
||||
// updates so you can see how the this example works without needing to wait a full minute for each change.
|
||||
|
||||
new SpanEvent(5000); // check for events on this Service every 5 seconds
|
||||
|
||||
// Next we instantiate the main Characteristic for a Temperature Sensor, namely the Current Temperature, and set its initial value
|
||||
// First we instantiate the main Characteristic for a Temperature Sensor, namely the Current Temperature, and set its initial value
|
||||
// to 20 degrees. For a real sensor, we would take a reading and initialize it to that value instead. NOTE: HomeKit uses
|
||||
// Celsius for all temperature settings. HomeKit will DISPLAY temperatures in the HomeKit app according to the settings on your iPhone.
|
||||
// Though the HAP documentation includes a Characteristic that appears to allow the device to over-ride this setting by specifying a display
|
||||
|
|
@ -25,35 +17,38 @@ struct DEV_TempSensor : Service::TemperatureSensor { // A standalone Tempera
|
|||
|
||||
temp=new Characteristic::CurrentTemperature(20.0); // instantiate the Current Temperature Characteristic
|
||||
|
||||
Serial.print("Configuring Temperature Sensor"); // initialization message
|
||||
Serial.print("Configuring Temperature Sensor"); // initialization message
|
||||
Serial.print("\n");
|
||||
|
||||
} // end constructor
|
||||
|
||||
// Lastly, we create the event() method. This method take no arguments and returns no values. It will be called every 5 seconds
|
||||
// as specified above in the instantiation of SpanEvent(). In order to simulate a temperature change from an actual sensor we
|
||||
// will read the current value of the temp Characteristic using the getVal() function, with <float> as the template parameter;
|
||||
// add 0.5 degrees Celsius; and then store the result in a float variable named "temperature." This will simulate an increment of
|
||||
// 0.5 degrees Celsius (a little less than 1 degree F) every 5 seconds. We will cap the temperature to 35.0 degrees C, after which
|
||||
// it resets to 10.0 and starts over.
|
||||
// Next we create the loop() method. This method take no arguments and returns no values. In order to simulate a temperature change
|
||||
// from an actual sensor we will read the current value of the temp Characteristic using the getVal() function, with <float> as the
|
||||
// template parameter; add 0.5 degrees Celsius; and then store the result in a float variable named "temperature." This will simulate
|
||||
// an increment of 0.5 degrees Celsius (a little less than 1 degree F). We will cap the temperature to 35.0 degrees C, after which
|
||||
// it resets to 10.0 and starts over. Most importantly, we will do this once every 5 seconds by checking the elapsed time since the
|
||||
// previous modification using timeVal().
|
||||
|
||||
// All of the action happens in the last line, in which we set the value of the temp Characteristic to the new value of temperature.
|
||||
// All of the action happens in the setVal() line where we set the value of the temp Characteristic to the new value of temperature.
|
||||
// This tells HomeKit to send an Event Notification message to all available Controllers making them aware of the new temperature.
|
||||
// Note that setVal() is NOT a template function and does not require you to specify <float> as a template parameter. This is because
|
||||
// setVal() can determine the type from the argument you specify. If there is any chance of ambiguity, you can always specifically
|
||||
// cast the argument such: setVal((float)temperature).
|
||||
|
||||
void event(){
|
||||
|
||||
float temperature=temp->getVal<float>()+0.5; // here we "simulate" a half-degree temperature change...
|
||||
if(temperature>35.0) // ...but cap the maximum at 35 degrees before starting over at 10 degrees
|
||||
temperature=10.0;
|
||||
|
||||
temp->setVal(temperature); // don't forgot to update the temperature Characteristic to the new value!
|
||||
|
||||
} // event
|
||||
|
||||
void loop(){
|
||||
|
||||
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...
|
||||
if(temperature>35.0) // ...but cap the maximum at 35C before starting over at 10C
|
||||
temperature=10.0;
|
||||
|
||||
temp->setVal(temperature); // set the new temperature; this generates an Event Notification andalso resets the elapsed time
|
||||
|
||||
LOG1("Temperature Update: ");
|
||||
LOG1(temperature*9/5+32);
|
||||
LOG1("\n");
|
||||
}
|
||||
|
||||
} // loop
|
||||
|
||||
};
|
||||
|
|
@ -70,8 +65,6 @@ struct DEV_AirQualitySensor : Service::AirQualitySensor { // A standalone Ai
|
|||
SpanCharacteristic *no2Density; // reference to the Nitrogen Dioxide Characteristic, which is a float from 0 to 1000
|
||||
|
||||
DEV_AirQualitySensor(ServiceType sType=ServiceType::Regular) : Service::AirQualitySensor(sType){ // constructor() method
|
||||
|
||||
new SpanEvent(10000); // check for events on this Service every 10 seconds
|
||||
|
||||
airQuality=new Characteristic::AirQuality(1); // instantiate the Air Quality Characteristic and set initial value to 1
|
||||
o3Density=new Characteristic::OzoneDensity(300.0); // instantiate the Ozone Density Characteristic and set initial value to 300.0
|
||||
|
|
@ -82,17 +75,18 @@ struct DEV_AirQualitySensor : Service::AirQualitySensor { // A standalone Ai
|
|||
|
||||
} // end constructor
|
||||
|
||||
void event(){
|
||||
|
||||
airQuality->setVal((airQuality->getVal()+1)%6); // simulate a change in Air Quality by incrementing the current value by one, and keeping in range 0-5
|
||||
o3Density->setVal((double)random(200,500)); // change the Ozone Density to some random value between 200 and 499. Note use of (double) cast since random returns an integer
|
||||
void loop(){
|
||||
|
||||
// Note we are NOT updating the Nitrogen Dioxide Density Characteristic. This should therefore remain steady at its initial value of 700.0
|
||||
|
||||
} // event
|
||||
|
||||
void loop(){
|
||||
if(airQuality->timeVal()>5000) // modify the Air Quality Characteristic every 5 seconds
|
||||
airQuality->setVal((airQuality->getVal()+1)%6); // simulate a change in Air Quality by incrementing the current value by one, and keeping in range 0-5
|
||||
|
||||
if(o3Density->timeVal()>10000) // modify the Ozone Density Characteristic value every 10 seconds
|
||||
o3Density->setVal((double)random(200,500)); // simulate a change with a random value between 200 and 499. Note use of (double) cast since random() returns an integer
|
||||
|
||||
} // loop
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////
|
||||
|
|
@ -113,13 +107,9 @@ struct DEV_AirQualitySensor : Service::AirQualitySensor { // A standalone Ai
|
|||
// never use setVal() to update this Characteristic.
|
||||
|
||||
// If you run HomeSpan at a VERBOSITY level of 2 (as specified in the library's Settings.h file), you can see that under the hood HomeSpan is sending Event Notification
|
||||
// messages to all registered controllers every 5 seconds for the Temp Sensor, and every 10 seconds for the Air Quality Sensor. If you look carefully you'll see that
|
||||
// messages to all registered controllers every 5 seconds for the Temp Sensor, and every 5 and 10 seconds for the Air Quality Sensor. If you look carefully you'll see that
|
||||
// the Event Notification message for the Air Quality Sensor only include two values - one for the Air Quality state and one for the Ozone Density. HomeSpan is NOT
|
||||
// sending a value for the Nitrogen Dioxide Density Characteristic since it has not been changed with a setVal() function. This is an important design feature and
|
||||
// shows that the instantiation of a new SpanEvent only determines how often the event() method is checked by HomeSpan, not whether Event Notifications are actually sent.
|
||||
// If the event() method ALWAYS updates a Characteristic, then an Event Notification will always be generated. However, if event() does not update a Characteristic,
|
||||
// or only updates it under certain circumstances, then no message will be generated. This allows you to create a SpanEvent that frequenty checks a Service for an
|
||||
// event update, without generating Event Notifications that simply repeat the existing value of a Characteristic. We will see how this comes into play in the next example.
|
||||
// sending a value for the Nitrogen Dioxide Density Characteristic since it has not been changed with a setVal() function.
|
||||
|
||||
// FINAL NOTE: The number of decimals HomeKit displays for temperature in the HomeKit app is independent of the step size of the value itself. This seems to be
|
||||
// hardcoded by HomeKit: for Fahrenheit a Temperature Sensor tile shows no decimals and ROUNDS to the nearest whole degree (e.g. 72, 73, 74 degrees); for Celsius
|
||||
|
|
@ -64,7 +64,7 @@ void setup() {
|
|||
|
||||
Serial.begin(115200);
|
||||
|
||||
homeSpan.begin(Category::Bridges,"HomeSpan Bridge Test");
|
||||
homeSpan.begin(Category::Bridges,"HomeSpan Bridge");
|
||||
|
||||
|
||||
new SpanAccessory();
|
||||
|
|
|
|||
40
src/HAP.cpp
40
src/HAP.cpp
|
|
@ -1185,46 +1185,6 @@ void HAPClient::checkNotifications(){
|
|||
|
||||
//////////////////////////////////////
|
||||
|
||||
void HAPClient::checkEvents(){
|
||||
|
||||
unsigned long cTime=millis(); // current time
|
||||
vector<SpanBuf> spanBuf; // vector to SpanBuf objects
|
||||
|
||||
for(int i=0;i<homeSpan.Events.size();i++){ // loop over all defined Events
|
||||
if(cTime>homeSpan.Events[i]->alarmTime){ // if alarm time has passed
|
||||
|
||||
homeSpan.Events[i]->alarmTime=cTime+homeSpan.Events[i]->period; // set new alarm time to current time plus alarm period
|
||||
homeSpan.Events[i]->service->event(); // check service for new EVENTS
|
||||
|
||||
for(int j=0;j<homeSpan.Events[i]->service->Characteristics.size();j++){ // loop over all characteristics
|
||||
if(homeSpan.Events[i]->service->Characteristics[j]->isUpdated){ // if characteristic is updated
|
||||
|
||||
SpanBuf sb; // create SpanBuf object
|
||||
sb.characteristic=homeSpan.Events[i]->service->Characteristics[j]; // set characteristic
|
||||
sb.status=StatusCode::OK; // set status
|
||||
sb.val=""; // set dummy "val" so that sprintfNotify knows to consider this "update"
|
||||
spanBuf.push_back(sb);
|
||||
|
||||
LOG1("Event Notification for aid=");
|
||||
LOG1(homeSpan.Events[i]->service->Characteristics[j]->aid);
|
||||
LOG1(" iid=");
|
||||
LOG1(homeSpan.Events[i]->service->Characteristics[j]->iid);
|
||||
LOG1("\n");
|
||||
|
||||
homeSpan.Events[i]->service->Characteristics[j]->isUpdated=false; // reset isUpdated flag
|
||||
|
||||
} // if characteristic is updated
|
||||
} // characteristic loop
|
||||
} // alarm triggered
|
||||
} // events loop
|
||||
|
||||
if(spanBuf.size()>0) // if updated items are found
|
||||
eventNotify(&spanBuf[0],spanBuf.size()); // transmit EVENT Notifications
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
void HAPClient::checkTimedResets(){
|
||||
|
||||
unsigned long cTime=millis(); // current time
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ struct HAPClient {
|
|||
static void printControllers(); // prints IDs of all allocated (paired) Controller
|
||||
static void checkTimedResets(); // checks for Timed Resets and reports to controllers as needed (HAP Section 6.8)
|
||||
static void callServiceLoops(); // call the loop() method for any Service with that over-rode the default method
|
||||
static void checkEvents(); // checks for Event Notifications and reports to controllers as needed (HAP Section 6.8)
|
||||
static void checkNotifications(); // checks for Event Notifications and reports to controllers as needed (HAP Section 6.8)
|
||||
static void checkTimedWrites(); // checks for expired Timed Write PIDs, and clears any found (HAP Section 6.7.2.4)
|
||||
static void eventNotify(SpanBuf *pObj, int nObj, int ignoreClient=-1); // transmits EVENT Notifications for nObj SpanBuf objects, pObj, with optional flag to ignore a specific client
|
||||
|
|
|
|||
|
|
@ -1158,23 +1158,6 @@ SpanTimedReset::SpanTimedReset(int waitTime){
|
|||
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// SpanEvent //
|
||||
///////////////////////////////
|
||||
|
||||
SpanEvent::SpanEvent(int period){
|
||||
|
||||
if(homeSpan.Accessories.empty() || homeSpan.Accessories.back()->Services.empty() ){
|
||||
Serial.print("*** FATAL ERROR: Can't create new Timed Reset without a defined Service. Program halted!\n\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
this->service=homeSpan.Accessories.back()->Services.back();
|
||||
this->period=period;
|
||||
homeSpan.Events.push_back(this);
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// SpanRange //
|
||||
///////////////////////////////
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ struct SpanCharacteristic;
|
|||
struct SpanRange;
|
||||
struct SpanBuf;
|
||||
struct SpanTimedReset;
|
||||
struct SpanEvent;
|
||||
|
||||
///////////////////////////////
|
||||
|
||||
|
|
@ -50,7 +49,6 @@ struct Span{
|
|||
SpanConfig hapConfig; // track configuration changes to the HAP Accessory database; used to increment the configuration number (c#) when changes found
|
||||
vector<SpanAccessory *> Accessories; // vector of pointers to all Accessories
|
||||
vector<SpanTimedReset *> TimedResets; // vector of pointers to all TimedResets
|
||||
vector<SpanEvent *> Events; // vector of pointer to all Events
|
||||
vector<SpanService *> Loops; // vector of pointer to all Services that have over-ridden loop() methods
|
||||
vector<SpanBuf> Notifications; // vector of SpanBuf objects that store info for Characteristics that are updated with setVal() and require a Notification Event
|
||||
unordered_map<uint64_t, uint32_t> TimedWrites; // map of timed-write PIDs and Alarm Times (based on TTLs)
|
||||
|
|
@ -247,16 +245,6 @@ struct SpanTimedReset{
|
|||
SpanTimedReset(int waitTime);
|
||||
};
|
||||
|
||||
///////////////////////////////
|
||||
|
||||
struct SpanEvent{
|
||||
SpanService *service; // service to check for events
|
||||
int period; // time period between checks (in milliseconds)
|
||||
unsigned long alarmTime=0; // alarm time to trigger next check
|
||||
|
||||
SpanEvent(int period);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Extern Variables
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue