Describe interfaces with PROGMEM descriptor rows; drop the switch tables
AlexaInterfaces.h/.cpp hold one row per interface in program memory (28: namespace, version, property names, flags, type), each row and string an object of its own, so the linker keeps only the rows a sketch names. addCapability(AlexaInterfaceType) is an always-inline switch that folds to one row; a type without a row is refused with an error. The Event handler gets its type from the capabilities of the device. Versions follow the interface pages (EndpointHealth 3.1, ThermostatController 3.2), HumiditySensor is new, the two withdrawn interfaces and AlexaInterfaceUtils are gone. Display category names are in flash. The discovery objects of the five examples are unchanged: 14 new host tests compare them with what the previous commit announced. basicLight on a D1 mini: static RAM 34,508 -> 30,788, flash 338,533 -> 330,509; it links two rows, EndpointHealth and PowerController. Host tests: 47 -> 61. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
d534f23f27
commit
8b11cc2394
13 changed files with 909 additions and 777 deletions
|
|
@ -427,7 +427,7 @@ void Alex2ESP::processDirective()
|
|||
}
|
||||
else
|
||||
{
|
||||
device->triggerEvent("Event", message, AlexaInterfaceUtils::fromString(interfaceName));
|
||||
device->triggerEvent("Event", message, device->getInterfaceType(interfaceName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
// Lets the sources that have no hardware dependency compile on a host (pio test -e native), where the
|
||||
// program-memory helpers of the Arduino cores do not exist. On a board this is Arduino.h and nothing else.
|
||||
// program-memory helpers of the Arduino cores do not exist: there a PROGMEM object is an ordinary constant and a
|
||||
// pointer to one an ordinary pointer. On a board this is Arduino.h and nothing else.
|
||||
#ifndef ALEXA_COMPAT_H
|
||||
#define ALEXA_COMPAT_H
|
||||
|
||||
#if defined(ARDUINO)
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#ifndef PSTR
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#define PROGMEM
|
||||
#define PGM_P const char *
|
||||
#define PSTR(text) (text)
|
||||
#endif
|
||||
#define F(text) (text)
|
||||
#define FPSTR(text) (text)
|
||||
#define pgm_read_byte(address) (*reinterpret_cast<const uint8_t *>(address))
|
||||
#define pgm_read_ptr(address) (*reinterpret_cast<const void *const *>(address))
|
||||
#define strcmp_P strcmp
|
||||
#define strncpy_P strncpy
|
||||
#endif
|
||||
|
||||
#endif // ALEXA_COMPAT_H
|
||||
|
|
|
|||
|
|
@ -72,23 +72,43 @@ String AlexaDevice::getSoftwareVersion() const {
|
|||
}
|
||||
|
||||
|
||||
AlexaInterface* AlexaDevice::addCapability(AlexaInterfaceType type) {
|
||||
// Check if a interface with the given type already exists
|
||||
AlexaInterface* AlexaDevice::addCapability(const AlexaInterfaceDesc& row) {
|
||||
// Check if a interface with the given row already exists
|
||||
for (auto& iface : capabilities) {
|
||||
if (iface.getType() == type) {
|
||||
if (&iface.getRow() == &row) {
|
||||
return &iface; // Return the existing interface
|
||||
}
|
||||
}
|
||||
|
||||
// If the interface doesn't exist, create a new one
|
||||
capabilities.emplace_back(type);
|
||||
capabilities.emplace_back(row);
|
||||
|
||||
ALEX2ESP_LOGI("%s: capability %s added", endpointId.c_str(), capabilities.back().getTypeString().c_str());
|
||||
// The namespace is in program memory, where the %s of the log cannot read it
|
||||
char interfaceName[40];
|
||||
strncpy_P(interfaceName, row.ns, sizeof(interfaceName) - 1);
|
||||
interfaceName[sizeof(interfaceName) - 1] = '\0';
|
||||
ALEX2ESP_LOGI("%s: capability %s added", endpointId.c_str(), interfaceName);
|
||||
|
||||
// Return a pointer to the newly created device
|
||||
return &capabilities.back();
|
||||
}
|
||||
|
||||
AlexaInterface* AlexaDevice::refuseCapability(AlexaInterfaceType type) {
|
||||
ALEX2ESP_LOGE("%s: capability not added: the library has no description of interface type %d; "
|
||||
"readme.md lists the interfaces it has (Interface Types)",
|
||||
endpointId.c_str(), static_cast<int>(type));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AlexaInterfaceType AlexaDevice::getInterfaceType(const char* interfaceName) const {
|
||||
for (const AlexaInterface& capability : capabilities) {
|
||||
if (strcmp_P(interfaceName, capability.getRow().ns) == 0) {
|
||||
return capability.getType();
|
||||
}
|
||||
}
|
||||
return AlexaInterfaceType::UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
JsonDocument AlexaDevice::getDeviceJSON() const {
|
||||
|
|
@ -104,7 +124,7 @@ JsonDocument AlexaDevice::getDeviceJSON() const {
|
|||
|
||||
|
||||
JsonArray displayCategories = json["displayCategories"].to<JsonArray>();
|
||||
displayCategories.add(DisplayCategoryUtils::toString(displayCategory));
|
||||
displayCategories.add(FPSTR(alexaDisplayCategoryName(displayCategory)));
|
||||
|
||||
JsonObject additionalAttributes = json["additionalAttributes"].to<JsonObject>();
|
||||
additionalAttributes["manufacturer"] = manufacturer;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include "AlexaInterface.h"
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include "AlexaStatusMessage.h"
|
||||
|
|
@ -16,137 +15,16 @@
|
|||
|
||||
#define MAX_EVENTS 10
|
||||
|
||||
enum class DisplayCategory {
|
||||
ACTIVITY_TRIGGER,
|
||||
AIR_CONDITIONER,
|
||||
AIR_FRESHENER,
|
||||
AIR_PURIFIER,
|
||||
AIR_QUALITY_MONITOR,
|
||||
ALEXA_VOICE_ENABLED,
|
||||
AUTO_ACCESSORY,
|
||||
BLUETOOTH_SPEAKER,
|
||||
CAMERA,
|
||||
CHRISTMAS_TREE,
|
||||
COFFEE_MAKER,
|
||||
COMPUTER,
|
||||
CONTACT_SENSOR,
|
||||
DISHWASHER,
|
||||
DOOR,
|
||||
DOORBELL,
|
||||
DRYER,
|
||||
EXTERIOR_BLIND,
|
||||
FAN,
|
||||
GAME_CONSOLE,
|
||||
GARAGE_DOOR,
|
||||
HEADPHONES,
|
||||
HUB,
|
||||
INTERIOR_BLIND,
|
||||
LAPTOP,
|
||||
LIGHT,
|
||||
MICROWAVE,
|
||||
MOBILE_PHONE,
|
||||
MOTION_SENSOR,
|
||||
MUSIC_SYSTEM,
|
||||
NETWORK_HARDWARE,
|
||||
OTHER,
|
||||
OVEN,
|
||||
PHONE,
|
||||
PRINTER,
|
||||
REMOTE,
|
||||
ROUTER,
|
||||
SCENE_TRIGGER,
|
||||
SCREEN,
|
||||
SECURITY_PANEL,
|
||||
SECURITY_SYSTEM,
|
||||
SLOW_COOKER,
|
||||
SMARTLOCK,
|
||||
SMARTPLUG,
|
||||
SPEAKER,
|
||||
STREAMING_DEVICE,
|
||||
SWITCH,
|
||||
TABLET,
|
||||
TEMPERATURE_SENSOR,
|
||||
THERMOSTAT,
|
||||
TV,
|
||||
VACUUM_CLEANER,
|
||||
VEHICLE,
|
||||
WASHER,
|
||||
WATER_HEATER,
|
||||
WEARABLE
|
||||
};
|
||||
|
||||
class DisplayCategoryUtils {
|
||||
public:
|
||||
static String toString(DisplayCategory category) {
|
||||
static const std::unordered_map<DisplayCategory, String> categoryMap = {
|
||||
{DisplayCategory::ACTIVITY_TRIGGER, "ACTIVITY_TRIGGER"},
|
||||
{DisplayCategory::AIR_CONDITIONER, "AIR_CONDITIONER"},
|
||||
{DisplayCategory::AIR_FRESHENER, "AIR_FRESHENER"},
|
||||
{DisplayCategory::AIR_PURIFIER, "AIR_PURIFIER"},
|
||||
{DisplayCategory::AIR_QUALITY_MONITOR, "AIR_QUALITY_MONITOR"},
|
||||
{DisplayCategory::ALEXA_VOICE_ENABLED, "ALEXA_VOICE_ENABLED"},
|
||||
{DisplayCategory::AUTO_ACCESSORY, "AUTO_ACCESSORY"},
|
||||
{DisplayCategory::BLUETOOTH_SPEAKER, "BLUETOOTH_SPEAKER"},
|
||||
{DisplayCategory::CAMERA, "CAMERA"},
|
||||
{DisplayCategory::CHRISTMAS_TREE, "CHRISTMAS_TREE"},
|
||||
{DisplayCategory::COFFEE_MAKER, "COFFEE_MAKER"},
|
||||
{DisplayCategory::COMPUTER, "COMPUTER"},
|
||||
{DisplayCategory::CONTACT_SENSOR, "CONTACT_SENSOR"},
|
||||
{DisplayCategory::DISHWASHER, "DISHWASHER"},
|
||||
{DisplayCategory::DOOR, "DOOR"},
|
||||
{DisplayCategory::DOORBELL, "DOORBELL"},
|
||||
{DisplayCategory::DRYER, "DRYER"},
|
||||
{DisplayCategory::EXTERIOR_BLIND, "EXTERIOR_BLIND"},
|
||||
{DisplayCategory::FAN, "FAN"},
|
||||
{DisplayCategory::GAME_CONSOLE, "GAME_CONSOLE"},
|
||||
{DisplayCategory::GARAGE_DOOR, "GARAGE_DOOR"},
|
||||
{DisplayCategory::HEADPHONES, "HEADPHONES"},
|
||||
{DisplayCategory::HUB, "HUB"},
|
||||
{DisplayCategory::INTERIOR_BLIND, "INTERIOR_BLIND"},
|
||||
{DisplayCategory::LAPTOP, "LAPTOP"},
|
||||
{DisplayCategory::LIGHT, "LIGHT"},
|
||||
{DisplayCategory::MICROWAVE, "MICROWAVE"},
|
||||
{DisplayCategory::MOBILE_PHONE, "MOBILE_PHONE"},
|
||||
{DisplayCategory::MOTION_SENSOR, "MOTION_SENSOR"},
|
||||
{DisplayCategory::MUSIC_SYSTEM, "MUSIC_SYSTEM"},
|
||||
{DisplayCategory::NETWORK_HARDWARE, "NETWORK_HARDWARE"},
|
||||
{DisplayCategory::OTHER, "OTHER"},
|
||||
{DisplayCategory::OVEN, "OVEN"},
|
||||
{DisplayCategory::PHONE, "PHONE"},
|
||||
{DisplayCategory::PRINTER, "PRINTER"},
|
||||
{DisplayCategory::REMOTE, "REMOTE"},
|
||||
{DisplayCategory::ROUTER, "ROUTER"},
|
||||
{DisplayCategory::SCENE_TRIGGER, "SCENE_TRIGGER"},
|
||||
{DisplayCategory::SCREEN, "SCREEN"},
|
||||
{DisplayCategory::SECURITY_PANEL, "SECURITY_PANEL"},
|
||||
{DisplayCategory::SECURITY_SYSTEM, "SECURITY_SYSTEM"},
|
||||
{DisplayCategory::SLOW_COOKER, "SLOW_COOKER"},
|
||||
{DisplayCategory::SMARTLOCK, "SMARTLOCK"},
|
||||
{DisplayCategory::SMARTPLUG, "SMARTPLUG"},
|
||||
{DisplayCategory::SPEAKER, "SPEAKER"},
|
||||
{DisplayCategory::STREAMING_DEVICE, "STREAMING_DEVICE"},
|
||||
{DisplayCategory::SWITCH, "SWITCH"},
|
||||
{DisplayCategory::TABLET, "TABLET"},
|
||||
{DisplayCategory::TEMPERATURE_SENSOR, "TEMPERATURE_SENSOR"},
|
||||
{DisplayCategory::THERMOSTAT, "THERMOSTAT"},
|
||||
{DisplayCategory::TV, "TV"},
|
||||
{DisplayCategory::VACUUM_CLEANER, "VACUUM_CLEANER"},
|
||||
{DisplayCategory::VEHICLE, "VEHICLE"},
|
||||
{DisplayCategory::WASHER, "WASHER"},
|
||||
{DisplayCategory::WATER_HEATER, "WATER_HEATER"},
|
||||
{DisplayCategory::WEARABLE, "WEARABLE"}
|
||||
};
|
||||
|
||||
auto it = categoryMap.find(category);
|
||||
if (it != categoryMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return "UNKNOWN";
|
||||
return String(FPSTR(alexaDisplayCategoryName(category)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class AlexaDevice {
|
||||
public:
|
||||
// Devices are created by Alex2ESP::getDevice(), which passes the bridge as the transport that publishes the
|
||||
|
|
@ -180,9 +58,23 @@ public:
|
|||
|
||||
JsonDocument getDeviceJSON() const;
|
||||
|
||||
// Returns the capability of this type, creating it on first use. The pointer stays valid for the lifetime of
|
||||
// the device: capabilities live in a std::deque, which never relocates its elements when another one is added.
|
||||
AlexaInterface* addCapability(AlexaInterfaceType type);
|
||||
// Returns the capability that describes this interface, creating it on first use. The pointer stays valid for
|
||||
// the lifetime of the device: capabilities live in a std::deque, which never relocates its elements when
|
||||
// another one is added.
|
||||
AlexaInterface* addCapability(const AlexaInterfaceDesc& row);
|
||||
|
||||
// The same by the type of the interface, as 1.x sketches write it. A type without a row in AlexaInterfaces
|
||||
// cannot be described: nothing is added, the reason is printed and nullptr returned. Inlined, so that a type
|
||||
// written out in the sketch links its row only (alexaInterfaceRow).
|
||||
__attribute__((always_inline)) AlexaInterface* addCapability(AlexaInterfaceType type) {
|
||||
const AlexaInterfaceDesc* row = alexaInterfaceRow(type);
|
||||
return row != nullptr ? addCapability(*row) : refuseCapability(type);
|
||||
}
|
||||
|
||||
// The type of the capability of this device with the namespace of a directive ("Alexa.PowerController"),
|
||||
// UNKNOWN when the device has none
|
||||
AlexaInterfaceType getInterfaceType(const char* interfaceName) const;
|
||||
|
||||
|
||||
void registerEvent(const char* eventName, void (*callback)(const JsonDocument&, const AlexaInterfaceType&));
|
||||
|
||||
|
|
@ -194,6 +86,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
AlexaInterface* refuseCapability(AlexaInterfaceType type);
|
||||
|
||||
String name;
|
||||
String endpointId;
|
||||
String rootTopic;
|
||||
|
|
|
|||
|
|
@ -3,548 +3,11 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "AlexaInterfaces.h"
|
||||
#include "AlexaLog.h"
|
||||
|
||||
// Enum for Alexa Interface Types
|
||||
enum class AlexaInterfaceType
|
||||
{
|
||||
APPLICATION_STATE_REPORTER,
|
||||
AUDIO_PLAY_QUEUE,
|
||||
AUTHORIZATION_CONTROLLER,
|
||||
AUTOMATION_MANAGEMENT,
|
||||
AUTOMOTIVE_VEHICLE_DATA,
|
||||
BRIGHTNESS_CONTROLLER,
|
||||
CAMERA_LIVE_VIEW_CONTROLLER,
|
||||
CAMERA_STREAM_CONTROLLER,
|
||||
CHANNEL_CONTROLLER,
|
||||
COLOR_CONTROLLER,
|
||||
COLOR_TEMPERATURE_CONTROLLER,
|
||||
COMMISSIONABLE,
|
||||
CONSENT_MANAGEMENT_CONSENT_REQUIRED_REPORTER,
|
||||
CONTACT_SENSOR,
|
||||
COOKING,
|
||||
COOKING_FOOD_TEMPERATURE_CONTROLLER,
|
||||
COOKING_FOOD_TEMPERATURE_SENSOR,
|
||||
COOKING_PRESET_CONTROLLER,
|
||||
COOKING_TEMPERATURE_CONTROLLER,
|
||||
COOKING_TEMPERATURE_SENSOR,
|
||||
COOKING_TIME_CONTROLLER,
|
||||
DATA_CONTROLLER,
|
||||
DEVICE_USAGE_ESTIMATION,
|
||||
DEVICE_USAGE_METER,
|
||||
DOORBELL_EVENT_SOURCE,
|
||||
ENDPOINT_HEALTH,
|
||||
EQUALIZER_CONTROLLER,
|
||||
INPUT_CONTROLLER,
|
||||
INVENTORY_LEVEL_SENSOR,
|
||||
INVENTORY_LEVEL_USAGE_SENSOR,
|
||||
INVENTORY_USAGE_SENSOR,
|
||||
KEYPAD_CONTROLLER,
|
||||
LAUNCHER,
|
||||
LOCK_CONTROLLER,
|
||||
MEDIA_PLAYBACK,
|
||||
MEDIA_PLAY_QUEUE,
|
||||
MEDIA_SEARCH,
|
||||
MODE_CONTROLLER,
|
||||
MOTION_SENSOR,
|
||||
PERCENTAGE_CONTROLLER,
|
||||
PLAYBACK_CONTROLLER,
|
||||
PLAYBACK_STATE_REPORTER,
|
||||
POWER_CONTROLLER,
|
||||
POWER_LEVEL_CONTROLLER,
|
||||
PROACTIVE_NOTIFICATION_SOURCE,
|
||||
RANGE_CONTROLLER,
|
||||
RECORD_CONTROLLER,
|
||||
REMOTE_VIDEO_PLAYER,
|
||||
RTC_SESSION_CONTROLLER,
|
||||
SCENE_CONTROLLER,
|
||||
SECURITY_PANEL_CONTROLLER,
|
||||
SECURITY_PANEL_CONTROLLER_ALERT,
|
||||
SEEK_CONTROLLER,
|
||||
SIMPLE_EVENT_SOURCE,
|
||||
SMART_VISION_OBJECT_DETECTION_SENSOR,
|
||||
SMART_VISION_SNAPSHOT_PROVIDER,
|
||||
SPEAKER,
|
||||
STEP_SPEAKER,
|
||||
TEMPERATURE_SENSOR,
|
||||
THERMOSTAT_CONTROLLER,
|
||||
THERMOSTAT_CONTROLLER_CONFIGURATION,
|
||||
THERMOSTAT_CONTROLLER_HVAC_COMPONENTS,
|
||||
THERMOSTAT_CONTROLLER_SCHEDULE,
|
||||
TIME_HOLD_CONTROLLER,
|
||||
TOGGLE_CONTROLLER,
|
||||
UI_CONTROLLER,
|
||||
USER_PREFERENCE,
|
||||
VIDEO_RECORDER,
|
||||
WAKE_ON_LAN_CONTROLLER,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
// Utility class to handle Alexa Interface type details
|
||||
class AlexaInterfaceUtils
|
||||
{
|
||||
public:
|
||||
|
||||
static AlexaInterfaceType fromString(const String& str)
|
||||
{
|
||||
if (str == "Alexa.ApplicationStateReporter")
|
||||
return AlexaInterfaceType::APPLICATION_STATE_REPORTER;
|
||||
if (str == "Alexa.Audio.PlayQueue")
|
||||
return AlexaInterfaceType::AUDIO_PLAY_QUEUE;
|
||||
if (str == "Alexa.AuthorizationController")
|
||||
return AlexaInterfaceType::AUTHORIZATION_CONTROLLER;
|
||||
if (str == "Alexa.AutomationManagement")
|
||||
return AlexaInterfaceType::AUTOMATION_MANAGEMENT;
|
||||
if (str == "Alexa.Automotive.VehicleData")
|
||||
return AlexaInterfaceType::AUTOMOTIVE_VEHICLE_DATA;
|
||||
if (str == "Alexa.BrightnessController")
|
||||
return AlexaInterfaceType::BRIGHTNESS_CONTROLLER;
|
||||
if (str == "Alexa.Camera.LiveViewController")
|
||||
return AlexaInterfaceType::CAMERA_LIVE_VIEW_CONTROLLER;
|
||||
if (str == "Alexa.CameraStreamController")
|
||||
return AlexaInterfaceType::CAMERA_STREAM_CONTROLLER;
|
||||
if (str == "Alexa.ChannelController")
|
||||
return AlexaInterfaceType::CHANNEL_CONTROLLER;
|
||||
if (str == "Alexa.ColorController")
|
||||
return AlexaInterfaceType::COLOR_CONTROLLER;
|
||||
if (str == "Alexa.ColorTemperatureController")
|
||||
return AlexaInterfaceType::COLOR_TEMPERATURE_CONTROLLER;
|
||||
if (str == "Alexa.Commissionable")
|
||||
return AlexaInterfaceType::COMMISSIONABLE;
|
||||
if (str == "Alexa.ConsentManagement.ConsentRequiredReporter")
|
||||
return AlexaInterfaceType::CONSENT_MANAGEMENT_CONSENT_REQUIRED_REPORTER;
|
||||
if (str == "Alexa.ContactSensor")
|
||||
return AlexaInterfaceType::CONTACT_SENSOR;
|
||||
if (str == "Alexa.Cooking")
|
||||
return AlexaInterfaceType::COOKING;
|
||||
if (str == "Alexa.Cooking.FoodTemperatureController")
|
||||
return AlexaInterfaceType::COOKING_FOOD_TEMPERATURE_CONTROLLER;
|
||||
if (str == "Alexa.Cooking.FoodTemperatureSensor")
|
||||
return AlexaInterfaceType::COOKING_FOOD_TEMPERATURE_SENSOR;
|
||||
if (str == "Alexa.Cooking.PresetController")
|
||||
return AlexaInterfaceType::COOKING_PRESET_CONTROLLER;
|
||||
if (str == "Alexa.Cooking.TemperatureController")
|
||||
return AlexaInterfaceType::COOKING_TEMPERATURE_CONTROLLER;
|
||||
if (str == "Alexa.Cooking.TemperatureSensor")
|
||||
return AlexaInterfaceType::COOKING_TEMPERATURE_SENSOR;
|
||||
if (str == "Alexa.Cooking.TimeController")
|
||||
return AlexaInterfaceType::COOKING_TIME_CONTROLLER;
|
||||
if (str == "Alexa.DataController")
|
||||
return AlexaInterfaceType::DATA_CONTROLLER;
|
||||
if (str == "Alexa.DeviceUsage.Estimation")
|
||||
return AlexaInterfaceType::DEVICE_USAGE_ESTIMATION;
|
||||
if (str == "Alexa.DeviceUsage.Meter")
|
||||
return AlexaInterfaceType::DEVICE_USAGE_METER;
|
||||
if (str == "Alexa.DoorbellEventSource")
|
||||
return AlexaInterfaceType::DOORBELL_EVENT_SOURCE;
|
||||
if (str == "Alexa.EndpointHealth")
|
||||
return AlexaInterfaceType::ENDPOINT_HEALTH;
|
||||
if (str == "Alexa.EqualizerController")
|
||||
return AlexaInterfaceType::EQUALIZER_CONTROLLER;
|
||||
if (str == "Alexa.InputController")
|
||||
return AlexaInterfaceType::INPUT_CONTROLLER;
|
||||
if (str == "Alexa.InventoryLevelSensor")
|
||||
return AlexaInterfaceType::INVENTORY_LEVEL_SENSOR;
|
||||
if (str == "Alexa.InventoryLevelUsageSensor")
|
||||
return AlexaInterfaceType::INVENTORY_LEVEL_USAGE_SENSOR;
|
||||
if (str == "Alexa.InventoryUsageSensor")
|
||||
return AlexaInterfaceType::INVENTORY_USAGE_SENSOR;
|
||||
if (str == "Alexa.KeypadController")
|
||||
return AlexaInterfaceType::KEYPAD_CONTROLLER;
|
||||
if (str == "Alexa.Launcher")
|
||||
return AlexaInterfaceType::LAUNCHER;
|
||||
if (str == "Alexa.LockController")
|
||||
return AlexaInterfaceType::LOCK_CONTROLLER;
|
||||
if (str == "Alexa.Media.Playback")
|
||||
return AlexaInterfaceType::MEDIA_PLAYBACK;
|
||||
if (str == "Alexa.Media.PlayQueue")
|
||||
return AlexaInterfaceType::MEDIA_PLAY_QUEUE;
|
||||
if (str == "Alexa.Media.Search")
|
||||
return AlexaInterfaceType::MEDIA_SEARCH;
|
||||
if (str == "Alexa.ModeController")
|
||||
return AlexaInterfaceType::MODE_CONTROLLER;
|
||||
if (str == "Alexa.MotionSensor")
|
||||
return AlexaInterfaceType::MOTION_SENSOR;
|
||||
if (str == "Alexa.PercentageController")
|
||||
return AlexaInterfaceType::PERCENTAGE_CONTROLLER;
|
||||
if (str == "Alexa.PlaybackController")
|
||||
return AlexaInterfaceType::PLAYBACK_CONTROLLER;
|
||||
if (str == "Alexa.PlaybackStateReporter")
|
||||
return AlexaInterfaceType::PLAYBACK_STATE_REPORTER;
|
||||
if (str == "Alexa.PowerController")
|
||||
return AlexaInterfaceType::POWER_CONTROLLER;
|
||||
if (str == "Alexa.PowerLevelController")
|
||||
return AlexaInterfaceType::POWER_LEVEL_CONTROLLER;
|
||||
if (str == "Alexa.ProactiveNotificationSource")
|
||||
return AlexaInterfaceType::PROACTIVE_NOTIFICATION_SOURCE;
|
||||
if (str == "Alexa.RangeController")
|
||||
return AlexaInterfaceType::RANGE_CONTROLLER;
|
||||
if (str == "Alexa.RecordController")
|
||||
return AlexaInterfaceType::RECORD_CONTROLLER;
|
||||
if (str == "Alexa.RemoteVideoPlayer")
|
||||
return AlexaInterfaceType::REMOTE_VIDEO_PLAYER;
|
||||
if (str == "Alexa.RTCSessionController")
|
||||
return AlexaInterfaceType::RTC_SESSION_CONTROLLER;
|
||||
if (str == "Alexa.SceneController")
|
||||
return AlexaInterfaceType::SCENE_CONTROLLER;
|
||||
if (str == "Alexa.SecurityPanelController")
|
||||
return AlexaInterfaceType::SECURITY_PANEL_CONTROLLER;
|
||||
if (str == "Alexa.SecurityPanelController.Alert")
|
||||
return AlexaInterfaceType::SECURITY_PANEL_CONTROLLER_ALERT;
|
||||
if (str == "Alexa.SeekController")
|
||||
return AlexaInterfaceType::SEEK_CONTROLLER;
|
||||
if (str == "Alexa.SimpleEventSource")
|
||||
return AlexaInterfaceType::SIMPLE_EVENT_SOURCE;
|
||||
if (str == "Alexa.SmartVision.ObjectDetectionSensor")
|
||||
return AlexaInterfaceType::SMART_VISION_OBJECT_DETECTION_SENSOR;
|
||||
if (str == "Alexa.SmartVision.SnapshotProvider")
|
||||
return AlexaInterfaceType::SMART_VISION_SNAPSHOT_PROVIDER;
|
||||
if (str == "Alexa.Speaker")
|
||||
return AlexaInterfaceType::SPEAKER;
|
||||
if (str == "Alexa.StepSpeaker")
|
||||
return AlexaInterfaceType::STEP_SPEAKER;
|
||||
if (str == "Alexa.TemperatureSensor")
|
||||
return AlexaInterfaceType::TEMPERATURE_SENSOR;
|
||||
if (str == "Alexa.ThermostatController")
|
||||
return AlexaInterfaceType::THERMOSTAT_CONTROLLER;
|
||||
if (str == "Alexa.ThermostatController.Configuration")
|
||||
return AlexaInterfaceType::THERMOSTAT_CONTROLLER_CONFIGURATION;
|
||||
if (str == "Alexa.ThermostatController.HVAC.Components")
|
||||
return AlexaInterfaceType::THERMOSTAT_CONTROLLER_HVAC_COMPONENTS;
|
||||
if (str == "Alexa.ThermostatController.Schedule")
|
||||
return AlexaInterfaceType::THERMOSTAT_CONTROLLER_SCHEDULE;
|
||||
if (str == "Alexa.TimeHoldController")
|
||||
return AlexaInterfaceType::TIME_HOLD_CONTROLLER;
|
||||
if (str == "Alexa.ToggleController")
|
||||
return AlexaInterfaceType::TOGGLE_CONTROLLER;
|
||||
if (str == "Alexa.UIController")
|
||||
return AlexaInterfaceType::UI_CONTROLLER;
|
||||
if (str == "Alexa.UserPreference")
|
||||
return AlexaInterfaceType::USER_PREFERENCE;
|
||||
if (str == "Alexa.VideoRecorder")
|
||||
return AlexaInterfaceType::VIDEO_RECORDER;
|
||||
if (str == "Alexa.WakeOnLANController")
|
||||
return AlexaInterfaceType::WAKE_ON_LAN_CONTROLLER;
|
||||
|
||||
return AlexaInterfaceType::UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
static String toString(AlexaInterfaceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AlexaInterfaceType::APPLICATION_STATE_REPORTER:
|
||||
return "Alexa.ApplicationStateReporter";
|
||||
case AlexaInterfaceType::AUDIO_PLAY_QUEUE:
|
||||
return "Alexa.Audio.PlayQueue";
|
||||
case AlexaInterfaceType::AUTHORIZATION_CONTROLLER:
|
||||
return "Alexa.AuthorizationController";
|
||||
case AlexaInterfaceType::AUTOMATION_MANAGEMENT:
|
||||
return "Alexa.AutomationManagement";
|
||||
case AlexaInterfaceType::AUTOMOTIVE_VEHICLE_DATA:
|
||||
return "Alexa.Automotive.VehicleData";
|
||||
case AlexaInterfaceType::BRIGHTNESS_CONTROLLER:
|
||||
return "Alexa.BrightnessController";
|
||||
case AlexaInterfaceType::CAMERA_LIVE_VIEW_CONTROLLER:
|
||||
return "Alexa.Camera.LiveViewController";
|
||||
case AlexaInterfaceType::CAMERA_STREAM_CONTROLLER:
|
||||
return "Alexa.CameraStreamController";
|
||||
case AlexaInterfaceType::CHANNEL_CONTROLLER:
|
||||
return "Alexa.ChannelController";
|
||||
case AlexaInterfaceType::COLOR_CONTROLLER:
|
||||
return "Alexa.ColorController";
|
||||
case AlexaInterfaceType::COLOR_TEMPERATURE_CONTROLLER:
|
||||
return "Alexa.ColorTemperatureController";
|
||||
case AlexaInterfaceType::COMMISSIONABLE:
|
||||
return "Alexa.Commissionable";
|
||||
case AlexaInterfaceType::CONSENT_MANAGEMENT_CONSENT_REQUIRED_REPORTER:
|
||||
return "Alexa.ConsentManagement.ConsentRequiredReporter";
|
||||
case AlexaInterfaceType::CONTACT_SENSOR:
|
||||
return "Alexa.ContactSensor";
|
||||
case AlexaInterfaceType::COOKING:
|
||||
return "Alexa.Cooking";
|
||||
case AlexaInterfaceType::COOKING_FOOD_TEMPERATURE_CONTROLLER:
|
||||
return "Alexa.Cooking.FoodTemperatureController";
|
||||
case AlexaInterfaceType::COOKING_FOOD_TEMPERATURE_SENSOR:
|
||||
return "Alexa.Cooking.FoodTemperatureSensor";
|
||||
case AlexaInterfaceType::COOKING_PRESET_CONTROLLER:
|
||||
return "Alexa.Cooking.PresetController";
|
||||
case AlexaInterfaceType::COOKING_TEMPERATURE_CONTROLLER:
|
||||
return "Alexa.Cooking.TemperatureController";
|
||||
case AlexaInterfaceType::COOKING_TEMPERATURE_SENSOR:
|
||||
return "Alexa.Cooking.TemperatureSensor";
|
||||
case AlexaInterfaceType::COOKING_TIME_CONTROLLER:
|
||||
return "Alexa.Cooking.TimeController";
|
||||
case AlexaInterfaceType::DATA_CONTROLLER:
|
||||
return "Alexa.DataController";
|
||||
case AlexaInterfaceType::DEVICE_USAGE_ESTIMATION:
|
||||
return "Alexa.DeviceUsage.Estimation";
|
||||
case AlexaInterfaceType::DEVICE_USAGE_METER:
|
||||
return "Alexa.DeviceUsage.Meter";
|
||||
case AlexaInterfaceType::DOORBELL_EVENT_SOURCE:
|
||||
return "Alexa.DoorbellEventSource";
|
||||
case AlexaInterfaceType::ENDPOINT_HEALTH:
|
||||
return "Alexa.EndpointHealth";
|
||||
case AlexaInterfaceType::EQUALIZER_CONTROLLER:
|
||||
return "Alexa.EqualizerController";
|
||||
case AlexaInterfaceType::INPUT_CONTROLLER:
|
||||
return "Alexa.InputController";
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_SENSOR:
|
||||
return "Alexa.InventoryLevelSensor";
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_USAGE_SENSOR:
|
||||
return "Alexa.InventoryLevelUsageSensor";
|
||||
case AlexaInterfaceType::INVENTORY_USAGE_SENSOR:
|
||||
return "Alexa.InventoryUsageSensor";
|
||||
case AlexaInterfaceType::KEYPAD_CONTROLLER:
|
||||
return "Alexa.KeypadController";
|
||||
case AlexaInterfaceType::LAUNCHER:
|
||||
return "Alexa.Launcher";
|
||||
case AlexaInterfaceType::LOCK_CONTROLLER:
|
||||
return "Alexa.LockController";
|
||||
case AlexaInterfaceType::MEDIA_PLAYBACK:
|
||||
return "Alexa.Media.Playback";
|
||||
case AlexaInterfaceType::MEDIA_PLAY_QUEUE:
|
||||
return "Alexa.Media.PlayQueue";
|
||||
case AlexaInterfaceType::MEDIA_SEARCH:
|
||||
return "Alexa.Media.Search";
|
||||
case AlexaInterfaceType::MODE_CONTROLLER:
|
||||
return "Alexa.ModeController";
|
||||
case AlexaInterfaceType::MOTION_SENSOR:
|
||||
return "Alexa.MotionSensor";
|
||||
case AlexaInterfaceType::PERCENTAGE_CONTROLLER:
|
||||
return "Alexa.PercentageController";
|
||||
case AlexaInterfaceType::PLAYBACK_CONTROLLER:
|
||||
return "Alexa.PlaybackController";
|
||||
case AlexaInterfaceType::PLAYBACK_STATE_REPORTER:
|
||||
return "Alexa.PlaybackStateReporter";
|
||||
case AlexaInterfaceType::POWER_CONTROLLER:
|
||||
return "Alexa.PowerController";
|
||||
case AlexaInterfaceType::POWER_LEVEL_CONTROLLER:
|
||||
return "Alexa.PowerLevelController";
|
||||
case AlexaInterfaceType::PROACTIVE_NOTIFICATION_SOURCE:
|
||||
return "Alexa.ProactiveNotificationSource";
|
||||
case AlexaInterfaceType::RANGE_CONTROLLER:
|
||||
return "Alexa.RangeController";
|
||||
case AlexaInterfaceType::RECORD_CONTROLLER:
|
||||
return "Alexa.RecordController";
|
||||
case AlexaInterfaceType::REMOTE_VIDEO_PLAYER:
|
||||
return "Alexa.RemoteVideoPlayer";
|
||||
case AlexaInterfaceType::RTC_SESSION_CONTROLLER:
|
||||
return "Alexa.RTCSessionController";
|
||||
case AlexaInterfaceType::SCENE_CONTROLLER:
|
||||
return "Alexa.SceneController";
|
||||
case AlexaInterfaceType::SECURITY_PANEL_CONTROLLER:
|
||||
return "Alexa.SecurityPanelController";
|
||||
case AlexaInterfaceType::SECURITY_PANEL_CONTROLLER_ALERT:
|
||||
return "Alexa.SecurityPanelController.Alert";
|
||||
case AlexaInterfaceType::SEEK_CONTROLLER:
|
||||
return "Alexa.SeekController";
|
||||
case AlexaInterfaceType::SIMPLE_EVENT_SOURCE:
|
||||
return "Alexa.SimpleEventSource";
|
||||
case AlexaInterfaceType::SMART_VISION_OBJECT_DETECTION_SENSOR:
|
||||
return "Alexa.SmartVision.ObjectDetectionSensor";
|
||||
case AlexaInterfaceType::SMART_VISION_SNAPSHOT_PROVIDER:
|
||||
return "Alexa.SmartVision.SnapshotProvider";
|
||||
case AlexaInterfaceType::SPEAKER:
|
||||
return "Alexa.Speaker";
|
||||
case AlexaInterfaceType::STEP_SPEAKER:
|
||||
return "Alexa.StepSpeaker";
|
||||
case AlexaInterfaceType::TEMPERATURE_SENSOR:
|
||||
return "Alexa.TemperatureSensor";
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER:
|
||||
return "Alexa.ThermostatController";
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_CONFIGURATION:
|
||||
return "Alexa.ThermostatController.Configuration";
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_HVAC_COMPONENTS:
|
||||
return "Alexa.ThermostatController.HVAC.Components";
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_SCHEDULE:
|
||||
return "Alexa.ThermostatController.Schedule";
|
||||
case AlexaInterfaceType::TIME_HOLD_CONTROLLER:
|
||||
return "Alexa.TimeHoldController";
|
||||
case AlexaInterfaceType::TOGGLE_CONTROLLER:
|
||||
return "Alexa.ToggleController";
|
||||
case AlexaInterfaceType::UI_CONTROLLER:
|
||||
return "Alexa.UIController";
|
||||
case AlexaInterfaceType::USER_PREFERENCE:
|
||||
return "Alexa.UserPreference";
|
||||
case AlexaInterfaceType::VIDEO_RECORDER:
|
||||
return "Alexa.VideoRecorder";
|
||||
case AlexaInterfaceType::WAKE_ON_LAN_CONTROLLER:
|
||||
return "Alexa.WakeOnLANController";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static String getVersion(AlexaInterfaceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AlexaInterfaceType::APPLICATION_STATE_REPORTER:
|
||||
case AlexaInterfaceType::AUDIO_PLAY_QUEUE:
|
||||
case AlexaInterfaceType::AUTHORIZATION_CONTROLLER:
|
||||
case AlexaInterfaceType::AUTOMATION_MANAGEMENT:
|
||||
case AlexaInterfaceType::AUTOMOTIVE_VEHICLE_DATA:
|
||||
case AlexaInterfaceType::COMMISSIONABLE:
|
||||
case AlexaInterfaceType::CONSENT_MANAGEMENT_CONSENT_REQUIRED_REPORTER:
|
||||
case AlexaInterfaceType::COOKING:
|
||||
case AlexaInterfaceType::COOKING_FOOD_TEMPERATURE_CONTROLLER:
|
||||
case AlexaInterfaceType::COOKING_FOOD_TEMPERATURE_SENSOR:
|
||||
case AlexaInterfaceType::COOKING_PRESET_CONTROLLER:
|
||||
case AlexaInterfaceType::COOKING_TEMPERATURE_CONTROLLER:
|
||||
case AlexaInterfaceType::COOKING_TEMPERATURE_SENSOR:
|
||||
case AlexaInterfaceType::COOKING_TIME_CONTROLLER:
|
||||
case AlexaInterfaceType::DATA_CONTROLLER:
|
||||
case AlexaInterfaceType::DEVICE_USAGE_ESTIMATION:
|
||||
case AlexaInterfaceType::DEVICE_USAGE_METER:
|
||||
case AlexaInterfaceType::EQUALIZER_CONTROLLER:
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_SENSOR:
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_USAGE_SENSOR:
|
||||
case AlexaInterfaceType::INVENTORY_USAGE_SENSOR:
|
||||
case AlexaInterfaceType::KEYPAD_CONTROLLER:
|
||||
case AlexaInterfaceType::MEDIA_PLAYBACK:
|
||||
case AlexaInterfaceType::MEDIA_PLAY_QUEUE:
|
||||
case AlexaInterfaceType::MEDIA_SEARCH:
|
||||
case AlexaInterfaceType::PLAYBACK_STATE_REPORTER:
|
||||
case AlexaInterfaceType::PROACTIVE_NOTIFICATION_SOURCE:
|
||||
case AlexaInterfaceType::REMOTE_VIDEO_PLAYER:
|
||||
case AlexaInterfaceType::RTC_SESSION_CONTROLLER:
|
||||
case AlexaInterfaceType::SECURITY_PANEL_CONTROLLER:
|
||||
case AlexaInterfaceType::SECURITY_PANEL_CONTROLLER_ALERT:
|
||||
case AlexaInterfaceType::SIMPLE_EVENT_SOURCE:
|
||||
case AlexaInterfaceType::SMART_VISION_OBJECT_DETECTION_SENSOR:
|
||||
case AlexaInterfaceType::SMART_VISION_SNAPSHOT_PROVIDER:
|
||||
case AlexaInterfaceType::SPEAKER:
|
||||
case AlexaInterfaceType::STEP_SPEAKER:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_CONFIGURATION:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_HVAC_COMPONENTS:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_SCHEDULE:
|
||||
case AlexaInterfaceType::UI_CONTROLLER:
|
||||
case AlexaInterfaceType::USER_PREFERENCE:
|
||||
case AlexaInterfaceType::VIDEO_RECORDER:
|
||||
case AlexaInterfaceType::WAKE_ON_LAN_CONTROLLER:
|
||||
return "1";
|
||||
|
||||
case AlexaInterfaceType::BRIGHTNESS_CONTROLLER:
|
||||
case AlexaInterfaceType::CAMERA_STREAM_CONTROLLER:
|
||||
case AlexaInterfaceType::CHANNEL_CONTROLLER:
|
||||
case AlexaInterfaceType::COLOR_CONTROLLER:
|
||||
case AlexaInterfaceType::COLOR_TEMPERATURE_CONTROLLER:
|
||||
case AlexaInterfaceType::CONTACT_SENSOR:
|
||||
case AlexaInterfaceType::DOORBELL_EVENT_SOURCE:
|
||||
case AlexaInterfaceType::INPUT_CONTROLLER:
|
||||
case AlexaInterfaceType::LOCK_CONTROLLER:
|
||||
case AlexaInterfaceType::MODE_CONTROLLER:
|
||||
case AlexaInterfaceType::MOTION_SENSOR:
|
||||
case AlexaInterfaceType::PERCENTAGE_CONTROLLER:
|
||||
case AlexaInterfaceType::PLAYBACK_CONTROLLER:
|
||||
case AlexaInterfaceType::POWER_CONTROLLER:
|
||||
case AlexaInterfaceType::POWER_LEVEL_CONTROLLER:
|
||||
case AlexaInterfaceType::RANGE_CONTROLLER:
|
||||
case AlexaInterfaceType::RECORD_CONTROLLER:
|
||||
case AlexaInterfaceType::SCENE_CONTROLLER:
|
||||
case AlexaInterfaceType::SEEK_CONTROLLER:
|
||||
case AlexaInterfaceType::TEMPERATURE_SENSOR:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER:
|
||||
case AlexaInterfaceType::TOGGLE_CONTROLLER:
|
||||
return "3";
|
||||
|
||||
case AlexaInterfaceType::LAUNCHER:
|
||||
return "1.1";
|
||||
case AlexaInterfaceType::ENDPOINT_HEALTH:
|
||||
return "3.3";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<String> getProps(AlexaInterfaceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AlexaInterfaceType::AUTOMATION_MANAGEMENT:
|
||||
return {"automationStatuses"};
|
||||
case AlexaInterfaceType::BRIGHTNESS_CONTROLLER:
|
||||
return {"brightness"};
|
||||
case AlexaInterfaceType::CHANNEL_CONTROLLER:
|
||||
return {"channel"};
|
||||
case AlexaInterfaceType::COLOR_CONTROLLER:
|
||||
return {"color"};
|
||||
case AlexaInterfaceType::COLOR_TEMPERATURE_CONTROLLER:
|
||||
return {"colorTemperatureInKelvin"};
|
||||
case AlexaInterfaceType::CONTACT_SENSOR:
|
||||
return {"detectionState"};
|
||||
case AlexaInterfaceType::POWER_CONTROLLER:
|
||||
return {"powerState"};
|
||||
case AlexaInterfaceType::ENDPOINT_HEALTH:
|
||||
return {"connectivity"};
|
||||
case AlexaInterfaceType::TOGGLE_CONTROLLER:
|
||||
return {"toggleState"};
|
||||
case AlexaInterfaceType::TEMPERATURE_SENSOR:
|
||||
return {"temperature"};
|
||||
|
||||
case AlexaInterfaceType::APPLICATION_STATE_REPORTER:
|
||||
case AlexaInterfaceType::AUDIO_PLAY_QUEUE:
|
||||
case AlexaInterfaceType::AUTHORIZATION_CONTROLLER:
|
||||
case AlexaInterfaceType::AUTOMOTIVE_VEHICLE_DATA:
|
||||
case AlexaInterfaceType::CAMERA_LIVE_VIEW_CONTROLLER:
|
||||
case AlexaInterfaceType::CAMERA_STREAM_CONTROLLER:
|
||||
case AlexaInterfaceType::COMMISSIONABLE:
|
||||
case AlexaInterfaceType::CONSENT_MANAGEMENT_CONSENT_REQUIRED_REPORTER:
|
||||
case AlexaInterfaceType::COOKING:
|
||||
case AlexaInterfaceType::DATA_CONTROLLER:
|
||||
case AlexaInterfaceType::DEVICE_USAGE_ESTIMATION:
|
||||
case AlexaInterfaceType::DEVICE_USAGE_METER:
|
||||
case AlexaInterfaceType::DOORBELL_EVENT_SOURCE:
|
||||
case AlexaInterfaceType::EQUALIZER_CONTROLLER:
|
||||
case AlexaInterfaceType::INPUT_CONTROLLER:
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_SENSOR:
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_USAGE_SENSOR:
|
||||
case AlexaInterfaceType::INVENTORY_USAGE_SENSOR:
|
||||
case AlexaInterfaceType::KEYPAD_CONTROLLER:
|
||||
case AlexaInterfaceType::LAUNCHER:
|
||||
case AlexaInterfaceType::LOCK_CONTROLLER:
|
||||
case AlexaInterfaceType::MEDIA_PLAYBACK:
|
||||
case AlexaInterfaceType::MEDIA_SEARCH:
|
||||
case AlexaInterfaceType::MODE_CONTROLLER:
|
||||
case AlexaInterfaceType::MOTION_SENSOR:
|
||||
case AlexaInterfaceType::PERCENTAGE_CONTROLLER:
|
||||
case AlexaInterfaceType::PLAYBACK_CONTROLLER:
|
||||
case AlexaInterfaceType::PLAYBACK_STATE_REPORTER:
|
||||
case AlexaInterfaceType::PROACTIVE_NOTIFICATION_SOURCE:
|
||||
case AlexaInterfaceType::RANGE_CONTROLLER:
|
||||
case AlexaInterfaceType::RECORD_CONTROLLER:
|
||||
case AlexaInterfaceType::REMOTE_VIDEO_PLAYER:
|
||||
case AlexaInterfaceType::RTC_SESSION_CONTROLLER:
|
||||
case AlexaInterfaceType::SCENE_CONTROLLER:
|
||||
case AlexaInterfaceType::SECURITY_PANEL_CONTROLLER:
|
||||
case AlexaInterfaceType::SEEK_CONTROLLER:
|
||||
case AlexaInterfaceType::SIMPLE_EVENT_SOURCE:
|
||||
case AlexaInterfaceType::SMART_VISION_OBJECT_DETECTION_SENSOR:
|
||||
case AlexaInterfaceType::SMART_VISION_SNAPSHOT_PROVIDER:
|
||||
case AlexaInterfaceType::SPEAKER:
|
||||
case AlexaInterfaceType::STEP_SPEAKER:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_CONFIGURATION:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_HVAC_COMPONENTS:
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER_SCHEDULE:
|
||||
case AlexaInterfaceType::TIME_HOLD_CONTROLLER:
|
||||
case AlexaInterfaceType::UI_CONTROLLER:
|
||||
case AlexaInterfaceType::USER_PREFERENCE:
|
||||
case AlexaInterfaceType::VIDEO_RECORDER:
|
||||
case AlexaInterfaceType::WAKE_ON_LAN_CONTROLLER:
|
||||
return {};
|
||||
|
||||
default:
|
||||
return {"UNKNOWN"};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum class AlexaActions {
|
||||
Open,
|
||||
Close,
|
||||
|
|
@ -627,11 +90,11 @@ public:
|
|||
|
||||
|
||||
|
||||
// AlexaInterface class definition
|
||||
// A capability of a device: a row of AlexaInterfaces and what this device adds to it
|
||||
class AlexaInterface
|
||||
{
|
||||
private:
|
||||
AlexaInterfaceType type;
|
||||
const AlexaInterfaceDesc *row; // in program memory, never nullptr
|
||||
bool retrievable;
|
||||
bool proactivelyReported;
|
||||
std::vector<ActionMapping> actionMappings; // Array of ActionMappings
|
||||
|
|
@ -642,14 +105,23 @@ private:
|
|||
bool nameSet = false;
|
||||
public:
|
||||
// Constructor
|
||||
AlexaInterface(AlexaInterfaceType type, bool retrievable = true, bool proactivelyReported = false)
|
||||
: type(type), retrievable(retrievable), proactivelyReported(proactivelyReported) {}
|
||||
AlexaInterface(const AlexaInterfaceDesc &row, bool retrievable = true, bool proactivelyReported = false)
|
||||
: row(&row), retrievable(retrievable), proactivelyReported(proactivelyReported) {}
|
||||
|
||||
// Getters
|
||||
AlexaInterfaceType getType() const { return type; }
|
||||
String getTypeString() const { return AlexaInterfaceUtils::toString(type); }
|
||||
String getVersion() const { return AlexaInterfaceUtils::getVersion(type); }
|
||||
std::vector<String> getProps() const { return AlexaInterfaceUtils::getProps(type); }
|
||||
const AlexaInterfaceDesc &getRow() const { return *row; }
|
||||
AlexaInterfaceType getType() const { return row->interfaceType(); }
|
||||
String getTypeString() const { return String(FPSTR(row->ns)); }
|
||||
String getVersion() const { return String(FPSTR(row->version)); }
|
||||
std::vector<String> getProps() const
|
||||
{
|
||||
std::vector<String> props;
|
||||
for (uint8_t i = 0; i < row->propertyCount(); i++)
|
||||
{
|
||||
props.push_back(String(FPSTR(row->property(i))));
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
void setInstance(const char* name){
|
||||
instance=name;
|
||||
|
|
@ -676,23 +148,21 @@ public:
|
|||
JsonDocument doc;
|
||||
|
||||
// Set base properties
|
||||
doc["interface"] = getTypeString();
|
||||
doc["version"] = getVersion();
|
||||
doc["interface"] = FPSTR(row->ns);
|
||||
doc["version"] = FPSTR(row->version);
|
||||
doc["type"] = "AlexaInterface";
|
||||
|
||||
// Add properties
|
||||
JsonObject properties = doc["properties"].to<JsonObject>();
|
||||
properties["retrievable"] = retrievable;
|
||||
properties["proactivelyReported"] = proactivelyReported;
|
||||
// Add properties, unless the interface has none to report (a scene, a doorbell)
|
||||
if (!row->has(AIF_NO_PROPERTIES)) {
|
||||
JsonObject properties = doc["properties"].to<JsonObject>();
|
||||
properties["retrievable"] = retrievable;
|
||||
properties["proactivelyReported"] = proactivelyReported;
|
||||
|
||||
std::vector<String> props = getProps();
|
||||
|
||||
JsonArray supported = properties["supported"].to<JsonArray>();
|
||||
int index = 0;
|
||||
for (String prop : props)
|
||||
{
|
||||
supported[index]["name"] = prop;
|
||||
index++;
|
||||
JsonArray supported = properties["supported"].to<JsonArray>();
|
||||
for (uint8_t i = 0; i < row->propertyCount(); i++)
|
||||
{
|
||||
supported.add<JsonObject>()["name"] = FPSTR(row->property(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
159
src/AlexaInterfaces.cpp
Normal file
159
src/AlexaInterfaces.cpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
#include "AlexaInterfaces.h"
|
||||
|
||||
// Every string and every row is a PROGMEM object of its own: what no capability of the sketch refers to is not
|
||||
// linked. A new interface is its strings and one ALEXA_ROW here, an extern and a case in AlexaInterfaces.h.
|
||||
#define ALEXA_TEXT(name, text) static const char name[] PROGMEM = text
|
||||
#define ALEXA_ROW(row, ns, version, props, propCount, flags, type) \
|
||||
const AlexaInterfaceDesc AlexaInterfaces::row PROGMEM = {ns, version, props, propCount, flags, AlexaInterfaceType::type}
|
||||
|
||||
ALEXA_TEXT(VERSION_1_0, "1.0");
|
||||
ALEXA_TEXT(VERSION_3, "3");
|
||||
ALEXA_TEXT(VERSION_3_1, "3.1");
|
||||
ALEXA_TEXT(VERSION_3_2, "3.2");
|
||||
|
||||
ALEXA_TEXT(NS_ENDPOINT_HEALTH, "Alexa.EndpointHealth");
|
||||
ALEXA_TEXT(NS_POWER, "Alexa.PowerController");
|
||||
ALEXA_TEXT(NS_BRIGHTNESS, "Alexa.BrightnessController");
|
||||
ALEXA_TEXT(NS_COLOR, "Alexa.ColorController");
|
||||
ALEXA_TEXT(NS_COLOR_TEMPERATURE, "Alexa.ColorTemperatureController");
|
||||
ALEXA_TEXT(NS_POWER_LEVEL, "Alexa.PowerLevelController");
|
||||
ALEXA_TEXT(NS_PERCENTAGE, "Alexa.PercentageController");
|
||||
ALEXA_TEXT(NS_RANGE, "Alexa.RangeController");
|
||||
ALEXA_TEXT(NS_MODE, "Alexa.ModeController");
|
||||
ALEXA_TEXT(NS_TOGGLE, "Alexa.ToggleController");
|
||||
ALEXA_TEXT(NS_THERMOSTAT, "Alexa.ThermostatController");
|
||||
ALEXA_TEXT(NS_TEMPERATURE_SENSOR, "Alexa.TemperatureSensor");
|
||||
ALEXA_TEXT(NS_HUMIDITY_SENSOR, "Alexa.HumiditySensor");
|
||||
ALEXA_TEXT(NS_LOCK, "Alexa.LockController");
|
||||
ALEXA_TEXT(NS_SCENE, "Alexa.SceneController");
|
||||
ALEXA_TEXT(NS_CONTACT_SENSOR, "Alexa.ContactSensor");
|
||||
ALEXA_TEXT(NS_MOTION_SENSOR, "Alexa.MotionSensor");
|
||||
ALEXA_TEXT(NS_DOORBELL, "Alexa.DoorbellEventSource");
|
||||
ALEXA_TEXT(NS_TIME_HOLD, "Alexa.TimeHoldController");
|
||||
ALEXA_TEXT(NS_SPEAKER, "Alexa.Speaker");
|
||||
ALEXA_TEXT(NS_STEP_SPEAKER, "Alexa.StepSpeaker");
|
||||
ALEXA_TEXT(NS_PLAYBACK, "Alexa.PlaybackController");
|
||||
ALEXA_TEXT(NS_PLAYBACK_STATE, "Alexa.PlaybackStateReporter");
|
||||
ALEXA_TEXT(NS_INPUT, "Alexa.InputController");
|
||||
ALEXA_TEXT(NS_CHANNEL, "Alexa.ChannelController");
|
||||
ALEXA_TEXT(NS_INVENTORY_LEVEL, "Alexa.InventoryLevelSensor");
|
||||
ALEXA_TEXT(NS_SIMPLE_EVENT, "Alexa.SimpleEventSource");
|
||||
ALEXA_TEXT(NS_WAKE_ON_LAN, "Alexa.WakeOnLANController");
|
||||
|
||||
ALEXA_TEXT(PROPERTY_CONNECTIVITY, "connectivity");
|
||||
ALEXA_TEXT(PROPERTY_POWER_STATE, "powerState");
|
||||
ALEXA_TEXT(PROPERTY_BRIGHTNESS, "brightness");
|
||||
ALEXA_TEXT(PROPERTY_COLOR, "color");
|
||||
ALEXA_TEXT(PROPERTY_COLOR_TEMPERATURE_IN_KELVIN, "colorTemperatureInKelvin");
|
||||
ALEXA_TEXT(PROPERTY_POWER_LEVEL, "powerLevel");
|
||||
ALEXA_TEXT(PROPERTY_PERCENTAGE, "percentage");
|
||||
ALEXA_TEXT(PROPERTY_RANGE_VALUE, "rangeValue");
|
||||
ALEXA_TEXT(PROPERTY_MODE, "mode");
|
||||
ALEXA_TEXT(PROPERTY_TOGGLE_STATE, "toggleState");
|
||||
ALEXA_TEXT(PROPERTY_TARGET_SETPOINT, "targetSetpoint");
|
||||
ALEXA_TEXT(PROPERTY_LOWER_SETPOINT, "lowerSetpoint");
|
||||
ALEXA_TEXT(PROPERTY_UPPER_SETPOINT, "upperSetpoint");
|
||||
ALEXA_TEXT(PROPERTY_THERMOSTAT_MODE, "thermostatMode");
|
||||
ALEXA_TEXT(PROPERTY_TEMPERATURE, "temperature");
|
||||
ALEXA_TEXT(PROPERTY_RELATIVE_HUMIDITY, "relativeHumidity");
|
||||
ALEXA_TEXT(PROPERTY_LOCK_STATE, "lockState");
|
||||
ALEXA_TEXT(PROPERTY_DETECTION_STATE, "detectionState");
|
||||
ALEXA_TEXT(PROPERTY_HOLD_START_TIME, "holdStartTime");
|
||||
ALEXA_TEXT(PROPERTY_HOLD_END_TIME, "holdEndTime");
|
||||
ALEXA_TEXT(PROPERTY_VOLUME, "volume");
|
||||
ALEXA_TEXT(PROPERTY_MUTED, "muted");
|
||||
ALEXA_TEXT(PROPERTY_PLAYBACK_STATE, "playbackState");
|
||||
ALEXA_TEXT(PROPERTY_INPUT, "input");
|
||||
ALEXA_TEXT(PROPERTY_CHANNEL, "channel");
|
||||
ALEXA_TEXT(PROPERTY_LEVEL, "level");
|
||||
|
||||
static const char *const PROPS_ENDPOINT_HEALTH[] PROGMEM = {PROPERTY_CONNECTIVITY};
|
||||
static const char *const PROPS_POWER[] PROGMEM = {PROPERTY_POWER_STATE};
|
||||
static const char *const PROPS_BRIGHTNESS[] PROGMEM = {PROPERTY_BRIGHTNESS};
|
||||
static const char *const PROPS_COLOR[] PROGMEM = {PROPERTY_COLOR};
|
||||
static const char *const PROPS_COLOR_TEMPERATURE[] PROGMEM = {PROPERTY_COLOR_TEMPERATURE_IN_KELVIN};
|
||||
static const char *const PROPS_POWER_LEVEL[] PROGMEM = {PROPERTY_POWER_LEVEL};
|
||||
static const char *const PROPS_PERCENTAGE[] PROGMEM = {PROPERTY_PERCENTAGE};
|
||||
static const char *const PROPS_RANGE[] PROGMEM = {PROPERTY_RANGE_VALUE};
|
||||
static const char *const PROPS_MODE[] PROGMEM = {PROPERTY_MODE};
|
||||
static const char *const PROPS_TOGGLE[] PROGMEM = {PROPERTY_TOGGLE_STATE};
|
||||
static const char *const PROPS_THERMOSTAT[] PROGMEM = {PROPERTY_TARGET_SETPOINT, PROPERTY_LOWER_SETPOINT, PROPERTY_UPPER_SETPOINT, PROPERTY_THERMOSTAT_MODE};
|
||||
static const char *const PROPS_TEMPERATURE_SENSOR[] PROGMEM = {PROPERTY_TEMPERATURE};
|
||||
static const char *const PROPS_HUMIDITY_SENSOR[] PROGMEM = {PROPERTY_RELATIVE_HUMIDITY};
|
||||
static const char *const PROPS_LOCK[] PROGMEM = {PROPERTY_LOCK_STATE};
|
||||
static const char *const PROPS_DETECTION[] PROGMEM = {PROPERTY_DETECTION_STATE};
|
||||
static const char *const PROPS_TIME_HOLD[] PROGMEM = {PROPERTY_HOLD_START_TIME, PROPERTY_HOLD_END_TIME};
|
||||
static const char *const PROPS_SPEAKER[] PROGMEM = {PROPERTY_VOLUME, PROPERTY_MUTED};
|
||||
static const char *const PROPS_PLAYBACK_STATE[] PROGMEM = {PROPERTY_PLAYBACK_STATE};
|
||||
static const char *const PROPS_INPUT[] PROGMEM = {PROPERTY_INPUT};
|
||||
static const char *const PROPS_CHANNEL[] PROGMEM = {PROPERTY_CHANNEL};
|
||||
static const char *const PROPS_INVENTORY_LEVEL[] PROGMEM = {PROPERTY_LEVEL};
|
||||
|
||||
ALEXA_ROW(EndpointHealth, NS_ENDPOINT_HEALTH, VERSION_3_1, PROPS_ENDPOINT_HEALTH, 1, AIF_NONE, ENDPOINT_HEALTH);
|
||||
ALEXA_ROW(PowerController, NS_POWER, VERSION_3, PROPS_POWER, 1, AIF_NONE, POWER_CONTROLLER);
|
||||
ALEXA_ROW(BrightnessController, NS_BRIGHTNESS, VERSION_3, PROPS_BRIGHTNESS, 1, AIF_NONE, BRIGHTNESS_CONTROLLER);
|
||||
ALEXA_ROW(ColorController, NS_COLOR, VERSION_3, PROPS_COLOR, 1, AIF_NONE, COLOR_CONTROLLER);
|
||||
ALEXA_ROW(ColorTemperatureController, NS_COLOR_TEMPERATURE, VERSION_3, PROPS_COLOR_TEMPERATURE, 1, AIF_NONE, COLOR_TEMPERATURE_CONTROLLER);
|
||||
ALEXA_ROW(PowerLevelController, NS_POWER_LEVEL, VERSION_3, PROPS_POWER_LEVEL, 1, AIF_NONE, POWER_LEVEL_CONTROLLER);
|
||||
ALEXA_ROW(PercentageController, NS_PERCENTAGE, VERSION_3, PROPS_PERCENTAGE, 1, AIF_NONE, PERCENTAGE_CONTROLLER);
|
||||
ALEXA_ROW(RangeController, NS_RANGE, VERSION_3, PROPS_RANGE, 1, AIF_INSTANCED | AIF_SEMANTICS, RANGE_CONTROLLER);
|
||||
ALEXA_ROW(ModeController, NS_MODE, VERSION_3, PROPS_MODE, 1, AIF_INSTANCED | AIF_SEMANTICS, MODE_CONTROLLER);
|
||||
ALEXA_ROW(ToggleController, NS_TOGGLE, VERSION_3, PROPS_TOGGLE, 1, AIF_INSTANCED | AIF_SEMANTICS, TOGGLE_CONTROLLER);
|
||||
ALEXA_ROW(ThermostatController, NS_THERMOSTAT, VERSION_3_2, PROPS_THERMOSTAT, 4, AIF_NONE, THERMOSTAT_CONTROLLER);
|
||||
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(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(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(DoorbellEventSource, NS_DOORBELL, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES, DOORBELL_EVENT_SOURCE);
|
||||
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(StepSpeaker, NS_STEP_SPEAKER, VERSION_3, nullptr, 0, AIF_NO_PROPERTIES, STEP_SPEAKER);
|
||||
ALEXA_ROW(PlaybackController, NS_PLAYBACK, VERSION_3, nullptr, 0, AIF_NONE, PLAYBACK_CONTROLLER);
|
||||
ALEXA_ROW(PlaybackStateReporter, NS_PLAYBACK_STATE, VERSION_3, PROPS_PLAYBACK_STATE, 1, AIF_NONE, PLAYBACK_STATE_REPORTER);
|
||||
ALEXA_ROW(InputController, NS_INPUT, VERSION_3, PROPS_INPUT, 1, AIF_NONE, INPUT_CONTROLLER);
|
||||
ALEXA_ROW(ChannelController, NS_CHANNEL, VERSION_3, PROPS_CHANNEL, 1, AIF_NONE, CHANNEL_CONTROLLER);
|
||||
ALEXA_ROW(InventoryLevelSensor, NS_INVENTORY_LEVEL, VERSION_3, PROPS_INVENTORY_LEVEL, 1, AIF_INSTANCED, INVENTORY_LEVEL_SENSOR);
|
||||
ALEXA_ROW(SimpleEventSource, NS_SIMPLE_EVENT, VERSION_1_0, nullptr, 0, AIF_INSTANCED | AIF_NO_PROPERTIES, SIMPLE_EVENT_SOURCE);
|
||||
ALEXA_ROW(WakeOnLANController, NS_WAKE_ON_LAN, VERSION_3, nullptr, 0, AIF_NONE, WAKE_ON_LAN_CONTROLLER);
|
||||
|
||||
// The display categories in the order of the enum. Their names are looked up by a value that is only known when
|
||||
// the sketch runs, so this table is always linked (about 1 KB of flash).
|
||||
#define ALEXA_DISPLAY_CATEGORIES(X) \
|
||||
X(ACTIVITY_TRIGGER) X(AIR_CONDITIONER) X(AIR_FRESHENER) X(AIR_PURIFIER) X(AIR_QUALITY_MONITOR) \
|
||||
X(ALEXA_VOICE_ENABLED) X(AUTO_ACCESSORY) X(BLUETOOTH_SPEAKER) X(CAMERA) X(CHRISTMAS_TREE) X(COFFEE_MAKER) \
|
||||
X(COMPUTER) X(CONTACT_SENSOR) X(DISHWASHER) X(DOOR) X(DOORBELL) X(DRYER) X(EXTERIOR_BLIND) X(FAN) \
|
||||
X(GAME_CONSOLE) X(GARAGE_DOOR) X(HEADPHONES) X(HUB) X(INTERIOR_BLIND) X(LAPTOP) X(LIGHT) X(MICROWAVE) \
|
||||
X(MOBILE_PHONE) X(MOTION_SENSOR) X(MUSIC_SYSTEM) X(NETWORK_HARDWARE) X(OTHER) X(OVEN) X(PHONE) X(PRINTER) \
|
||||
X(REMOTE) X(ROUTER) X(SCENE_TRIGGER) X(SCREEN) X(SECURITY_PANEL) X(SECURITY_SYSTEM) X(SLOW_COOKER) \
|
||||
X(SMARTLOCK) X(SMARTPLUG) X(SPEAKER) X(STREAMING_DEVICE) X(SWITCH) X(TABLET) X(TEMPERATURE_SENSOR) \
|
||||
X(THERMOSTAT) X(TV) X(VACUUM_CLEANER) X(VEHICLE) X(WASHER) X(WATER_HEATER) X(WEARABLE)
|
||||
|
||||
#define ALEXA_CATEGORY_TEXT(name) static const char CATEGORY_##name[] PROGMEM = #name;
|
||||
ALEXA_DISPLAY_CATEGORIES(ALEXA_CATEGORY_TEXT)
|
||||
|
||||
#define ALEXA_CATEGORY_ENTRY(name) CATEGORY_##name,
|
||||
static const char *const CATEGORY_NAMES[] PROGMEM = {ALEXA_DISPLAY_CATEGORIES(ALEXA_CATEGORY_ENTRY)};
|
||||
|
||||
// A category that is added to the enum and not to the list above, or at another place, does not compile
|
||||
enum CategoryPlace : size_t
|
||||
{
|
||||
#define ALEXA_CATEGORY_PLACE(name) PLACE_##name,
|
||||
ALEXA_DISPLAY_CATEGORIES(ALEXA_CATEGORY_PLACE)
|
||||
PLACE_COUNT
|
||||
};
|
||||
#define ALEXA_CATEGORY_CHECK(name) \
|
||||
static_assert(static_cast<size_t>(DisplayCategory::name) == PLACE_##name, "display category " #name " is out of place");
|
||||
ALEXA_DISPLAY_CATEGORIES(ALEXA_CATEGORY_CHECK)
|
||||
static_assert(static_cast<size_t>(DisplayCategory::WEARABLE) + 1 == PLACE_COUNT, "a display category has no name");
|
||||
|
||||
PGM_P alexaDisplayCategoryName(DisplayCategory category)
|
||||
{
|
||||
size_t place = static_cast<size_t>(category);
|
||||
if (place >= PLACE_COUNT)
|
||||
{
|
||||
place = PLACE_OTHER;
|
||||
}
|
||||
return static_cast<PGM_P>(pgm_read_ptr(&CATEGORY_NAMES[place]));
|
||||
}
|
||||
251
src/AlexaInterfaces.h
Normal file
251
src/AlexaInterfaces.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
// The Alexa interfaces the library can describe. Every interface is one row in program memory: its namespace, its
|
||||
// version, the names of the properties it reports and what its discovery object carries. A sketch names the rows
|
||||
// it uses, device->addCapability(AlexaInterfaces::PowerController), and the linker leaves out every other row and
|
||||
// its strings: each is an object of its own, and the ESP8266 core links with --gc-sections. That only works while
|
||||
// nothing refers to all rows at once, so there is no table that leads from an AlexaInterfaceType to its row.
|
||||
#ifndef ALEXA_INTERFACES_H
|
||||
#define ALEXA_INTERFACES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "AlexaCompat.h"
|
||||
|
||||
// What the handler of "Event" is told about the directive. The values without a row in AlexaInterfaces are
|
||||
// interfaces the library cannot describe yet: addCapability() refuses them.
|
||||
enum class AlexaInterfaceType : uint8_t
|
||||
{
|
||||
APPLICATION_STATE_REPORTER,
|
||||
AUDIO_PLAY_QUEUE,
|
||||
AUTOMATION_MANAGEMENT,
|
||||
BRIGHTNESS_CONTROLLER,
|
||||
CAMERA_LIVE_VIEW_CONTROLLER,
|
||||
CAMERA_STREAM_CONTROLLER,
|
||||
CHANNEL_CONTROLLER,
|
||||
COLOR_CONTROLLER,
|
||||
COLOR_TEMPERATURE_CONTROLLER,
|
||||
COMMISSIONABLE,
|
||||
CONSENT_MANAGEMENT_CONSENT_REQUIRED_REPORTER,
|
||||
CONTACT_SENSOR,
|
||||
COOKING,
|
||||
COOKING_FOOD_TEMPERATURE_CONTROLLER,
|
||||
COOKING_FOOD_TEMPERATURE_SENSOR,
|
||||
COOKING_PRESET_CONTROLLER,
|
||||
COOKING_TEMPERATURE_CONTROLLER,
|
||||
COOKING_TEMPERATURE_SENSOR,
|
||||
COOKING_TIME_CONTROLLER,
|
||||
DATA_CONTROLLER,
|
||||
DEVICE_USAGE_ESTIMATION,
|
||||
DEVICE_USAGE_METER,
|
||||
DOORBELL_EVENT_SOURCE,
|
||||
ENDPOINT_HEALTH,
|
||||
EQUALIZER_CONTROLLER,
|
||||
HUMIDITY_SENSOR,
|
||||
INPUT_CONTROLLER,
|
||||
INVENTORY_LEVEL_SENSOR,
|
||||
INVENTORY_LEVEL_USAGE_SENSOR,
|
||||
INVENTORY_USAGE_SENSOR,
|
||||
KEYPAD_CONTROLLER,
|
||||
LAUNCHER,
|
||||
LOCK_CONTROLLER,
|
||||
MEDIA_PLAYBACK,
|
||||
MEDIA_PLAY_QUEUE,
|
||||
MEDIA_SEARCH,
|
||||
MODE_CONTROLLER,
|
||||
MOTION_SENSOR,
|
||||
PERCENTAGE_CONTROLLER,
|
||||
PLAYBACK_CONTROLLER,
|
||||
PLAYBACK_STATE_REPORTER,
|
||||
POWER_CONTROLLER,
|
||||
POWER_LEVEL_CONTROLLER,
|
||||
PROACTIVE_NOTIFICATION_SOURCE,
|
||||
RANGE_CONTROLLER,
|
||||
RECORD_CONTROLLER,
|
||||
REMOTE_VIDEO_PLAYER,
|
||||
RTC_SESSION_CONTROLLER,
|
||||
SCENE_CONTROLLER,
|
||||
SECURITY_PANEL_CONTROLLER,
|
||||
SECURITY_PANEL_CONTROLLER_ALERT,
|
||||
SEEK_CONTROLLER,
|
||||
SIMPLE_EVENT_SOURCE,
|
||||
SMART_VISION_OBJECT_DETECTION_SENSOR,
|
||||
SMART_VISION_SNAPSHOT_PROVIDER,
|
||||
SPEAKER,
|
||||
STEP_SPEAKER,
|
||||
TEMPERATURE_SENSOR,
|
||||
THERMOSTAT_CONTROLLER,
|
||||
THERMOSTAT_CONTROLLER_CONFIGURATION,
|
||||
THERMOSTAT_CONTROLLER_HVAC_COMPONENTS,
|
||||
THERMOSTAT_CONTROLLER_SCHEDULE,
|
||||
TIME_HOLD_CONTROLLER,
|
||||
TOGGLE_CONTROLLER,
|
||||
UI_CONTROLLER,
|
||||
USER_PREFERENCE,
|
||||
VIDEO_RECORDER,
|
||||
WAKE_ON_LAN_CONTROLLER,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
enum AlexaInterfaceFlags : uint8_t
|
||||
{
|
||||
AIF_NONE = 0,
|
||||
AIF_INSTANCED = 1, // a generic controller: needs an instance and friendly names
|
||||
AIF_NO_PROPERTIES = 2, // the discovery object has no "properties" (scenes, doorbells, step speakers)
|
||||
AIF_SEMANTICS = 4 // may carry action and state mappings
|
||||
};
|
||||
|
||||
// 16 bytes in program memory. The ESP8266 reads flash in whole words only: the pointers can be read as they are,
|
||||
// the three single bytes through the functions below.
|
||||
struct AlexaInterfaceDesc
|
||||
{
|
||||
PGM_P ns; // "Alexa.PowerController"
|
||||
PGM_P version; // "3"
|
||||
const char *const *props; // the names of the properties, propCount of them; nullptr when there are none
|
||||
uint8_t propCount;
|
||||
uint8_t flags; // AlexaInterfaceFlags
|
||||
AlexaInterfaceType type;
|
||||
|
||||
uint8_t propertyCount() const { return pgm_read_byte(&propCount); }
|
||||
bool has(AlexaInterfaceFlags flag) const { return (pgm_read_byte(&flags) & flag) != 0; }
|
||||
AlexaInterfaceType interfaceType() const { return static_cast<AlexaInterfaceType>(pgm_read_byte(&type)); }
|
||||
|
||||
// The name of a property, index below propertyCount()
|
||||
PGM_P property(uint8_t index) const { return static_cast<PGM_P>(pgm_read_ptr(&props[index])); }
|
||||
};
|
||||
|
||||
// Versions and property names are those of the interface pages under
|
||||
// https://developer.amazon.com/en-US/docs/alexa/device-apis/
|
||||
namespace AlexaInterfaces
|
||||
{
|
||||
extern const AlexaInterfaceDesc EndpointHealth;
|
||||
extern const AlexaInterfaceDesc PowerController;
|
||||
extern const AlexaInterfaceDesc BrightnessController;
|
||||
extern const AlexaInterfaceDesc ColorController;
|
||||
extern const AlexaInterfaceDesc ColorTemperatureController;
|
||||
extern const AlexaInterfaceDesc PowerLevelController;
|
||||
extern const AlexaInterfaceDesc PercentageController;
|
||||
extern const AlexaInterfaceDesc RangeController;
|
||||
extern const AlexaInterfaceDesc ModeController;
|
||||
extern const AlexaInterfaceDesc ToggleController;
|
||||
extern const AlexaInterfaceDesc ThermostatController;
|
||||
extern const AlexaInterfaceDesc TemperatureSensor;
|
||||
extern const AlexaInterfaceDesc HumiditySensor;
|
||||
extern const AlexaInterfaceDesc LockController;
|
||||
extern const AlexaInterfaceDesc SceneController;
|
||||
extern const AlexaInterfaceDesc ContactSensor;
|
||||
extern const AlexaInterfaceDesc MotionSensor;
|
||||
extern const AlexaInterfaceDesc DoorbellEventSource;
|
||||
extern const AlexaInterfaceDesc TimeHoldController;
|
||||
extern const AlexaInterfaceDesc Speaker;
|
||||
extern const AlexaInterfaceDesc StepSpeaker;
|
||||
extern const AlexaInterfaceDesc PlaybackController;
|
||||
extern const AlexaInterfaceDesc PlaybackStateReporter;
|
||||
extern const AlexaInterfaceDesc InputController;
|
||||
extern const AlexaInterfaceDesc ChannelController;
|
||||
extern const AlexaInterfaceDesc InventoryLevelSensor;
|
||||
extern const AlexaInterfaceDesc SimpleEventSource;
|
||||
extern const AlexaInterfaceDesc WakeOnLANController;
|
||||
}
|
||||
|
||||
// The row of a type, nullptr for a type without one. Always inlined, so that a type the compiler knows, as in
|
||||
// addCapability(AlexaInterfaceType::POWER_CONTROLLER), leaves one row behind and not the switch. With a type that
|
||||
// is only known when the sketch runs, the sketch links every row.
|
||||
__attribute__((always_inline)) inline const AlexaInterfaceDesc *alexaInterfaceRow(AlexaInterfaceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AlexaInterfaceType::ENDPOINT_HEALTH: return &AlexaInterfaces::EndpointHealth;
|
||||
case AlexaInterfaceType::POWER_CONTROLLER: return &AlexaInterfaces::PowerController;
|
||||
case AlexaInterfaceType::BRIGHTNESS_CONTROLLER: return &AlexaInterfaces::BrightnessController;
|
||||
case AlexaInterfaceType::COLOR_CONTROLLER: return &AlexaInterfaces::ColorController;
|
||||
case AlexaInterfaceType::COLOR_TEMPERATURE_CONTROLLER: return &AlexaInterfaces::ColorTemperatureController;
|
||||
case AlexaInterfaceType::POWER_LEVEL_CONTROLLER: return &AlexaInterfaces::PowerLevelController;
|
||||
case AlexaInterfaceType::PERCENTAGE_CONTROLLER: return &AlexaInterfaces::PercentageController;
|
||||
case AlexaInterfaceType::RANGE_CONTROLLER: return &AlexaInterfaces::RangeController;
|
||||
case AlexaInterfaceType::MODE_CONTROLLER: return &AlexaInterfaces::ModeController;
|
||||
case AlexaInterfaceType::TOGGLE_CONTROLLER: return &AlexaInterfaces::ToggleController;
|
||||
case AlexaInterfaceType::THERMOSTAT_CONTROLLER: return &AlexaInterfaces::ThermostatController;
|
||||
case AlexaInterfaceType::TEMPERATURE_SENSOR: return &AlexaInterfaces::TemperatureSensor;
|
||||
case AlexaInterfaceType::HUMIDITY_SENSOR: return &AlexaInterfaces::HumiditySensor;
|
||||
case AlexaInterfaceType::LOCK_CONTROLLER: return &AlexaInterfaces::LockController;
|
||||
case AlexaInterfaceType::SCENE_CONTROLLER: return &AlexaInterfaces::SceneController;
|
||||
case AlexaInterfaceType::CONTACT_SENSOR: return &AlexaInterfaces::ContactSensor;
|
||||
case AlexaInterfaceType::MOTION_SENSOR: return &AlexaInterfaces::MotionSensor;
|
||||
case AlexaInterfaceType::DOORBELL_EVENT_SOURCE: return &AlexaInterfaces::DoorbellEventSource;
|
||||
case AlexaInterfaceType::TIME_HOLD_CONTROLLER: return &AlexaInterfaces::TimeHoldController;
|
||||
case AlexaInterfaceType::SPEAKER: return &AlexaInterfaces::Speaker;
|
||||
case AlexaInterfaceType::STEP_SPEAKER: return &AlexaInterfaces::StepSpeaker;
|
||||
case AlexaInterfaceType::PLAYBACK_CONTROLLER: return &AlexaInterfaces::PlaybackController;
|
||||
case AlexaInterfaceType::PLAYBACK_STATE_REPORTER: return &AlexaInterfaces::PlaybackStateReporter;
|
||||
case AlexaInterfaceType::INPUT_CONTROLLER: return &AlexaInterfaces::InputController;
|
||||
case AlexaInterfaceType::CHANNEL_CONTROLLER: return &AlexaInterfaces::ChannelController;
|
||||
case AlexaInterfaceType::INVENTORY_LEVEL_SENSOR: return &AlexaInterfaces::InventoryLevelSensor;
|
||||
case AlexaInterfaceType::SIMPLE_EVENT_SOURCE: return &AlexaInterfaces::SimpleEventSource;
|
||||
case AlexaInterfaceType::WAKE_ON_LAN_CONTROLLER: return &AlexaInterfaces::WakeOnLANController;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
enum class DisplayCategory : uint8_t
|
||||
{
|
||||
ACTIVITY_TRIGGER,
|
||||
AIR_CONDITIONER,
|
||||
AIR_FRESHENER,
|
||||
AIR_PURIFIER,
|
||||
AIR_QUALITY_MONITOR,
|
||||
ALEXA_VOICE_ENABLED,
|
||||
AUTO_ACCESSORY,
|
||||
BLUETOOTH_SPEAKER,
|
||||
CAMERA,
|
||||
CHRISTMAS_TREE,
|
||||
COFFEE_MAKER,
|
||||
COMPUTER,
|
||||
CONTACT_SENSOR,
|
||||
DISHWASHER,
|
||||
DOOR,
|
||||
DOORBELL,
|
||||
DRYER,
|
||||
EXTERIOR_BLIND,
|
||||
FAN,
|
||||
GAME_CONSOLE,
|
||||
GARAGE_DOOR,
|
||||
HEADPHONES,
|
||||
HUB,
|
||||
INTERIOR_BLIND,
|
||||
LAPTOP,
|
||||
LIGHT,
|
||||
MICROWAVE,
|
||||
MOBILE_PHONE,
|
||||
MOTION_SENSOR,
|
||||
MUSIC_SYSTEM,
|
||||
NETWORK_HARDWARE,
|
||||
OTHER,
|
||||
OVEN,
|
||||
PHONE,
|
||||
PRINTER,
|
||||
REMOTE,
|
||||
ROUTER,
|
||||
SCENE_TRIGGER,
|
||||
SCREEN,
|
||||
SECURITY_PANEL,
|
||||
SECURITY_SYSTEM,
|
||||
SLOW_COOKER,
|
||||
SMARTLOCK,
|
||||
SMARTPLUG,
|
||||
SPEAKER,
|
||||
STREAMING_DEVICE,
|
||||
SWITCH,
|
||||
TABLET,
|
||||
TEMPERATURE_SENSOR,
|
||||
THERMOSTAT,
|
||||
TV,
|
||||
VACUUM_CLEANER,
|
||||
VEHICLE,
|
||||
WASHER,
|
||||
WATER_HEATER,
|
||||
WEARABLE
|
||||
};
|
||||
|
||||
// The name Alexa knows the category by, in program memory. A value that is not a category gives "OTHER".
|
||||
PGM_P alexaDisplayCategoryName(DisplayCategory category);
|
||||
|
||||
#endif // ALEXA_INTERFACES_H
|
||||
|
|
@ -3,9 +3,8 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "AlexaInterface.h"
|
||||
#include "AlexaInterfaces.h"
|
||||
#include "AlexaTransport.h"
|
||||
#include "AlexaUtils.h"
|
||||
|
||||
enum class EndpointHealth
|
||||
{
|
||||
|
|
@ -35,13 +34,13 @@ public:
|
|||
{
|
||||
JsonDocument healthValue;
|
||||
healthValue["value"] = (endpointHealth == EndpointHealth::OK) ? "OK" : "UNREACHABLE";
|
||||
return AddProperty(AlexaInterfaceType::ENDPOINT_HEALTH, "connectivity", healthValue.as<JsonObject>(), uncertaintyInMs);
|
||||
return AddProperty(AlexaInterfaces::EndpointHealth, healthValue.as<JsonObject>(), uncertaintyInMs);
|
||||
}
|
||||
|
||||
AlexaStatusMessage &AddPowerControllerProp(PowerController powerController, unsigned int uncertaintyInMs = 0)
|
||||
{
|
||||
String value = (powerController == PowerController::ON) ? "ON" : "OFF";
|
||||
return AddProperty(AlexaInterfaceType::POWER_CONTROLLER, "powerState", value, uncertaintyInMs);
|
||||
return AddProperty(AlexaInterfaces::PowerController, value, uncertaintyInMs);
|
||||
}
|
||||
|
||||
AlexaStatusMessage &AddTemperatureSensorProp(TemperatureSensorScale tempSensor,float value, unsigned int uncertaintyInMs = 0)
|
||||
|
|
@ -52,21 +51,21 @@ public:
|
|||
if((tempSensor == TemperatureSensorScale::FAHRENHEIT)){
|
||||
tempValue["value"] = (value - 32) * 5.0 / 9.0;
|
||||
}
|
||||
return AddProperty(AlexaInterfaceType::TEMPERATURE_SENSOR, "temperature", tempValue.as<JsonObject>(), uncertaintyInMs);
|
||||
return AddProperty(AlexaInterfaces::TemperatureSensor, tempValue.as<JsonObject>(), uncertaintyInMs);
|
||||
}
|
||||
|
||||
AlexaStatusMessage &AddBrightnessControllerProp(unsigned int brightness, unsigned int uncertaintyInMs = 0)
|
||||
{
|
||||
return AddProperty(AlexaInterfaceType::BRIGHTNESS_CONTROLLER, "brightness", brightness, uncertaintyInMs);
|
||||
return AddProperty(AlexaInterfaces::BrightnessController, brightness, uncertaintyInMs);
|
||||
}
|
||||
AlexaStatusMessage &AddColorTemperatureControllerProp(unsigned int colorTemperature, unsigned int uncertaintyInMs = 0)
|
||||
{
|
||||
return AddProperty(AlexaInterfaceType::COLOR_TEMPERATURE_CONTROLLER, "colorTemperatureInKelvin", colorTemperature, uncertaintyInMs);
|
||||
return AddProperty(AlexaInterfaces::ColorTemperatureController, colorTemperature, uncertaintyInMs);
|
||||
}
|
||||
AlexaStatusMessage &AddToggleControllerProp(PowerController powerController,String instanceName, unsigned int uncertaintyInMs = 0)
|
||||
{
|
||||
String value = (powerController == PowerController::ON) ? "ON" : "OFF";
|
||||
return AddProperty(AlexaInterfaceType::TOGGLE_CONTROLLER, "toggleState", value, uncertaintyInMs,instanceName);
|
||||
return AddProperty(AlexaInterfaces::ToggleController, value, uncertaintyInMs,instanceName);
|
||||
}
|
||||
|
||||
// Adds a property the sketch built itself. Its timeOfSample is set to the current time when the object has
|
||||
|
|
@ -88,12 +87,13 @@ private:
|
|||
String generateMessageId();
|
||||
void setTimeOfSample(JsonObject property);
|
||||
|
||||
// Adds the first property of the row: every interface with a helper above reports one
|
||||
template <typename T>
|
||||
AlexaStatusMessage &AddProperty(AlexaInterfaceType type, const String &propertyName, const T &value, unsigned int uncertaintyInMs = 0,const String &instanceName="")
|
||||
AlexaStatusMessage &AddProperty(const AlexaInterfaceDesc &row, const T &value, unsigned int uncertaintyInMs = 0,const String &instanceName="")
|
||||
{
|
||||
JsonObject prop = contextProperties.add<JsonObject>();
|
||||
prop["namespace"] = AlexaInterfaceUtils::toString(type);
|
||||
prop["name"] = propertyName;
|
||||
prop["namespace"] = FPSTR(row.ns);
|
||||
prop["name"] = FPSTR(row.property(0));
|
||||
|
||||
if (!instanceName.isEmpty()) {
|
||||
prop["instance"] = instanceName;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue