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"], });