Announce a doorbell with proactivelyReported and a scene with supportsDeactivation
An interface without properties says beside its name what Alexa has to know of it; the library left both out. With a board and Alexa on 2026-09-28 the discovery of a doorbell was accepted (202), the endpoint was not listed, and its DoorbellPress was answered with 500 INTERNAL_SERVICE_EXCEPTION. DoorbellEventSource now always carries "proactivelyReported": true. SceneController carries "supportsDeactivation", false until the sketch calls setSupportsDeactivation(true); on another interface the call is refused and logged. The Scene example says that it can be undone. 148 host tests. Light: static RAM 30,616 B, flash 332,705 B (+140 B). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
1b8a5ff806
commit
c3d02f462e
11 changed files with 65 additions and 18 deletions
|
|
@ -76,7 +76,7 @@ void setup()
|
||||||
// The name Alexa shows, and the id of the endpoint: every device of an account has its own
|
// The name Alexa shows, and the id of the endpoint: every device of an account has its own
|
||||||
doorbell = alexa.getDevice("Front Door Bell", "esp-doorbell");
|
doorbell = alexa.getDevice("Front Door Bell", "esp-doorbell");
|
||||||
doorbell->setDisplayCategory(DisplayCategory::DOORBELL);
|
doorbell->setDisplayCategory(DisplayCategory::DOORBELL);
|
||||||
doorbell->addCapability(AlexaInterfaces::DoorbellEventSource)->setProactivelyReported(true);
|
doorbell->addCapability(AlexaInterfaces::DoorbellEventSource);
|
||||||
doorbell->addCapability(AlexaInterfaces::EndpointHealth);
|
doorbell->addCapability(AlexaInterfaces::EndpointHealth);
|
||||||
doorbell->onDirective(onDirective);
|
doorbell->onDirective(onDirective);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,6 @@ not been tried.
|
||||||
|
|
||||||
## Limits
|
## Limits
|
||||||
|
|
||||||
- Scene: the discovery object does not carry `supportsDeactivation`. The sketch answers `Deactivate`, but Alexa
|
|
||||||
may never send it.
|
|
||||||
- Doorbell, ContactSensor: an event or a change while there is no session with the broker is not sent later.
|
- Doorbell, ContactSensor: an event or a change while there is no session with the broker is not sent later.
|
||||||
- Lock: the answer after the DeferredResponse is sent once. If the session is lost while the bolt moves, Alexa gets
|
- Lock: the answer after the DeferredResponse is sent once. If the session is lost while the bolt moves, Alexa gets
|
||||||
the state with its next ReportState.
|
the state with its next ReportState.
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
// with DeactivationStarted. The scene of this sketch switches two outputs: the ceiling lamp off and the lamp
|
// with DeactivationStarted. The scene of this sketch switches two outputs: the ceiling lamp off and the lamp
|
||||||
// behind the screen on.
|
// behind the screen on.
|
||||||
//
|
//
|
||||||
// The discovery object of the library does not say that the scene can be deactivated (supportsDeactivation), so
|
// setSupportsDeactivation(true) tells Alexa that the scene can be undone: "Alexa, turn off Movie Night" then
|
||||||
// Alexa may never send Deactivate. The handler answers it all the same.
|
// arrives as Deactivate.
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <Alex2ESP.h>
|
#include <Alex2ESP.h>
|
||||||
|
|
@ -93,7 +93,7 @@ void setup()
|
||||||
// The name Alexa shows, and the id of the endpoint: every device of an account has its own
|
// The name Alexa shows, and the id of the endpoint: every device of an account has its own
|
||||||
AlexaDevice *scene = alexa.getDevice("Movie Night", "esp-scene");
|
AlexaDevice *scene = alexa.getDevice("Movie Night", "esp-scene");
|
||||||
scene->setDisplayCategory(DisplayCategory::SCENE_TRIGGER);
|
scene->setDisplayCategory(DisplayCategory::SCENE_TRIGGER);
|
||||||
scene->addCapability(AlexaInterfaces::SceneController);
|
scene->addCapability(AlexaInterfaces::SceneController)->setSupportsDeactivation(true);
|
||||||
scene->addCapability(AlexaInterfaces::EndpointHealth);
|
scene->addCapability(AlexaInterfaces::EndpointHealth);
|
||||||
scene->onDirective(onDirective);
|
scene->onDirective(onDirective);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ addStateMapping KEYWORD2
|
||||||
addFriendlyAsset KEYWORD2
|
addFriendlyAsset KEYWORD2
|
||||||
setConfiguration KEYWORD2
|
setConfiguration KEYWORD2
|
||||||
setNonControllable KEYWORD2
|
setNonControllable KEYWORD2
|
||||||
|
setSupportsDeactivation KEYWORD2
|
||||||
isNonControllable KEYWORD2
|
isNonControllable KEYWORD2
|
||||||
getInstance KEYWORD2
|
getInstance KEYWORD2
|
||||||
getRow KEYWORD2
|
getRow KEYWORD2
|
||||||
|
|
|
||||||
|
|
@ -685,7 +685,6 @@ What changes for a 1.x sketch that is compiled against 2.0:
|
||||||
- Reports are published with QoS 0 and sent once. An event or a change while there is no session with the broker is not sent later; `send()` returns `false` and the sketch decides.
|
- Reports are published with QoS 0 and sent once. An event or a change while there is no session with the broker is not sent later; `send()` returns `false` and the sketch decides.
|
||||||
- Tried with Alexa from this library: the six interfaces marked in [Interface Types](#interface-types). Not tried from this library: `ColorController`, `ThermostatController`, `LockController` and the deferred answer, `SceneController`, the ErrorResponse, the ChangeReports, `DoorbellPress` and every interface without an example. Voice commands have not been tried.
|
- Tried with Alexa from this library: the six interfaces marked in [Interface Types](#interface-types). Not tried from this library: `ColorController`, `ThermostatController`, `LockController` and the deferred answer, `SceneController`, the ErrorResponse, the ChangeReports, `DoorbellPress` and every interface without an example. Voice commands have not been tried.
|
||||||
- The examples are compiled, with 0 warnings, and what each announces in discovery is checked by the host tests. They have not run on a board and have not been built with the Arduino IDE.
|
- The examples are compiled, with 0 warnings, and what each announces in discovery is checked by the host tests. They have not run on a board and have not been built with the Arduino IDE.
|
||||||
- The discovery object of a scene does not carry `supportsDeactivation`, so Alexa may never send `Deactivate`.
|
|
||||||
- The library keeps no state of the devices. What a device is set to is a variable of the sketch and starts from its initial value after a reset.
|
- The library keeps no state of the devices. What a device is set to is a variable of the sketch and starts from its initial value after a reset.
|
||||||
- 28 of the interfaces of Alexa have a row. The others cannot be announced.
|
- 28 of the interfaces of Alexa have a row. The others cannot be announced.
|
||||||
- The Arduino IDE builds with the default limits.
|
- The Arduino IDE builds with the default limits.
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ AlexaCapabilityName::AlexaCapabilityName(const AlexaInterfaceDesc &row, const ch
|
||||||
}
|
}
|
||||||
|
|
||||||
AlexaCapability::AlexaCapability(const AlexaInterfaceDesc &row, const char *instance)
|
AlexaCapability::AlexaCapability(const AlexaInterfaceDesc &row, const char *instance)
|
||||||
: row(&row), retrievable(true), proactivelyReported(false), nonControllable(false), valid(true)
|
: row(&row), retrievable(true), proactivelyReported(false), nonControllable(false), deactivation(false), valid(true)
|
||||||
{
|
{
|
||||||
setInstance(instance);
|
setInstance(instance);
|
||||||
}
|
}
|
||||||
|
|
@ -185,6 +185,18 @@ AlexaCapability &AlexaCapability::setNonControllable(bool value)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AlexaCapability &AlexaCapability::setSupportsDeactivation(bool value)
|
||||||
|
{
|
||||||
|
if (!row->has(AIF_DEACTIVATION))
|
||||||
|
{
|
||||||
|
const AlexaCapabilityName name(*row, instance);
|
||||||
|
ALEX2ESP_LOGE("%s: setSupportsDeactivation() ignored: only a SceneController can be deactivated", name.text);
|
||||||
|
return refused();
|
||||||
|
}
|
||||||
|
deactivation = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
AlexaCapability &AlexaCapability::setConfiguration(AlexaConfigurationFiller fill, void *context)
|
AlexaCapability &AlexaCapability::setConfiguration(AlexaConfigurationFiller fill, void *context)
|
||||||
{
|
{
|
||||||
fillConfiguration = fill;
|
fillConfiguration = fill;
|
||||||
|
|
@ -354,6 +366,17 @@ bool AlexaCapability::toJson(JsonArray capabilities, const char *endpointId) con
|
||||||
properties[F("nonControllable")] = true;
|
properties[F("nonControllable")] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// An interface without properties says beside its name what Alexa has to know of it. Without these Alexa
|
||||||
|
// accepts the discovery and leaves the endpoint out: a doorbell announced without proactivelyReported was not
|
||||||
|
// listed, and its DoorbellPress was answered with an error.
|
||||||
|
if (row->has(AIF_EVENTS))
|
||||||
|
{
|
||||||
|
capability[F("proactivelyReported")] = true;
|
||||||
|
}
|
||||||
|
if (row->has(AIF_DEACTIVATION))
|
||||||
|
{
|
||||||
|
capability[F("supportsDeactivation")] = static_cast<bool>(deactivation);
|
||||||
|
}
|
||||||
|
|
||||||
writeSemantics(capability);
|
writeSemantics(capability);
|
||||||
if (instance != nullptr)
|
if (instance != nullptr)
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,10 @@ public:
|
||||||
// true: Alexa reports the state and sends no directive that changes it
|
// true: Alexa reports the state and sends no directive that changes it
|
||||||
AlexaCapability &setNonControllable(bool value);
|
AlexaCapability &setNonControllable(bool value);
|
||||||
|
|
||||||
|
// For a scene: true when it can be undone, and Alexa then sends Deactivate as well as Activate. A scene is
|
||||||
|
// announced with "supportsDeactivation": false until this is called.
|
||||||
|
AlexaCapability &setSupportsDeactivation(bool value);
|
||||||
|
|
||||||
AlexaCapability &setConfiguration(AlexaConfigurationFiller fill, void *context = nullptr);
|
AlexaCapability &setConfiguration(AlexaConfigurationFiller fill, void *context = nullptr);
|
||||||
|
|
||||||
// Only for an interface that takes semantics: RangeController, ModeController, ToggleController
|
// Only for an interface that takes semantics: RangeController, ModeController, ToggleController
|
||||||
|
|
@ -200,6 +204,7 @@ private:
|
||||||
bool retrievable : 1;
|
bool retrievable : 1;
|
||||||
bool proactivelyReported : 1;
|
bool proactivelyReported : 1;
|
||||||
bool nonControllable : 1;
|
bool nonControllable : 1;
|
||||||
|
bool deactivation : 1;
|
||||||
bool valid : 1;
|
bool valid : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,10 +103,10 @@ ALEXA_ROW(ThermostatController, NS_THERMOSTAT, VERSION_3_2, PROPS_THERMOSTAT, 4,
|
||||||
ALEXA_ROW(TemperatureSensor, NS_TEMPERATURE_SENSOR, VERSION_3, PROPS_TEMPERATURE_SENSOR, 1, AIF_NONE, TEMPERATURE_SENSOR);
|
ALEXA_ROW(TemperatureSensor, NS_TEMPERATURE_SENSOR, VERSION_3, PROPS_TEMPERATURE_SENSOR, 1, AIF_NONE, TEMPERATURE_SENSOR);
|
||||||
ALEXA_ROW(HumiditySensor, NS_HUMIDITY_SENSOR, VERSION_3, PROPS_HUMIDITY_SENSOR, 1, AIF_NONE, HUMIDITY_SENSOR);
|
ALEXA_ROW(HumiditySensor, NS_HUMIDITY_SENSOR, VERSION_3, PROPS_HUMIDITY_SENSOR, 1, AIF_NONE, HUMIDITY_SENSOR);
|
||||||
ALEXA_ROW(LockController, NS_LOCK, VERSION_3, PROPS_LOCK, 1, AIF_NONE, LOCK_CONTROLLER);
|
ALEXA_ROW(LockController, NS_LOCK, VERSION_3, PROPS_LOCK, 1, AIF_NONE, LOCK_CONTROLLER);
|
||||||
ALEXA_ROW(SceneController, NS_SCENE, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES, SCENE_CONTROLLER);
|
ALEXA_ROW(SceneController, NS_SCENE, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES | AIF_DEACTIVATION, SCENE_CONTROLLER);
|
||||||
ALEXA_ROW(ContactSensor, NS_CONTACT_SENSOR, VERSION_3, PROPS_DETECTION, 1, AIF_NONE, CONTACT_SENSOR);
|
ALEXA_ROW(ContactSensor, NS_CONTACT_SENSOR, VERSION_3, PROPS_DETECTION, 1, AIF_NONE, CONTACT_SENSOR);
|
||||||
ALEXA_ROW(MotionSensor, NS_MOTION_SENSOR, VERSION_3, PROPS_DETECTION, 1, AIF_NONE, MOTION_SENSOR);
|
ALEXA_ROW(MotionSensor, NS_MOTION_SENSOR, VERSION_3, PROPS_DETECTION, 1, AIF_NONE, MOTION_SENSOR);
|
||||||
ALEXA_ROW(DoorbellEventSource, NS_DOORBELL, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES, DOORBELL_EVENT_SOURCE);
|
ALEXA_ROW(DoorbellEventSource, NS_DOORBELL, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES | AIF_EVENTS, DOORBELL_EVENT_SOURCE);
|
||||||
ALEXA_ROW(TimeHoldController, NS_TIME_HOLD, VERSION_3, PROPS_TIME_HOLD, 2, AIF_NONE, TIME_HOLD_CONTROLLER);
|
ALEXA_ROW(TimeHoldController, NS_TIME_HOLD, VERSION_3, PROPS_TIME_HOLD, 2, AIF_NONE, TIME_HOLD_CONTROLLER);
|
||||||
ALEXA_ROW(Speaker, NS_SPEAKER, VERSION_3, PROPS_SPEAKER, 2, AIF_NONE, SPEAKER);
|
ALEXA_ROW(Speaker, NS_SPEAKER, VERSION_3, PROPS_SPEAKER, 2, AIF_NONE, SPEAKER);
|
||||||
ALEXA_ROW(StepSpeaker, NS_STEP_SPEAKER, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES, STEP_SPEAKER);
|
ALEXA_ROW(StepSpeaker, NS_STEP_SPEAKER, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES, STEP_SPEAKER);
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,9 @@ enum AlexaInterfaceFlags : uint8_t
|
||||||
AIF_INSTANCED = 1, // a device may have several: each needs an instance and a friendly name
|
AIF_INSTANCED = 1, // a device may have several: each needs an instance and a friendly name
|
||||||
AIF_NO_PROPERTIES = 2, // the discovery object has no "properties" (scenes, doorbells, step speakers)
|
AIF_NO_PROPERTIES = 2, // the discovery object has no "properties" (scenes, doorbells, step speakers)
|
||||||
AIF_SEMANTICS = 4, // may carry action and state mappings
|
AIF_SEMANTICS = 4, // may carry action and state mappings
|
||||||
AIF_EMPTY_PROPERTIES = 8 // the discovery object has "properties": {}, as the page of the interface shows it
|
AIF_EMPTY_PROPERTIES = 8, // the discovery object has "properties": {}, as the page of the interface shows it
|
||||||
|
AIF_EVENTS = 16, // what it reports are events: "proactivelyReported": true beside the interface (doorbell)
|
||||||
|
AIF_DEACTIVATION = 32 // says whether it can be undone: "supportsDeactivation" beside the interface (scene)
|
||||||
};
|
};
|
||||||
|
|
||||||
// 16 bytes in program memory. The ESP8266 reads flash in whole words only: the pointers can be read as they are,
|
// 16 bytes in program memory. The ESP8266 reads flash in whole words only: the pointers can be read as they are,
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ void test_scene_is_announced_without_properties(void)
|
||||||
device.addCapability(AlexaInterfaces::SceneController);
|
device.addCapability(AlexaInterfaces::SceneController);
|
||||||
|
|
||||||
assertDiscovery(endpoint("Movie Night", "SCENE_TRIGGER",
|
assertDiscovery(endpoint("Movie Night", "SCENE_TRIGGER",
|
||||||
"{\"interface\":\"Alexa.SceneController\",\"version\":\"3\",\"type\":\"AlexaInterface\"}"),
|
"{\"interface\":\"Alexa.SceneController\",\"version\":\"3\",\"type\":\"AlexaInterface\",\"supportsDeactivation\":false}"),
|
||||||
device);
|
device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,14 +421,32 @@ void test_toggle_controller_that_only_reports_is_announced_as_non_controllable(v
|
||||||
device);
|
device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alexa-scenecontroller.html: supportsDeactivation says whether Alexa may send Deactivate
|
||||||
|
void test_scene_that_can_be_undone_says_so_and_no_other_interface_can(void)
|
||||||
|
{
|
||||||
|
AlexaDevice device("Movie Night", "root", "ESP-01");
|
||||||
|
device.setDisplayCategory(DisplayCategory::SCENE_TRIGGER);
|
||||||
|
device.addCapability(AlexaInterfaces::SceneController)->setSupportsDeactivation(true);
|
||||||
|
|
||||||
|
assertDiscovery(endpoint("Movie Night", "SCENE_TRIGGER",
|
||||||
|
"{\"interface\":\"Alexa.SceneController\",\"version\":\"3\",\"type\":\"AlexaInterface\",\"supportsDeactivation\":true}"),
|
||||||
|
device);
|
||||||
|
|
||||||
|
AlexaDevice lamp("Lamp", "root", "ESP-02");
|
||||||
|
AlexaCapability *power = lamp.addCapability(AlexaInterfaces::PowerController);
|
||||||
|
TEST_ASSERT_TRUE(power->isValid());
|
||||||
|
power->setSupportsDeactivation(true);
|
||||||
|
TEST_ASSERT_FALSE_MESSAGE(power->isValid(), "a call the interface cannot take is a refused call");
|
||||||
|
}
|
||||||
|
|
||||||
void test_doorbell_is_announced_without_properties(void)
|
void test_doorbell_is_announced_without_properties(void)
|
||||||
{
|
{
|
||||||
AlexaDevice device("Front Door", "root", "ESP-01");
|
AlexaDevice device("Front Door", "root", "ESP-01");
|
||||||
device.setDisplayCategory(DisplayCategory::DOORBELL);
|
device.setDisplayCategory(DisplayCategory::DOORBELL);
|
||||||
device.addCapability(AlexaInterfaces::DoorbellEventSource)->setProactivelyReported(true);
|
device.addCapability(AlexaInterfaces::DoorbellEventSource);
|
||||||
|
|
||||||
assertDiscovery(endpoint("Front Door", "DOORBELL",
|
assertDiscovery(endpoint("Front Door", "DOORBELL",
|
||||||
"{\"interface\":\"Alexa.DoorbellEventSource\",\"version\":\"3\",\"type\":\"AlexaInterface\"}"),
|
"{\"interface\":\"Alexa.DoorbellEventSource\",\"version\":\"3\",\"type\":\"AlexaInterface\",\"proactivelyReported\":true}"),
|
||||||
device);
|
device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -769,6 +787,7 @@ int main(int, char **)
|
||||||
RUN_TEST(test_range_controller_blind_is_announced_with_names_configuration_and_semantics);
|
RUN_TEST(test_range_controller_blind_is_announced_with_names_configuration_and_semantics);
|
||||||
RUN_TEST(test_mode_controller_is_announced_with_its_modes_and_text_states);
|
RUN_TEST(test_mode_controller_is_announced_with_its_modes_and_text_states);
|
||||||
RUN_TEST(test_toggle_controller_that_only_reports_is_announced_as_non_controllable);
|
RUN_TEST(test_toggle_controller_that_only_reports_is_announced_as_non_controllable);
|
||||||
|
RUN_TEST(test_scene_that_can_be_undone_says_so_and_no_other_interface_can);
|
||||||
RUN_TEST(test_doorbell_is_announced_without_properties);
|
RUN_TEST(test_doorbell_is_announced_without_properties);
|
||||||
RUN_TEST(test_playback_and_wake_on_lan_are_announced_with_empty_properties);
|
RUN_TEST(test_playback_and_wake_on_lan_are_announced_with_empty_properties);
|
||||||
RUN_TEST(test_instance_and_friendly_name_are_copied);
|
RUN_TEST(test_instance_and_friendly_name_are_copied);
|
||||||
|
|
|
||||||
|
|
@ -239,11 +239,11 @@ void test_scene_discovery(void)
|
||||||
{
|
{
|
||||||
AlexaDevice scene("Movie Night", "root", "esp-scene");
|
AlexaDevice scene("Movie Night", "root", "esp-scene");
|
||||||
scene.setDisplayCategory(DisplayCategory::SCENE_TRIGGER);
|
scene.setDisplayCategory(DisplayCategory::SCENE_TRIGGER);
|
||||||
scene.addCapability(AlexaInterfaces::SceneController);
|
scene.addCapability(AlexaInterfaces::SceneController)->setSupportsDeactivation(true);
|
||||||
scene.addCapability(AlexaInterfaces::EndpointHealth);
|
scene.addCapability(AlexaInterfaces::EndpointHealth);
|
||||||
|
|
||||||
assertDiscovery(endpoint("esp-scene", "Movie Night", "SCENE_TRIGGER",
|
assertDiscovery(endpoint("esp-scene", "Movie Night", "SCENE_TRIGGER",
|
||||||
list({"{\"interface\":\"Alexa.SceneController\",\"version\":\"3\",\"type\":\"AlexaInterface\"}",
|
list({"{\"interface\":\"Alexa.SceneController\",\"version\":\"3\",\"type\":\"AlexaInterface\",\"supportsDeactivation\":true}",
|
||||||
HEALTH})),
|
HEALTH})),
|
||||||
scene);
|
scene);
|
||||||
}
|
}
|
||||||
|
|
@ -252,12 +252,12 @@ void test_doorbell_discovery(void)
|
||||||
{
|
{
|
||||||
AlexaDevice doorbell("Front Door Bell", "root", "esp-doorbell");
|
AlexaDevice doorbell("Front Door Bell", "root", "esp-doorbell");
|
||||||
doorbell.setDisplayCategory(DisplayCategory::DOORBELL);
|
doorbell.setDisplayCategory(DisplayCategory::DOORBELL);
|
||||||
doorbell.addCapability(AlexaInterfaces::DoorbellEventSource)->setProactivelyReported(true);
|
doorbell.addCapability(AlexaInterfaces::DoorbellEventSource);
|
||||||
doorbell.addCapability(AlexaInterfaces::EndpointHealth);
|
doorbell.addCapability(AlexaInterfaces::EndpointHealth);
|
||||||
|
|
||||||
assertDiscovery(
|
assertDiscovery(
|
||||||
endpoint("esp-doorbell", "Front Door Bell", "DOORBELL",
|
endpoint("esp-doorbell", "Front Door Bell", "DOORBELL",
|
||||||
list({"{\"interface\":\"Alexa.DoorbellEventSource\",\"version\":\"3\",\"type\":\"AlexaInterface\"}",
|
list({"{\"interface\":\"Alexa.DoorbellEventSource\",\"version\":\"3\",\"type\":\"AlexaInterface\",\"proactivelyReported\":true}",
|
||||||
HEALTH})),
|
HEALTH})),
|
||||||
doorbell);
|
doorbell);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue