Updated Examples 1-11

Completely replaced Example 11, which showed how to use setPrimary() since this no longer seems to have any impact on HomeKit.  Changed sketch name from ServiceOptions to ServiceNames.
This commit is contained in:
Gregg 2022-04-09 18:17:59 -05:00
parent ac0344ebb2
commit 9241398f9b
9 changed files with 212 additions and 344 deletions

View File

@ -76,6 +76,8 @@ void setup() {
// can also change the name of any Accessory Tile, even after pairing, directly from the Home App by opening the settings page // can also change the name of any Accessory Tile, even after pairing, directly from the Home App by opening the settings page
// for any given Tile. // for any given Tile.
// In Example 7 we will demonstrate how the default names can be changed from within a HomeSpan sketch.
// IMPORTANT: You should NOT have to re-pair your device with HomeKit when moving from Example 1 to Example 2. HomeSpan will note // IMPORTANT: You should NOT have to re-pair your device with HomeKit when moving from Example 1 to Example 2. HomeSpan will note
// that the Attribute Database has been updated, and will broadcast a new configuration number when the program restarts. This should // that the Attribute Database has been updated, and will broadcast a new configuration number when the program restarts. This should
// cause all iOS and MacOS HomeKit Controllers to automatically update and reflect the new configuration above. // cause all iOS and MacOS HomeKit Controllers to automatically update and reflect the new configuration above.

View File

@ -47,6 +47,8 @@ void setup() {
homeSpan.begin(Category::Fans,"HomeSpan Ceiling Fan"); // Initialize HomeSpan - note the Category has been set to "Fans" homeSpan.begin(Category::Fans,"HomeSpan Ceiling Fan"); // Initialize HomeSpan - note the Category has been set to "Fans"
// We begin by creating a Light Bulb Accessory just as in Examples 1 and 2 // We begin by creating a Light Bulb Accessory just as in Examples 1 and 2
new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), no arguments needed
new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, with the required Identify Characteristic new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, with the required Identify Characteristic
new Characteristic::Identify(); // Create the required Identify new Characteristic::Identify(); // Create the required Identify
@ -59,11 +61,40 @@ void setup() {
new Service::Fan(); // Create the Fan Service new Service::Fan(); // Create the Fan Service
new Characteristic::Active(); // This Service requires the "Active" Characterstic to turn the fan on and off new Characteristic::Active(); // This Service requires the "Active" Characterstic to turn the fan on and off
// If everything worked correctly you should now see a single Tile named "HomeSpan Ceiling Fan" within the Home App. // Similar to Example 2, we will also implement a LightBulb as a second Accessory
// Clicking that Tile should open a window displaying two on/off controls - one for the Fan, and one for the Light.
new SpanAccessory(); // Begin by creating a new Accessory using SpanAccessory(), no arguments needed
new Service::AccessoryInformation(); // HAP requires every Accessory to implement an AccessoryInformation Service, with the required Identify Characteristic
new Characteristic::Identify(); // Create the required Identify
new Service::LightBulb(); // Create the Light Bulb Service
new Characteristic::On(); // This Service requires the "On" Characterstic to turn the light on and off
// If everything worked correctly you should now see two Tiles in the Home App:
//
// * a Tile named "HomeSpan Ceiling Fan" with an icon of a Fan. Clicking this Tile should open the
// control page showing a Fan control on the left, and a Light control on the right
//
// * a Tile named "HomeSpan Ceiling Fan 2" with an icon of a LightBulb. Clicking this Tile should
// toggle the Light On/Off
// The reason for including the second LightBulb Accessories in this example is to illustrate the impact of the device's Category
// on various icons. Setting Category to Fan in homeSpan.begin() serves two purposes. First, it sets the icon for the device itself,
// as shown by the Home App during initial pairing, to a Fan. Second, it helps the Home App to determine which icon to use for an
// Accessory Tile when there is ambiguity. The second Accessory contains nothing but a LightBulb Service, so the Home App sensibly
// uses a LightBulb icon for the Tile. But what icon should the Home App use for the first Accessory containing both a Fan Service
// and a LightBulb Service? Either a Fan or LightBulb icon would make sense. Setting the Category of the device to Fan causes
// the Home App to choose a Fan icon for the first Accessory.
// As a test of this, unpair the device; change the Category to Lighting (as in Example 2); re-load the sketch; and re-pair the device.
// You should now see the icon for the "HomeSpan Ceiling Fan" Tile is a LightBulb, and the control screen for the Accessory should
// show the Light control on the left and the Fan control on the right.
// IMPORTANT: HomeKit Controllers often cache a lot of information. If your Controller does not update to match the above configuration, // IMPORTANT: HomeKit Controllers often cache a lot of information. If your Controller does not update to match the above configuration,
// simply select the Accessory in your Controller and under setting, select "Remove Accessory" and then re-pair. // simply select the Accessory in your Controller and under settings, select "Remove Accessory", but BEFORE re-pairing the device, type
// 'H' into the HomeSpan CLI. This forces HomeSpan to reboot and generate a new device ID so that it will look "brand new" to the Home App
// when you re-pair.
} // end of setup() } // end of setup()

View File

@ -40,7 +40,7 @@
void setup() { void setup() {
// Example 4 expands on Example 3 by adding Characteristics to set FAN SPEED, FAN DIRECTION, and LIGHT BRIGHTNESS. // Example 4 expands on the first Accessory in Example 3 by adding Characteristics to set FAN SPEED, FAN DIRECTION, and LIGHT BRIGHTNESS.
// For ease of reading, all prior comments have been removed and new comments added to show explicit changes from the previous example. // For ease of reading, all prior comments have been removed and new comments added to show explicit changes from the previous example.
Serial.begin(115200); Serial.begin(115200);

View File

@ -41,7 +41,7 @@
void setup() { void setup() {
// As discusses in previous examples, the Home App automatically generate default names for each Accessory Tile // As discusses in previous examples, the Home App automatically generates default names for each Accessory Tile
// based on the Name provided in the second argument of homeSpan.begin(). And though you can change these names // based on the Name provided in the second argument of homeSpan.begin(). And though you can change these names
// both during, and anytime after, pairing, HAP also allows you to customize the default names themselves, so // both during, and anytime after, pairing, HAP also allows you to customize the default names themselves, so
// something more intuitive is presented to the user when the device is first paired. // something more intuitive is presented to the user when the device is first paired.

View File

@ -62,9 +62,8 @@ void setup() {
Serial.begin(115200); Serial.begin(115200);
// Below we replace Category::Lighting with Category::Bridges. This changes the icon of the device shown when pairing // Below we replace Category::Lighting with Category::Bridges. This changes the icon of the device shown when pairing
// with the Home App. It does NOT change any of the icons for an Accessory Tile (these are determined by the types of // with the Home App, but does NOT change the icons of the Accessory Tiles. You can choose any Category you like.
// Services implemented in each Accessory - see Example 9). Note you can choose any Category you like - for instance, // For instance, we could have continued to use Category::Lighting, even though we are configuring the device as a Bridge.
// we could have continued to use Category::Lighting, even though we are configuring the device as a Bridge.
homeSpan.begin(Category::Bridges,"HomeSpan Bridge"); homeSpan.begin(Category::Bridges,"HomeSpan Bridge");
@ -75,7 +74,7 @@ void setup() {
new SpanAccessory(); // This second Accessory is the same as the first Accessory in Example 7, with the exception that Characteristic::Name() now does something new SpanAccessory(); // This second Accessory is the same as the first Accessory in Example 7, with the exception that Characteristic::Name() now does something
new Service::AccessoryInformation(); new Service::AccessoryInformation();
new Characteristic::Identify(); new Characteristic::Identify();
new Characteristic::Name("Simple LED"); // Note that unlike in Example 7, this use of Name() is properly implented by the Home App since it is not the first Accessory (the Bridge above is the first) new Characteristic::Name("Simple LED"); // Note that unlike in Example 7, this use of Name() is now utilized by the Home App since it is not the first Accessory (the Bridge above is the first)
new DEV_LED(16); new DEV_LED(16);
new SpanAccessory(); // This third Accessory is the same as the second Accessory in Example 7 new SpanAccessory(); // This third Accessory is the same as the second Accessory in Example 7

View File

@ -0,0 +1,171 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2020-2022 Gregg E. Berman
*
* https://github.com/HomeSpan/HomeSpan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
********************************************************************************/
////////////////////////////////////////////////////////////
// //
// HomeSpan: A HomeKit implementation for the ESP32 //
// ------------------------------------------------ //
// //
// Example 11: Service Names: //
// * setting the names of individual Services //
// * changing the icons in a bridge Accessory //
// //
////////////////////////////////////////////////////////////
#include "HomeSpan.h"
void setup() {
// As described in previous examples, when pairing a device the Home App will choose default names for each
// Accessory Tile, unless you override those default names with your own names by adding a Name Characteristic
// to the Accessory Information Service for each Accessory (except the first, which is typically the Bridge Accessory).
// The same process holds true for the names of the Services in an Accessory with multiple Services, such as a Ceiling Fan with a Light.
// When pairing, the Home App will choose default names for each Service (such as Fan, Fan 2, Light, Light 2) depending on the types
// of Services included. Similar to the names of Accessory Tiles, you can change the names of individual Services when prompted
// during the pairing process, or at any time after pairing from within the appropriate settings pages in the Home App. More importantly,
// you can override the default Service names generated by the Home App by simply adding the Name Characteristic to any Service.
// However, note that Service names (whether or not overridden) only appear in the Home App if there is a chance of ambiguity,
// such as a Accessory with two Services of the same type. But even if a Service name does not appear in the Home App,
// it will still be used by Siri to control a specific Service within an Accessory by voice.
// In the example below we create 5 different functional Accessories, each illustrating how names, as well as icons, are chosen by the Home App
Serial.begin(115200);
// This device will be configured as a Bridge, with the Category set to Bridges
homeSpan.begin(Category::Bridges,"HomeSpan Bridge");
// Our first Accessory is the "Bridge" Accessory
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
// Our second Accessory is a Ceiling Fan with a single Light. There are three things to note:
//
// * when pairing, the Home App will generate default names of "Light" and "Fan" for the two Services.
// However, these names are not displayed on the control screen of the Accessory since there is no
// ambiguity between the Light and Fan controls - the Home App displays them differently
//
// * the icon used by the Home App for the Accessory Tile is a Lightbulb. Why does it choose this instead of a Fan icon?
// Recall from Example 3 that for Accessories with multiple Services, if there is any ambiguity of which icon to use,
// the Home App chooses based on the Category of the device. But since this device is configured as a Bridge, the
// Category provides no helpful information to the Home App. In such cases the Home App picks an icon for the
// Accessory Tile that matches the first functional Service in the Accessory, which in this instance in a LightBulb
//
// * when opening the control screen by clicking the Accessory Tile, the LightBulb control will appear on the left, and
// the Fan control will appear on the right
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::Name("Light with Fan"); // this sets the name of the Accessory Tile
new Service::LightBulb(); // the icon of the Accessory Tile will be a Lightbulb, since this is the first functional Service
new Characteristic::On();
new Service::Fan();
new Characteristic::Active();
// Our third Accessory is identical to the second, except we swapped the order of the Lightbulb and Fan Services.
// The result is that the Home App now displays the Accessory Tile with a Fan icon intead of a Lightbulb icon.
// Also, when opening the control screen by clicking on the Accessory Tile, the Fan control will now appear on the
// left, and the LightBulb control on the right.
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::Name("Fan with Light"); // this sets the name of the Accessory Tile
new Service::Fan(); // the icon of the Accessory Tile will be a Fan, since this is the first functional Service
new Characteristic::Active();
new Service::LightBulb();
new Characteristic::On();
// Our fourth Accessory shows what happens if we implement two identical LightBulb Services (without any Fan Service).
// Since both Services are LightBulbs, the Home App sensibly picks a Lightbulb icon for the Accessory Tile. However,
// when you click the Accessory Tile and open the control screen, you'll note that the Home App now does display the names
// of the Service beneath each control. In this case the Home App uses the default names "Light 1" and "Light 2". The Home App
// presumably shows the names of each Service since the two controls are identical and there is otherwise no way of telling which
// control operates which light.
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::Name("Ceiling Lights"); // this sets the name of the Accessory Tile
new Service::LightBulb();
new Characteristic::On();
new Service::LightBulb();
new Characteristic::On();
// Our fifth Accessory combines a single Fan Service with two identical LightBulb Services. Since the first functional Service implemented
// is a Fan, the Home App will pick a Fan icon for the Accessory Tile. Also, since we added Name Characteristics to two LightBulb
// Services, their default names generated by the Home App ("Light 1" and "Light 2") will be changed to the names specified. Finally,
// note that the Home App displays a more compact form of controls on the control screen since there are three Services. The arrangement
// and style of the controls will depend on what combination of Characteristics are implemented for each Service.
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::Name("Fan with Lights"); // this sets the name of the Accessory Tile
new Service::Fan();
new Characteristic::Active();
new Service::LightBulb();
new Characteristic::Name("Main Light"); // this changes the default name of this LightBulb Service from "Light 1" to "Main Light"
new Characteristic::On();
new Service::LightBulb();
new Characteristic::Name("Night Light"); // this changes the default name of this LightBulb Service from "Light 2" to "Night Light"
new Characteristic::On();
// Our sixth Accessory is similar to the fifth, except we added some more features to some of the Services. Note how this changes
// the layout of the controls on the control screen.
new SpanAccessory();
new Service::AccessoryInformation();
new Characteristic::Identify();
new Characteristic::Name("Multi-Function Fan");
new Service::Fan();
new Characteristic::Active();
new Characteristic::RotationDirection(); // add a control to change the direcion of rotation
new Characteristic::RotationSpeed(0); // add a control to set the rotation speed
new Service::LightBulb();
new Characteristic::Name("Main Light");
new Characteristic::On();
new Characteristic::Brightness(100); // make this light dimmable (with intitial value set to 100%)
new Service::LightBulb();
new Characteristic::Name("Night Light"); // don't add anything new to this light
new Characteristic::On();
} // end of setup()
//////////////////////////////////////
void loop(){
homeSpan.poll();
} // end of loop()

View File

@ -1,202 +0,0 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2020 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.
*
********************************************************************************/
////////////////////////////////////////////////////////////
// //
// HomeSpan: A HomeKit implementation for the ESP32 //
// ------------------------------------------------ //
// //
// Example 11: Service Options: //
// * setting the Primary Service //
// * setting Service Names //
// //
////////////////////////////////////////////////////////////
#include "HomeSpan.h"
#include "DEV_LED.h"
#include "DEV_Identify.h"
void setup() {
// Every Accessory we define has at least two Services, one of which will always be the required Accessory Information Service (and
// which we've conveniently wrapped into a derived Service we called DEV_Identify). The second is usually a Service that performs
// some sort of actual operation, such as the LightBulb Service or the Fan Service. It's this second operative Service that creates
// the controls we see in the HomeKit iOS or MacOS application. These appear as tiles with a lightbulb control or fan control.
// We've also created Accessories with more than two operational Service, such as our definition of a ceiling fan that includes
// BOTH a Fan Service and a LightBulb Service. The HomeKit application can display an Accessory with two or more operational Services
// in one of two ways: one way is to display each Service as a separate tile, so that our ceiling fan would show up as one standalone
// lightbulb tile for the LightBulb Service and one standalone fan tile for the Fan Service. The second way is for HomeKit to display
// our ceiling fan as a single tile that you click to open a new screen showing both the fan control and the lightbulb control side by side.
// HomeSpan has no control over whether HomeKit displays multiple Services as separate tiles or as a single combined single tile.
// This is determined by the user from within the HomeKit iOS or MacOS application (the default is to use the combined tile mode).
// However, HomeSpan does have control over the which icon is used to display the ceiling fan in combined-tile mode. Should it be a
// lightbulb or a fan?
// HomeKit determines which icon to show on the combined tile according to what is considered the Primary Service of the Accessory.
// HomeKit will also list the Primary Service first when you click a combined tile to open its controls.
// A Service can be set to Primary with the setPrimary() method. The easiest way to do this is by "chaining" setPrimary() to the
// end of a new Service when first instantiated. See below for examples of how to do this.
// To begin, we first initialize HomeSpan and define our Bridge Accessory as in the previous examples:
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");
// Next, we create two Accessories each configured to control a Ceiling Fan containing a bi-directional, multi-speed fan AND a dimmable light.
// In Ceiling Fan #1 we specify the Dimmable LED as the Primary Service. In Ceiling Fan #2 we specify the Fan as the Primary Service.
// If you set HomeKit to display each of these Accessories as combined tiles, you'll immediately see the difference. Ceiling Fan #1 shows as
// Lightbulb Tile with the dimmable LED listed first when you click open its controls. Ceiling Fan #2 shows as a Fan Tile with the fan listed first
// when you click open its controls. Nice and easy.
new SpanAccessory();
new DEV_Identify("Ceiling Fan #1","HomeSpan","123-ABC","20mA LED","0.9",0);
(new DEV_DimmableLED(17))->setPrimary(); // Here we specify DEV_DimmableLED as the Primary Service by "chaining" setPrimary() to the pointer return by new. Note parentheses!
new Service::Fan();
new Characteristic::Active();
new Characteristic::RotationDirection();
new Characteristic::RotationSpeed(0);
new SpanAccessory();
new DEV_Identify("Ceiling Fan #2","HomeSpan","123-ABC","20mA LED","0.9",0);
new DEV_DimmableLED(17);
(new Service::Fan())->setPrimary(); // Here we specify the Fan as the Primary Service. Again, note how we encapsulated the "new" command in parentheses, then chained setPrimary()
new Characteristic::Active();
new Characteristic::RotationDirection();
new Characteristic::RotationSpeed(0);
//////////////////////////////////
// In addition to being able to specify which Service in an Accessory is the Primary Service, HomeKit also allows you to give names to each of
// the individual Services. This is done by instantiating a Name Characteristic for a Service. We've already used this feature in creating
// DEV_Identify --- the first argument is used to to name the Service (see DEV_Identify.h). In fact, the Name Characteristic is required
// for the AccessoryInformation Service, so we had to instantiate as part of DEV_Identify.
// For all other Services the name Characteristic is optional. If not instantiated, the name will be defaulted to whatever name we specified
// in DEV_Identify, which means that if we have more than one operational Service in an Accessory, they will all be named the same.
// This is not necessarily a problem since names don't always come into play in the HomeKit interface. In the examples above, the only name
// that gets displayed in combined-tile mode is "Ceiling Fan #1" or "Ceiling Fan #2", which makes sense. When you click open the controls
// for either Accessory you see a lightbulb control and a fan control. They are not individually named, but the controls look different (one
// is a light control, the other a fan control) so there is no confusion.
// If instead you set HomeKit to display the controls for these Accessories as separate tiles, you'll see that each of the light and fan controls
// has their own name. But since in the above examples we did not provide specific names for each of these Services, they will simply inherit the
// name "Ceiling Fan #1" or "Ceiling Fan #2". Again, there is no confusion since the light and fan controls each look different.
// The situation becomes more interesting when you have an Accessory with 3 or more operational Services. Sometimes HomeKit will display the names
// of the Services on the control panel even in combined-tile mode. Consider our ceiling fan example above, but with the added feature of a night-light,
// which we will represent as a simple On/Off LED. Let's instantiate the Name Characteristic for each Service, as shown below.
new SpanAccessory();
new DEV_Identify("Ceiling Fan #3","HomeSpan","123-ABC","20mA LED","0.9",0);
new DEV_DimmableLED(17);
new Characteristic::Name("Main Light"); // Here we create a name for the Dimmable LED
new DEV_LED(16);
new Characteristic::Name("Night Light"); // Here we create a name for the On/Off LED
(new Service::Fan())->setPrimary();
new Characteristic::Active();
new Characteristic::RotationDirection();
new Characteristic::RotationSpeed(0);
new Characteristic::Name("Fan"); // Here we create a name for the Fan
// If you let HomeKit display this as a single, combined tile, you'll notice two things. The first is that the name of the tile is now "Fan" instead
// of "Ceiling Fan #3". Why is that? It's because we set Fan to be the Primary Service AND gave it a name --- this is the name that shows up
// on the combined tile. If we did not give it a name, it would have inherited the name "Ceiling Fan #3", which would have been the name of the tile
// as in the prior example.
// The second thing you'll notice is that these names now appear next to each control if you click open the combined tile. It says "Fan" next to the Fan
// control, "Main Light" next to the Dimmable LED control, and "Night Light" next to the On/Off LED control.
// If instead you tell HomeKit to display the controls for Ceiling Fan #3 as three separate tiles, you'll see that each tile contains the name specified
// above for that Service. In some circumstances that can be helpful, in others it can be confusing. For instance, if you had two ceiling fans that
// each had a main light and a night night, how would you know which "Main Light" is which? One solution is to create names like "Main Light #3" and
// "Main Light #4". The other solution is to keep them combined in a single tile, but keep the name "Ceiling Fan #3" for the combined tile, instead of
// having it over-ridden with the word "Fan"
// This is easily done by specifying DEV_Identify as the Primary Service, instead of Fan, as follows:
new SpanAccessory();
(new DEV_Identify("Ceiling Fan #4","HomeSpan","123-ABC","20mA LED","0.9",0))->setPrimary(); // specify DEV_Identify as the Primary Service
new DEV_DimmableLED(17);
new Characteristic::Name("Main Light");
new DEV_LED(16);
new Characteristic::Name("Night Light");
new Service::Fan();
new Characteristic::Active();
new Characteristic::RotationDirection();
new Characteristic::RotationSpeed(0);
new Characteristic::Name("Fan");
// HomeKit now shows the name "Ceiling Fan #4" for the combined tile AND it still shows the individual names for each control when you click open the tile.
// The only downside to this configuration is that since the Fan is no longer specified as the Primary Service, the main icon on the combined tile now shows
// as a lightbulb, instead of the fan. HomeKit documentation is not clear on how the main icon is chosen under these circumstances, but I've found
// that changing the order of Services as they are instantiated can impact the icon. Here is the same example as above, but with the Fan
// instantiated as the first operational Service, ahead of the Main Light and Night Night:
new SpanAccessory();
(new DEV_Identify("Ceiling Fan #5","HomeSpan","123-ABC","20mA LED","0.9",0))->setPrimary(); // specify DEV_Identify as the Primary Service
new Service::Fan();
new Characteristic::Active();
new Characteristic::RotationDirection();
new Characteristic::RotationSpeed(0);
new Characteristic::Name("Fan");
new DEV_DimmableLED(17);
new Characteristic::Name("Main Light");
new DEV_LED(16);
new Characteristic::Name("Night Light");
// This seems to cause HomeKit to display the Fan icon on the combined tile, as well as to list the Fan Service control first when the tile is clicked
// open, almost as if it were the Primary Service in all ways except for its name.
// As you can see, there is no right or wrong way for how to name your Accessories and Services, including whether or not to even bother naming your
// individual Services. It's purely a matter of taste - experiment and see which combinations best serve your purposes.
// IMPORTANT: HomeKit tries to cache as many items as possible, and although it should know when configurations change, it does not always respond
// as expected. If you are experimenting and find that name changes are NOT being reflected in the HomeKit interface, simply unpair HomeSpan and
// re-pair. This often causes a refresh. If not, after unpairing you can additionally reset the HAP data in HomeSpan so that its HAP ID changes (see
// HomeSpan documentation for how to easily do this). This way when you re-pair, HomeKit should think this is a completely new device and start with
// a clean slate. *** In some limited circumstances, HomeKit may get so confused it refuses to operate the Accessories at all. You may get a No Response
// icon even though HomeSpan is operating correctly. Though it is possible to misconfigure HomeSpan in ways that cause this, if you do get this
// error please try the re-pairing methods above as it often fixes the problem.
} // end of setup()
//////////////////////////////////////
void loop(){
homeSpan.poll();
} // end of loop()

View File

@ -1,38 +0,0 @@
//////////////////////////////////
// DEVICE-SPECIFIC SERVICES //
//////////////////////////////////
struct DEV_Identify : Service::AccessoryInformation {
int nBlinks; // number of times to blink built-in LED in identify routine
SpanCharacteristic *identify; // reference to the Identify Characteristic
DEV_Identify(const char *name, const char *manu, const char *sn, const char *model, const char *version, int nBlinks) : Service::AccessoryInformation(){
new Characteristic::Name(name); // create all the required Characteristics with values set based on above arguments
new Characteristic::Manufacturer(manu);
new Characteristic::SerialNumber(sn);
new Characteristic::Model(model);
new Characteristic::FirmwareRevision(version);
identify=new Characteristic::Identify(); // store a reference to the Identify Characteristic for use below
this->nBlinks=nBlinks; // store the number of times to blink the LED
pinMode(homeSpan.getStatusPin(),OUTPUT); // make sure LED is set for output
}
boolean update(){
for(int i=0;i<nBlinks;i++){
digitalWrite(homeSpan.getStatusPin(),LOW);
delay(250);
digitalWrite(homeSpan.getStatusPin(),HIGH);
delay(250);
}
return(true); // return true
} // update
};

View File

@ -1,95 +0,0 @@
////////////////////////////////////
// DEVICE-SPECIFIC LED SERVICES //
////////////////////////////////////
#include "extras/PwmPin.h" // library of various PWM functions
////////////////////////////////////
struct DEV_LED : Service::LightBulb { // ON/OFF LED
int ledPin; // pin number defined for this LED
SpanCharacteristic *power; // reference to the On Characteristic
DEV_LED(int ledPin) : Service::LightBulb(){
power=new Characteristic::On();
this->ledPin=ledPin;
pinMode(ledPin,OUTPUT);
Serial.print("Configuring On/Off LED: Pin="); // initialization message
Serial.print(ledPin);
Serial.print("\n");
} // end constructor
boolean update(){ // update() method
LOG1("Updating On/Off LED on pin=");
LOG1(ledPin);
LOG1(": Current Power=");
LOG1(power->getVal()?"true":"false");
LOG1(" New Power=");
LOG1(power->getNewVal()?"true":"false");
LOG1("\n");
digitalWrite(ledPin,power->getNewVal());
return(true); // return true
} // update
};
//////////////////////////////////
struct DEV_DimmableLED : Service::LightBulb { // Dimmable LED
LedPin *ledPin; // reference to Led Pin
SpanCharacteristic *power; // reference to the On Characteristic
SpanCharacteristic *level; // reference to the Brightness Characteristic
DEV_DimmableLED(int pin) : Service::LightBulb(){ // constructor() method
power=new Characteristic::On();
level=new Characteristic::Brightness(50); // Brightness Characteristic with an initial value of 50%
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->ledPin=new LedPin(pin); // configures a PWM LED for output to the specified pin
Serial.print("Configuring Dimmable LED: Pin="); // initialization message
Serial.print(ledPin->getPin());
Serial.print("\n");
} // end constructor
boolean update(){ // update() method
LOG1("Updating Dimmable LED on pin=");
LOG1(ledPin->getPin());
LOG1(": Current Power=");
LOG1(power->getVal()?"true":"false");
LOG1(" Current Brightness=");
LOG1(level->getVal());
if(power->updated()){
LOG1(" New Power=");
LOG1(power->getNewVal()?"true":"false");
}
if(level->updated()){
LOG1(" New Brightness=");
LOG1(level->getNewVal());
}
LOG1("\n");
ledPin->set(power->getNewVal()*level->getNewVal());
return(true); // return true
} // update
};
//////////////////////////////////