2025-07-24 16:34:58 +02:00

294 lines
11 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.

import { InclusionReport } from '../fimp/inclusion_report';
import {
VinculumPd7Device,
VinculumPd7Service,
} from '../fimp/vinculum_pd7_device';
import { log } from '../logger';
import { basic__components } from '../services/basic';
import { battery__components } from '../services/battery';
import { color_ctrl__components } from '../services/color_ctrl';
import { fan_ctrl__components } from '../services/fan_ctrl';
import { out_bin_switch__components } from '../services/out_bin_switch';
import { out_lvl_switch__components } from '../services/out_lvl_switch';
import { scene_ctrl__components } from '../services/scene_ctrl';
import { sensor_accelx__components } from '../services/sensor_accelx';
import { sensor_accely__components } from '../services/sensor_accely';
import { sensor_accelz__components } from '../services/sensor_accelz';
import { sensor_airflow__components } from '../services/sensor_airflow';
import { sensor_airq__components } from '../services/sensor_airq';
import { sensor_anglepos__components } from '../services/sensor_anglepos';
import { sensor_atmo__components } from '../services/sensor_atmo';
import { sensor_baro__components } from '../services/sensor_baro';
import { sensor_co__components } from '../services/sensor_co';
import { sensor_co2__components } from '../services/sensor_co2';
import { sensor_contact__components } from '../services/sensor_contact';
import { sensor_current__components } from '../services/sensor_current';
import { sensor_dew__components } from '../services/sensor_dew';
import { sensor_direct__components } from '../services/sensor_direct';
import { sensor_distance__components } from '../services/sensor_distance';
import { sensor_elresist__components } from '../services/sensor_elresist';
import { sensor_freq__components } from '../services/sensor_freq';
import { sensor_gp__components } from '../services/sensor_gp';
import { sensor_gust__components } from '../services/sensor_gust';
import { sensor_humid__components } from '../services/sensor_humid';
import { sensor_lumin__components } from '../services/sensor_lumin';
import { sensor_moist__components } from '../services/sensor_moist';
import { sensor_noise__components } from '../services/sensor_noise';
import { sensor_power__components } from '../services/sensor_power';
import { sensor_presence__components } from '../services/sensor_presence';
import { sensor_rain__components } from '../services/sensor_rain';
import { sensor_rotation__components } from '../services/sensor_rotation';
import { sensor_seismicint__components } from '../services/sensor_seismicint';
import { sensor_seismicmag__components } from '../services/sensor_seismicmag';
import { sensor_solarrad__components } from '../services/sensor_solarrad';
import { sensor_tank__components } from '../services/sensor_tank';
import { sensor_temp__components } from '../services/sensor_temp';
import { sensor_tidelvl__components } from '../services/sensor_tidelvl';
import { sensor_uv__components } from '../services/sensor_uv';
import { sensor_veloc__components } from '../services/sensor_veloc';
import { sensor_voltage__components } from '../services/sensor_voltage';
import { sensor_watflow__components } from '../services/sensor_watflow';
import { sensor_watpressure__components } from '../services/sensor_watpressure';
import { sensor_wattemp__components } from '../services/sensor_wattemp';
import { sensor_weight__components } from '../services/sensor_weight';
import { thermostat__components } from '../services/thermostat';
import { abbreviateHaMqttKeys } from './abbreviate_ha_mqtt_keys';
import { ha } from './globals';
import { HaMqttComponent } from './mqtt_components/_component';
type HaDeviceConfig = {
/**
* Information about the device this sensor is a part of to tie it into the [device registry](https://developers.home-assistant.io/docs/device_registry_index/).
* Only works when [`unique_id`](#unique_id) is set.
* At least one of identifiers or connections must be present to identify the device.
*/
device?: {
/**
* A link to the webpage that can manage the configuration of this device.
* Can be either an `http://`, `https://` or an internal `homeassistant://` URL.
*/
configuration_url?: string;
/**
* A list of connections of the device to the outside world as a list of tuples `[connection_type, connection_identifier]`.
* For example the MAC address of a network interface:
* `"connections": [["mac", "02:5b:26:a8:dc:12"]]`.
*/
connections?: Array<[string, string]>;
/**
* The hardware version of the device.
*/
hw_version?: string;
/**
* A list of IDs that uniquely identify the device.
* For example a serial number.
*/
identifiers?: string | string[];
/**
* The manufacturer of the device.
*/
manufacturer?: string;
/**
* The model of the device.
*/
model?: string;
/**
* The model identifier of the device.
*/
model_id?: string;
/**
* The name of the device.
*/
name?: string;
/**
* The serial number of the device.
*/
serial_number?: string;
/**
* Suggest an area if the device isnt in one yet.
*/
suggested_area?: string;
/**
* The firmware version of the device.
*/
sw_version?: string;
/**
* Identifier of a device that routes messages between this device and Home Assistant.
* Examples of such devices are hubs, or parent devices of a sub-device.
* This is used to show device topology in Home Assistant.
*/
via_device?: string;
};
origin: {
name: 'futurehome';
support_url: 'https://github.com/adrianjagielak/home-assistant-futurehome';
};
components: {
[key: string]: HaMqttComponent;
};
state_topic: string;
availability_topic: string;
qos: number;
};
export type ServiceComponentsCreationResult = {
components: { [key: string]: HaMqttComponent };
commandHandlers?: CommandHandlers;
};
export type CommandHandlers = {
[topic: string]: (payload: string) => Promise<void>;
};
const serviceHandlers: {
[name: string]: (
topicPrefix: string,
device: VinculumPd7Device,
svc: VinculumPd7Service,
) => ServiceComponentsCreationResult | undefined;
} = {
basic: basic__components,
battery: battery__components,
color_ctrl: color_ctrl__components,
fan_ctrl: fan_ctrl__components,
out_bin_switch: out_bin_switch__components,
out_lvl_switch: out_lvl_switch__components,
scene_ctrl: scene_ctrl__components,
sensor_accelx: sensor_accelx__components,
sensor_accely: sensor_accely__components,
sensor_accelz: sensor_accelz__components,
sensor_airflow: sensor_airflow__components,
sensor_airq: sensor_airq__components,
sensor_anglepos: sensor_anglepos__components,
sensor_atmo: sensor_atmo__components,
sensor_baro: sensor_baro__components,
sensor_co: sensor_co__components,
sensor_co2: sensor_co2__components,
sensor_contact: sensor_contact__components,
sensor_current: sensor_current__components,
sensor_dew: sensor_dew__components,
sensor_direct: sensor_direct__components,
sensor_distance: sensor_distance__components,
sensor_elresist: sensor_elresist__components,
sensor_freq: sensor_freq__components,
sensor_gp: sensor_gp__components,
sensor_gust: sensor_gust__components,
sensor_humid: sensor_humid__components,
sensor_lumin: sensor_lumin__components,
sensor_moist: sensor_moist__components,
sensor_noise: sensor_noise__components,
sensor_power: sensor_power__components,
sensor_presence: sensor_presence__components,
sensor_rain: sensor_rain__components,
sensor_rotation: sensor_rotation__components,
sensor_seismicint: sensor_seismicint__components,
sensor_seismicmag: sensor_seismicmag__components,
sensor_solarrad: sensor_solarrad__components,
sensor_tank: sensor_tank__components,
sensor_temp: sensor_temp__components,
sensor_tidelvl: sensor_tidelvl__components,
sensor_uv: sensor_uv__components,
sensor_veloc: sensor_veloc__components,
sensor_voltage: sensor_voltage__components,
sensor_watflow: sensor_watflow__components,
sensor_watpressure: sensor_watpressure__components,
sensor_wattemp: sensor_wattemp__components,
sensor_weight: sensor_weight__components,
thermostat: thermostat__components,
};
export function haPublishDevice(parameters: {
hubId: string;
vinculumDeviceData: VinculumPd7Device;
deviceInclusionReport: InclusionReport | undefined;
}): { commandHandlers: CommandHandlers } {
const components: { [key: string]: HaMqttComponent } = {};
const handlers: CommandHandlers = {};
// e.g. "homeassistant/device/futurehome_123456_1"
const topicPrefix = `homeassistant/device/futurehome_${parameters.hubId}_${parameters.vinculumDeviceData.id}`;
for (const [svcName, svc] of Object.entries(
parameters.vinculumDeviceData.services ?? {},
)) {
if (!svcName) {
continue;
}
if (!svc.addr) {
continue;
}
if (!svc.enabled) {
continue;
}
const handler = serviceHandlers[svcName];
if (!handler) {
log.error(`No handler for service: ${svcName}`);
continue;
}
const result = handler(topicPrefix, parameters.vinculumDeviceData, svc);
if (!result) {
log.error(
`Invalid service data prevented component creation: ${parameters.vinculumDeviceData} ${svc}`,
);
continue;
}
Object.assign(components, result.components);
Object.assign(handlers, result.commandHandlers);
}
const configTopic = `${topicPrefix}/config`;
const stateTopic = `${topicPrefix}/state`;
const availabilityTopic = `${topicPrefix}/availability`;
const config: HaDeviceConfig = {
device: {
identifiers: parameters.vinculumDeviceData.id.toString(),
name:
parameters.vinculumDeviceData?.client?.name ??
parameters.vinculumDeviceData?.modelAlias ??
parameters.deviceInclusionReport?.product_name ??
undefined,
manufacturer:
parameters.deviceInclusionReport?.manufacturer_id ?? undefined,
model:
parameters.vinculumDeviceData?.modelAlias ??
parameters.deviceInclusionReport?.product_id ??
undefined,
sw_version: parameters.deviceInclusionReport?.sw_ver ?? undefined,
serial_number:
parameters.deviceInclusionReport?.product_hash ?? undefined,
hw_version: parameters.deviceInclusionReport?.hw_ver ?? undefined,
via_device: 'todo_hub_id',
},
origin: {
name: 'futurehome',
support_url:
'https://github.com/adrianjagielak/home-assistant-futurehome',
},
components: components,
state_topic: stateTopic,
availability_topic: availabilityTopic,
qos: 2,
};
log.debug(`Publishing HA device "${configTopic}"`);
ha?.publish(configTopic, JSON.stringify(abbreviateHaMqttKeys(config)), {
retain: true,
qos: 2,
});
return { commandHandlers: handlers };
}