Files
home-assistant-futurehome/futurehome/src/services/scene_ctrl.ts
2025-07-24 16:48:33 +02:00

87 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Maps a Futurehome “scene_ctrl” service to MQTT entities
// ─────────────────────────────────────────────────────────────
// FIMP ➞ HA state paths used by the value templates
// value_json[svc.addr].scene last reported scene name (string)
// value_json[svc.addr].lvl last reported level (int)
//
// HA ➞ FIMP commands
// <topicPrefix><addr>/scene/command → cmd.scene.set
// ─────────────────────────────────────────────────────────────
import { sendFimpMsg } from '../fimp/fimp';
import {
VinculumPd7Device,
VinculumPd7Service,
} from '../fimp/vinculum_pd7_device';
import { HaMqttComponent } from '../ha/mqtt_components/_component';
import {
CommandHandlers,
ServiceComponentsCreationResult,
} from '../ha/publish_device';
/**
* Creates MQTT components for a single *scene_ctrl* service.
*/
export function scene_ctrl__components(
topicPrefix: string,
_device: VinculumPd7Device,
svc: VinculumPd7Service,
): ServiceComponentsCreationResult | undefined {
const components: Record<string, HaMqttComponent> = {};
const handlers: CommandHandlers = {};
// ───────────── read-only entities ─────────────
if (svc.intf?.includes('evt.scene.report')) {
components[`${svc.addr}_scene`] = {
unique_id: `${svc.addr}_scene`,
platform: 'sensor',
unit_of_measurement: '',
value_template: `{{ value_json['${svc.addr}'].scene }}`,
};
}
if (svc.intf?.includes('evt.lvl.report')) {
components[`${svc.addr}_lvl`] = {
unique_id: `${svc.addr}_lvl`,
platform: 'sensor',
unit_of_measurement: '',
value_template: `{{ value_json['${svc.addr}'].lvl }}`,
};
}
// ───────────── writeable “select” (scene activator) ─────────────
const supScenes: string[] = svc.props?.sup_scenes ?? [];
if (svc.intf?.includes('cmd.scene.set') && supScenes.length) {
const commandTopic = `${topicPrefix}${svc.addr}/scene/command`;
components[`${svc.addr}_select`] = {
unique_id: `${svc.addr}_select`,
platform: 'select',
options: supScenes,
command_topic: commandTopic,
optimistic: false,
value_template: `{{ value_json['${svc.addr}'].scene }}`,
};
handlers[commandTopic] = async (payload: string) => {
if (!supScenes.includes(payload)) return; // ignore bogus payloads
await sendFimpMsg({
address: svc.addr!,
service: 'scene_ctrl',
cmd: 'cmd.scene.set',
val_t: 'string',
val: payload,
});
};
}
// Nothing useful to expose?
if (!Object.keys(components).length) return undefined;
return {
components,
commandHandlers: Object.keys(handlers).length ? handlers : undefined,
};
}