diff --git a/futurehome/config.yaml b/futurehome/config.yaml index 4f4bf53..deea287 100644 --- a/futurehome/config.yaml +++ b/futurehome/config.yaml @@ -1,6 +1,6 @@ # https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config name: Futurehome -version: "0.0.31" +version: "0.0.32" slug: futurehome description: Local Futurehome Smarthub integration url: "https://github.com/adrianjagielak/home-assistant-futurehome" diff --git a/futurehome/src/ha/publish_device.ts b/futurehome/src/ha/publish_device.ts index 15438d9..86803a7 100644 --- a/futurehome/src/ha/publish_device.ts +++ b/futurehome/src/ha/publish_device.ts @@ -1,98 +1,160 @@ -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 { ha } from "./globals"; -import { HaMqttComponent } from "./mqtt_components/_component"; +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 { ha } from './globals'; +import { HaMqttComponent } from './mqtt_components/_component'; type HaDeviceConfig = { - // device - dev: { - ids: string | null | undefined, - name: string | null | undefined, - // manufacturer - mf: string | null | undefined, - // model - mdl: string | null | undefined, - // software version - sw: string | null | undefined, - // serial number - sn: string | null | undefined, - // hardware number - hw: string | null | undefined, + /** + * 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 isn’t 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 - o: { - name: 'futurehome', - url: 'https://github.com/adrianjagielak/home-assistant-futurehome', + origin: { + name: 'futurehome'; + url: 'https://github.com/adrianjagielak/home-assistant-futurehome'; }; - // components - cmps: { + components: { [key: string]: HaMqttComponent; - }, - // state topic - stat_t: string, - // availability topic - avty_t: string, - qos: number, -} + }; + 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 } +export type CommandHandlers = { + [topic: string]: (payload: string) => Promise; +}; const serviceHandlers: { - [name: string]: (topicPrefix: string, device: VinculumPd7Device, svc: VinculumPd7Service) => ServiceComponentsCreationResult | undefined + [name: string]: ( + topicPrefix: string, + device: VinculumPd7Device, + svc: VinculumPd7Service, + ) => ServiceComponentsCreationResult | undefined; } = { basic: basic__components, battery: battery__components, @@ -144,17 +206,29 @@ const serviceHandlers: { thermostat: thermostat__components, }; -export function haPublishDevice(parameters: { hubId: string, vinculumDeviceData: VinculumPd7Device, deviceInclusionReport: InclusionReport | undefined }): { commandHandlers: CommandHandlers } { +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; } + 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) { @@ -164,7 +238,9 @@ export function haPublishDevice(parameters: { hubId: string, vinculumDeviceData: const result = handler(topicPrefix, parameters.vinculumDeviceData, svc); if (!result) { - log.error(`Invalid service data prevented component creation: ${parameters.vinculumDeviceData} ${svc}`); + log.error( + `Invalid service data prevented component creation: ${parameters.vinculumDeviceData} ${svc}`, + ); continue; } @@ -172,26 +248,36 @@ export function haPublishDevice(parameters: { hubId: string, vinculumDeviceData: Object.assign(handlers, result.commandHandlers); } - const configTopic = `${topicPrefix}/config` - const stateTopic = `${topicPrefix}/state` - const availabilityTopic = `${topicPrefix}/availability` + const configTopic = `${topicPrefix}/config`; + const stateTopic = `${topicPrefix}/state`; + const availabilityTopic = `${topicPrefix}/availability`; const config: HaDeviceConfig = { - dev: { - ids: parameters.vinculumDeviceData.id.toString(), - name: parameters.vinculumDeviceData?.client?.name ?? parameters.vinculumDeviceData?.modelAlias ?? parameters.deviceInclusionReport?.product_name, - mf: parameters.deviceInclusionReport?.manufacturer_id, - mdl: parameters.vinculumDeviceData?.modelAlias ?? parameters.deviceInclusionReport?.product_id, - sw: parameters.deviceInclusionReport?.sw_ver, - sn: parameters.deviceInclusionReport?.product_hash, - hw: parameters.deviceInclusionReport?.hw_ver, + 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', }, - o: { + origin: { name: 'futurehome', url: 'https://github.com/adrianjagielak/home-assistant-futurehome', }, - cmps: components, - stat_t: stateTopic, - avty_t: availabilityTopic, + components: components, + state_topic: stateTopic, + availability_topic: availabilityTopic, qos: 2, }; @@ -199,4 +285,4 @@ export function haPublishDevice(parameters: { hubId: string, vinculumDeviceData: ha?.publish(configTopic, JSON.stringify(config), { retain: true, qos: 2 }); return { commandHandlers: handlers }; -} \ No newline at end of file +}