iobroker.assistant 1.4.8 → 1.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/build/lib/piAgent.js +2 -0
- package/build/lib/piAgent.js.map +1 -1
- package/build/lib/timers.js +7 -0
- package/build/lib/timers.js.map +1 -1
- package/build/lib/voice/esphome.js +44 -24
- package/build/lib/voice/esphome.js.map +1 -1
- package/build/main.js +76 -16
- package/build/main.js.map +1 -1
- package/io-package.json +14 -14
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esphome.js","sourceRoot":"","sources":["../../../src/lib/voice/esphome.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ESPHome voice satellites — the fourth transport, next to the UDP server (`voiceServer.ts`) and the\n * Wyoming endpoint (`wyoming.ts`).\n *\n * Unlike those two, this one is a **client**: an ESPHome voice satellite is a *server* that waits on\n * TCP 6053 for the home-automation controller to connect and drive it. We therefore dial out to each\n * configured device and play the role Home Assistant normally plays. That covers the ThirdReality\n * Voice & Music Assistant (Dev Edition), the Home Assistant Voice PE and any box running\n * OHF-Voice/linux-voice-assistant.\n *\n * Flow for one utterance (verified against the firmware's `src/satellite/Satellite.cpp`):\n *\n * device → VoiceAssistantRequest{start, wake_word_phrase} wake word fired on the device\n * we → VoiceAssistantResponse{port:0} 0 = audio over the API, no UDP\n * we → RUN_START, WAKE_WORD_END, STT_START, STT_VAD_START\n * device → VoiceAssistantAudio … 16 kHz mono s16le, *until told to stop*\n * we → STT_VAD_END ← the device has no VAD of its own\n * we → STT_END{text}, INTENT_START, INTENT_END, TTS_START{text}, TTS_END{url}, RUN_END\n * device → fetches the URL over HTTP, plays it, VoiceAssistantAnnounceFinished\n *\n * Two consequences shape this file: end-of-speech detection is ours (`vad.ts`), and the spoken reply\n * has to be reachable over HTTP (`mediaServer.ts`) rather than streamed down the socket.\n */\nimport * as net from 'node:net';\nimport {\n pb,\n encode,\n decode,\n type PbMessage,\n type AuthenticationResponse,\n type DeviceInfoResponse,\n type HelloResponse,\n type VoiceAssistantAnnounceFinished,\n type VoiceAssistantAudio,\n type VoiceAssistantConfigurationResponse,\n type VoiceAssistantEventData,\n type VoiceAssistantRequestMsg,\n} from './esphomeProto';\nimport { EntityRegistry, isEntityStateMessage, isListEntityMessage, type EsphomeEntity } from './esphomeEntities';\nimport { SpeechDetector, type CaptureEnd, type Bytes, type VadReport } from './vad';\nimport { prepareForStt } from './speechAudio';\nimport { chooseReplyFormat, encodeReply, type ExternalEncoder, type ReplyFormat } from './replyFormat';\nimport { levelProfile, type DiscardedCapture, type DiscardReason } from './captures';\nimport type { SttEngine } from './stt';\nimport type { TtsEngine } from './tts';\nimport type { SatelliteState } from './protocol';\n\n/** `VoiceAssistantEvent` (api.proto) — the subset we emit. */\nconst EVENT = {\n ERROR: 0,\n RUN_START: 1,\n RUN_END: 2,\n STT_START: 3,\n STT_END: 4,\n INTENT_START: 5,\n INTENT_END: 6,\n TTS_START: 7,\n TTS_END: 8,\n WAKE_WORD_END: 10,\n STT_VAD_START: 11,\n STT_VAD_END: 12,\n} as const;\n\n/** `SubscribeVoiceAssistantRequest.flags`: audio over the API socket instead of a UDP side channel. */\nconst SUBSCRIBE_API_AUDIO = 1;\n/** ESPHome voice satellites always capture at 16 kHz mono 16-bit. */\nconst MIC_SAMPLE_RATE = 16000;\n/**\n * Leading audio to keep out of the end-of-speech analysis. These devices acknowledge the wake word\n * with a chirp through their own speaker and hear it back on their own microphone, far louder than\n * the speech that follows. Without this the chirp alone satisfies the detector's speech test — so\n * `sawSpeech` stops meaning \"somebody said something\" and a false wake is billed to STT — and it\n * drags the noise floor up with it.\n *\n * Measured over four captures from a ThirdReality Voice & Music Assistant (RMS per 50 ms, remarkably\n * repeatable across all four):\n *\n * ms 0 50 100 150 200 250 300 350 400 450 500 550 600\n * rms ~20 ~900 ~11k ~19k ~14k ~1.3k ~990 ~780 ~610 ~370 ~330 ~165 ~180\n *\n * so the chirp is still above the gate at 500 ms and only clears it around 550–600. 600 ms is the\n * smallest value that rejects a chirp-only wake while still detecting the speech in every one of the\n * four captures, with no change to when the utterance closes. Only the analysis skips it: STT gets the audio\n * from 400 ms before the detected speech (`speechAudio.ts`), so a speaker who starts inside this window loses\n * nothing but a late gate open.\n */\nconst WAKE_CHIRP_MS = 600;\n/** Default API port of an ESPHome device. */\nconst DEFAULT_PORT = 6053;\n/** Keepalive interval; two missed replies count as a dead link. */\nconst PING_INTERVAL_MS = 20_000;\n/** Wait between reconnect attempts. Devices reboot, and a Wi-Fi speaker drops off now and then. */\nconst RECONNECT_MS = 10_000;\n/** Give up on a pipeline that produced no audio at all (device wedged mid-stream). */\nconst PIPELINE_TIMEOUT_MS = 30_000;\n/** How long we wait for the device to report that it finished playing before forcing it back to idle. */\nconst PLAYBACK_TIMEOUT_MS = 60_000;\n/**\n * Default lowest RMS that counts as speech (the noise floor can only raise the gate above it). Fits the\n * ThirdReality speaker; quieter microphones get their own value per device ({@link EsphomeDevice.speechLevel}).\n */\nexport const DEFAULT_SPEECH_LEVEL = 250;\n/**\n * Close the microphone when nobody has started speaking this long after the wake word. Without it a false wake\n * kept the stream open for the full 12 s cap: on a ThirdReality speaker with a custom wake word that was ten\n * times in one night, each 12.6 s of an open mic (and of music ducked, if any played).\n */\nconst NO_SPEECH_MS = 5000;\n/** The same after a follow-up question re-opened the mic: the user may need a moment to think. */\nconst NO_SPEECH_FOLLOW_UP_MS = 8000;\n/** Silence that ends an utterance when the configuration leaves it empty. */\nconst DEFAULT_SILENCE_MS = 900;\n/**\n * After this much speech a pause may be {@link LONG_PAUSE_FACTOR} times as long before the utterance ends: whoever\n * talks that long is dictating a request and pauses to think, while \"Licht an\" should still close quickly. Field\n * report 2026-11-03: \"Я хочу, чтоб ты создал задачу, чтобы утром говорить мне…\" was cut off right there.\n */\nconst LONG_REQUEST_MS = 2500;\nconst LONG_PAUSE_FACTOR = 1.5;\n/**\n * Sound needed before a loud moment counts as speech. On vitanova (2026-11-03) a single 100 ms sound at RMS 197\n * after a false wake opened the gate (threshold 150), and Whisper made \"и все просят.\" of the amplified silence\n * around it. The shortest real answer, \"да\", lasts about 250 ms.\n */\nconst MIN_SPEECH_MS = 200;\n/**\n * Close the utterance when the device stops sending audio without ending the stream. Seen on a ThirdReality\n * speaker: the audio stopped after 2.7 s, and the satellite showed \"listening\" for the 30 s of\n * {@link PIPELINE_TIMEOUT_MS}. A device streams every few tens of ms while the mic is open.\n */\nconst STREAM_STALL_MS = 2000;\n/** The same before the first audio arrives: a device needs a moment to open the microphone. */\nconst STREAM_START_MS = 5000;\n/** How often a running capture checks for a stalled stream. */\nconst STALL_CHECK_MS = 250;\n/** Silence threshold as a share of the speech threshold — keeps the default pair 250/150. */\nconst SILENCE_SHARE = 0.6;\n/**\n * The firmware answers an ERROR event with a stop request of its own (`signal_stop_`). One arriving this soon after\n * our error belongs to it and needs no reply — the run is already over.\n */\nconst ERROR_ECHO_MS = 2000;\n/**\n * What ends a run that produced no request. Home Assistant sends the same code when the speech recognition finds no\n * text, and the Voice PE firmware deliberately plays no error sound for it.\n */\nconst NO_TEXT_ERROR = { code: 'stt-no-text-recognized', message: 'No text recognized' };\n/**\n * A dropped utterance whose loudest frame reached this share of the speech threshold was probably a voice\n * that was too quiet, not an empty room — worth telling the user where to lower the threshold.\n */\nconst QUIET_VOICE_SHARE = 0.4;\n/**\n * Event entity of a satellite with a screen: the user answered the open question by touch, event type `yes` or `no`.\n * Pressing it is the same as saying \"yes\"/\"no\" into the open microphone — no speech recognition to get it wrong\n * (a German \"Ja\" came back as \"Я\" once).\n */\nconst CONFIRM_ENTITY = 'confirm_answer';\n/** Select entity of a satellite with a screen: the language of the date and the hints it shows. */\nconst DISPLAY_LANGUAGE_ENTITY = 'display_language';\n/**\n * After a reply that asks something: how long, beyond the reply's own length, the device may take to play it and\n * open the microphone. Until then a button press answers the question.\n */\nconst FOLLOW_UP_START_MS = 10_000;\n/**\n * A button press still answers the question this long after the follow-up microphone closed: the firmware may stop\n * the microphone on the press before it reports which button it was.\n */\nconst CONFIRM_GRACE_MS = 3000;\n/**\n * After a button answer: a follow-up microphone the device opens this soon was asked for by the question the button\n * already answered, and is closed at once (unless our reply asked something again).\n */\nconst IGNORE_FOLLOW_UP_MS = 15_000;\n\n/** \"Yes\" and \"no\" as a button answer is passed on: the words of the satellite's language, which pi-agent also takes. */\nconst YES_NO: Record<string, [yes: string, no: string]> = {\n en: ['Yes', 'No'],\n de: ['Ja', 'Nein'],\n ru: ['Да', 'Нет'],\n pt: ['Sim', 'Não'],\n nl: ['Ja', 'Nee'],\n fr: ['Oui', 'Non'],\n it: ['Sì', 'No'],\n es: ['Sí', 'No'],\n pl: ['Tak', 'Nie'],\n uk: ['Так', 'Ні'],\n zh: ['是', '不'],\n};\n\n/** The word a yes/no button stands for in `language` (ISO 639-1, `zh-cn` too); English for an unknown one. */\nexport function yesNoWord(language: string, yes: boolean): string {\n const base = (language || 'en').trim().toLowerCase().split(/[-_]/)[0];\n return (YES_NO[base] ?? YES_NO.en)[yes ? 0 : 1];\n}\n\n/** The event type of a {@link CONFIRM_ENTITY} as yes (true) or no (false); null for anything else. */\nexport function confirmAnswerOf(eventType: unknown): boolean | null {\n const type = typeof eventType === 'string' ? eventType.trim().toLowerCase() : '';\n if (type === 'yes' || type === 'confirm') {\n return true;\n }\n if (type === 'no' || type === 'cancel') {\n return false;\n }\n return null;\n}\n\n/**\n * Names of the adapter's languages in that language, for a display-language select. `Intl.DisplayNames` covers the\n * rest, but a Node.js built with only English ICU data knows no \"Deutsch\" or \"Русский\".\n */\nconst NATIVE_LANGUAGE_NAMES: Record<string, string> = {\n en: 'english',\n de: 'deutsch',\n ru: 'русский',\n pt: 'português',\n nl: 'nederlands',\n fr: 'français',\n it: 'italiano',\n es: 'español',\n pl: 'polski',\n uk: 'українська',\n zh: '中文',\n};\n\n/**\n * The option of a display-language select that means `language`: its name in that language (\"Deutsch\"), in English\n * (\"German\") or its code (\"de\", \"de-DE\"), case ignored. Null when the device offers none of them.\n */\nexport function displayLanguageOption(options: string[], language: string): string | null {\n const code = (language || '').trim().toLowerCase();\n const base = code.split(/[-_]/)[0];\n if (!base) {\n return null;\n }\n const names = new Set<string>([code, base]);\n if (NATIVE_LANGUAGE_NAMES[base]) {\n names.add(NATIVE_LANGUAGE_NAMES[base]);\n }\n for (const locale of [base, 'en']) {\n try {\n const name = new Intl.DisplayNames([locale], { type: 'language' }).of(base);\n if (name) {\n names.add(name.toLocaleLowerCase(locale));\n }\n } catch {\n /* not a language code Intl knows */\n }\n }\n const norm = (option: string): string => option.trim().toLocaleLowerCase();\n return (\n options.find(o => names.has(norm(o))) ??\n options.find(o => norm(o).split(/[-_]/)[0] === base && /^[a-z]{2,3}([-_][a-z0-9]+)?$/.test(norm(o))) ??\n null\n );\n}\n\n/** The configured speech threshold of a device, or 0 for the default. Table cells may arrive as strings. */\nexport function speechLevelOf(device: EsphomeDevice): number {\n const level = Math.round(Number(device.speechLevel));\n return Number.isFinite(level) && level > 0 ? level : 0;\n}\n\n/** How a configured device is identified: `ip`, or `ip:port` when it does not use the default port. */\nexport function esphomeAddress(device: Pick<EsphomeDevice, 'ip' | 'port'>): string {\n const ip = (device.ip || '').trim().toLowerCase();\n const port = Number(device.port) || DEFAULT_PORT;\n return port === DEFAULT_PORT ? ip : `${ip}:${port}`;\n}\n\nexport interface EsphomeDevice {\n /** Host name or IP of the satellite. */\n ip: string;\n /** API port; empty/0 → 6053. */\n port?: number | string;\n /** API password, if one is configured on the device. */\n password?: string;\n /** Room this satellite belongs to (drives `satellites.<room>.*` and the answer context). */\n room?: string;\n /**\n * Lowest RMS that counts as speech on this device (empty/0 → {@link DEFAULT_SPEECH_LEVEL}). Microphone\n * levels differ a lot: a ThirdReality speaker hears normal speech at RMS 350–470, a phone running a\n * satellite app at under 200, so one fixed floor cannot fit both.\n */\n speechLevel?: number | string | null;\n}\n\nexport interface EsphomeSatellitesOptions {\n devices: EsphomeDevice[];\n /** ISO-639-1 language hint for STT/TTS ('' = auto/provider default). */\n language: string;\n stt: SttEngine;\n tts: TtsEngine;\n /**\n * Produce the assistant reply for a transcribed utterance. `audioMs` is the length of the recording,\n * `vad` what the voice activity detection made of it (both for the request journal). An answer given with the\n * device's yes/no button ({@link CONFIRM_ENTITY}) comes as the yes or no word, with `button` and no recording.\n */\n answer: (\n question: string,\n ctx: {\n device: string;\n room: string;\n /** Wake word of the recording; '' = the mic was re-opened for a follow-up; absent for a button. */\n wakeWord?: string;\n sttMs?: number;\n audioMs?: number;\n vad?: VadReport;\n button?: 'yes' | 'no';\n },\n ) => Promise<string>;\n /** The reply was synthesised: how long that took and how long it plays (for the request journal). */\n onSpoken?: (device: string, info: { ms: number; audioMs: number }) => void;\n /** Optional STT vocabulary hints (device/room names) to bias recognition; re-read per utterance. */\n getHints?: () => string[] | Promise<string[]>;\n /** Where spoken replies are published for the device to fetch. */\n media: MediaHost;\n /**\n * Host the device should call back on. Empty → the local address of our socket to that device,\n * which is automatically the right interface on a multi-homed host.\n */\n mediaHost?: string;\n /** Silence that ends an utterance, in ms ('' / 0 → the detector default). */\n silenceMs?: number;\n log: ioBroker.Logger;\n /**\n * Notified on every satellite state transition (idle/listening/processing/speaking/offline). `host` is the\n * configured address (`ip`, or `ip:port` for another port than 6053), so the adapter can tell which table row\n * a satellite belongs to.\n */\n onStatus?: (device: string, room: string, state: SatelliteState | 'offline', host: string) => void;\n /**\n * Writes replies as MP3 or Opus, for a media player that takes nothing else (ffmpeg in the adapter). Without it\n * such a device gets FLAC or WAV if it lists one of them, and a warning otherwise.\n */\n encodeAudio?: ExternalEncoder;\n /** Notified with the device's wake-word configuration, on connect and after every change. */\n onWakeWords?: (device: string, room: string, config: WakeWordConfig) => void;\n /** Notified once per connect with everything the device exposes besides the voice pipeline. */\n onEntities?: (device: string, room: string, entities: EsphomeEntity[]) => void;\n /** Notified whenever one of those entities changes (and once per entity right after connecting). */\n onEntityState?: (device: string, room: string, entity: EsphomeEntity) => void;\n /** True when the reply asks something back, so the device should re-open its mic without a wake word. */\n expectsFollowUp?: (answer: string, device: string) => boolean;\n /**\n * A recording that never became a request: dropped as silence, or returned empty by the speech recognition.\n * For diagnosis (the adapter stores it when asked to); absent → nothing is kept.\n */\n onDiscarded?: (capture: DiscardedCapture) => void;\n /**\n * Custom wake words to offer the devices, re-read for every configuration request. The device lists\n * them next to its own and downloads one (from the media server) only when it is selected.\n */\n externalWakeWords?: () => ExternalWakeWordOffer[];\n}\n\n/** A custom wake word as offered to the devices; the files are on the media server under `path`. */\nexport interface ExternalWakeWordOffer {\n id: string;\n phrase: string;\n languages: string[];\n /** Size of the `.tflite` in bytes. */\n size: number;\n /** SHA-256 of the `.tflite`, lower-case hex. */\n sha256: string;\n /** URL path of the JSON config, e.g. `/wakeword/hey_hannah_1a2b3c4d.json`; the model sits next to it. */\n path: string;\n}\n\n/** What a device reports about its wake words: what the firmware ships plus the custom ones we offered. */\nexport interface WakeWordConfig {\n /** Ids currently listening, e.g. `['okay_nabu']`. */\n active: string[];\n /** Every wake word the device can use, with the spoken phrase and the languages it was trained on. */\n available: { id: string; phrase: string; languages: string[] }[];\n /** How many may listen at once — 2 on the ThirdReality speaker, which has a sensitivity per slot. */\n max: number;\n}\n\n/** `VoiceAssistantTimerEvent` in api.proto. */\nexport const TIMER_EVENT = { started: 0, updated: 1, cancelled: 2, finished: 3 } as const;\n\n/** One assistant timer, as the device wants to hear about it. */\nexport interface TimerEvent {\n type: keyof typeof TIMER_EVENT;\n id: string;\n name: string;\n totalSeconds: number;\n secondsLeft: number;\n /** False once it has finished or been cancelled — the device clears its ring on that. */\n active: boolean;\n}\n\n/** The slice of `MediaServer` this module needs (kept narrow so tests can pass a stub). */\nexport interface MediaHost {\n port: number;\n publish(body: Buffer, contentType?: string, ttlMs?: number): string;\n}\n\n/**\n * All configured ESPHome satellites. Owns one connection per device and offers the same surface the\n * adapter already uses for the UDP server: `devices()` and `announce()`.\n */\nexport class EsphomeSatellites {\n private readonly connections: EsphomeConnection[] = [];\n\n constructor(private readonly opts: EsphomeSatellitesOptions) {}\n\n async start(): Promise<void> {\n for (const device of this.opts.devices) {\n if (!device.ip?.trim()) {\n continue;\n }\n const connection = new EsphomeConnection(device, this.opts);\n this.connections.push(connection);\n connection.start();\n }\n if (!this.connections.length) {\n this.opts.log.warn('ESPHome satellites enabled, but no device addresses are configured.');\n }\n return Promise.resolve();\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.connections.map(c => c.stop()));\n this.connections.length = 0;\n }\n\n /** Device names of the satellites currently connected. */\n devices(): string[] {\n return this.connections.filter(c => c.online).map(c => c.deviceName);\n }\n\n /** Wake-word configuration of one connected satellite, or null if it is unknown/offline. */\n wakeWords(device: string): WakeWordConfig | null {\n return this.connections.find(c => c.online && c.deviceName === device)?.wakeWordConfig ?? null;\n }\n\n /**\n * Choose which wake words listen on one satellite. Ids come from {@link WakeWordConfig.available};\n * the device stores the selection itself, so it survives a restart of the adapter.\n */\n setWakeWords(device: string, ids: string[]): boolean {\n const target = this.connections.find(c => c.online && c.deviceName === device);\n if (!target) {\n return false;\n }\n target.setWakeWords(ids);\n return true;\n }\n\n /**\n * Offer the current custom wake words to every connected satellite again — after one was uploaded\n * or deleted. Each device answers with its new configuration (→ `onWakeWords`).\n */\n refreshWakeWords(): number {\n const online = this.connections.filter(c => c.online);\n online.forEach(c => c.requestWakeWordConfig());\n return online.length;\n }\n\n /** Everything one satellite exposes besides the voice pipeline (gain, noise suppression, …). */\n entities(device: string): EsphomeEntity[] {\n return this.connections.find(c => c.online && c.deviceName === device)?.entities.list() ?? [];\n }\n\n /**\n * Write one of those entities. Returns false when the satellite is offline, the entity is unknown\n * or read-only, or the value is not one the device accepts.\n */\n setEntity(device: string, objectId: string, value: unknown): boolean {\n const target = this.connections.find(c => c.online && c.deviceName === device);\n return target ? target.setEntity(objectId, value) : false;\n }\n\n /**\n * Mirror an assistant timer onto the satellites so they can show it on their own LED ring and ring\n * it themselves. `device` null broadcasts. Returns how many devices were told.\n */\n timerEvent(device: string | null, event: TimerEvent): number {\n const targets = this.connections.filter(c => c.online && (!device || c.deviceName === device));\n targets.forEach(c => c.sendTimerEvent(event));\n return targets.length;\n }\n\n /**\n * Play a ready PCM buffer on one satellite (by device name) or all of them. Returns how many\n * devices it was handed to.\n *\n * With `startConversation` the device opens its microphone as soon as the clip has played, without\n * a wake word — that is how a question gets its answer (see `PendingQuestions`).\n */\n async announce(device: string | null, pcm: Buffer, sampleRate: number, startConversation = false): Promise<number> {\n const targets = this.connections.filter(c => c.online && (!device || c.deviceName === device));\n if (!targets.length) {\n return 0;\n }\n await Promise.all(\n targets.map(c =>\n c\n .announce(pcm, sampleRate, startConversation)\n .catch(e => this.opts.log.warn(`announce to ${c.deviceName} failed: ${(e as Error).message}`)),\n ),\n );\n return targets.length;\n }\n}\n\n/** State of the utterance currently being captured. */\ninterface Capture {\n chunks: Buffer[];\n detector: SpeechDetector;\n conversationId: string;\n /** Wake word that opened this capture; '' when the mic was re-opened for a follow-up/question. */\n wakeWord: string;\n /** The mic was re-opened for a reply that asked something: a yes/no button press answers it too. */\n answersQuestion: boolean;\n timer: NodeJS.Timeout;\n /** Watches for a device that stops sending audio without ending the stream. */\n stallCheck: NodeJS.Timeout;\n startedAt: number;\n /** When the last audio arrived; 0 = none yet. */\n lastAudioAt: number;\n closed: boolean;\n}\n\n/** One satellite: socket lifecycle, handshake, and the voice pipeline. */\nclass EsphomeConnection {\n /** Device name as reported by the device; falls back to its address until the handshake answers. */\n deviceName: string;\n online = false;\n /** Last wake-word configuration the device reported; null until the handshake answers. */\n wakeWordConfig: WakeWordConfig | null = null;\n /**\n * One entry per configuration request in flight, in send order (the device answers each one, in\n * order): the ids a preceding `SetConfiguration` asked for, or null. The read-back is the only\n * failure signal the device gives.\n */\n private configChecks: (string[] | null)[] = [];\n /** Everything else the device exposes — rebuilt from scratch on every reconnect. */\n readonly entities = new EntityRegistry();\n\n private readonly host: string;\n private readonly port: number;\n private readonly room: string;\n\n private socket: net.Socket | null = null;\n private rx: Bytes = Buffer.alloc(0);\n private pingTimer: NodeJS.Timeout | null = null;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private missedPings = 0;\n private stopping = false;\n private capture: Capture | null = null;\n private playbackTimer: NodeJS.Timeout | null = null;\n private readonly password: string;\n /** Configured speech threshold, 0 = {@link DEFAULT_SPEECH_LEVEL}. */\n private readonly speechLevel: number;\n /** `ip`, or `ip:port` for another port than the default — how the adapter recognises the table row. */\n private readonly address: string;\n /** The device's friendly name, for entities without a name of their own. */\n private friendlyName = '';\n /**\n * Number of the current pipeline run. A run whose number is no longer current was ended — the device asked to\n * stop, started over, or went away — and whatever STT, answer or TTS is still in flight for it stays silent.\n */\n private run = 0;\n /** From RUN_START until we sent RUN_END: the device waits for that RUN_END. */\n private runOpen = false;\n /** When we last sent an ERROR event (see {@link ERROR_ECHO_MS}). */\n private errorSentAt = 0;\n /** The reply format last reported in the log, to log it again only when it changes. */\n private loggedFormat = '';\n /**\n * The last reply asked something (`continue_conversation`, or an announcement with `start_conversation`): until\n * when a yes/no button press answers it while no follow-up recording is open. 0 = no open question.\n */\n private questionUntil = 0;\n /** After a button answer: until when a follow-up microphone is the stale one of the answered question. */\n private ignoreFollowUpUntil = 0;\n /** The display language was compared with ours since the last connect. */\n private displayLanguageChecked = false;\n\n constructor(\n device: EsphomeDevice,\n private readonly opts: EsphomeSatellitesOptions,\n ) {\n this.host = device.ip.trim();\n this.port = Number(device.port) || DEFAULT_PORT;\n this.room = (device.room || '').trim();\n this.password = device.password || '';\n this.speechLevel = speechLevelOf(device);\n this.address = esphomeAddress(device);\n this.deviceName = this.host;\n }\n\n // ── lifecycle ───────────────────────────────────────────────────────────────────────────────────\n\n start(): void {\n this.connect();\n }\n\n async stop(): Promise<void> {\n this.stopping = true;\n this.clearTimers();\n this.abortCapture();\n const socket = this.socket;\n this.socket = null;\n if (socket) {\n try {\n socket.write(encode(new pb.DisconnectRequest()));\n } catch {\n /* socket already gone — nothing to say goodbye on */\n }\n socket.destroy();\n }\n this.setOffline();\n return Promise.resolve();\n }\n\n private connect(): void {\n if (this.stopping) {\n return;\n }\n this.rx = Buffer.alloc(0);\n this.missedPings = 0;\n // The device re-announces everything after a reconnect, and the keys are not stable across\n // reboots, so starting from a clean slate is the only safe option.\n this.entities.clear();\n this.configChecks = [];\n this.displayLanguageChecked = false;\n\n const socket = net.createConnection({ host: this.host, port: this.port }, () => {\n this.opts.log.debug(`ESPHome ${this.host}:${this.port} connected`);\n this.handshake();\n });\n this.socket = socket;\n socket.setNoDelay(true);\n\n socket.on('data', data => this.onData(data));\n socket.on('error', e => {\n // A satellite that is switched off is normal, so this is not an error-level event.\n this.opts.log.debug(`ESPHome ${this.host}: ${e.message}`);\n });\n socket.on('close', () => {\n if (this.socket === socket) {\n this.socket = null;\n this.onDisconnected();\n }\n });\n }\n\n private onDisconnected(): void {\n this.clearTimers();\n this.abortCapture();\n // A reply still being worked out must not land on the next connection, in the middle of another run.\n this.run++;\n this.runOpen = false;\n this.questionUntil = 0;\n this.ignoreFollowUpUntil = 0;\n if (this.online) {\n this.opts.log.info(`ESPHome satellite offline: ${this.deviceName}`);\n }\n this.setOffline();\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.stopping || this.reconnectTimer) {\n return;\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, RECONNECT_MS);\n this.reconnectTimer.unref();\n }\n\n private clearTimers(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.playbackTimer) {\n clearTimeout(this.playbackTimer);\n this.playbackTimer = null;\n }\n }\n\n private setOffline(): void {\n if (this.online) {\n this.online = false;\n this.opts.onStatus?.(this.deviceName, this.room, 'offline', this.address);\n }\n }\n\n private status(state: SatelliteState): void {\n this.opts.onStatus?.(this.deviceName, this.room, state, this.address);\n }\n\n // ── protocol plumbing ───────────────────────────────────────────────────────────────────────────\n\n private send(message: PbMessage): void {\n const socket = this.socket;\n if (!socket || socket.destroyed) {\n return;\n }\n try {\n socket.write(encode(message));\n } catch (e) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: send failed — ${(e as Error).message}`);\n }\n }\n\n private onData(data: Buffer): void {\n this.rx = this.rx.length ? Buffer.concat([this.rx, data]) : data;\n let frames;\n try {\n ({ frames, rest: this.rx } = decode(this.rx));\n } catch (e) {\n this.opts.log.error(`ESPHome ${this.deviceName}: ${(e as Error).message}`);\n this.socket?.destroy();\n return;\n }\n for (const frame of frames) {\n if (frame.error) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: cannot parse ${frame.name}`);\n continue;\n }\n if (!frame.name || !frame.message) {\n continue; // unknown id — already skipped by its declared length\n }\n try {\n this.onMessage(frame.name, frame.message);\n } catch (e) {\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: ${frame.name} handler failed — ${(e as Error).message}`,\n );\n }\n }\n }\n\n private handshake(): void {\n const hello = new pb.HelloRequest();\n hello.setClientInfo('ioBroker.assistant');\n hello.setApiVersionMajor(1);\n hello.setApiVersionMinor(10);\n this.send(hello);\n\n const auth = new pb.AuthenticationRequest();\n auth.setPassword(this.password);\n this.send(auth);\n\n this.send(new pb.DeviceInfoRequest());\n // Ask for the entity announcements *before* subscribing to their states: a state message whose\n // entity we have not seen yet has nothing to attach to and is dropped.\n this.send(new pb.ListEntitiesRequest());\n this.send(new pb.SubscribeStatesRequest());\n\n const subscribe = new pb.SubscribeVoiceAssistantRequest();\n subscribe.setSubscribe(true);\n subscribe.setFlags(SUBSCRIBE_API_AUDIO);\n this.send(subscribe);\n\n this.requestWakeWordConfig();\n\n this.pingTimer = setInterval(() => {\n if (++this.missedPings > 2) {\n this.opts.log.info(`ESPHome ${this.deviceName}: no reply to keepalive — reconnecting`);\n this.socket?.destroy();\n return;\n }\n this.send(new pb.PingRequest());\n }, PING_INTERVAL_MS);\n this.pingTimer.unref();\n }\n\n private onMessage(name: string, message: unknown): void {\n switch (name) {\n case 'HelloResponse': {\n const hello = message as HelloResponse;\n this.opts.log.debug(\n `ESPHome ${this.host}: ${hello.getServerInfo()} (API ${hello.getApiVersionMajor()}.${hello.getApiVersionMinor()})`,\n );\n return;\n }\n\n case 'AuthenticationResponse':\n if ((message as AuthenticationResponse).getInvalidPassword()) {\n this.opts.log.error(\n `ESPHome ${this.host}: API password rejected — check the device's password in the settings.`,\n );\n this.socket?.destroy();\n }\n return;\n\n case 'DeviceInfoResponse': {\n const info = message as DeviceInfoResponse;\n this.deviceName = info.getName() || this.host;\n this.friendlyName = info.getFriendlyName?.() || info.getName() || '';\n this.online = true;\n this.opts.log.info(\n `ESPHome satellite online: ${this.deviceName} (${info.getModel()}) @ ${this.host}${this.room ? `, room ${this.room}` : ''}`,\n );\n this.status('idle');\n return;\n }\n\n case 'VoiceAssistantConfigurationResponse': {\n const config = message as VoiceAssistantConfigurationResponse;\n // A custom wake word the device already downloaded is listed twice: once from its own\n // model folder and once from our offer.\n const seen = new Set<string>();\n this.wakeWordConfig = {\n active: config.getActiveWakeWordsList(),\n available: config\n .getAvailableWakeWordsList()\n .map(w => ({\n id: w.getId(),\n phrase: w.getWakeWord(),\n languages: w.getTrainedLanguagesList(),\n }))\n .filter(w => !seen.has(w.id) && !!seen.add(w.id)),\n max: config.getMaxActiveWakeWords(),\n };\n const active = this.wakeWordConfig.active.join(', ') || '(none active)';\n const available = this.wakeWordConfig.available.map(w => w.id);\n this.opts.log.info(\n `ESPHome ${this.deviceName}: wake words ${active}${available.length ? ` (available: ${available.join(', ')})` : ''}`,\n );\n const requested = this.configChecks.shift();\n const missing = requested?.filter(id => !this.wakeWordConfig?.active.includes(id)) ?? [];\n if (missing.length) {\n // The device answers a model it cannot fetch or load with silence, not an error.\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: could not activate wake word(s) ${missing.join(', ')}. ` +\n `For an uploaded wake word the device must reach ${this.mediaUrl('/')} and the model ` +\n `must be a microWakeWord .tflite.`,\n );\n }\n this.opts.onWakeWords?.(this.deviceName, this.room, this.wakeWordConfig);\n return;\n }\n\n case 'VoiceAssistantRequest':\n this.onPipelineRequest(message as VoiceAssistantRequestMsg);\n return;\n\n case 'VoiceAssistantAudio':\n this.onAudio(message as VoiceAssistantAudio);\n return;\n\n case 'VoiceAssistantAnnounceFinished':\n if (this.playbackTimer) {\n clearTimeout(this.playbackTimer);\n this.playbackTimer = null;\n }\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: playback finished (success=${(message as VoiceAssistantAnnounceFinished).getSuccess()})`,\n );\n this.status('idle');\n return;\n\n case 'PingRequest':\n this.send(new pb.PingResponse());\n return;\n\n case 'PingResponse':\n this.missedPings = 0;\n return;\n\n case 'GetTimeRequest': {\n // The device has no RTC and syncs its clock from us — its timer ring depends on it.\n const time = new pb.GetTimeResponse();\n time.setEpochSeconds(Math.floor(Date.now() / 1000));\n this.send(time);\n return;\n }\n\n case 'DisconnectRequest':\n this.send(new pb.DisconnectResponse());\n this.socket?.destroy();\n return;\n\n case 'ListEntitiesDoneResponse': {\n const list = this.entities.list();\n if (list.length) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${list.length} entities — ${list.map(e => e.objectId).join(', ')}`,\n );\n }\n this.opts.onEntities?.(this.deviceName, this.room, list);\n return;\n }\n\n default:\n if (isListEntityMessage(name)) {\n this.entities.addFromAnnouncement(name, message, this.friendlyName);\n } else if (isEntityStateMessage(name)) {\n const entity = this.entities.applyState(name, message);\n if (entity) {\n this.opts.onEntityState?.(this.deviceName, this.room, entity);\n this.onEntityChange(entity);\n }\n }\n return;\n }\n }\n\n /** Entities of a satellite with a screen that take part in the conversation (see {@link CONFIRM_ENTITY}). */\n private onEntityChange(entity: EsphomeEntity): void {\n if (entity.objectId === CONFIRM_ENTITY && entity.kind === 'event') {\n this.onConfirmButton(entity.value);\n } else if (entity.objectId === DISPLAY_LANGUAGE_ENTITY && entity.kind === 'select') {\n // Once per connect, with the state the device reports on subscribing: a language the user picks on the\n // device afterwards stays until the next connect (a change of the voice language restarts the adapter).\n if (!this.displayLanguageChecked) {\n this.displayLanguageChecked = true;\n this.syncDisplayLanguage(entity);\n }\n }\n }\n\n /** Show the device's screen in the voice language, if it offers that language. */\n private syncDisplayLanguage(entity: EsphomeEntity): void {\n const language = this.opts.language;\n if (!language) {\n return;\n }\n const option = displayLanguageOption(entity.options ?? [], language);\n if (!option) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${DISPLAY_LANGUAGE_ENTITY} has no option for \"${language}\" ` +\n `(${(entity.options ?? []).join(', ')})`,\n );\n return;\n }\n if (entity.value === option) {\n return;\n }\n const shown = typeof entity.value === 'string' ? entity.value : '?';\n this.opts.log.info(`ESPHome ${this.deviceName}: display language ${shown} → ${option}`);\n this.setEntity(DISPLAY_LANGUAGE_ENTITY, option);\n }\n\n /** Whether a yes/no button press now answers a question the last reply asked. */\n private questionOpen(): boolean {\n return !!this.capture?.answersQuestion || Date.now() < this.questionUntil;\n }\n\n /**\n * The user pressed yes or no on the device's screen. While a reply waits for an answer that is the answer: the\n * microphone opened for it is closed, the yes or no word goes on as the user's reply (pi-agent decides its\n * confirmation on it like on a spoken one), and the reply to that is announced on this device.\n */\n private onConfirmButton(eventType: unknown): void {\n const yes = confirmAnswerOf(eventType);\n if (yes === null) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${CONFIRM_ENTITY} \"${String(eventType)}\" — not yes/no, ignored`,\n );\n return;\n }\n if (!this.questionOpen()) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${CONFIRM_ENTITY} \"${yes ? 'yes' : 'no'}\" without an open question — ignored`,\n );\n return;\n }\n this.questionUntil = 0;\n if (this.capture) {\n // A RUN_END while the microphone streams stops it and puts the device back to idle — without the error\n // display an empty recognition would end with.\n this.abortCapture();\n this.event(EVENT.RUN_END);\n }\n // Whatever is still in flight for the question stays silent; so does the follow-up microphone the device may\n // still open for it.\n const run = ++this.run;\n this.ignoreFollowUpUntil = Date.now() + IGNORE_FOLLOW_UP_MS;\n void this.answerButton(yes, run);\n }\n\n /** Pass a button answer on and announce the reply (see {@link onConfirmButton}). */\n private async answerButton(yes: boolean, run: number): Promise<void> {\n const text = yesNoWord(this.opts.language, yes);\n this.opts.log.info(`ESPHome ${this.deviceName}: answered \"${text}\" with the button`);\n this.status('processing');\n try {\n const answer = (\n await this.opts.answer(text, { device: this.deviceName, room: this.room, button: yes ? 'yes' : 'no' })\n ).trim();\n if (run !== this.run) {\n return;\n }\n if (!answer) {\n this.status('idle');\n return;\n }\n const followUp = this.opts.expectsFollowUp?.(answer, this.deviceName) === true;\n const ttsStart = Date.now();\n const { pcm, sampleRate } = await this.opts.tts.synthesize(answer, this.opts.language);\n if (run !== this.run) {\n return;\n }\n this.opts.onSpoken?.(this.deviceName, {\n ms: Date.now() - ttsStart,\n audioMs: (pcm.length / 2 / sampleRate) * 1000,\n });\n await this.announce(pcm, sampleRate, followUp, answer);\n } catch (e) {\n this.opts.log.warn(`ESPHome ${this.deviceName}: answer to the button failed — ${(e as Error).message}`);\n if (run === this.run) {\n this.status('idle');\n }\n }\n }\n\n /** Write one of the device's entities. See {@link EsphomeSatellites.setEntity}. */\n setEntity(objectId: string, value: unknown): boolean {\n const message = this.entities.command(objectId, value);\n if (!message) {\n const entity = this.entities.get(objectId);\n const known = this.entities\n .list()\n .map(e => e.objectId)\n .join(', ');\n const options = entity?.options\n ? ` (one of: ${entity.options.join(', ')})`\n : entity?.kind === 'text'\n ? ` (${entity.minLength || 0}–${entity.maxLength ?? '∞'} bytes${entity.pattern ? `, pattern ${entity.pattern}` : ''})`\n : '';\n this.opts.log.warn(\n entity\n ? `ESPHome ${this.deviceName}: ${JSON.stringify(value)} is not a value \"${objectId}\" accepts${options}`\n : `ESPHome ${this.deviceName}: no entity \"${objectId}\" (have: ${known})`,\n );\n return false;\n }\n this.send(message);\n this.opts.log.debug(`ESPHome ${this.deviceName}: ${objectId} := ${JSON.stringify(value)}`);\n return true;\n }\n\n /** Push one assistant timer to the device so it can show and ring it itself. */\n sendTimerEvent(event: TimerEvent): void {\n const message = new pb.VoiceAssistantTimerEventResponse();\n message.setEventType(TIMER_EVENT[event.type]);\n message.setTimerId(event.id);\n message.setName(event.name);\n message.setTotalSeconds(Math.max(0, Math.round(event.totalSeconds)));\n message.setSecondsLeft(Math.max(0, Math.round(event.secondsLeft)));\n message.setIsActive(event.active);\n this.send(message);\n }\n\n // ── voice pipeline ──────────────────────────────────────────────────────────────────────────────\n\n private onPipelineRequest(request: VoiceAssistantRequestMsg): void {\n if (!request.getStart()) {\n this.onStopRequest();\n return;\n }\n if (this.capture) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: pipeline already running — ignoring wake`);\n return;\n }\n const phrase = request.getWakeWordPhrase();\n if (!phrase && Date.now() < this.ignoreFollowUpUntil) {\n // The microphone for the question a button already answered: close it at once. In this state the device\n // takes a RUN_END as \"stop the microphone\" and goes back to idle.\n this.ignoreFollowUpUntil = 0;\n this.opts.log.debug(`ESPHome ${this.deviceName}: follow-up of a question answered by button — closing it`);\n this.event(EVENT.RUN_END);\n return;\n }\n if (this.runOpen) {\n // The device started over while the last request was still being answered: that answer is not\n // wanted any more, and its events would land in the middle of the new run.\n this.opts.log.debug(`ESPHome ${this.deviceName}: new wake while answering — dropping the old reply`);\n }\n this.run++;\n // Without a wake word the device re-opened the mic for the reply that asked something; with one, the user\n // started over and the question is gone.\n const answersQuestion = !phrase && Date.now() < this.questionUntil;\n if (phrase) {\n this.questionUntil = 0;\n }\n\n this.opts.log.debug(`ESPHome ${this.deviceName}: wake \"${phrase || '(follow-up)'}\"`);\n\n const response = new pb.VoiceAssistantResponse();\n response.setPort(0); // 0 = stream the audio over this socket\n response.setError(false);\n this.send(response);\n\n const timer = setTimeout(() => {\n this.opts.log.warn(`ESPHome ${this.deviceName}: no end of speech within ${PIPELINE_TIMEOUT_MS} ms`);\n void this.finishCapture('pipeline-timeout');\n }, PIPELINE_TIMEOUT_MS);\n timer.unref();\n const stallCheck = setInterval(() => this.checkStall(), STALL_CHECK_MS);\n stallCheck.unref();\n\n const silenceMs = this.opts.silenceMs || DEFAULT_SILENCE_MS;\n this.capture = {\n chunks: [],\n detector: new SpeechDetector({\n sampleRate: MIC_SAMPLE_RATE,\n silenceMs,\n longSilenceMs: Math.round(silenceMs * LONG_PAUSE_FACTOR),\n longAfterMs: LONG_REQUEST_MS,\n // Microphone gain differs wildly between these devices, so fixed RMS levels do not\n // travel: derive them from the room instead, once the wake chirp is out of the way.\n skipMs: WAKE_CHIRP_MS,\n adaptive: true,\n startTimeoutMs: phrase ? NO_SPEECH_MS : NO_SPEECH_FOLLOW_UP_MS,\n minStartLevel: this.speechLevel || DEFAULT_SPEECH_LEVEL,\n minEndLevel: Math.round((this.speechLevel || DEFAULT_SPEECH_LEVEL) * SILENCE_SHARE),\n minSpeechMs: MIN_SPEECH_MS,\n }),\n conversationId: request.getConversationId(),\n wakeWord: phrase || '',\n answersQuestion,\n timer,\n stallCheck,\n startedAt: Date.now(),\n lastAudioAt: 0,\n closed: false,\n };\n\n this.status('listening');\n this.event(EVENT.RUN_START);\n if (phrase) {\n this.event(EVENT.WAKE_WORD_END, { wake_word_phrase: phrase });\n }\n this.event(EVENT.STT_START);\n this.event(EVENT.STT_VAD_START);\n }\n\n /**\n * The device asks to end the conversation (`VoiceAssistantRequest{start:false}`): a button, or the wake word\n * said again while a request is running — that is how ESPHome's voice_assistant stops. While it waits for an\n * answer, the firmware leaves that state only on our RUN_END; without one it stays \"in the conversation\", and\n * every further wake word just sends another stop (field report 2026-11-03).\n */\n private onStopRequest(): void {\n const running = !!this.capture || this.runOpen;\n // A device with yes/no buttons may stop its microphone on the press before it reports which button it was.\n this.questionUntil = this.questionOpen() ? Date.now() + CONFIRM_GRACE_MS : 0;\n this.abortCapture();\n if (running) {\n this.run++; // whatever is still being answered stays silent\n this.opts.log.debug(`ESPHome ${this.deviceName}: the device ended the conversation`);\n this.event(EVENT.RUN_END);\n this.status('idle');\n return;\n }\n if (Date.now() - this.errorSentAt < ERROR_ECHO_MS) {\n return; // the device's own reaction to our ERROR event\n }\n // Nothing is open on our side, but the device still thinks so (it missed a RUN_END): end it there too.\n this.opts.log.debug(`ESPHome ${this.deviceName}: stop outside a conversation — ending it on the device`);\n this.event(EVENT.RUN_END);\n }\n\n private onAudio(audio: VoiceAssistantAudio): void {\n const capture = this.capture;\n if (!capture || capture.closed) {\n return;\n }\n const chunk = Buffer.from(audio.getData_asU8());\n if (chunk.length) {\n capture.lastAudioAt = Date.now();\n capture.chunks.push(chunk);\n const end = capture.detector.push(chunk);\n if (end) {\n void this.finishCapture(end);\n return;\n }\n }\n if (audio.getEnd()) {\n void this.finishCapture('stream');\n }\n }\n\n /** End a capture whose device stopped sending audio without ending the stream. */\n private checkStall(): void {\n const capture = this.capture;\n if (!capture || capture.closed) {\n return;\n }\n const now = Date.now();\n const quietMs = capture.lastAudioAt ? now - capture.lastAudioAt : now - capture.startedAt;\n if (quietMs < (capture.lastAudioAt ? STREAM_STALL_MS : STREAM_START_MS)) {\n return;\n }\n const audioMs = Math.round(capture.chunks.reduce((sum, c) => sum + c.length, 0) / 2 / (MIC_SAMPLE_RATE / 1000));\n this.opts.log.info(\n `ESPHome ${this.deviceName}: the device ${\n capture.lastAudioAt ? `stopped sending audio after ${(audioMs / 1000).toFixed(2)} s` : 'sent no audio'\n } without ending the stream — closing the utterance after ${(quietMs / 1000).toFixed(1)} s of nothing`,\n );\n void this.finishCapture('stall');\n }\n\n /** Hand a recording that never became a request to {@link EsphomeSatellitesOptions.onDiscarded}. */\n private discard(capture: Capture, pcm: Bytes, reason: DiscardReason, vad: VadReport): void {\n if (!this.opts.onDiscarded || !pcm.length) {\n return;\n }\n try {\n this.opts.onDiscarded({\n device: this.deviceName,\n room: this.room,\n wakeWord: capture.wakeWord,\n reason,\n pcm,\n sampleRate: MIC_SAMPLE_RATE,\n // The store writes its own level profile next to it.\n vad: { ...vad, levels: undefined },\n });\n } catch (e) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: keeping the recording failed — ${(e as Error).message}`);\n }\n }\n\n /** Stop the mic stream and run STT → answer → TTS for what was captured. */\n private async finishCapture(end: CaptureEnd): Promise<void> {\n const capture = this.capture;\n if (!capture || capture.closed) {\n return;\n }\n capture.closed = true;\n this.capture = null;\n clearTimeout(capture.timer);\n clearInterval(capture.stallCheck);\n const run = this.run;\n /** False once the run was ended elsewhere — then nothing more may be sent for it. */\n const current = (): boolean => {\n if (run === this.run) {\n return true;\n }\n this.opts.log.debug(`ESPHome ${this.deviceName}: conversation ended meanwhile — dropping the reply`);\n return false;\n };\n\n // Send this first: the device streams until it sees it.\n this.event(EVENT.STT_VAD_END);\n\n const pcm = Buffer.concat(capture.chunks);\n const seconds = pcm.length / 2 / MIC_SAMPLE_RATE;\n const vad: VadReport = { ...capture.detector.report(), end };\n const startedAt =\n vad.speechStartMs !== undefined ? `, speech from ${(vad.speechStartMs / 1000).toFixed(2)} s` : '';\n const endedBy = vad.end === 'speech-end' ? `ended after ${vad.silenceMs} ms of silence` : `ended by ${vad.end}`;\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: captured ${seconds.toFixed(2)} s ` +\n `(peak RMS ${vad.peak}, noise floor ${vad.noiseFloor}, speech/silence gate ${vad.startLevel}/${vad.endLevel}` +\n `${startedAt}, ${endedBy})`,\n );\n\n if (capture.answersQuestion) {\n // Spoken: that is the answer, a button press now would be a second one. Silent: the buttons still answer\n // for a moment, as the screen may still show them.\n this.questionUntil = capture.detector.sawSpeech ? 0 : Date.now() + CONFIRM_GRACE_MS;\n }\n\n if (!pcm.length || !capture.detector.sawSpeech) {\n const loudest = Math.round(capture.detector.analysedPeak);\n const gate = Math.round(capture.detector.startLevel);\n if (capture.detector.longestSoundMs > 0) {\n // Something crossed the gate, but too briefly for a word: a click, a knock, a cough.\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: only a short sound (${capture.detector.longestSoundMs} ms, ` +\n `RMS ${loudest}) — too short for speech (${MIN_SPEECH_MS} ms), dropping the utterance`,\n );\n } else if (pcm.length && loudest >= gate * QUIET_VOICE_SHARE) {\n // Not an empty room: something came close to the gate. Typically a microphone that is quieter\n // than the default threshold expects (a phone) — say where to change it.\n this.opts.log.info(\n `ESPHome ${this.deviceName}: dropped the utterance — the loudest sound (RMS ${loudest}) stayed ` +\n `below the speech threshold ${gate}. If somebody spoke, lower \"Speech threshold\" for this ` +\n `device in the ESPHome satellites table (Voice tab), e.g. to ${Math.max(\n 30,\n Math.round((loudest * 0.6) / 10) * 10,\n )}.`,\n );\n } else {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: nothing but silence${\n end === 'no-speech' ? ' (nobody started speaking)' : ''\n } — dropping the utterance`,\n );\n }\n this.discard(capture, pcm, end === 'no-speech' ? 'no-speech' : 'silence', vad);\n this.endWithoutRequest();\n return;\n }\n\n this.status('processing');\n try {\n const hints = this.opts.getHints ? await this.opts.getHints() : undefined;\n if (!current()) {\n return;\n }\n const speech = prepareForStt(pcm, MIC_SAMPLE_RATE, { startMs: vad.speechStartMs, endLevel: vad.endLevel });\n vad.stt = { fromMs: speech.fromMs, toMs: speech.toMs, gain: speech.gain };\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: speech recognition gets ${(speech.fromMs / 1000).toFixed(2)}–` +\n `${(speech.toMs / 1000).toFixed(2)} s${speech.gain > 1 ? `, amplified ×${speech.gain}` : ''}`,\n );\n const sttStart = Date.now();\n const text = (\n await this.opts.stt.transcribe(speech.pcm, MIC_SAMPLE_RATE, this.opts.language, hints)\n ).trim();\n const sttMs = Date.now() - sttStart;\n if (!current()) {\n return;\n }\n if (!text) {\n // Speech was heard, so the user waits for an answer: say why none comes. Typically a word in another\n // language than the STT listens in (a German \"Ja\" to a Russian STT comes back empty).\n this.opts.log.info(\n `Voice Q (${this.deviceName}): (empty) — speech recognition returned no text for ${seconds.toFixed(1)} s of audio`,\n );\n this.discard(capture, pcm, 'empty-stt', vad);\n if (capture.answersQuestion) {\n this.questionUntil = Date.now() + CONFIRM_GRACE_MS;\n }\n // No STT_END without text — like Home Assistant, which reports this case as an error only.\n this.endWithoutRequest();\n return;\n }\n this.event(EVENT.STT_END, { text });\n\n this.event(EVENT.INTENT_START);\n const answer = (\n await this.opts.answer(text, {\n device: this.deviceName,\n room: this.room,\n wakeWord: capture.wakeWord,\n sttMs,\n audioMs: Math.round(seconds * 1000),\n // Numbers only, no audio: shows where a request was cut off without keeping recordings.\n vad: { ...vad, levels: levelProfile(pcm, MIC_SAMPLE_RATE) },\n })\n ).trim();\n if (!current()) {\n return;\n }\n const followUp = !!answer && this.opts.expectsFollowUp?.(answer, this.deviceName) === true;\n // Always say it, \"0\" included: ESPHome keeps the flag of the last INTENT_END that carried it, so after\n // one question every later reply re-opened the microphone (field report 2026-11-04). Home Assistant\n // sends \"0\" just the same.\n const conversation = { continue_conversation: followUp ? '1' : '0' };\n this.event(EVENT.INTENT_END, conversation);\n\n if (!answer) {\n this.event(EVENT.RUN_END);\n this.status('idle');\n return;\n }\n\n const ttsStart = Date.now();\n const { pcm: ttsPcm, sampleRate } = await this.opts.tts.synthesize(answer, this.opts.language);\n if (!current()) {\n return;\n }\n this.opts.onSpoken?.(this.deviceName, {\n ms: Date.now() - ttsStart,\n audioMs: (ttsPcm.length / 2 / sampleRate) * 1000,\n });\n const url = await this.publish(ttsPcm, sampleRate);\n if (!current()) {\n return;\n }\n\n this.status('speaking');\n this.event(EVENT.TTS_START, { text: answer });\n this.event(EVENT.TTS_END, { url });\n // linux-voice-assistant reads the flag here (ignoring \"0\"), ESPHome at INTENT_END\n this.event(EVENT.RUN_END, conversation);\n this.questionUntil = followUp\n ? Date.now() + (ttsPcm.length / 2 / sampleRate) * 1000 + FOLLOW_UP_START_MS\n : 0;\n this.armPlaybackTimeout();\n } catch (e) {\n const reason = (e as Error).message;\n this.opts.log.error(`ESPHome ${this.deviceName}: voice pipeline failed — ${reason}`);\n if (run !== this.run) {\n return; // the conversation is over already — nothing to tell the device\n }\n // Without this the device stays ducked and its LED keeps spinning.\n this.event(EVENT.ERROR, { code: 'pipeline-failed', message: reason });\n this.event(EVENT.RUN_END);\n this.status('idle');\n }\n }\n\n /**\n * End a run that produced no request. A RUN_END right after STT_VAD_END gets lost: the firmware is still stopping\n * its microphone then, ignores RUN_END in that state, and afterwards waits for an answer that never comes — the\n * satellite stays in the conversation (field report 2026-11-03). An ERROR event puts it back to idle in any state,\n * so it goes first, with the code Home Assistant uses for this case.\n */\n private endWithoutRequest(): void {\n this.event(EVENT.ERROR, NO_TEXT_ERROR);\n this.event(EVENT.RUN_END);\n this.status('idle');\n }\n\n /**\n * Select which wake words listen on this device. Unknown ids are dropped and the list is trimmed\n * to what the firmware allows, because the device answers a rejected list with silence rather than\n * an error — better to send something valid and report what we changed.\n *\n * The device persists the selection and echoes it back in a `VoiceAssistantConfigurationResponse`,\n * so we ask for one instead of assuming the write took.\n */\n setWakeWords(ids: string[]): void {\n const known = this.wakeWordConfig?.available.map(w => w.id) ?? [];\n const wanted = [...new Set(ids.map(i => i.trim()).filter(Boolean))];\n const unknown = wanted.filter(i => !known.includes(i));\n if (unknown.length) {\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: unknown wake word(s) ${unknown.join(', ')} — ignored. ` +\n `Available: ${known.join(', ') || '(none reported)'}`,\n );\n }\n let valid = wanted.filter(i => known.includes(i));\n const max = this.wakeWordConfig?.max || 0;\n if (max > 0 && valid.length > max) {\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: device allows ${max} active wake word(s), keeping ${valid\n .slice(0, max)\n .join(', ')}`,\n );\n valid = valid.slice(0, max);\n }\n\n const message = new pb.VoiceAssistantSetConfiguration();\n message.setActiveWakeWordsList(valid);\n this.send(message);\n this.opts.log.info(`ESPHome ${this.deviceName}: wake words set to ${valid.join(', ') || '(none)'}`);\n // Read back, so the reported state is the device's and not our guess. The device resolves a\n // custom wake word (and downloads it) while handling the SetConfiguration, so this answer\n // already tells whether that worked.\n this.requestWakeWordConfig(valid);\n }\n\n /**\n * Ask the device for its wake-word configuration. The request always carries the current custom\n * wake words: the firmware replaces its list of offered models with every request, so one sent\n * without them would make an uploaded wake word vanish from the device until the next offer.\n *\n * @param check ids a SetConfiguration just asked for — warned about if the answer lacks them\n */\n requestWakeWordConfig(check: string[] | null = null): void {\n const request = new pb.VoiceAssistantConfigurationRequest();\n const offers = this.opts.externalWakeWords?.() ?? [];\n request.setExternalWakeWordsList(\n offers.map(offer => {\n const w = new pb.VoiceAssistantExternalWakeWord();\n w.setId(offer.id);\n w.setWakeWord(offer.phrase);\n w.setTrainedLanguagesList(offer.languages);\n w.setModelType('micro');\n w.setModelSize(offer.size);\n w.setModelHash(offer.sha256);\n w.setUrl(this.mediaUrl(offer.path));\n return w;\n }),\n );\n // A device that never answers must not let this grow without bound.\n if (this.configChecks.length < 16) {\n this.configChecks.push(check);\n }\n this.send(request);\n }\n\n /** Drop a half-finished capture (device went away, or told us to stop). */\n private abortCapture(): void {\n const capture = this.capture;\n if (!capture) {\n return;\n }\n this.capture = null;\n capture.closed = true;\n clearTimeout(capture.timer);\n clearInterval(capture.stallCheck);\n }\n\n // ── announcements ───────────────────────────────────────────────────────────────────────────────\n\n /**\n * Speak a ready PCM buffer on this device (timers, alarms, `tts.text`, jingles). With\n * `startConversation` the microphone opens once the clip has played, to catch the answer to a question.\n */\n async announce(pcm: Buffer, sampleRate: number, startConversation = false, text = ''): Promise<void> {\n if (!this.online || !pcm.length) {\n return;\n }\n const request = new pb.VoiceAssistantAnnounceRequest();\n request.setMediaId(await this.publish(pcm, sampleRate));\n // What a device with a screen shows while it plays (its on_tts_start)\n request.setText(text);\n request.setPreannounceMediaId('');\n // Needs feature flag 32 (START_CONVERSATION); on a device without it the clip still plays and\n // only the microphone stays shut, so there is nothing to guard here.\n request.setStartConversation(startConversation);\n if (startConversation) {\n // A question: the microphone the device opens after it is wanted, and a button press answers it\n this.ignoreFollowUpUntil = 0;\n this.questionUntil = Date.now() + (pcm.length / 2 / sampleRate) * 1000 + FOLLOW_UP_START_MS;\n }\n this.status('speaking');\n this.send(request);\n this.armPlaybackTimeout();\n }\n\n /** The format replies should have on this device, from what its media player announced. */\n private replyFormat(): ReplyFormat {\n const formats = this.entities\n .list()\n .filter(e => e.kind === 'mediaPlayer')\n .flatMap(e => e.formats ?? []);\n return chooseReplyFormat(formats, !!this.opts.encodeAudio);\n }\n\n /**\n * Publish PCM on the media server, in the format the device plays, and build the URL it should fetch.\n *\n * The host matters: on a multi-homed ioBroker machine the device can usually only reach one of the\n * addresses, and the local end of *this* socket is by definition one it can talk to.\n */\n private async publish(pcm: Buffer, sampleRate: number): Promise<string> {\n let format = this.replyFormat();\n let encoded: { body: Buffer; contentType: string };\n try {\n encoded = await encodeReply(pcm, sampleRate, format, this.opts.encodeAudio);\n } catch (e) {\n // MP3/Opus need ffmpeg. Without it a native format is the only chance, whether the device lists it or not.\n const fallback: ReplyFormat = { ...format, codec: 'flac', source: `${format.source}, FLAC as fallback` };\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: cannot write the reply as ${format.codec.toUpperCase()} ` +\n `(${(e as Error).message}) — sending FLAC, which the device may not play. Install ffmpeg.`,\n );\n format = fallback;\n encoded = await encodeReply(pcm, sampleRate, format);\n }\n const key = `${format.codec}/${format.sampleRate}/${format.channels}`;\n if (key !== this.loggedFormat) {\n this.loggedFormat = key;\n const what = !format.source\n ? 'WAV (the device lists no formats)'\n : `${format.codec.toUpperCase()}${format.sampleRate ? ` ${format.sampleRate} Hz` : ''}` +\n `${format.channels === 2 ? ' stereo' : ''} (device: ${format.source})`;\n this.opts.log.info(`ESPHome ${this.deviceName}: spoken replies as ${what}`);\n }\n return this.mediaUrl(this.opts.media.publish(encoded.body, encoded.contentType));\n }\n\n /** Absolute URL of a path on the media server, with a host this device can reach. */\n private mediaUrl(path: string): string {\n const local = (this.socket?.localAddress || '').replace(/^::ffff:/, '');\n const host = this.opts.mediaHost?.trim() || local || '127.0.0.1';\n // An IPv6 literal has to be bracketed in a URL.\n const authority = host.includes(':') ? `[${host}]` : host;\n return `http://${authority}:${this.opts.media.port}${path}`;\n }\n\n /** Fall back to `idle` if the device never reports that it finished playing. */\n private armPlaybackTimeout(): void {\n if (this.playbackTimer) {\n clearTimeout(this.playbackTimer);\n }\n this.playbackTimer = setTimeout(() => {\n this.playbackTimer = null;\n this.status('idle');\n }, PLAYBACK_TIMEOUT_MS);\n this.playbackTimer.unref();\n }\n\n private event(type: number, data?: Record<string, string>): void {\n if (type === EVENT.RUN_START) {\n this.runOpen = true;\n } else if (type === EVENT.RUN_END) {\n this.runOpen = false;\n } else if (type === EVENT.ERROR) {\n this.errorSentAt = Date.now();\n }\n const message = new pb.VoiceAssistantEventResponse();\n message.setEventType(type);\n const items: VoiceAssistantEventData[] = [];\n for (const [name, value] of Object.entries(data || {})) {\n const item = new pb.VoiceAssistantEventData();\n item.setName(name);\n item.setValue(value);\n items.push(item);\n }\n message.setDataList(items);\n this.send(message);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"esphome.js","sourceRoot":"","sources":["../../../src/lib/voice/esphome.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ESPHome voice satellites — the fourth transport, next to the UDP server (`voiceServer.ts`) and the\n * Wyoming endpoint (`wyoming.ts`).\n *\n * Unlike those two, this one is a **client**: an ESPHome voice satellite is a *server* that waits on\n * TCP 6053 for the home-automation controller to connect and drive it. We therefore dial out to each\n * configured device and play the role Home Assistant normally plays. That covers the ThirdReality\n * Voice & Music Assistant (Dev Edition), the Home Assistant Voice PE and any box running\n * OHF-Voice/linux-voice-assistant.\n *\n * Flow for one utterance (verified against the firmware's `src/satellite/Satellite.cpp`):\n *\n * device → VoiceAssistantRequest{start, wake_word_phrase} wake word fired on the device\n * we → VoiceAssistantResponse{port:0} 0 = audio over the API, no UDP\n * we → RUN_START, WAKE_WORD_END, STT_START, STT_VAD_START\n * device → VoiceAssistantAudio … 16 kHz mono s16le, *until told to stop*\n * we → STT_VAD_END ← the device has no VAD of its own\n * we → STT_END{text}, INTENT_START, INTENT_END, TTS_START{text}, TTS_END{url}, RUN_END\n * device → fetches the URL over HTTP, plays it, VoiceAssistantAnnounceFinished\n *\n * Two consequences shape this file: end-of-speech detection is ours (`vad.ts`), and the spoken reply\n * has to be reachable over HTTP (`mediaServer.ts`) rather than streamed down the socket.\n */\nimport * as net from 'node:net';\nimport {\n pb,\n encode,\n decode,\n type PbMessage,\n type AuthenticationResponse,\n type DeviceInfoResponse,\n type HelloResponse,\n type VoiceAssistantAnnounceFinished,\n type VoiceAssistantAudio,\n type VoiceAssistantConfigurationResponse,\n type VoiceAssistantEventData,\n type VoiceAssistantRequestMsg,\n} from './esphomeProto';\nimport { EntityRegistry, isEntityStateMessage, isListEntityMessage, type EsphomeEntity } from './esphomeEntities';\nimport { SpeechDetector, type CaptureEnd, type Bytes, type VadReport } from './vad';\nimport { prepareForStt } from './speechAudio';\nimport { chooseReplyFormat, encodeReply, type ExternalEncoder, type ReplyFormat } from './replyFormat';\nimport { levelProfile, type DiscardedCapture, type DiscardReason } from './captures';\nimport type { SttEngine } from './stt';\nimport type { TtsEngine } from './tts';\nimport type { SatelliteState } from './protocol';\n\n/** `VoiceAssistantEvent` (api.proto) — the subset we emit. */\nconst EVENT = {\n ERROR: 0,\n RUN_START: 1,\n RUN_END: 2,\n STT_START: 3,\n STT_END: 4,\n INTENT_START: 5,\n INTENT_END: 6,\n TTS_START: 7,\n TTS_END: 8,\n WAKE_WORD_END: 10,\n STT_VAD_START: 11,\n STT_VAD_END: 12,\n} as const;\n\n/** `SubscribeVoiceAssistantRequest.flags`: audio over the API socket instead of a UDP side channel. */\nconst SUBSCRIBE_API_AUDIO = 1;\n/** ESPHome voice satellites always capture at 16 kHz mono 16-bit. */\nconst MIC_SAMPLE_RATE = 16000;\n/**\n * Leading audio to keep out of the end-of-speech analysis. These devices acknowledge the wake word\n * with a chirp through their own speaker and hear it back on their own microphone, far louder than\n * the speech that follows. Without this the chirp alone satisfies the detector's speech test — so\n * `sawSpeech` stops meaning \"somebody said something\" and a false wake is billed to STT — and it\n * drags the noise floor up with it.\n *\n * Measured over four captures from a ThirdReality Voice & Music Assistant (RMS per 50 ms, remarkably\n * repeatable across all four):\n *\n * ms 0 50 100 150 200 250 300 350 400 450 500 550 600\n * rms ~20 ~900 ~11k ~19k ~14k ~1.3k ~990 ~780 ~610 ~370 ~330 ~165 ~180\n *\n * so the chirp is still above the gate at 500 ms and only clears it around 550–600. 600 ms is the\n * smallest value that rejects a chirp-only wake while still detecting the speech in every one of the\n * four captures, with no change to when the utterance closes. Only the analysis skips it: STT gets the audio\n * from 400 ms before the detected speech (`speechAudio.ts`), so a speaker who starts inside this window loses\n * nothing but a late gate open.\n */\nconst WAKE_CHIRP_MS = 600;\n/** Default API port of an ESPHome device. */\nconst DEFAULT_PORT = 6053;\n/** Keepalive interval; two missed replies count as a dead link. */\nconst PING_INTERVAL_MS = 20_000;\n/** Wait between reconnect attempts. Devices reboot, and a Wi-Fi speaker drops off now and then. */\nconst RECONNECT_MS = 10_000;\n/** Give up on a pipeline that produced no audio at all (device wedged mid-stream). */\nconst PIPELINE_TIMEOUT_MS = 30_000;\n/** How long we wait for the device to report that it finished playing before forcing it back to idle. */\nconst PLAYBACK_TIMEOUT_MS = 60_000;\n/**\n * Default lowest RMS that counts as speech (the noise floor can only raise the gate above it). Fits the\n * ThirdReality speaker; quieter microphones get their own value per device ({@link EsphomeDevice.speechLevel}).\n */\nexport const DEFAULT_SPEECH_LEVEL = 250;\n/**\n * Close the microphone when nobody has started speaking this long after the wake word. Without it a false wake\n * kept the stream open for the full 12 s cap: on a ThirdReality speaker with a custom wake word that was ten\n * times in one night, each 12.6 s of an open mic (and of music ducked, if any played).\n */\nconst NO_SPEECH_MS = 5000;\n/** The same after a follow-up question re-opened the mic: the user may need a moment to think. */\nconst NO_SPEECH_FOLLOW_UP_MS = 8000;\n/** Silence that ends an utterance when the configuration leaves it empty. */\nconst DEFAULT_SILENCE_MS = 900;\n/**\n * After this much speech a pause may be {@link LONG_PAUSE_FACTOR} times as long before the utterance ends: whoever\n * talks that long is dictating a request and pauses to think, while \"Licht an\" should still close quickly. Field\n * report 2026-11-03: \"Я хочу, чтоб ты создал задачу, чтобы утром говорить мне…\" was cut off right there.\n */\nconst LONG_REQUEST_MS = 2500;\nconst LONG_PAUSE_FACTOR = 1.5;\n/**\n * Sound needed before a loud moment counts as speech. On vitanova (2026-11-03) a single 100 ms sound at RMS 197\n * after a false wake opened the gate (threshold 150), and Whisper made \"и все просят.\" of the amplified silence\n * around it. The shortest real answer, \"да\", lasts about 250 ms.\n */\nconst MIN_SPEECH_MS = 200;\n/**\n * Close the utterance when the device stops sending audio without ending the stream. Seen on a ThirdReality\n * speaker: the audio stopped after 2.7 s, and the satellite showed \"listening\" for the 30 s of\n * {@link PIPELINE_TIMEOUT_MS}. A device streams every few tens of ms while the mic is open.\n */\nconst STREAM_STALL_MS = 2000;\n/** The same before the first audio arrives: a device needs a moment to open the microphone. */\nconst STREAM_START_MS = 5000;\n/** How often a running capture checks for a stalled stream. */\nconst STALL_CHECK_MS = 250;\n/** Silence threshold as a share of the speech threshold — keeps the default pair 250/150. */\nconst SILENCE_SHARE = 0.6;\n/**\n * The firmware answers an ERROR event with a stop request of its own (`signal_stop_`). One arriving this soon after\n * our error belongs to it and needs no reply — the run is already over.\n */\nconst ERROR_ECHO_MS = 2000;\n/**\n * What ends a run that produced no request. Home Assistant sends the same code when the speech recognition finds no\n * text, and the Voice PE firmware deliberately plays no error sound for it.\n */\nconst NO_TEXT_ERROR = { code: 'stt-no-text-recognized', message: 'No text recognized' };\n/**\n * A dropped utterance whose loudest frame reached this share of the speech threshold was probably a voice\n * that was too quiet, not an empty room — worth telling the user where to lower the threshold.\n */\nconst QUIET_VOICE_SHARE = 0.4;\n/**\n * Event entity of a satellite with a screen: the user answered the open question by touch, event type `yes` or `no`.\n * Pressing it is the same as saying \"yes\"/\"no\" into the open microphone — no speech recognition to get it wrong\n * (a German \"Ja\" came back as \"Я\" once).\n */\nconst CONFIRM_ENTITY = 'confirm_answer';\n/** Select entity of a satellite with a screen: the language of the date and the hints it shows. */\nconst DISPLAY_LANGUAGE_ENTITY = 'display_language';\n/**\n * After a reply that asks something: how long, beyond the reply's own length, the question stays open — the next\n * pipeline the device starts answers it, and so does a yes/no button press. Answering it (by voice or button) closes\n * it earlier. The wake word phrase cannot tell a follow-up from a new request: ESPHome sends the phrase of the last\n * wake word with every request, the follow-up microphone included (field report 2026-11-05).\n */\nconst QUESTION_OPEN_MS = 30_000;\n/**\n * A button press still answers the question this long after the follow-up microphone closed: the firmware may stop\n * the microphone on the press before it reports which button it was.\n */\nconst CONFIRM_GRACE_MS = 3000;\n/**\n * After a button answer: a follow-up microphone the device opens this soon was asked for by the question the button\n * already answered, and is closed at once (unless our reply asked something again).\n */\nconst IGNORE_FOLLOW_UP_MS = 15_000;\n\n/** \"Yes\" and \"no\" as a button answer is passed on: the words of the satellite's language, which pi-agent also takes. */\nconst YES_NO: Record<string, [yes: string, no: string]> = {\n en: ['Yes', 'No'],\n de: ['Ja', 'Nein'],\n ru: ['Да', 'Нет'],\n pt: ['Sim', 'Não'],\n nl: ['Ja', 'Nee'],\n fr: ['Oui', 'Non'],\n it: ['Sì', 'No'],\n es: ['Sí', 'No'],\n pl: ['Tak', 'Nie'],\n uk: ['Так', 'Ні'],\n zh: ['是', '不'],\n};\n\n/** The word a yes/no button stands for in `language` (ISO 639-1, `zh-cn` too); English for an unknown one. */\nexport function yesNoWord(language: string, yes: boolean): string {\n const base = (language || 'en').trim().toLowerCase().split(/[-_]/)[0];\n return (YES_NO[base] ?? YES_NO.en)[yes ? 0 : 1];\n}\n\n/** The event type of a {@link CONFIRM_ENTITY} as yes (true) or no (false); null for anything else. */\nexport function confirmAnswerOf(eventType: unknown): boolean | null {\n const type = typeof eventType === 'string' ? eventType.trim().toLowerCase() : '';\n if (type === 'yes' || type === 'confirm') {\n return true;\n }\n if (type === 'no' || type === 'cancel') {\n return false;\n }\n return null;\n}\n\n/**\n * Names of the adapter's languages in that language, for a display-language select. `Intl.DisplayNames` covers the\n * rest, but a Node.js built with only English ICU data knows no \"Deutsch\" or \"Русский\".\n */\nconst NATIVE_LANGUAGE_NAMES: Record<string, string> = {\n en: 'english',\n de: 'deutsch',\n ru: 'русский',\n pt: 'português',\n nl: 'nederlands',\n fr: 'français',\n it: 'italiano',\n es: 'español',\n pl: 'polski',\n uk: 'українська',\n zh: '中文',\n};\n\n/**\n * The option of a display-language select that means `language`: its name in that language (\"Deutsch\"), in English\n * (\"German\") or its code (\"de\", \"de-DE\"), case ignored. Null when the device offers none of them.\n */\nexport function displayLanguageOption(options: string[], language: string): string | null {\n const code = (language || '').trim().toLowerCase();\n const base = code.split(/[-_]/)[0];\n if (!base) {\n return null;\n }\n const names = new Set<string>([code, base]);\n if (NATIVE_LANGUAGE_NAMES[base]) {\n names.add(NATIVE_LANGUAGE_NAMES[base]);\n }\n for (const locale of [base, 'en']) {\n try {\n const name = new Intl.DisplayNames([locale], { type: 'language' }).of(base);\n if (name) {\n names.add(name.toLocaleLowerCase(locale));\n }\n } catch {\n /* not a language code Intl knows */\n }\n }\n const norm = (option: string): string => option.trim().toLocaleLowerCase();\n return (\n options.find(o => names.has(norm(o))) ??\n options.find(o => norm(o).split(/[-_]/)[0] === base && /^[a-z]{2,3}([-_][a-z0-9]+)?$/.test(norm(o))) ??\n null\n );\n}\n\n/** The configured speech threshold of a device, or 0 for the default. Table cells may arrive as strings. */\nexport function speechLevelOf(device: EsphomeDevice): number {\n const level = Math.round(Number(device.speechLevel));\n return Number.isFinite(level) && level > 0 ? level : 0;\n}\n\n/** How a configured device is identified: `ip`, or `ip:port` when it does not use the default port. */\nexport function esphomeAddress(device: Pick<EsphomeDevice, 'ip' | 'port'>): string {\n const ip = (device.ip || '').trim().toLowerCase();\n const port = Number(device.port) || DEFAULT_PORT;\n return port === DEFAULT_PORT ? ip : `${ip}:${port}`;\n}\n\nexport interface EsphomeDevice {\n /** Host name or IP of the satellite. */\n ip: string;\n /** API port; empty/0 → 6053. */\n port?: number | string;\n /** API password, if one is configured on the device. */\n password?: string;\n /** Room this satellite belongs to (drives `satellites.<room>.*` and the answer context). */\n room?: string;\n /**\n * Lowest RMS that counts as speech on this device (empty/0 → {@link DEFAULT_SPEECH_LEVEL}). Microphone\n * levels differ a lot: a ThirdReality speaker hears normal speech at RMS 350–470, a phone running a\n * satellite app at under 200, so one fixed floor cannot fit both.\n */\n speechLevel?: number | string | null;\n}\n\nexport interface EsphomeSatellitesOptions {\n devices: EsphomeDevice[];\n /** ISO-639-1 language hint for STT/TTS ('' = auto/provider default). */\n language: string;\n stt: SttEngine;\n tts: TtsEngine;\n /**\n * Produce the assistant reply for a transcribed utterance. `audioMs` is the length of the recording,\n * `vad` what the voice activity detection made of it (both for the request journal). An answer given with the\n * device's yes/no button ({@link CONFIRM_ENTITY}) comes as the yes or no word, with `button` and no recording.\n */\n answer: (\n question: string,\n ctx: {\n device: string;\n room: string;\n /** Wake word of the recording; '' = the mic was re-opened for a follow-up; absent for a button. */\n wakeWord?: string;\n sttMs?: number;\n audioMs?: number;\n vad?: VadReport;\n button?: 'yes' | 'no';\n },\n ) => Promise<string>;\n /** The reply was synthesised: how long that took and how long it plays (for the request journal). */\n onSpoken?: (device: string, info: { ms: number; audioMs: number }) => void;\n /** Optional STT vocabulary hints (device/room names) to bias recognition; re-read per utterance. */\n getHints?: () => string[] | Promise<string[]>;\n /** Where spoken replies are published for the device to fetch. */\n media: MediaHost;\n /**\n * Host the device should call back on. Empty → the local address of our socket to that device,\n * which is automatically the right interface on a multi-homed host.\n */\n mediaHost?: string;\n /** Silence that ends an utterance, in ms ('' / 0 → the detector default). */\n silenceMs?: number;\n log: ioBroker.Logger;\n /**\n * Notified on every satellite state transition (idle/listening/processing/speaking/offline). `host` is the\n * configured address (`ip`, or `ip:port` for another port than 6053), so the adapter can tell which table row\n * a satellite belongs to.\n */\n onStatus?: (device: string, room: string, state: SatelliteState | 'offline', host: string) => void;\n /**\n * Writes replies as MP3 or Opus, for a media player that takes nothing else (ffmpeg in the adapter). Without it\n * such a device gets FLAC or WAV if it lists one of them, and a warning otherwise.\n */\n encodeAudio?: ExternalEncoder;\n /** Notified with the device's wake-word configuration, on connect and after every change. */\n onWakeWords?: (device: string, room: string, config: WakeWordConfig) => void;\n /** Notified once per connect with everything the device exposes besides the voice pipeline. */\n onEntities?: (device: string, room: string, entities: EsphomeEntity[]) => void;\n /** Notified whenever one of those entities changes (and once per entity right after connecting). */\n onEntityState?: (device: string, room: string, entity: EsphomeEntity) => void;\n /** True when the reply asks something back, so the device should re-open its mic without a wake word. */\n expectsFollowUp?: (answer: string, device: string) => boolean;\n /**\n * A recording that never became a request: dropped as silence, or returned empty by the speech recognition.\n * For diagnosis (the adapter stores it when asked to); absent → nothing is kept.\n */\n onDiscarded?: (capture: DiscardedCapture) => void;\n /**\n * Custom wake words to offer the devices, re-read for every configuration request. The device lists\n * them next to its own and downloads one (from the media server) only when it is selected.\n */\n externalWakeWords?: () => ExternalWakeWordOffer[];\n}\n\n/** A custom wake word as offered to the devices; the files are on the media server under `path`. */\nexport interface ExternalWakeWordOffer {\n id: string;\n phrase: string;\n languages: string[];\n /** Size of the `.tflite` in bytes. */\n size: number;\n /** SHA-256 of the `.tflite`, lower-case hex. */\n sha256: string;\n /** URL path of the JSON config, e.g. `/wakeword/hey_hannah_1a2b3c4d.json`; the model sits next to it. */\n path: string;\n}\n\n/** What a device reports about its wake words: what the firmware ships plus the custom ones we offered. */\nexport interface WakeWordConfig {\n /** Ids currently listening, e.g. `['okay_nabu']`. */\n active: string[];\n /** Every wake word the device can use, with the spoken phrase and the languages it was trained on. */\n available: { id: string; phrase: string; languages: string[] }[];\n /** How many may listen at once — 2 on the ThirdReality speaker, which has a sensitivity per slot. */\n max: number;\n}\n\n/** `VoiceAssistantTimerEvent` in api.proto. */\nexport const TIMER_EVENT = { started: 0, updated: 1, cancelled: 2, finished: 3 } as const;\n\n/** One assistant timer, as the device wants to hear about it. */\nexport interface TimerEvent {\n type: keyof typeof TIMER_EVENT;\n id: string;\n name: string;\n totalSeconds: number;\n secondsLeft: number;\n /** False once it has finished or been cancelled — the device clears its ring on that. */\n active: boolean;\n}\n\n/** The slice of `MediaServer` this module needs (kept narrow so tests can pass a stub). */\nexport interface MediaHost {\n port: number;\n publish(body: Buffer, contentType?: string, ttlMs?: number): string;\n}\n\n/**\n * All configured ESPHome satellites. Owns one connection per device and offers the same surface the\n * adapter already uses for the UDP server: `devices()` and `announce()`.\n */\nexport class EsphomeSatellites {\n private readonly connections: EsphomeConnection[] = [];\n\n constructor(private readonly opts: EsphomeSatellitesOptions) {}\n\n async start(): Promise<void> {\n for (const device of this.opts.devices) {\n if (!device.ip?.trim()) {\n continue;\n }\n const connection = new EsphomeConnection(device, this.opts);\n this.connections.push(connection);\n connection.start();\n }\n if (!this.connections.length) {\n this.opts.log.warn('ESPHome satellites enabled, but no device addresses are configured.');\n }\n return Promise.resolve();\n }\n\n async stop(): Promise<void> {\n await Promise.all(this.connections.map(c => c.stop()));\n this.connections.length = 0;\n }\n\n /** Device names of the satellites currently connected. */\n devices(): string[] {\n return this.connections.filter(c => c.online).map(c => c.deviceName);\n }\n\n /** Wake-word configuration of one connected satellite, or null if it is unknown/offline. */\n wakeWords(device: string): WakeWordConfig | null {\n return this.connections.find(c => c.online && c.deviceName === device)?.wakeWordConfig ?? null;\n }\n\n /**\n * Choose which wake words listen on one satellite. Ids come from {@link WakeWordConfig.available};\n * the device stores the selection itself, so it survives a restart of the adapter.\n */\n setWakeWords(device: string, ids: string[]): boolean {\n const target = this.connections.find(c => c.online && c.deviceName === device);\n if (!target) {\n return false;\n }\n target.setWakeWords(ids);\n return true;\n }\n\n /**\n * Offer the current custom wake words to every connected satellite again — after one was uploaded\n * or deleted. Each device answers with its new configuration (→ `onWakeWords`).\n */\n refreshWakeWords(): number {\n const online = this.connections.filter(c => c.online);\n online.forEach(c => c.requestWakeWordConfig());\n return online.length;\n }\n\n /** Everything one satellite exposes besides the voice pipeline (gain, noise suppression, …). */\n entities(device: string): EsphomeEntity[] {\n return this.connections.find(c => c.online && c.deviceName === device)?.entities.list() ?? [];\n }\n\n /**\n * Write one of those entities. Returns false when the satellite is offline, the entity is unknown\n * or read-only, or the value is not one the device accepts.\n */\n setEntity(device: string, objectId: string, value: unknown): boolean {\n const target = this.connections.find(c => c.online && c.deviceName === device);\n return target ? target.setEntity(objectId, value) : false;\n }\n\n /**\n * Mirror an assistant timer onto the satellites so they can show it on their own LED ring and ring\n * it themselves. `device` null broadcasts. Returns how many devices were told.\n */\n timerEvent(device: string | null, event: TimerEvent): number {\n const targets = this.connections.filter(c => c.online && (!device || c.deviceName === device));\n targets.forEach(c => c.sendTimerEvent(event));\n return targets.length;\n }\n\n /**\n * Play a ready PCM buffer on one satellite (by device name) or all of them. Returns how many\n * devices it was handed to.\n *\n * With `startConversation` the device opens its microphone as soon as the clip has played, without\n * a wake word — that is how a question gets its answer (see `PendingQuestions`).\n */\n async announce(device: string | null, pcm: Buffer, sampleRate: number, startConversation = false): Promise<number> {\n const targets = this.connections.filter(c => c.online && (!device || c.deviceName === device));\n if (!targets.length) {\n return 0;\n }\n await Promise.all(\n targets.map(c =>\n c\n .announce(pcm, sampleRate, startConversation)\n .catch(e => this.opts.log.warn(`announce to ${c.deviceName} failed: ${(e as Error).message}`)),\n ),\n );\n return targets.length;\n }\n}\n\n/** State of the utterance currently being captured. */\ninterface Capture {\n chunks: Buffer[];\n detector: SpeechDetector;\n conversationId: string;\n /** Wake word that opened this capture; '' when the mic was re-opened for a follow-up/question. */\n wakeWord: string;\n /** The mic was re-opened for a reply that asked something: a yes/no button press answers it too. */\n answersQuestion: boolean;\n timer: NodeJS.Timeout;\n /** Watches for a device that stops sending audio without ending the stream. */\n stallCheck: NodeJS.Timeout;\n startedAt: number;\n /** When the last audio arrived; 0 = none yet. */\n lastAudioAt: number;\n closed: boolean;\n}\n\n/** One satellite: socket lifecycle, handshake, and the voice pipeline. */\nclass EsphomeConnection {\n /** Device name as reported by the device; falls back to its address until the handshake answers. */\n deviceName: string;\n online = false;\n /** Last wake-word configuration the device reported; null until the handshake answers. */\n wakeWordConfig: WakeWordConfig | null = null;\n /**\n * One entry per configuration request in flight, in send order (the device answers each one, in\n * order): the ids a preceding `SetConfiguration` asked for, or null. The read-back is the only\n * failure signal the device gives.\n */\n private configChecks: (string[] | null)[] = [];\n /** Everything else the device exposes — rebuilt from scratch on every reconnect. */\n readonly entities = new EntityRegistry();\n\n private readonly host: string;\n private readonly port: number;\n private readonly room: string;\n\n private socket: net.Socket | null = null;\n private rx: Bytes = Buffer.alloc(0);\n private pingTimer: NodeJS.Timeout | null = null;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private missedPings = 0;\n private stopping = false;\n private capture: Capture | null = null;\n private playbackTimer: NodeJS.Timeout | null = null;\n private readonly password: string;\n /** Configured speech threshold, 0 = {@link DEFAULT_SPEECH_LEVEL}. */\n private readonly speechLevel: number;\n /** `ip`, or `ip:port` for another port than the default — how the adapter recognises the table row. */\n private readonly address: string;\n /** The device's friendly name, for entities without a name of their own. */\n private friendlyName = '';\n /**\n * Number of the current pipeline run. A run whose number is no longer current was ended — the device asked to\n * stop, started over, or went away — and whatever STT, answer or TTS is still in flight for it stays silent.\n */\n private run = 0;\n /** From RUN_START until we sent RUN_END: the device waits for that RUN_END. */\n private runOpen = false;\n /** When we last sent an ERROR event (see {@link ERROR_ECHO_MS}). */\n private errorSentAt = 0;\n /** The reply format last reported in the log, to log it again only when it changes. */\n private loggedFormat = '';\n /**\n * The last reply asked something (`continue_conversation`, or an announcement with `start_conversation`): until\n * when the next request of the device, or a yes/no button press, answers it. 0 = no open question.\n */\n private questionUntil = 0;\n /** After a button answer: until when a follow-up microphone is the stale one of the answered question. */\n private ignoreFollowUpUntil = 0;\n /** When a yes/no button press last answered a question. */\n private buttonAt = 0;\n /** When the device last asked to stop (`VoiceAssistantRequest{start:false}`). */\n private stoppedAt = 0;\n /** The display language was compared with ours since the last connect. */\n private displayLanguageChecked = false;\n\n constructor(\n device: EsphomeDevice,\n private readonly opts: EsphomeSatellitesOptions,\n ) {\n this.host = device.ip.trim();\n this.port = Number(device.port) || DEFAULT_PORT;\n this.room = (device.room || '').trim();\n this.password = device.password || '';\n this.speechLevel = speechLevelOf(device);\n this.address = esphomeAddress(device);\n this.deviceName = this.host;\n }\n\n // ── lifecycle ───────────────────────────────────────────────────────────────────────────────────\n\n start(): void {\n this.connect();\n }\n\n async stop(): Promise<void> {\n this.stopping = true;\n this.clearTimers();\n this.abortCapture();\n const socket = this.socket;\n this.socket = null;\n if (socket) {\n try {\n socket.write(encode(new pb.DisconnectRequest()));\n } catch {\n /* socket already gone — nothing to say goodbye on */\n }\n socket.destroy();\n }\n this.setOffline();\n return Promise.resolve();\n }\n\n private connect(): void {\n if (this.stopping) {\n return;\n }\n this.rx = Buffer.alloc(0);\n this.missedPings = 0;\n // The device re-announces everything after a reconnect, and the keys are not stable across\n // reboots, so starting from a clean slate is the only safe option.\n this.entities.clear();\n this.configChecks = [];\n this.displayLanguageChecked = false;\n\n const socket = net.createConnection({ host: this.host, port: this.port }, () => {\n this.opts.log.debug(`ESPHome ${this.host}:${this.port} connected`);\n this.handshake();\n });\n this.socket = socket;\n socket.setNoDelay(true);\n\n socket.on('data', data => this.onData(data));\n socket.on('error', e => {\n // A satellite that is switched off is normal, so this is not an error-level event.\n this.opts.log.debug(`ESPHome ${this.host}: ${e.message}`);\n });\n socket.on('close', () => {\n if (this.socket === socket) {\n this.socket = null;\n this.onDisconnected();\n }\n });\n }\n\n private onDisconnected(): void {\n this.clearTimers();\n this.abortCapture();\n // A reply still being worked out must not land on the next connection, in the middle of another run.\n this.run++;\n this.runOpen = false;\n this.questionUntil = 0;\n this.ignoreFollowUpUntil = 0;\n if (this.online) {\n this.opts.log.info(`ESPHome satellite offline: ${this.deviceName}`);\n }\n this.setOffline();\n this.scheduleReconnect();\n }\n\n private scheduleReconnect(): void {\n if (this.stopping || this.reconnectTimer) {\n return;\n }\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, RECONNECT_MS);\n this.reconnectTimer.unref();\n }\n\n private clearTimers(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n }\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.playbackTimer) {\n clearTimeout(this.playbackTimer);\n this.playbackTimer = null;\n }\n }\n\n private setOffline(): void {\n if (this.online) {\n this.online = false;\n this.opts.onStatus?.(this.deviceName, this.room, 'offline', this.address);\n }\n }\n\n private status(state: SatelliteState): void {\n this.opts.onStatus?.(this.deviceName, this.room, state, this.address);\n }\n\n // ── protocol plumbing ───────────────────────────────────────────────────────────────────────────\n\n private send(message: PbMessage): void {\n const socket = this.socket;\n if (!socket || socket.destroyed) {\n return;\n }\n try {\n socket.write(encode(message));\n } catch (e) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: send failed — ${(e as Error).message}`);\n }\n }\n\n private onData(data: Buffer): void {\n this.rx = this.rx.length ? Buffer.concat([this.rx, data]) : data;\n let frames;\n try {\n ({ frames, rest: this.rx } = decode(this.rx));\n } catch (e) {\n this.opts.log.error(`ESPHome ${this.deviceName}: ${(e as Error).message}`);\n this.socket?.destroy();\n return;\n }\n for (const frame of frames) {\n if (frame.error) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: cannot parse ${frame.name}`);\n continue;\n }\n if (!frame.name || !frame.message) {\n continue; // unknown id — already skipped by its declared length\n }\n try {\n this.onMessage(frame.name, frame.message);\n } catch (e) {\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: ${frame.name} handler failed — ${(e as Error).message}`,\n );\n }\n }\n }\n\n private handshake(): void {\n const hello = new pb.HelloRequest();\n hello.setClientInfo('ioBroker.assistant');\n hello.setApiVersionMajor(1);\n hello.setApiVersionMinor(10);\n this.send(hello);\n\n const auth = new pb.AuthenticationRequest();\n auth.setPassword(this.password);\n this.send(auth);\n\n this.send(new pb.DeviceInfoRequest());\n // Ask for the entity announcements *before* subscribing to their states: a state message whose\n // entity we have not seen yet has nothing to attach to and is dropped.\n this.send(new pb.ListEntitiesRequest());\n this.send(new pb.SubscribeStatesRequest());\n\n const subscribe = new pb.SubscribeVoiceAssistantRequest();\n subscribe.setSubscribe(true);\n subscribe.setFlags(SUBSCRIBE_API_AUDIO);\n this.send(subscribe);\n\n this.requestWakeWordConfig();\n\n this.pingTimer = setInterval(() => {\n if (++this.missedPings > 2) {\n this.opts.log.info(`ESPHome ${this.deviceName}: no reply to keepalive — reconnecting`);\n this.socket?.destroy();\n return;\n }\n this.send(new pb.PingRequest());\n }, PING_INTERVAL_MS);\n this.pingTimer.unref();\n }\n\n private onMessage(name: string, message: unknown): void {\n switch (name) {\n case 'HelloResponse': {\n const hello = message as HelloResponse;\n this.opts.log.debug(\n `ESPHome ${this.host}: ${hello.getServerInfo()} (API ${hello.getApiVersionMajor()}.${hello.getApiVersionMinor()})`,\n );\n return;\n }\n\n case 'AuthenticationResponse':\n if ((message as AuthenticationResponse).getInvalidPassword()) {\n this.opts.log.error(\n `ESPHome ${this.host}: API password rejected — check the device's password in the settings.`,\n );\n this.socket?.destroy();\n }\n return;\n\n case 'DeviceInfoResponse': {\n const info = message as DeviceInfoResponse;\n this.deviceName = info.getName() || this.host;\n this.friendlyName = info.getFriendlyName?.() || info.getName() || '';\n this.online = true;\n this.opts.log.info(\n `ESPHome satellite online: ${this.deviceName} (${info.getModel()}) @ ${this.host}${this.room ? `, room ${this.room}` : ''}`,\n );\n this.status('idle');\n return;\n }\n\n case 'VoiceAssistantConfigurationResponse': {\n const config = message as VoiceAssistantConfigurationResponse;\n // A custom wake word the device already downloaded is listed twice: once from its own\n // model folder and once from our offer.\n const seen = new Set<string>();\n this.wakeWordConfig = {\n active: config.getActiveWakeWordsList(),\n available: config\n .getAvailableWakeWordsList()\n .map(w => ({\n id: w.getId(),\n phrase: w.getWakeWord(),\n languages: w.getTrainedLanguagesList(),\n }))\n .filter(w => !seen.has(w.id) && !!seen.add(w.id)),\n max: config.getMaxActiveWakeWords(),\n };\n const active = this.wakeWordConfig.active.join(', ') || '(none active)';\n const available = this.wakeWordConfig.available.map(w => w.id);\n this.opts.log.info(\n `ESPHome ${this.deviceName}: wake words ${active}${available.length ? ` (available: ${available.join(', ')})` : ''}`,\n );\n const requested = this.configChecks.shift();\n const missing = requested?.filter(id => !this.wakeWordConfig?.active.includes(id)) ?? [];\n if (missing.length) {\n // The device answers a model it cannot fetch or load with silence, not an error.\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: could not activate wake word(s) ${missing.join(', ')}. ` +\n `For an uploaded wake word the device must reach ${this.mediaUrl('/')} and the model ` +\n `must be a microWakeWord .tflite.`,\n );\n }\n this.opts.onWakeWords?.(this.deviceName, this.room, this.wakeWordConfig);\n return;\n }\n\n case 'VoiceAssistantRequest':\n this.onPipelineRequest(message as VoiceAssistantRequestMsg);\n return;\n\n case 'VoiceAssistantAudio':\n this.onAudio(message as VoiceAssistantAudio);\n return;\n\n case 'VoiceAssistantAnnounceFinished':\n if (this.playbackTimer) {\n clearTimeout(this.playbackTimer);\n this.playbackTimer = null;\n }\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: playback finished (success=${(message as VoiceAssistantAnnounceFinished).getSuccess()})`,\n );\n this.status('idle');\n return;\n\n case 'PingRequest':\n this.send(new pb.PingResponse());\n return;\n\n case 'PingResponse':\n this.missedPings = 0;\n return;\n\n case 'GetTimeRequest': {\n // The device has no RTC and syncs its clock from us — its timer ring depends on it.\n const time = new pb.GetTimeResponse();\n time.setEpochSeconds(Math.floor(Date.now() / 1000));\n this.send(time);\n return;\n }\n\n case 'DisconnectRequest':\n this.send(new pb.DisconnectResponse());\n this.socket?.destroy();\n return;\n\n case 'ListEntitiesDoneResponse': {\n const list = this.entities.list();\n if (list.length) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${list.length} entities — ${list.map(e => e.objectId).join(', ')}`,\n );\n }\n this.opts.onEntities?.(this.deviceName, this.room, list);\n return;\n }\n\n default:\n if (isListEntityMessage(name)) {\n this.entities.addFromAnnouncement(name, message, this.friendlyName);\n } else if (isEntityStateMessage(name)) {\n const entity = this.entities.applyState(name, message);\n if (entity) {\n this.opts.onEntityState?.(this.deviceName, this.room, entity);\n this.onEntityChange(entity);\n }\n }\n return;\n }\n }\n\n /** Entities of a satellite with a screen that take part in the conversation (see {@link CONFIRM_ENTITY}). */\n private onEntityChange(entity: EsphomeEntity): void {\n if (entity.objectId === CONFIRM_ENTITY && entity.kind === 'event') {\n this.onConfirmButton(entity.value);\n } else if (entity.objectId === DISPLAY_LANGUAGE_ENTITY && entity.kind === 'select') {\n // Once per connect, with the state the device reports on subscribing: a language the user picks on the\n // device afterwards stays until the next connect (a change of the voice language restarts the adapter).\n if (!this.displayLanguageChecked) {\n this.displayLanguageChecked = true;\n this.syncDisplayLanguage(entity);\n }\n }\n }\n\n /** Show the device's screen in the voice language, if it offers that language. */\n private syncDisplayLanguage(entity: EsphomeEntity): void {\n const language = this.opts.language;\n if (!language) {\n return;\n }\n const option = displayLanguageOption(entity.options ?? [], language);\n if (!option) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${DISPLAY_LANGUAGE_ENTITY} has no option for \"${language}\" ` +\n `(${(entity.options ?? []).join(', ')})`,\n );\n return;\n }\n if (entity.value === option) {\n return;\n }\n const shown = typeof entity.value === 'string' ? entity.value : '?';\n this.opts.log.info(`ESPHome ${this.deviceName}: display language ${shown} → ${option}`);\n this.setEntity(DISPLAY_LANGUAGE_ENTITY, option);\n }\n\n /** Whether a yes/no button press now answers a question the last reply asked. */\n private questionOpen(): boolean {\n return !!this.capture?.answersQuestion || Date.now() < this.questionUntil;\n }\n\n /**\n * The user pressed yes or no on the device's screen. While a reply waits for an answer that is the answer: the\n * microphone opened for it is closed, the yes or no word goes on as the user's reply (pi-agent decides its\n * confirmation on it like on a spoken one), and the reply to that is announced on this device.\n */\n private onConfirmButton(eventType: unknown): void {\n const yes = confirmAnswerOf(eventType);\n if (yes === null) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${CONFIRM_ENTITY} \"${String(eventType)}\" — not yes/no, ignored`,\n );\n return;\n }\n if (!this.questionOpen()) {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${CONFIRM_ENTITY} \"${yes ? 'yes' : 'no'}\" without an open question — ignored`,\n );\n return;\n }\n this.questionUntil = 0;\n // Pressed while the question still played: the device may open the microphone for it afterwards. Not if the\n // microphone is open already (our RUN_END closes it for good), and not if the device just stopped its\n // conversation itself — the firmware does that on the press, which also drops its continue flag.\n const micStillComes = !this.capture && Date.now() - this.stoppedAt >= CONFIRM_GRACE_MS;\n if (this.capture) {\n // A RUN_END while the microphone streams stops it and puts the device back to idle — without the error\n // display an empty recognition would end with.\n this.abortCapture();\n this.event(EVENT.RUN_END);\n }\n // Whatever is still in flight for the question stays silent; so does the follow-up microphone the device may\n // still open for it.\n const run = ++this.run;\n this.buttonAt = Date.now();\n this.ignoreFollowUpUntil = micStillComes ? Date.now() + IGNORE_FOLLOW_UP_MS : 0;\n void this.answerButton(yes, run);\n }\n\n /** Pass a button answer on and announce the reply (see {@link onConfirmButton}). */\n private async answerButton(yes: boolean, run: number): Promise<void> {\n const text = yesNoWord(this.opts.language, yes);\n this.opts.log.info(`ESPHome ${this.deviceName}: answered \"${text}\" with the button`);\n this.status('processing');\n try {\n const answer = (\n await this.opts.answer(text, { device: this.deviceName, room: this.room, button: yes ? 'yes' : 'no' })\n ).trim();\n if (run !== this.run) {\n return;\n }\n if (!answer) {\n this.status('idle');\n return;\n }\n const followUp = this.opts.expectsFollowUp?.(answer, this.deviceName) === true;\n const ttsStart = Date.now();\n const { pcm, sampleRate } = await this.opts.tts.synthesize(answer, this.opts.language);\n if (run !== this.run) {\n return;\n }\n this.opts.onSpoken?.(this.deviceName, {\n ms: Date.now() - ttsStart,\n audioMs: (pcm.length / 2 / sampleRate) * 1000,\n });\n await this.announce(pcm, sampleRate, followUp, answer);\n } catch (e) {\n this.opts.log.warn(`ESPHome ${this.deviceName}: answer to the button failed — ${(e as Error).message}`);\n if (run === this.run) {\n this.status('idle');\n }\n }\n }\n\n /** Write one of the device's entities. See {@link EsphomeSatellites.setEntity}. */\n setEntity(objectId: string, value: unknown): boolean {\n const message = this.entities.command(objectId, value);\n if (!message) {\n const entity = this.entities.get(objectId);\n const known = this.entities\n .list()\n .map(e => e.objectId)\n .join(', ');\n const options = entity?.options\n ? ` (one of: ${entity.options.join(', ')})`\n : entity?.kind === 'text'\n ? ` (${entity.minLength || 0}–${entity.maxLength ?? '∞'} bytes${entity.pattern ? `, pattern ${entity.pattern}` : ''})`\n : '';\n this.opts.log.warn(\n entity\n ? `ESPHome ${this.deviceName}: ${JSON.stringify(value)} is not a value \"${objectId}\" accepts${options}`\n : `ESPHome ${this.deviceName}: no entity \"${objectId}\" (have: ${known})`,\n );\n return false;\n }\n this.send(message);\n this.opts.log.debug(`ESPHome ${this.deviceName}: ${objectId} := ${JSON.stringify(value)}`);\n return true;\n }\n\n /** Push one assistant timer to the device so it can show and ring it itself. */\n sendTimerEvent(event: TimerEvent): void {\n const message = new pb.VoiceAssistantTimerEventResponse();\n message.setEventType(TIMER_EVENT[event.type]);\n message.setTimerId(event.id);\n message.setName(event.name);\n message.setTotalSeconds(Math.max(0, Math.round(event.totalSeconds)));\n message.setSecondsLeft(Math.max(0, Math.round(event.secondsLeft)));\n message.setIsActive(event.active);\n this.send(message);\n }\n\n // ── voice pipeline ──────────────────────────────────────────────────────────────────────────────\n\n private onPipelineRequest(request: VoiceAssistantRequestMsg): void {\n if (!request.getStart()) {\n this.onStopRequest();\n return;\n }\n if (this.capture) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: pipeline already running — ignoring wake`);\n return;\n }\n const phrase = request.getWakeWordPhrase();\n if (Date.now() < this.ignoreFollowUpUntil) {\n // The microphone for the question a button already answered: close it at once. In this state the device\n // takes a RUN_END as \"stop the microphone\" and goes back to idle.\n this.ignoreFollowUpUntil = 0;\n this.opts.log.debug(`ESPHome ${this.deviceName}: follow-up of a question answered by button — closing it`);\n this.event(EVENT.RUN_END);\n return;\n }\n if (this.runOpen) {\n // The device started over while the last request was still being answered: that answer is not\n // wanted any more, and its events would land in the middle of the new run.\n this.opts.log.debug(`ESPHome ${this.deviceName}: new wake while answering — dropping the old reply`);\n }\n this.run++;\n // While a question is open the next request answers it. The phrase says nothing here: the follow-up\n // microphone carries the last wake word too. Should the user really have said the wake word, the utterance\n // is still the next one after the question — which is what pi-agent and askUser take as the answer anyway.\n const answersQuestion = Date.now() < this.questionUntil;\n const followUp = answersQuestion || !phrase;\n\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: ${answersQuestion ? 'answer to the question' : followUp ? 'follow-up' : `wake \"${phrase}\"`}`,\n );\n\n const response = new pb.VoiceAssistantResponse();\n response.setPort(0); // 0 = stream the audio over this socket\n response.setError(false);\n this.send(response);\n\n const timer = setTimeout(() => {\n this.opts.log.warn(`ESPHome ${this.deviceName}: no end of speech within ${PIPELINE_TIMEOUT_MS} ms`);\n void this.finishCapture('pipeline-timeout');\n }, PIPELINE_TIMEOUT_MS);\n timer.unref();\n const stallCheck = setInterval(() => this.checkStall(), STALL_CHECK_MS);\n stallCheck.unref();\n\n const silenceMs = this.opts.silenceMs || DEFAULT_SILENCE_MS;\n this.capture = {\n chunks: [],\n detector: new SpeechDetector({\n sampleRate: MIC_SAMPLE_RATE,\n silenceMs,\n longSilenceMs: Math.round(silenceMs * LONG_PAUSE_FACTOR),\n longAfterMs: LONG_REQUEST_MS,\n // Microphone gain differs wildly between these devices, so fixed RMS levels do not\n // travel: derive them from the room instead, once the wake chirp is out of the way.\n skipMs: WAKE_CHIRP_MS,\n adaptive: true,\n startTimeoutMs: followUp ? NO_SPEECH_FOLLOW_UP_MS : NO_SPEECH_MS,\n minStartLevel: this.speechLevel || DEFAULT_SPEECH_LEVEL,\n minEndLevel: Math.round((this.speechLevel || DEFAULT_SPEECH_LEVEL) * SILENCE_SHARE),\n minSpeechMs: MIN_SPEECH_MS,\n }),\n conversationId: request.getConversationId(),\n wakeWord: followUp ? '' : phrase,\n answersQuestion,\n timer,\n stallCheck,\n startedAt: Date.now(),\n lastAudioAt: 0,\n closed: false,\n };\n\n this.status('listening');\n this.event(EVENT.RUN_START);\n if (!followUp) {\n this.event(EVENT.WAKE_WORD_END, { wake_word_phrase: phrase });\n }\n this.event(EVENT.STT_START);\n this.event(EVENT.STT_VAD_START);\n }\n\n /**\n * The device asks to end the conversation (`VoiceAssistantRequest{start:false}`): a button, or the wake word\n * said again while a request is running — that is how ESPHome's voice_assistant stops. While it waits for an\n * answer, the firmware leaves that state only on our RUN_END; without one it stays \"in the conversation\", and\n * every further wake word just sends another stop (field report 2026-11-03).\n */\n private onStopRequest(): void {\n this.stoppedAt = Date.now();\n const running = !!this.capture || this.runOpen;\n if (!running && Date.now() - this.buttonAt < CONFIRM_GRACE_MS) {\n // A device with yes/no buttons reports the press and then stops its conversation itself: the button\n // answer ended our run already, and its reply is on the way — nothing to end, nothing to drop. With the\n // stop the device dropped its continue flag too, so no microphone opens for the answered question.\n this.ignoreFollowUpUntil = 0;\n this.opts.log.debug(`ESPHome ${this.deviceName}: the device ended the conversation after the button`);\n return;\n }\n // A device with yes/no buttons may also stop the microphone on the press before it reports which button it\n // was (state messages can be batched): the question stays open a moment longer for that report.\n this.questionUntil = this.questionOpen() ? Math.max(this.questionUntil, Date.now() + CONFIRM_GRACE_MS) : 0;\n this.abortCapture();\n if (running) {\n this.run++; // whatever is still being answered stays silent\n this.opts.log.debug(`ESPHome ${this.deviceName}: the device ended the conversation`);\n this.event(EVENT.RUN_END);\n this.status('idle');\n return;\n }\n if (Date.now() - this.errorSentAt < ERROR_ECHO_MS) {\n return; // the device's own reaction to our ERROR event\n }\n // Nothing is open on our side, but the device still thinks so (it missed a RUN_END): end it there too.\n this.opts.log.debug(`ESPHome ${this.deviceName}: stop outside a conversation — ending it on the device`);\n this.event(EVENT.RUN_END);\n }\n\n private onAudio(audio: VoiceAssistantAudio): void {\n const capture = this.capture;\n if (!capture || capture.closed) {\n return;\n }\n const chunk = Buffer.from(audio.getData_asU8());\n if (chunk.length) {\n capture.lastAudioAt = Date.now();\n capture.chunks.push(chunk);\n const end = capture.detector.push(chunk);\n if (end) {\n void this.finishCapture(end);\n return;\n }\n }\n if (audio.getEnd()) {\n void this.finishCapture('stream');\n }\n }\n\n /** End a capture whose device stopped sending audio without ending the stream. */\n private checkStall(): void {\n const capture = this.capture;\n if (!capture || capture.closed) {\n return;\n }\n const now = Date.now();\n const quietMs = capture.lastAudioAt ? now - capture.lastAudioAt : now - capture.startedAt;\n if (quietMs < (capture.lastAudioAt ? STREAM_STALL_MS : STREAM_START_MS)) {\n return;\n }\n const audioMs = Math.round(capture.chunks.reduce((sum, c) => sum + c.length, 0) / 2 / (MIC_SAMPLE_RATE / 1000));\n this.opts.log.info(\n `ESPHome ${this.deviceName}: the device ${\n capture.lastAudioAt ? `stopped sending audio after ${(audioMs / 1000).toFixed(2)} s` : 'sent no audio'\n } without ending the stream — closing the utterance after ${(quietMs / 1000).toFixed(1)} s of nothing`,\n );\n void this.finishCapture('stall');\n }\n\n /** Hand a recording that never became a request to {@link EsphomeSatellitesOptions.onDiscarded}. */\n private discard(capture: Capture, pcm: Bytes, reason: DiscardReason, vad: VadReport): void {\n if (!this.opts.onDiscarded || !pcm.length) {\n return;\n }\n try {\n this.opts.onDiscarded({\n device: this.deviceName,\n room: this.room,\n wakeWord: capture.wakeWord,\n reason,\n pcm,\n sampleRate: MIC_SAMPLE_RATE,\n // The store writes its own level profile next to it.\n vad: { ...vad, levels: undefined },\n });\n } catch (e) {\n this.opts.log.debug(`ESPHome ${this.deviceName}: keeping the recording failed — ${(e as Error).message}`);\n }\n }\n\n /** Stop the mic stream and run STT → answer → TTS for what was captured. */\n private async finishCapture(end: CaptureEnd): Promise<void> {\n const capture = this.capture;\n if (!capture || capture.closed) {\n return;\n }\n capture.closed = true;\n this.capture = null;\n clearTimeout(capture.timer);\n clearInterval(capture.stallCheck);\n const run = this.run;\n /** False once the run was ended elsewhere — then nothing more may be sent for it. */\n const current = (): boolean => {\n if (run === this.run) {\n return true;\n }\n this.opts.log.debug(`ESPHome ${this.deviceName}: conversation ended meanwhile — dropping the reply`);\n return false;\n };\n\n // Send this first: the device streams until it sees it.\n this.event(EVENT.STT_VAD_END);\n\n const pcm = Buffer.concat(capture.chunks);\n const seconds = pcm.length / 2 / MIC_SAMPLE_RATE;\n const vad: VadReport = { ...capture.detector.report(), end };\n const startedAt =\n vad.speechStartMs !== undefined ? `, speech from ${(vad.speechStartMs / 1000).toFixed(2)} s` : '';\n const endedBy = vad.end === 'speech-end' ? `ended after ${vad.silenceMs} ms of silence` : `ended by ${vad.end}`;\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: captured ${seconds.toFixed(2)} s ` +\n `(peak RMS ${vad.peak}, noise floor ${vad.noiseFloor}, speech/silence gate ${vad.startLevel}/${vad.endLevel}` +\n `${startedAt}, ${endedBy})`,\n );\n\n if (capture.answersQuestion) {\n // Spoken: that is the answer, a button press now would be a second one. Silent: the buttons still answer\n // for a moment, as the screen may still show them.\n this.questionUntil = capture.detector.sawSpeech\n ? 0\n : Math.max(this.questionUntil, Date.now() + CONFIRM_GRACE_MS);\n }\n\n if (!pcm.length || !capture.detector.sawSpeech) {\n const loudest = Math.round(capture.detector.analysedPeak);\n const gate = Math.round(capture.detector.startLevel);\n if (capture.detector.longestSoundMs > 0) {\n // Something crossed the gate, but too briefly for a word: a click, a knock, a cough.\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: only a short sound (${capture.detector.longestSoundMs} ms, ` +\n `RMS ${loudest}) — too short for speech (${MIN_SPEECH_MS} ms), dropping the utterance`,\n );\n } else if (pcm.length && loudest >= gate * QUIET_VOICE_SHARE) {\n // Not an empty room: something came close to the gate. Typically a microphone that is quieter\n // than the default threshold expects (a phone) — say where to change it.\n this.opts.log.info(\n `ESPHome ${this.deviceName}: dropped the utterance — the loudest sound (RMS ${loudest}) stayed ` +\n `below the speech threshold ${gate}. If somebody spoke, lower \"Speech threshold\" for this ` +\n `device in the ESPHome satellites table (Voice tab), e.g. to ${Math.max(\n 30,\n Math.round((loudest * 0.6) / 10) * 10,\n )}.`,\n );\n } else {\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: nothing but silence${\n end === 'no-speech' ? ' (nobody started speaking)' : ''\n } — dropping the utterance`,\n );\n }\n this.discard(capture, pcm, end === 'no-speech' ? 'no-speech' : 'silence', vad);\n this.endWithoutRequest();\n return;\n }\n\n this.status('processing');\n try {\n const hints = this.opts.getHints ? await this.opts.getHints() : undefined;\n if (!current()) {\n return;\n }\n const speech = prepareForStt(pcm, MIC_SAMPLE_RATE, { startMs: vad.speechStartMs, endLevel: vad.endLevel });\n vad.stt = { fromMs: speech.fromMs, toMs: speech.toMs, gain: speech.gain };\n this.opts.log.debug(\n `ESPHome ${this.deviceName}: speech recognition gets ${(speech.fromMs / 1000).toFixed(2)}–` +\n `${(speech.toMs / 1000).toFixed(2)} s${speech.gain > 1 ? `, amplified ×${speech.gain}` : ''}`,\n );\n const sttStart = Date.now();\n const text = (\n await this.opts.stt.transcribe(speech.pcm, MIC_SAMPLE_RATE, this.opts.language, hints)\n ).trim();\n const sttMs = Date.now() - sttStart;\n if (!current()) {\n return;\n }\n if (!text) {\n // Speech was heard, so the user waits for an answer: say why none comes. Typically a word in another\n // language than the STT listens in (a German \"Ja\" to a Russian STT comes back empty).\n this.opts.log.info(\n `Voice Q (${this.deviceName}): (empty) — speech recognition returned no text for ${seconds.toFixed(1)} s of audio`,\n );\n this.discard(capture, pcm, 'empty-stt', vad);\n if (capture.answersQuestion) {\n this.questionUntil = Math.max(this.questionUntil, Date.now() + CONFIRM_GRACE_MS);\n }\n // No STT_END without text — like Home Assistant, which reports this case as an error only.\n this.endWithoutRequest();\n return;\n }\n this.event(EVENT.STT_END, { text });\n\n this.event(EVENT.INTENT_START);\n const answer = (\n await this.opts.answer(text, {\n device: this.deviceName,\n room: this.room,\n wakeWord: capture.wakeWord,\n sttMs,\n audioMs: Math.round(seconds * 1000),\n // Numbers only, no audio: shows where a request was cut off without keeping recordings.\n vad: { ...vad, levels: levelProfile(pcm, MIC_SAMPLE_RATE) },\n })\n ).trim();\n if (!current()) {\n return;\n }\n const followUp = !!answer && this.opts.expectsFollowUp?.(answer, this.deviceName) === true;\n // Always say it, \"0\" included: ESPHome keeps the flag of the last INTENT_END that carried it, so after\n // one question every later reply re-opened the microphone (field report 2026-11-04). Home Assistant\n // sends \"0\" just the same.\n const conversation = { continue_conversation: followUp ? '1' : '0' };\n this.event(EVENT.INTENT_END, conversation);\n\n if (!answer) {\n this.event(EVENT.RUN_END);\n this.status('idle');\n return;\n }\n\n const ttsStart = Date.now();\n const { pcm: ttsPcm, sampleRate } = await this.opts.tts.synthesize(answer, this.opts.language);\n if (!current()) {\n return;\n }\n this.opts.onSpoken?.(this.deviceName, {\n ms: Date.now() - ttsStart,\n audioMs: (ttsPcm.length / 2 / sampleRate) * 1000,\n });\n const url = await this.publish(ttsPcm, sampleRate);\n if (!current()) {\n return;\n }\n\n this.status('speaking');\n this.event(EVENT.TTS_START, { text: answer });\n this.event(EVENT.TTS_END, { url });\n // linux-voice-assistant reads the flag here (ignoring \"0\"), ESPHome at INTENT_END\n this.event(EVENT.RUN_END, conversation);\n this.questionUntil = followUp ? Date.now() + (ttsPcm.length / 2 / sampleRate) * 1000 + QUESTION_OPEN_MS : 0;\n this.armPlaybackTimeout();\n } catch (e) {\n const reason = (e as Error).message;\n this.opts.log.error(`ESPHome ${this.deviceName}: voice pipeline failed — ${reason}`);\n if (run !== this.run) {\n return; // the conversation is over already — nothing to tell the device\n }\n // Without this the device stays ducked and its LED keeps spinning.\n this.event(EVENT.ERROR, { code: 'pipeline-failed', message: reason });\n this.event(EVENT.RUN_END);\n this.status('idle');\n }\n }\n\n /**\n * End a run that produced no request. A RUN_END right after STT_VAD_END gets lost: the firmware is still stopping\n * its microphone then, ignores RUN_END in that state, and afterwards waits for an answer that never comes — the\n * satellite stays in the conversation (field report 2026-11-03). An ERROR event puts it back to idle in any state,\n * so it goes first, with the code Home Assistant uses for this case.\n */\n private endWithoutRequest(): void {\n this.event(EVENT.ERROR, NO_TEXT_ERROR);\n this.event(EVENT.RUN_END);\n this.status('idle');\n }\n\n /**\n * Select which wake words listen on this device. Unknown ids are dropped and the list is trimmed\n * to what the firmware allows, because the device answers a rejected list with silence rather than\n * an error — better to send something valid and report what we changed.\n *\n * The device persists the selection and echoes it back in a `VoiceAssistantConfigurationResponse`,\n * so we ask for one instead of assuming the write took.\n */\n setWakeWords(ids: string[]): void {\n const known = this.wakeWordConfig?.available.map(w => w.id) ?? [];\n const wanted = [...new Set(ids.map(i => i.trim()).filter(Boolean))];\n const unknown = wanted.filter(i => !known.includes(i));\n if (unknown.length) {\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: unknown wake word(s) ${unknown.join(', ')} — ignored. ` +\n `Available: ${known.join(', ') || '(none reported)'}`,\n );\n }\n let valid = wanted.filter(i => known.includes(i));\n const max = this.wakeWordConfig?.max || 0;\n if (max > 0 && valid.length > max) {\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: device allows ${max} active wake word(s), keeping ${valid\n .slice(0, max)\n .join(', ')}`,\n );\n valid = valid.slice(0, max);\n }\n\n const message = new pb.VoiceAssistantSetConfiguration();\n message.setActiveWakeWordsList(valid);\n this.send(message);\n this.opts.log.info(`ESPHome ${this.deviceName}: wake words set to ${valid.join(', ') || '(none)'}`);\n // Read back, so the reported state is the device's and not our guess. The device resolves a\n // custom wake word (and downloads it) while handling the SetConfiguration, so this answer\n // already tells whether that worked.\n this.requestWakeWordConfig(valid);\n }\n\n /**\n * Ask the device for its wake-word configuration. The request always carries the current custom\n * wake words: the firmware replaces its list of offered models with every request, so one sent\n * without them would make an uploaded wake word vanish from the device until the next offer.\n *\n * @param check ids a SetConfiguration just asked for — warned about if the answer lacks them\n */\n requestWakeWordConfig(check: string[] | null = null): void {\n const request = new pb.VoiceAssistantConfigurationRequest();\n const offers = this.opts.externalWakeWords?.() ?? [];\n request.setExternalWakeWordsList(\n offers.map(offer => {\n const w = new pb.VoiceAssistantExternalWakeWord();\n w.setId(offer.id);\n w.setWakeWord(offer.phrase);\n w.setTrainedLanguagesList(offer.languages);\n w.setModelType('micro');\n w.setModelSize(offer.size);\n w.setModelHash(offer.sha256);\n w.setUrl(this.mediaUrl(offer.path));\n return w;\n }),\n );\n // A device that never answers must not let this grow without bound.\n if (this.configChecks.length < 16) {\n this.configChecks.push(check);\n }\n this.send(request);\n }\n\n /** Drop a half-finished capture (device went away, or told us to stop). */\n private abortCapture(): void {\n const capture = this.capture;\n if (!capture) {\n return;\n }\n this.capture = null;\n capture.closed = true;\n clearTimeout(capture.timer);\n clearInterval(capture.stallCheck);\n }\n\n // ── announcements ───────────────────────────────────────────────────────────────────────────────\n\n /**\n * Speak a ready PCM buffer on this device (timers, alarms, `tts.text`, jingles). With\n * `startConversation` the microphone opens once the clip has played, to catch the answer to a question.\n */\n async announce(pcm: Buffer, sampleRate: number, startConversation = false, text = ''): Promise<void> {\n if (!this.online || !pcm.length) {\n return;\n }\n const request = new pb.VoiceAssistantAnnounceRequest();\n request.setMediaId(await this.publish(pcm, sampleRate));\n // What a device with a screen shows while it plays (its on_tts_start)\n request.setText(text);\n request.setPreannounceMediaId('');\n // Needs feature flag 32 (START_CONVERSATION); on a device without it the clip still plays and\n // only the microphone stays shut, so there is nothing to guard here.\n request.setStartConversation(startConversation);\n if (startConversation) {\n // A question: the microphone the device opens after it is wanted, and a button press answers it\n this.ignoreFollowUpUntil = 0;\n this.questionUntil = Date.now() + (pcm.length / 2 / sampleRate) * 1000 + QUESTION_OPEN_MS;\n }\n this.status('speaking');\n this.send(request);\n this.armPlaybackTimeout();\n }\n\n /** The format replies should have on this device, from what its media player announced. */\n private replyFormat(): ReplyFormat {\n const formats = this.entities\n .list()\n .filter(e => e.kind === 'mediaPlayer')\n .flatMap(e => e.formats ?? []);\n return chooseReplyFormat(formats, !!this.opts.encodeAudio);\n }\n\n /**\n * Publish PCM on the media server, in the format the device plays, and build the URL it should fetch.\n *\n * The host matters: on a multi-homed ioBroker machine the device can usually only reach one of the\n * addresses, and the local end of *this* socket is by definition one it can talk to.\n */\n private async publish(pcm: Buffer, sampleRate: number): Promise<string> {\n let format = this.replyFormat();\n let encoded: { body: Buffer; contentType: string };\n try {\n encoded = await encodeReply(pcm, sampleRate, format, this.opts.encodeAudio);\n } catch (e) {\n // MP3/Opus need ffmpeg. Without it a native format is the only chance, whether the device lists it or not.\n const fallback: ReplyFormat = { ...format, codec: 'flac', source: `${format.source}, FLAC as fallback` };\n this.opts.log.warn(\n `ESPHome ${this.deviceName}: cannot write the reply as ${format.codec.toUpperCase()} ` +\n `(${(e as Error).message}) — sending FLAC, which the device may not play. Install ffmpeg.`,\n );\n format = fallback;\n encoded = await encodeReply(pcm, sampleRate, format);\n }\n const key = `${format.codec}/${format.sampleRate}/${format.channels}`;\n if (key !== this.loggedFormat) {\n this.loggedFormat = key;\n const what = !format.source\n ? 'WAV (the device lists no formats)'\n : `${format.codec.toUpperCase()}${format.sampleRate ? ` ${format.sampleRate} Hz` : ''}` +\n `${format.channels === 2 ? ' stereo' : ''} (device: ${format.source})`;\n this.opts.log.info(`ESPHome ${this.deviceName}: spoken replies as ${what}`);\n }\n return this.mediaUrl(this.opts.media.publish(encoded.body, encoded.contentType));\n }\n\n /** Absolute URL of a path on the media server, with a host this device can reach. */\n private mediaUrl(path: string): string {\n const local = (this.socket?.localAddress || '').replace(/^::ffff:/, '');\n const host = this.opts.mediaHost?.trim() || local || '127.0.0.1';\n // An IPv6 literal has to be bracketed in a URL.\n const authority = host.includes(':') ? `[${host}]` : host;\n return `http://${authority}:${this.opts.media.port}${path}`;\n }\n\n /** Fall back to `idle` if the device never reports that it finished playing. */\n private armPlaybackTimeout(): void {\n if (this.playbackTimer) {\n clearTimeout(this.playbackTimer);\n }\n this.playbackTimer = setTimeout(() => {\n this.playbackTimer = null;\n this.status('idle');\n }, PLAYBACK_TIMEOUT_MS);\n this.playbackTimer.unref();\n }\n\n private event(type: number, data?: Record<string, string>): void {\n if (type === EVENT.RUN_START) {\n this.runOpen = true;\n } else if (type === EVENT.RUN_END) {\n this.runOpen = false;\n } else if (type === EVENT.ERROR) {\n this.errorSentAt = Date.now();\n }\n const message = new pb.VoiceAssistantEventResponse();\n message.setEventType(type);\n const items: VoiceAssistantEventData[] = [];\n for (const [name, value] of Object.entries(data || {})) {\n const item = new pb.VoiceAssistantEventData();\n item.setName(name);\n item.setValue(value);\n items.push(item);\n }\n message.setDataList(items);\n this.send(message);\n }\n}\n"]}
|