The thermostat is described from its page: one, two or three setpoints with holdUntil, AdjustTargetTemperature, SetThermostatMode with the six modes (EM_HEAT is new), ResumeSchedule, adaptiveRecoveryStatus, and its seven error types under Alexa.ThermostatController. A declaration gives supportedModes, supportsScheduling and the properties the device has; without them discovery is what 1.5.2 sent: HEAT, COOL, AUTO, OFF and the three setpoints with thermostatMode. supportedModes without HEAT or COOL is refused where it is declared. ThermostatController.Schedule replaces its stub. Wire change for a 1.x declaration of it: version 3.2 (was 1) and scheduleEnabled listed (was nothing). SetAdaptiveRecovery is taken only with supportsAdaptiveRecovery. 24 examples of three pages are saved as fixtures; the page folds the SetWeeklySchedule example away, its payload is tested from the tables. 207 tests pass, 191 before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
77 lines
3.6 KiB
JavaScript
77 lines
3.6 KiB
JavaScript
import { s } from "../schema.js";
|
|
import { defineInterface } from "../types.js";
|
|
const FAN_MODES = ["ON", "AUTO", "CIRCULATE"];
|
|
// alexa-thermostatcontroller-schedule.html, "ScheduleEntry object": an entry ends where the next one starts
|
|
const entry = s.object({
|
|
startTimeInMinutes: s.number({ min: 0, max: 1439, integer: true }),
|
|
setpoints: s.object({ upperSetpoint: s.optional(s.temperature()), lowerSetpoint: s.optional(s.temperature()) }),
|
|
/** Without a mode the fan runs as the manufacturer set it. */
|
|
fanSetting: s.optional(s.object({ mode: s.optional(s.enum(...FAN_MODES)) })),
|
|
activityType: s.optional(s.object({ type: s.enum("AWAY", "HOME", "SLEEP") })),
|
|
});
|
|
const day = s.array(entry);
|
|
// Same page, "WeeklySchedule object"
|
|
const weeklySchedule = s.object({
|
|
temperatureScale: s.enum("CELSIUS", "FAHRENHEIT", "KELVIN"),
|
|
Monday: day,
|
|
Tuesday: day,
|
|
Wednesday: day,
|
|
Thursday: day,
|
|
Friday: day,
|
|
Saturday: day,
|
|
Sunday: day,
|
|
});
|
|
/**
|
|
* Version 3.2. The schedule a user writes in the Alexa app: the interface has no utterances. Discovery lists
|
|
* adaptiveRecoveryEnabled for a thermostat declared with supportsAdaptiveRecovery, and Alexa sends
|
|
* SetAdaptiveRecovery to such a thermostat only.
|
|
*/
|
|
export const ThermostatControllerSchedule = defineInterface({
|
|
namespace: "Alexa.ThermostatController.Schedule",
|
|
version: "3.2",
|
|
doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-thermostatcontroller-schedule.html",
|
|
kind: "controller",
|
|
tier: 2,
|
|
instanced: false,
|
|
properties: {
|
|
adaptiveRecoveryEnabled: { name: "adaptiveRecoveryEnabled", value: s.boolean() },
|
|
scheduleEnabled: { name: "scheduleEnabled", value: s.boolean() },
|
|
},
|
|
directives: {
|
|
SetWeeklySchedule: {
|
|
name: "SetWeeklySchedule",
|
|
payload: s.object({ weeklySchedule: s.optional(weeklySchedule) }),
|
|
note: "a schedule the thermostat cannot keep leaves the one it has and is answered with an error",
|
|
},
|
|
SetScheduleState: {
|
|
name: "SetScheduleState",
|
|
payload: s.object({ scheduleEnabled: s.boolean() }),
|
|
note: "a disabled schedule is kept: the user can enable it again",
|
|
},
|
|
SetAdaptiveRecovery: {
|
|
name: "SetAdaptiveRecovery",
|
|
payload: s.object({ adaptiveRecoveryEnabled: s.boolean() }),
|
|
when: ({ options }) => options.supportsAdaptiveRecovery === true,
|
|
},
|
|
},
|
|
options: s.object({
|
|
supportedFanModes: s.array(s.enum(...FAN_MODES)),
|
|
/** The thermostat heats or cools ahead of an entry, to be at its temperature when it starts. */
|
|
supportsAdaptiveRecovery: s.boolean(),
|
|
maxEntryPerDay: s.optional(s.number({ min: 1, integer: true })),
|
|
}, { unknownKeys: "reject" }),
|
|
// A capability declared the 1.x way has none of the options; check() says so, discovery lists what there is
|
|
discovery({ options: { supportedFanModes, supportsAdaptiveRecovery, maxEntryPerDay } }) {
|
|
const configuration = {
|
|
...(supportedFanModes && { supportedFanModes }),
|
|
...(supportsAdaptiveRecovery !== undefined && { supportsAdaptiveRecovery }),
|
|
...(maxEntryPerDay !== undefined && { maxEntryPerDay }),
|
|
};
|
|
return {
|
|
supported: supportsAdaptiveRecovery ? ["adaptiveRecoveryEnabled", "scheduleEnabled"] : ["scheduleEnabled"],
|
|
...(Object.keys(configuration).length > 0 && { configuration }),
|
|
};
|
|
},
|
|
errorNamespace: "Alexa.ThermostatController.Schedule",
|
|
errorTypes: ["INSUFFICIENT_SPACE"],
|
|
});
|