src/registry/ holds what the library knows about an interface: namespace, version, the page it was read from, properties with their value schemas and directives with their payload schemas. Five interfaces are described (Alexa, PowerController, BrightnessController, TemperatureSensor, EndpointHealth); the other 65 names of AlexaInterfaceType are stubs with the version and property names of 1.5.2. schema.ts is the run-time check behind it (241 lines, no new dependency), catalog.ts the vocabularies of the pages: 103 assets (23 units), 6 actions, 9 states, 56 display categories, 22 reserved words, 73 error types under 11 namespaces. AlexaInterface.getVersion() and getProps() read the registry; the two switch statements are gone (-167 lines). On the wire: Alexa.EndpointHealth is announced at 3.1 (was 3.3; the page is titled 3.1 and no page mentions 3.3), and TimeHoldController and Camera.LiveViewController at 3 and 1.7 (1.5.2 sent the string "UNKNOWN"). DisplayCategory gains VACUUM. New exports: registry, DeclarationError, SchemaError, Assets, Units, Actions, States, DisplayCategories and the descriptor types. Tests: 20 JSON examples of the five pages under test/fixtures/alexa-docs; every directive payload and property value in them parses with its descriptor. npm test: 57 pass (was 30) in 10.8 s, also on Node 18.20.8 and 20.20.2. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
129 lines
9.2 KiB
JavaScript
129 lines
9.2 KiB
JavaScript
// The fixed vocabularies of the Smart Home API, copied from Amazon's pages as read on 2026-09-28. The pages are under
|
|
// https://developer.amazon.com/docs/alexaplus/device-apis/. A value missing here is one Amazon added since.
|
|
/**
|
|
* The asset ids a friendly name can refer to: 103, the units of measure among them
|
|
* (resources-and-assets.html, "Global Alexa catalog").
|
|
*/
|
|
export const ASSETS = [
|
|
"Alexa.Actions.Charge", "Alexa.Actions.Clean", "Alexa.Actions.Dispense", "Alexa.Actions.Dock",
|
|
"Alexa.Actions.Empty", "Alexa.Actions.Mop", "Alexa.Actions.Skip", "Alexa.Actions.Sweep", "Alexa.Actions.Vacuum",
|
|
"Alexa.Button.OffButton", "Alexa.Button.OnButton", "Alexa.Button.BrightenButton", "Alexa.Button.DimButton",
|
|
"Alexa.Button.MainButton", "Alexa.Button.TopButton", "Alexa.Button.BottomButton", "Alexa.Button.CenterButton",
|
|
"Alexa.Button.MiddleButton", "Alexa.Button.UpButton", "Alexa.Button.DownButton", "Alexa.Button.LeftButton",
|
|
"Alexa.Button.RightButton", "Alexa.Button.FirstButton", "Alexa.Button.SecondButton", "Alexa.Button.ThirdButton",
|
|
"Alexa.Button.FourthButton", "Alexa.Button.FifthButton", "Alexa.Button.SixthButton", "Alexa.Button.SeventhButton",
|
|
"Alexa.Button.EighthButton", "Alexa.Button.DoublePress", "Alexa.Button.DoublePush", "Alexa.Button.LongPress",
|
|
"Alexa.Button.LongPush", "Alexa.Button.SinglePress", "Alexa.Button.SinglePush",
|
|
"Alexa.DeviceName.AirPurifier", "Alexa.DeviceName.Camera", "Alexa.DeviceName.Fan", "Alexa.DeviceName.Router",
|
|
"Alexa.DeviceName.Shade", "Alexa.DeviceName.Shower", "Alexa.DeviceName.SpaceHeater", "Alexa.DeviceName.Washer",
|
|
"Alexa.Gesture.DoubleClick", "Alexa.Gesture.SingleClick", "Alexa.Gesture.SwipeDown", "Alexa.Gesture.SwipeLeft",
|
|
"Alexa.Gesture.SwipeRight", "Alexa.Gesture.SwipeUp", "Alexa.Gesture.Tap",
|
|
// "Gestures", plural: the page spells this one id differently from the seven above
|
|
"Alexa.Gestures.DoubleTap",
|
|
"Alexa.Setting.2GGuestWiFi", "Alexa.Setting.5GGuestWiFi", "Alexa.Setting.Auto", "Alexa.Setting.Direction",
|
|
"Alexa.Setting.DryCycle", "Alexa.Setting.FanSpeed", "Alexa.Setting.GuestWiFi", "Alexa.Setting.Heat",
|
|
"Alexa.Setting.Mode", "Alexa.Setting.Night", "Alexa.Setting.Opening", "Alexa.Setting.Oscillate",
|
|
"Alexa.Setting.Preset", "Alexa.Setting.Quiet", "Alexa.Setting.Temperature", "Alexa.Setting.WashCycle",
|
|
"Alexa.Setting.WaterTemperature",
|
|
"Alexa.Shower.HandHeld", "Alexa.Shower.RainHead",
|
|
"Alexa.Unit.Angle.Degrees", "Alexa.Unit.Angle.Radians", "Alexa.Unit.Distance.Feet", "Alexa.Unit.Distance.Inches",
|
|
"Alexa.Unit.Distance.Kilometers", "Alexa.Unit.Distance.Meters", "Alexa.Unit.Distance.Miles",
|
|
"Alexa.Unit.Distance.Yards", "Alexa.Unit.Mass.Grams", "Alexa.Unit.Mass.Kilograms", "Alexa.Unit.Percent",
|
|
"Alexa.Unit.Temperature.Celsius", "Alexa.Unit.Temperature.Degrees", "Alexa.Unit.Temperature.Fahrenheit",
|
|
"Alexa.Unit.Temperature.Kelvin", "Alexa.Unit.Volume.CubicFeet", "Alexa.Unit.Volume.CubicMeters",
|
|
"Alexa.Unit.Volume.Gallons", "Alexa.Unit.Volume.Liters", "Alexa.Unit.Volume.Pints", "Alexa.Unit.Volume.Quarts",
|
|
"Alexa.Unit.Weight.Ounces", "Alexa.Unit.Weight.Pounds",
|
|
"Alexa.Value.Close", "Alexa.Value.Delicate", "Alexa.Value.High", "Alexa.Value.Low", "Alexa.Value.Maximum",
|
|
"Alexa.Value.Medium", "Alexa.Value.Minimum", "Alexa.Value.Open", "Alexa.Value.QuickWash",
|
|
];
|
|
export const UNITS_OF_MEASURE = ASSETS.filter((id) => id.startsWith("Alexa.Unit."));
|
|
/** The phrases an action mapping gives to a directive (alexa-discovery-objects.html, "ActionMappings object"). */
|
|
export const ACTIONS = [
|
|
"Alexa.Actions.Open", "Alexa.Actions.Close", "Alexa.Actions.Raise", "Alexa.Actions.Lower",
|
|
"Alexa.Actions.SetEcoOn", "Alexa.Actions.SetEcoOff",
|
|
];
|
|
/** The states a state mapping gives to a property value (alexa-discovery-objects.html, "StateMappings object"). */
|
|
export const STATES = [
|
|
"Alexa.States.Open", "Alexa.States.Closed", "Alexa.States.EcoOn", "Alexa.States.EcoOff", "Alexa.States.Low",
|
|
"Alexa.States.Empty", "Alexa.States.Full", "Alexa.States.Done", "Alexa.States.Stuck",
|
|
];
|
|
/**
|
|
* The 56 display categories (alexa-discovery.html, "Display categories"). The DisplayCategory enum also keeps
|
|
* VEHICLE from 1.x, which the page no longer lists.
|
|
*/
|
|
export const DISPLAY_CATEGORIES = [
|
|
"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", "VACUUM",
|
|
"WASHER", "WATER_HEATER", "WEARABLE",
|
|
];
|
|
/** Not to be used as a friendly name (resources-and-assets.html, "Reserved words"). */
|
|
export const RESERVED_WORDS = [
|
|
"alarm", "alarms", "all alarms", "away mode", "bass", "camera", "date", "date today", "day", "do not disturb",
|
|
"drop in", "music", "night light", "notification", "playing", "sleep sounds", "time", "timer", "today in music",
|
|
"treble", "volume", "way f. m.",
|
|
];
|
|
/**
|
|
* What a discovery answer may hold (alexa-discovery.html, "Interface limits"; alexa-discovery-objects.html,
|
|
* "Endpoint object details" and "AdditionalAttributes object details"; alexa-scenecontroller.html, "Discovery").
|
|
*/
|
|
export const LIMITS = {
|
|
endpointsPerCustomer: 300,
|
|
capabilitiesPerEndpoint: 100,
|
|
endpointIdLength: 256,
|
|
friendlyNameLength: 256,
|
|
sceneFriendlyNameLength: 128,
|
|
manufacturerNameLength: 128,
|
|
descriptionLength: 128,
|
|
additionalAttributeLength: 256,
|
|
cookieBytes: 5000,
|
|
};
|
|
// alexa-errorresponse.html, "Error type values". The Interface column names <namespace>.ErrorResponse; the event
|
|
// header carries the namespace and the name ErrorResponse, as the examples on the ThermostatController,
|
|
// SecurityPanelController and Safety error pages show. The other namespaces are as the table spells them.
|
|
// INVALID_VALUE is listed under Alexa and under SmartVision.ObjectDetectionSensor, SUBSCRIPTION_REQUIRED under both
|
|
// SmartVision interfaces: the first one listed is kept.
|
|
const ERROR_TYPES_BY_NAMESPACE = {
|
|
"Alexa": [
|
|
"ALREADY_IN_OPERATION", "BRIDGE_UNREACHABLE", "CLOUD_CONTROL_DISABLED", "DEVICE_STUCK", "DO_NOT_DISTURB_MODE",
|
|
"ENDPOINT_BUSY", "ENDPOINT_CONTROL_UNAVAILABLE", "ENDPOINT_LOW_POWER", "ENDPOINT_UNREACHABLE",
|
|
"EXPIRED_AUTHORIZATION_CREDENTIAL", "FIRMWARE_OUT_OF_DATE", "HARDWARE_MALFUNCTION", "INSUFFICIENT_PERMISSIONS",
|
|
"INSUFFICIENT_RESOURCE", "INTERNAL_ERROR", "INVALID_AUTHORIZATION_CREDENTIAL", "INVALID_DIRECTIVE",
|
|
"INVALID_VALUE", "MAINTENANCE_REQUIRED", "NO_SUCH_ENDPOINT", "NOT_CALIBRATED", "NOT_IN_OPERATION",
|
|
"NOT_SUPPORTED_IN_CURRENT_MODE", "NOT_SUPPORTED_WITH_CURRENT_BATTERY_CHARGE_STATE",
|
|
"PARTNER_APPLICATION_REDIRECTION", "POWER_LEVEL_NOT_SUPPORTED", "RATE_LIMIT_EXCEEDED",
|
|
"TEMPERATURE_VALUE_OUT_OF_RANGE", "TOO_MANY_FAILED_ATTEMPTS", "UNABLE_TO_CHARGE", "VALUE_OUT_OF_RANGE",
|
|
],
|
|
"Alexa.Commissionable.ReportCommissioningInformation": [
|
|
"FAILED_TO_BOOTSTRAP_COMMISSIONING_PROCESS", "MAX_COMMISSIONING_LIMIT_REACHED",
|
|
],
|
|
"Alexa.Cooking": [
|
|
"CHILD_LOCK", "COOK_DURATION_TOO_LONG", "DOOR_CLOSED_TOO_LONG", "DOOR_OPEN", "PREHEAT_REQUIRED",
|
|
"PROBE_REQUIRED", "REMOTE_START_NOT_SUPPORTED", "REMOVE_PROBE", "REMOTE_START_DISABLED",
|
|
],
|
|
"Alexa.DataController": ["DATA_DELETION_NOT_SUPPORTED", "DATA_RETRIEVAL_NOT_SUPPORTED"],
|
|
"Alexa.Safety": ["OBSTACLE_DETECTED", "SAFETY_BEAM_BREACHED"],
|
|
"Alexa.SecurityPanelController": [
|
|
"AUTHORIZATION_REQUIRED", "BYPASS_NEEDED", "NOT_READY", "UNAUTHORIZED", "UNCLEARED_ALARM", "UNCLEARED_TROUBLE",
|
|
],
|
|
"Alexa.SmartVision.ObjectDetectionSensor": ["SUBSCRIPTION_REQUIRED"],
|
|
"Alexa.SmartVision.SnapshotProvider": ["DISABLED_BY_USER"],
|
|
"Alexa.ThermostatController": [
|
|
"DUAL_SETPOINTS_UNSUPPORTED", "REQUESTED_SETPOINTS_TOO_CLOSE", "THERMOSTAT_IS_OFF",
|
|
"TRIPLE_SETPOINTS_UNSUPPORTED", "UNSUPPORTED_THERMOSTAT_MODE", "UNWILLING_TO_SET_SCHEDULE",
|
|
"UNWILLING_TO_SET_VALUE",
|
|
],
|
|
"Alexa.ThermostatController.Configuration": [
|
|
"CONFIGURATION_UPDATE_NOT_ALLOWED", "COOLING_LOCKOUT_TEMPERATURE_VALUE_OUT_OF_RANGE",
|
|
"COOLING_STAGES_EXCEEDS_LIMIT", "HEATING_LOCKOUT_TEMPERATURE_VALUE_OUT_OF_RANGE", "HEATING_STAGES_EXCEEDS_LIMIT",
|
|
"INVALID_AUXILIARY_HEATING_SYSTEM_TYPE", "INVALID_SYSTEM_TYPE", "INVALID_TARGET_STATE",
|
|
"INVALID_TEMPERATURE_SCALE", "INVALID_TERMINAL_CONNECTION", "MISSING_SETUP_INFORMATION",
|
|
],
|
|
"Alexa.ThermostatController.Schedule": ["INSUFFICIENT_SPACE"],
|
|
};
|
|
/** The 73 error types of the table, each with the namespace its ErrorResponse goes under. */
|
|
export const ERROR_TYPES = Object.fromEntries(Object.entries(ERROR_TYPES_BY_NAMESPACE).flatMap(([namespace, types]) => types.map((type) => [type, namespace])));
|