registry: RangeController, ModeController, ToggleController with resources, presets and semantics
The three generic controllers are described in full and leave the stub table (62 stubs remain). A declaration
takes an instance name, friendly names from text() and asset(), and the options of the interface: range, unit and
presets for a range; supportedModes and ordered for a mode; semantics() for all three, with actions mapped to
directives and states mapped to a value or a range of values.
Refused at device.add(), each with the endpoint, interface and instance in the message: no instance name or no
friendly name; an instance declared twice; a first friendly name or a phrase used by another capability of the
endpoint; a reserved word, an asset id that is not in the catalog; range.max not above range.min; a preset off the
precision grid or outside the range; fewer than two modes or a mode listed twice; a mapping to a directive the
interface does not have, to a payload that does not fit, to a mode that is not listed, to AdjustMode on modes
that are not ordered; SetEcoOn, SetEcoOff, EcoOn and EcoOff on anything but a toggle.
For 1.x callers: Alexa.RangeController lists rangeValue (1.5.2 sent supported: []); addSupportedModes() announces
a mode given as a string as { value } and notes it, and takes { ordered: false } as a second argument, the default
stays true as 1.5.2 sent it (device.add() defaults to false). Declared the 1.x way, the zoo fan and curtain give
the same JSON as before.
Tests: the zoo blind, whose range, unit and semantics were written by hand into the JSON of 1.5.2, is declared
with device.add() and equals that JSON plus the Alexa capability; five capability objects of Amazon's examples
are reproduced the same way. 27 examples of four pages added. npm test: 108 pass (was 85) in 10.5-11.3 s, also on
Node 18.20.8 and 20.20.2.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
c492ef74d1
commit
2558e21787
80 changed files with 3131 additions and 107 deletions
18
dist/types/compat/AlexaInterface.d.ts
vendored
18
dist/types/compat/AlexaInterface.d.ts
vendored
|
|
@ -1,6 +1,6 @@
|
|||
import { Capability } from "../device/Capability.js";
|
||||
import type { CapabilityJson } from "../device/Capability.js";
|
||||
import type { Semantics } from "../registry/types.js";
|
||||
import type { Label, Semantics } from "../registry/types.js";
|
||||
import type { ActionMapping } from "./ActionMapping.js";
|
||||
import type { AlexaInterfaceType } from "./enums.js";
|
||||
/** One ModeController mode as discovery lists it (configuration.supportedModes): the value plus its friendly names. */
|
||||
|
|
@ -19,7 +19,11 @@ export interface SupportedMode {
|
|||
}
|
||||
interface Options {
|
||||
semantics?: Semantics;
|
||||
supportedModes?: Array<string | SupportedMode>;
|
||||
supportedModes?: Array<{
|
||||
value: string;
|
||||
friendlyNames: Label[];
|
||||
}>;
|
||||
ordered?: boolean;
|
||||
}
|
||||
/**
|
||||
* A capability as 1.x declares it: device.addCapability(type, options), then the add and set methods below. It is a
|
||||
|
|
@ -33,8 +37,14 @@ export declare class AlexaInterface extends Capability<any, any, Options> {
|
|||
get type(): AlexaInterfaceType;
|
||||
addActionMapping(mapping: ActionMapping): void;
|
||||
addFriendlyName(name: string, locale: string): void;
|
||||
/** The modes of a ModeController, as { value, modeResources } objects. */
|
||||
addSupportedModes(modes: Array<string | SupportedMode>): void;
|
||||
/**
|
||||
* The modes of a ModeController, as { value, modeResources } objects. A mode given as a string is announced as
|
||||
* { value } and noted: Alexa wants friendly names for it. ordered is true unless options.ordered says otherwise,
|
||||
* as 1.x announced every mode list; with device.add() the default is false.
|
||||
*/
|
||||
addSupportedModes(modes: Array<string | SupportedMode>, options?: {
|
||||
ordered?: boolean;
|
||||
}): void;
|
||||
setInstance(name: string): void;
|
||||
getType(): AlexaInterfaceType;
|
||||
/** @deprecated The same as getType(). */
|
||||
|
|
|
|||
6
dist/types/index.d.ts
vendored
6
dist/types/index.d.ts
vendored
|
|
@ -5,11 +5,11 @@ export type { EndpointDefinition, EndpointJson } from "./device/Device.js";
|
|||
export { Capability } from "./device/Capability.js";
|
||||
export type { CapabilityJson, CommonOptions, Declaration } from "./device/Capability.js";
|
||||
export { registry, DeclarationError, SchemaError } from "./registry/index.js";
|
||||
export { Alexa, BrightnessController, TemperatureSensor } from "./registry/index.js";
|
||||
export { Alexa, BrightnessController, ModeController, RangeController, TemperatureSensor, ToggleController, } from "./registry/index.js";
|
||||
export { PowerController, EndpointHealth } from "./compat/enums.js";
|
||||
export { asset, text } from "./registry/resources.js";
|
||||
export { asset, text, semantics, SemanticsBuilder } from "./registry/index.js";
|
||||
export { ASSETS as Assets, UNITS_OF_MEASURE as Units, ACTIONS as Actions, STATES as States, DISPLAY_CATEGORIES as DisplayCategories, } from "./registry/index.js";
|
||||
export type { ActionId, AssetId, DisplayCategoryName, StateId, UnitOfMeasure, ActionsToDirective, AnyDescriptor, CapabilityExtras, Declared, DirectiveDescriptor, EndpointView, EventDescriptor, InterfaceDescriptor, Label, PropertyDescriptor, Semantics, StatesToRange, StatesToValue, Infer, Schema, Temperature, TimeInterval, } from "./registry/index.js";
|
||||
export type { ActionId, AssetId, DisplayCategoryName, StateId, UnitOfMeasure, ActionsToDirective, AnyDescriptor, CapabilityExtras, Declared, DirectiveDescriptor, EndpointView, EventDescriptor, InterfaceDescriptor, Label, PropertyDescriptor, Semantics, StatesToRange, StatesToValue, ActionName, StateName, Mode, Infer, Schema, Temperature, TimeInterval, } from "./registry/index.js";
|
||||
export { AlexaInterface } from "./compat/AlexaInterface.js";
|
||||
export type { SupportedMode } from "./compat/AlexaInterface.js";
|
||||
export { ActionMapping } from "./compat/ActionMapping.js";
|
||||
|
|
|
|||
9
dist/types/registry/index.d.ts
vendored
9
dist/types/registry/index.d.ts
vendored
|
|
@ -1,8 +1,11 @@
|
|||
import { Alexa } from "./interfaces/Alexa.js";
|
||||
import { BrightnessController } from "./interfaces/BrightnessController.js";
|
||||
import { EndpointHealth } from "./interfaces/EndpointHealth.js";
|
||||
import { ModeController } from "./interfaces/ModeController.js";
|
||||
import { PowerController } from "./interfaces/PowerController.js";
|
||||
import { RangeController } from "./interfaces/RangeController.js";
|
||||
import { TemperatureSensor } from "./interfaces/TemperatureSensor.js";
|
||||
import { ToggleController } from "./interfaces/ToggleController.js";
|
||||
import type { AnyDescriptor } from "./types.js";
|
||||
export declare const registry: {
|
||||
/** Whether an interface of this name is known. */
|
||||
|
|
@ -12,7 +15,11 @@ export declare const registry: {
|
|||
/** Every descriptor, ordered by namespace. */
|
||||
list(): AnyDescriptor[];
|
||||
};
|
||||
export { Alexa, BrightnessController, EndpointHealth, PowerController, TemperatureSensor };
|
||||
export { Alexa, BrightnessController, EndpointHealth, ModeController, PowerController, RangeController, TemperatureSensor, ToggleController, };
|
||||
export type { Mode } from "./interfaces/ModeController.js";
|
||||
export { asset, text } from "./resources.js";
|
||||
export { semantics, SemanticsBuilder } from "./semantics.js";
|
||||
export type { ActionName, StateName } from "./semantics.js";
|
||||
export { DeclarationError, defineInterface } from "./types.js";
|
||||
export type { ActionsToDirective, AnyDescriptor, CapabilityExtras, Declared, DirectiveDescriptor, EndpointView, EventDescriptor, InterfaceDescriptor, Label, PropertyDescriptor, Semantics, StatesToRange, StatesToValue, } from "./types.js";
|
||||
export { s, SchemaError } from "./schema.js";
|
||||
|
|
|
|||
43
dist/types/registry/interfaces/ModeController.d.ts
vendored
Normal file
43
dist/types/registry/interfaces/ModeController.d.ts
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import type { Schema } from "../schema.js";
|
||||
import type { Label } from "../types.js";
|
||||
/** One mode: its value and what the user calls it. */
|
||||
export interface Mode {
|
||||
value: string;
|
||||
friendlyNames: Label[];
|
||||
}
|
||||
/**
|
||||
* One of a list of values, under an instance name: the wash cycle of a washer, the position of a garage door. Amazon
|
||||
* certifies a garage door only with this interface and the display category GARAGE_DOOR.
|
||||
*/
|
||||
export declare const ModeController: import("../types.js").InterfaceDescriptor<{
|
||||
mode: {
|
||||
name: string;
|
||||
value: Schema<string | null>;
|
||||
note: string;
|
||||
};
|
||||
}, {
|
||||
SetMode: {
|
||||
name: string;
|
||||
payload: Schema<import("../schema.js").InferShape<{
|
||||
mode: Schema<string>;
|
||||
}>>;
|
||||
};
|
||||
AdjustMode: {
|
||||
name: string;
|
||||
payload: Schema<import("../schema.js").InferShape<{
|
||||
modeDelta: import("../schema.js").OptionalSchema<number>;
|
||||
}>>;
|
||||
when: ({ options }: {
|
||||
options: {
|
||||
ordered?: boolean;
|
||||
};
|
||||
}) => boolean;
|
||||
note: string;
|
||||
};
|
||||
}, import("../schema.js").InferShape<{
|
||||
/** At least two. When the modes have an order, in increasing order. */
|
||||
supportedModes: Schema<Mode[]>;
|
||||
/** The modes have an order, cold to hot, and the user can say "increase": Alexa sends AdjustMode. Default: false. */
|
||||
ordered: import("../schema.js").OptionalSchema<boolean>;
|
||||
semantics: import("../schema.js").OptionalSchema<import("../types.js").Semantics>;
|
||||
}>, true>;
|
||||
39
dist/types/registry/interfaces/RangeController.d.ts
vendored
Normal file
39
dist/types/registry/interfaces/RangeController.d.ts
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* A number in a range, under an instance name: the position of a blind, the speed of a fan. With nonControllable it
|
||||
* is a reading the user can ask for, like an air quality index.
|
||||
*/
|
||||
export declare const RangeController: import("../types.js").InterfaceDescriptor<{
|
||||
rangeValue: {
|
||||
name: string;
|
||||
value: import("../schema.js").Schema<number>;
|
||||
};
|
||||
}, {
|
||||
SetRangeValue: {
|
||||
name: string;
|
||||
payload: import("../schema.js").Schema<import("../schema.js").InferShape<{
|
||||
rangeValue: import("../schema.js").Schema<number>;
|
||||
}>>;
|
||||
};
|
||||
AdjustRangeValue: {
|
||||
name: string;
|
||||
payload: import("../schema.js").Schema<import("../schema.js").InferShape<{
|
||||
rangeValueDelta: import("../schema.js").Schema<number>;
|
||||
rangeValueDeltaDefault: import("../schema.js").Schema<boolean>;
|
||||
}>>;
|
||||
note: string;
|
||||
};
|
||||
}, import("../schema.js").InferShape<{
|
||||
/** precision is the step of the range and what "turn up the fan speed" changes it by. */
|
||||
range: import("../schema.js").Schema<import("../schema.js").InferShape<{
|
||||
min: import("../schema.js").Schema<number>;
|
||||
max: import("../schema.js").Schema<number>;
|
||||
precision: import("../schema.js").Schema<number>;
|
||||
}>>;
|
||||
unit: import("../schema.js").OptionalSchema<import("../catalog.js").UnitOfMeasure>;
|
||||
/** Names for values: "set the fan speed to maximum". */
|
||||
presets: import("../schema.js").OptionalSchema<import("../schema.js").InferShape<{
|
||||
value: import("../schema.js").Schema<number>;
|
||||
friendlyNames: import("../schema.js").Schema<import("../types.js").Label[]>;
|
||||
}>[]>;
|
||||
semantics: import("../schema.js").OptionalSchema<import("../types.js").Semantics>;
|
||||
}>, true>;
|
||||
21
dist/types/registry/interfaces/ToggleController.d.ts
vendored
Normal file
21
dist/types/registry/interfaces/ToggleController.d.ts
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Something that is on or off, under an instance name: the oscillation of a fan, the light of an oven. The one
|
||||
* generic controller that Alexa hunches work with (SetEcoOn, SetEcoOff, EcoOn, EcoOff).
|
||||
*/
|
||||
export declare const ToggleController: import("../types.js").InterfaceDescriptor<{
|
||||
toggleState: {
|
||||
name: string;
|
||||
value: import("../schema.js").EnumSchema<"ON" | "OFF">;
|
||||
};
|
||||
}, {
|
||||
TurnOn: {
|
||||
name: string;
|
||||
payload: import("../schema.js").Schema<import("../schema.js").InferShape<{}>>;
|
||||
};
|
||||
TurnOff: {
|
||||
name: string;
|
||||
payload: import("../schema.js").Schema<import("../schema.js").InferShape<{}>>;
|
||||
};
|
||||
}, import("../schema.js").InferShape<{
|
||||
semantics: import("../schema.js").OptionalSchema<import("../types.js").Semantics>;
|
||||
}>, true>;
|
||||
47
dist/types/registry/semantics.d.ts
vendored
Normal file
47
dist/types/registry/semantics.d.ts
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import type { ActionId, StateId } from "./catalog.js";
|
||||
import type { Schema } from "./schema.js";
|
||||
import type { ActionsToDirective, Directives, Semantics, StatesToRange, StatesToValue } from "./types.js";
|
||||
type Short<Id extends string, Prefix extends string> = Id extends `${Prefix}${infer Name}` ? Name : never;
|
||||
/** A phrase by its id or by its name: "Alexa.Actions.Open" or "Open". */
|
||||
export type ActionName = ActionId | Short<ActionId, "Alexa.Actions.">;
|
||||
/** A state by its id or by its name: "Alexa.States.Closed" or "Closed". */
|
||||
export type StateName = StateId | Short<StateId, "Alexa.States.">;
|
||||
/**
|
||||
* Collects the mappings of one capability:
|
||||
*
|
||||
* semantics()
|
||||
* .action("Close", "SetRangeValue", { rangeValue: 0 })
|
||||
* .action(["Open", "Raise"], "SetRangeValue", { rangeValue: 100 })
|
||||
* .state("Closed", 0)
|
||||
* .stateRange("Open", 1, 100)
|
||||
*
|
||||
* What is collected is checked when the capability is declared, against the directives and the property of its
|
||||
* interface.
|
||||
*/
|
||||
export declare class SemanticsBuilder implements Semantics {
|
||||
readonly actionMappings: ActionsToDirective[];
|
||||
readonly stateMappings: Array<StatesToValue | StatesToRange>;
|
||||
/** The phrases send the directive. payload is its payload; leave it out for a directive that has none. */
|
||||
action(actions: ActionName | readonly ActionName[], directive: string, payload?: Record<string, unknown>): this;
|
||||
/** The property at this value is in these states: "is the garage door open?" */
|
||||
state(states: StateName | readonly StateName[], value: unknown): this;
|
||||
/** The property between the two values, both included, is in these states. For an interface with a numeric property. */
|
||||
stateRange(states: StateName | readonly StateName[], minimumValue: number, maximumValue: number): this;
|
||||
}
|
||||
export declare function semantics(): SemanticsBuilder;
|
||||
export interface SemanticsRules {
|
||||
/** The directives of the interface: a mapping names one of them and gives its payload. */
|
||||
directives: Directives;
|
||||
/** The value of the property a state stands for. */
|
||||
stateValue: Schema<unknown>;
|
||||
/** States can be mapped to a range of values: the property is a number. */
|
||||
ranges?: boolean;
|
||||
/**
|
||||
* SetEcoOn, SetEcoOff, EcoOn and EcoOff can be mapped. "Semantics for Alexa hunches is supported only for
|
||||
* Alexa.ToggleController" (generic-controllers.html).
|
||||
*/
|
||||
hunches?: boolean;
|
||||
}
|
||||
/** The schema of the semantics option of one interface. It takes a semantics() builder or the object as discovery has it. */
|
||||
export declare function semanticsOf({ directives, stateValue, ranges, hunches }: SemanticsRules): Schema<Semantics>;
|
||||
export {};
|
||||
8
dist/types/registry/types.d.ts
vendored
8
dist/types/registry/types.d.ts
vendored
|
|
@ -120,7 +120,11 @@ export interface InterfaceDescriptor<P extends Properties = Properties, D extend
|
|||
events?: Record<string, EventDescriptor>;
|
||||
/** What a declaration can set beyond the fields every capability has: a range, the supported modes. */
|
||||
options?: Schema<O>;
|
||||
discovery?: (capability: Declared<O>) => CapabilityExtras;
|
||||
/**
|
||||
* What the interface adds to the capability object. The options may be incomplete: a capability declared the
|
||||
* 1.x way is announced with what it has, and check() of its device says what is missing.
|
||||
*/
|
||||
discovery?: (capability: Declared<Partial<O>>) => CapabilityExtras;
|
||||
/** The event that answers a directive when it is not Alexa / Response (Arm -> Arm.Response). */
|
||||
responseFor?: (directive: string) => {
|
||||
namespace: string;
|
||||
|
|
@ -132,7 +136,7 @@ export interface InterfaceDescriptor<P extends Properties = Properties, D extend
|
|||
errorTypes?: readonly string[];
|
||||
/** Amazon documents a DeferredResponse for the interface. */
|
||||
deferrable?: boolean;
|
||||
/** Rules a schema cannot state. Throws DeclarationError. */
|
||||
/** Rules a schema cannot state, for options that passed the schema. Throws DeclarationError. */
|
||||
validate?: (capability: Declared<O>, endpoint: EndpointView) => void;
|
||||
}
|
||||
export type AnyDescriptor = InterfaceDescriptor<any, any, any, boolean>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue