Use full device field names in MQTT discovery messages

This commit is contained in:
Adrian Jagielak 2025-07-24 16:13:39 +02:00
parent 09b98321a1
commit 6770d1c0c1
No known key found for this signature in database
GPG Key ID: 0818CF7AF6C62BFB
2 changed files with 192 additions and 106 deletions

View File

@ -1,6 +1,6 @@
# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config # https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config
name: Futurehome name: Futurehome
version: "0.0.31" version: "0.0.32"
slug: futurehome slug: futurehome
description: Local Futurehome Smarthub integration description: Local Futurehome Smarthub integration
url: "https://github.com/adrianjagielak/home-assistant-futurehome" url: "https://github.com/adrianjagielak/home-assistant-futurehome"

View File

@ -1,98 +1,160 @@
import { InclusionReport } from "../fimp/inclusion_report"; import { InclusionReport } from '../fimp/inclusion_report';
import { VinculumPd7Device, VinculumPd7Service } from "../fimp/vinculum_pd7_device"; import {
import { log } from "../logger"; VinculumPd7Device,
import { basic__components } from "../services/basic"; VinculumPd7Service,
import { battery__components } from "../services/battery"; } from '../fimp/vinculum_pd7_device';
import { color_ctrl__components } from "../services/color_ctrl"; import { log } from '../logger';
import { fan_ctrl__components } from "../services/fan_ctrl"; import { basic__components } from '../services/basic';
import { out_bin_switch__components } from "../services/out_bin_switch"; import { battery__components } from '../services/battery';
import { out_lvl_switch__components } from "../services/out_lvl_switch"; import { color_ctrl__components } from '../services/color_ctrl';
import { scene_ctrl__components } from "../services/scene_ctrl"; import { fan_ctrl__components } from '../services/fan_ctrl';
import { sensor_accelx__components } from "../services/sensor_accelx"; import { out_bin_switch__components } from '../services/out_bin_switch';
import { sensor_accely__components } from "../services/sensor_accely"; import { out_lvl_switch__components } from '../services/out_lvl_switch';
import { sensor_accelz__components } from "../services/sensor_accelz"; import { scene_ctrl__components } from '../services/scene_ctrl';
import { sensor_airflow__components } from "../services/sensor_airflow"; import { sensor_accelx__components } from '../services/sensor_accelx';
import { sensor_airq__components } from "../services/sensor_airq"; import { sensor_accely__components } from '../services/sensor_accely';
import { sensor_anglepos__components } from "../services/sensor_anglepos"; import { sensor_accelz__components } from '../services/sensor_accelz';
import { sensor_atmo__components } from "../services/sensor_atmo"; import { sensor_airflow__components } from '../services/sensor_airflow';
import { sensor_baro__components } from "../services/sensor_baro"; import { sensor_airq__components } from '../services/sensor_airq';
import { sensor_co__components } from "../services/sensor_co"; import { sensor_anglepos__components } from '../services/sensor_anglepos';
import { sensor_co2__components } from "../services/sensor_co2"; import { sensor_atmo__components } from '../services/sensor_atmo';
import { sensor_contact__components } from "../services/sensor_contact"; import { sensor_baro__components } from '../services/sensor_baro';
import { sensor_current__components } from "../services/sensor_current"; import { sensor_co__components } from '../services/sensor_co';
import { sensor_dew__components } from "../services/sensor_dew"; import { sensor_co2__components } from '../services/sensor_co2';
import { sensor_direct__components } from "../services/sensor_direct"; import { sensor_contact__components } from '../services/sensor_contact';
import { sensor_distance__components } from "../services/sensor_distance"; import { sensor_current__components } from '../services/sensor_current';
import { sensor_elresist__components } from "../services/sensor_elresist"; import { sensor_dew__components } from '../services/sensor_dew';
import { sensor_freq__components } from "../services/sensor_freq"; import { sensor_direct__components } from '../services/sensor_direct';
import { sensor_gp__components } from "../services/sensor_gp"; import { sensor_distance__components } from '../services/sensor_distance';
import { sensor_gust__components } from "../services/sensor_gust"; import { sensor_elresist__components } from '../services/sensor_elresist';
import { sensor_humid__components } from "../services/sensor_humid"; import { sensor_freq__components } from '../services/sensor_freq';
import { sensor_lumin__components } from "../services/sensor_lumin"; import { sensor_gp__components } from '../services/sensor_gp';
import { sensor_moist__components } from "../services/sensor_moist"; import { sensor_gust__components } from '../services/sensor_gust';
import { sensor_noise__components } from "../services/sensor_noise"; import { sensor_humid__components } from '../services/sensor_humid';
import { sensor_power__components } from "../services/sensor_power"; import { sensor_lumin__components } from '../services/sensor_lumin';
import { sensor_presence__components } from "../services/sensor_presence"; import { sensor_moist__components } from '../services/sensor_moist';
import { sensor_rain__components } from "../services/sensor_rain"; import { sensor_noise__components } from '../services/sensor_noise';
import { sensor_rotation__components } from "../services/sensor_rotation"; import { sensor_power__components } from '../services/sensor_power';
import { sensor_seismicint__components } from "../services/sensor_seismicint"; import { sensor_presence__components } from '../services/sensor_presence';
import { sensor_seismicmag__components } from "../services/sensor_seismicmag"; import { sensor_rain__components } from '../services/sensor_rain';
import { sensor_solarrad__components } from "../services/sensor_solarrad"; import { sensor_rotation__components } from '../services/sensor_rotation';
import { sensor_tank__components } from "../services/sensor_tank"; import { sensor_seismicint__components } from '../services/sensor_seismicint';
import { sensor_temp__components } from "../services/sensor_temp"; import { sensor_seismicmag__components } from '../services/sensor_seismicmag';
import { sensor_tidelvl__components } from "../services/sensor_tidelvl"; import { sensor_solarrad__components } from '../services/sensor_solarrad';
import { sensor_uv__components } from "../services/sensor_uv"; import { sensor_tank__components } from '../services/sensor_tank';
import { sensor_veloc__components } from "../services/sensor_veloc"; import { sensor_temp__components } from '../services/sensor_temp';
import { sensor_voltage__components } from "../services/sensor_voltage"; import { sensor_tidelvl__components } from '../services/sensor_tidelvl';
import { sensor_watflow__components } from "../services/sensor_watflow"; import { sensor_uv__components } from '../services/sensor_uv';
import { sensor_watpressure__components } from "../services/sensor_watpressure"; import { sensor_veloc__components } from '../services/sensor_veloc';
import { sensor_wattemp__components } from "../services/sensor_wattemp"; import { sensor_voltage__components } from '../services/sensor_voltage';
import { sensor_weight__components } from "../services/sensor_weight"; import { sensor_watflow__components } from '../services/sensor_watflow';
import { thermostat__components } from "../services/thermostat"; import { sensor_watpressure__components } from '../services/sensor_watpressure';
import { ha } from "./globals"; import { sensor_wattemp__components } from '../services/sensor_wattemp';
import { HaMqttComponent } from "./mqtt_components/_component"; 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 = { type HaDeviceConfig = {
// device /**
dev: { * 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/).
ids: string | null | undefined, * Only works when [`unique_id`](#unique_id) is set.
name: string | null | undefined, * At least one of identifiers or connections must be present to identify the device.
// manufacturer */
mf: string | null | undefined, device?: {
// model /**
mdl: string | null | undefined, * A link to the webpage that can manage the configuration of this device.
// software version * Can be either an `http://`, `https://` or an internal `homeassistant://` URL.
sw: string | null | undefined, */
// serial number configuration_url?: string;
sn: string | null | undefined,
// hardware number /**
hw: string | null | undefined, * 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 origin: {
o: { name: 'futurehome';
name: 'futurehome', url: 'https://github.com/adrianjagielak/home-assistant-futurehome';
url: 'https://github.com/adrianjagielak/home-assistant-futurehome',
}; };
// components components: {
cmps: {
[key: string]: HaMqttComponent; [key: string]: HaMqttComponent;
}, };
// state topic state_topic: string;
stat_t: string, availability_topic: string;
// availability topic qos: number;
avty_t: string, };
qos: number,
}
export type ServiceComponentsCreationResult = { export type ServiceComponentsCreationResult = {
components: { [key: string]: HaMqttComponent }; components: { [key: string]: HaMqttComponent };
commandHandlers?: CommandHandlers; commandHandlers?: CommandHandlers;
} };
export type CommandHandlers = { [topic: string]: (payload: string) => Promise<void> } export type CommandHandlers = {
[topic: string]: (payload: string) => Promise<void>;
};
const serviceHandlers: { 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, basic: basic__components,
battery: battery__components, battery: battery__components,
@ -144,17 +206,29 @@ const serviceHandlers: {
thermostat: thermostat__components, 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 components: { [key: string]: HaMqttComponent } = {};
const handlers: CommandHandlers = {}; const handlers: CommandHandlers = {};
// e.g. "homeassistant/device/futurehome_123456_1" // e.g. "homeassistant/device/futurehome_123456_1"
const topicPrefix = `homeassistant/device/futurehome_${parameters.hubId}_${parameters.vinculumDeviceData.id}`; const topicPrefix = `homeassistant/device/futurehome_${parameters.hubId}_${parameters.vinculumDeviceData.id}`;
for (const [svcName, svc] of Object.entries(parameters.vinculumDeviceData.services ?? {})) { for (const [svcName, svc] of Object.entries(
if (!svcName) { continue; } parameters.vinculumDeviceData.services ?? {},
if (!svc.addr) { continue; } )) {
if (!svc.enabled) { continue; } if (!svcName) {
continue;
}
if (!svc.addr) {
continue;
}
if (!svc.enabled) {
continue;
}
const handler = serviceHandlers[svcName]; const handler = serviceHandlers[svcName];
if (!handler) { if (!handler) {
@ -164,7 +238,9 @@ export function haPublishDevice(parameters: { hubId: string, vinculumDeviceData:
const result = handler(topicPrefix, parameters.vinculumDeviceData, svc); const result = handler(topicPrefix, parameters.vinculumDeviceData, svc);
if (!result) { 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; continue;
} }
@ -172,26 +248,36 @@ export function haPublishDevice(parameters: { hubId: string, vinculumDeviceData:
Object.assign(handlers, result.commandHandlers); Object.assign(handlers, result.commandHandlers);
} }
const configTopic = `${topicPrefix}/config` const configTopic = `${topicPrefix}/config`;
const stateTopic = `${topicPrefix}/state` const stateTopic = `${topicPrefix}/state`;
const availabilityTopic = `${topicPrefix}/availability` const availabilityTopic = `${topicPrefix}/availability`;
const config: HaDeviceConfig = { const config: HaDeviceConfig = {
dev: { device: {
ids: parameters.vinculumDeviceData.id.toString(), identifiers: parameters.vinculumDeviceData.id.toString(),
name: parameters.vinculumDeviceData?.client?.name ?? parameters.vinculumDeviceData?.modelAlias ?? parameters.deviceInclusionReport?.product_name, name:
mf: parameters.deviceInclusionReport?.manufacturer_id, parameters.vinculumDeviceData?.client?.name ??
mdl: parameters.vinculumDeviceData?.modelAlias ?? parameters.deviceInclusionReport?.product_id, parameters.vinculumDeviceData?.modelAlias ??
sw: parameters.deviceInclusionReport?.sw_ver, parameters.deviceInclusionReport?.product_name ??
sn: parameters.deviceInclusionReport?.product_hash, undefined,
hw: parameters.deviceInclusionReport?.hw_ver, 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', name: 'futurehome',
url: 'https://github.com/adrianjagielak/home-assistant-futurehome', url: 'https://github.com/adrianjagielak/home-assistant-futurehome',
}, },
cmps: components, components: components,
stat_t: stateTopic, state_topic: stateTopic,
avty_t: availabilityTopic, availability_topic: availabilityTopic,
qos: 2, qos: 2,
}; };