import { s } from "../schema.js"; import { DeclarationError, defineInterface } from "../types.js"; const BANDS = ["BASS", "MIDRANGE", "TREBLE"] as const; const MODES = ["MOVIE", "MUSIC", "NIGHT", "SPORT", "TV"] as const; const band = s.enum(...BANDS); const level = s.number({ integer: true }); /** * The bands of an equalizer, its modes, or both. Discovery lists bands for a device declared with bands and mode * for one declared with modes. A band or a mode the device does not have is answered with INVALID_VALUE. */ export const EqualizerController = defineInterface({ namespace: "Alexa.EqualizerController", version: "3", doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-equalizercontroller.html", kind: "controller", tier: 2, instanced: false, properties: { bands: { name: "bands", value: s.array(s.object({ name: band, value: level })) }, mode: { name: "mode", value: s.enum(...MODES) }, }, directives: { SetMode: { name: "SetMode", payload: s.object({ mode: s.enum(...MODES) }) }, SetBands: { name: "SetBands", payload: s.object({ bands: s.array(s.object({ name: band, value: level }), { min: 1 }) }) }, AdjustBands: { name: "AdjustBands", payload: s.object({ bands: s.array(s.object({ name: band, levelDelta: s.optional(level), levelDirection: s.enum("UP", "DOWN") }), { min: 1 }), }), note: "without levelDelta the band moves by the step the device has for it", }, ResetBands: { name: "ResetBands", payload: s.object({ bands: s.array(s.object({ name: band }), { min: 1 }) }) }, }, options: s.object({ /** The bands of the device and the levels they take. Left out for a device that has modes only. */ bands: s.optional(s.object({ supported: s.array(band, { min: 1 }), range: s.object({ minimum: level, maximum: level }, { unknownKeys: "reject" }), }, { unknownKeys: "reject" })), /** Left out for a device that has bands only. */ modes: s.optional(s.array(s.enum(...MODES), { min: 1 })), }, { unknownKeys: "reject" }), // A capability declared the 1.x way has neither; check() says so, discovery lists both properties discovery({ options: { bands, modes } }) { if (!bands && !modes) return {}; return { supported: [...(bands ? ["bands"] : []), ...(modes ? ["mode"] : [])], configurations: { ...(bands && { bands: { supported: bands.supported.map((name) => ({ name })), range: bands.range } }), ...(modes && { modes: { supported: modes.map((name) => ({ name })) } }), }, }; }, validate(capability) { const { bands, modes = [] } = capability.options; if (!bands && modes.length === 0) throw new DeclarationError(capability, "needs bands, modes or both: declare what the equalizer has"); if (bands && bands.range.maximum <= bands.range.minimum) { throw new DeclarationError(capability, `bands.range.maximum ${bands.range.maximum} is not above bands.range.minimum ${bands.range.minimum}`); } const lists: ReadonlyArray = [bands?.supported ?? [], modes]; for (const list of lists) { const twice = list.find((entry, i) => list.indexOf(entry) !== i); if (twice) throw new DeclarationError(capability, `${twice} is listed twice`); } }, });