Add support for 'parameters' service

This commit is contained in:
Adrian Jagielak 2025-07-27 01:08:05 +02:00
parent 9aac6c489f
commit b882cbab91
No known key found for this signature in database
GPG Key ID: 0818CF7AF6C62BFB
8 changed files with 151 additions and 19 deletions

View File

@ -65,8 +65,9 @@ todo add info about factory reset hub to restore 30 day trial
| Name | Service | Implementation status | Home Assistant entity |
| --- | --- | --- | --- |
| Identify device | [indicator_ctrl](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/indicator_ctrl.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/) |
| Reboot device | [dev_sys](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/dev_sys.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/) |
| Identify device | [indicator_ctrl](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/indicator_ctrl.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/) |
| Advanced configuration of a device | [parameters](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/parameters.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/), [Sensor](https://www.home-assistant.io/integrations/sensor/), [Number](https://www.home-assistant.io/integrations/number/), [Select](https://www.home-assistant.io/integrations/select/), [Text](https://www.home-assistant.io/integrations/text/) |
## Other system, meta, unused, or not essential services
@ -80,10 +81,9 @@ todo add info about factory reset hub to restore 30 day trial
| inverter_grid_conn | No devices or hub support this stub service. |
| inverter_solar_conn | No devices or hub support this stub service. |
| ota | Managing OTA updates of devices |
| parameters | |
| Power regulator | [power_regulator](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/power_regulator.ts) | [16A Puck Relé](https://www.futurehome.io/en_no/shop/puck-relay-16a) | | |
| power_regulator | Automation. Easily reproducible using Home Assistant's built-in configuration. |
| schedule | No devices or hub support this stub service. |
| technology_specific | |
| technology_specific | Should be covered by other services |
| time | Z-wave service for setting and reading time |
| time_parameters | Z-wave service for setting and reading time |
| version | Device hardware and software versions. Exposed through other means. |

View File

@ -12,6 +12,7 @@
- Added support for 'doorman' service (Yale door locks).
- Added support for 'complex_alarm_system' service (part of alarm sirens control).
- Added support for 'dev_sys' service (reboot device).
- Added support for 'parameters' service (advanced configuration of a device).
## 0.1.5 (25.07.2025)

View File

@ -64,8 +64,9 @@ todo add info about factory reset hub to restore 30 day trial
| Name | Service | Implementation status | Home Assistant entity |
| --- | --- | --- | --- |
| Identify device | [indicator_ctrl](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/indicator_ctrl.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/) |
| Reboot device | [dev_sys](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/dev_sys.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/) |
| Identify device | [indicator_ctrl](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/indicator_ctrl.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/) |
| Advanced configuration of a device | [parameters](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/parameters.ts) | | ✅ | [Button](https://www.home-assistant.io/integrations/button/), [Sensor](https://www.home-assistant.io/integrations/sensor/), [Number](https://www.home-assistant.io/integrations/number/), [Select](https://www.home-assistant.io/integrations/select/), [Text](https://www.home-assistant.io/integrations/text/) |
## Other system, meta, unused, or not essential services
@ -79,10 +80,9 @@ todo add info about factory reset hub to restore 30 day trial
| inverter_grid_conn | No devices or hub support this stub service. |
| inverter_solar_conn | No devices or hub support this stub service. |
| ota | Managing OTA updates of devices |
| parameters | |
| Power regulator | [power_regulator](https://github.com/adrianjagielak/home-assistant-futurehome/blob/master/futurehome/src/services/power_regulator.ts) | [16A Puck Relé](https://www.futurehome.io/en_no/shop/puck-relay-16a) | | |
| power_regulator | Automation. Easily reproducible using Home Assistant's built-in configuration. |
| schedule | No devices or hub support this stub service. |
| technology_specific | |
| technology_specific | Should be covered by other services |
| time | Z-wave service for setting and reading time |
| time_parameters | Z-wave service for setting and reading time |
| version | Device hardware and software versions. Exposed through other means. |

View File

@ -22,6 +22,7 @@ import { indicator_ctrl__components } from '../services/indicator_ctrl';
import { media_player__components } from '../services/media_player';
import { out_bin_switch__components } from '../services/out_bin_switch';
import { out_lvl_switch__components } from '../services/out_lvl_switch';
import { parameters__components } from '../services/parameters';
import { scene_ctrl__components } from '../services/scene_ctrl';
import { schedule_entry__components } from '../services/schedule_entry';
import { siren_ctrl__components } from '../services/siren_ctrl';
@ -169,6 +170,7 @@ const serviceHandlers: {
meter_cooling: _meter__components,
out_bin_switch: out_bin_switch__components,
out_lvl_switch: out_lvl_switch__components,
parameters: parameters__components,
scene_ctrl: scene_ctrl__components,
schedule_entry: schedule_entry__components,
sensor_accelx: _sensor_numeric__components,
@ -301,9 +303,6 @@ export function haPublishDevice(parameters: {
svcName,
);
if (!result) {
log.error(
`Invalid service data prevented component creation: ${parameters.vinculumDeviceData} ${svc}`,
);
continue;
}

View File

@ -179,6 +179,7 @@ const attributeTypeKeyMap: Record<string, string> = {
alarm: 'event',
meter: 'props.unit',
meter_export: 'props.unit',
param: 'parameter_id',
};
function getNestedValue(obj: any, path: string): any {
@ -211,10 +212,21 @@ function processAttributeValues(values: any[], attrName?: string): any {
return undefined;
}
// Sort by timestamp to get the latest values first
// Special handling for "param" attributes
if (attrName === 'param') {
const paramMap: Record<string, any> = {};
for (const entry of values) {
if (entry.parameter_id) {
paramMap[entry.parameter_id] = { ...entry };
}
}
return paramMap;
}
// Sort by timestamp to get the latest values first (only if ts exists)
const sortedValues = [...values].sort((a, b) => {
const tsA = new Date(a.ts).getTime();
const tsB = new Date(b.ts).getTime();
const tsA = a.ts ? new Date(a.ts).getTime() : 0;
const tsB = b.ts ? new Date(b.ts).getTime() : 0;
return tsB - tsA; // Latest first
});

View File

@ -2303,9 +2303,9 @@
"type": "meter"
},
"services": {
"meter_heat": {
"name": "meter_heat",
"addr": "/rt:dev/rn:hoiax/ad:1/sv:meter_heat/ad:298",
"meter_heating": {
"name": "meter_heating",
"addr": "/rt:dev/rn:hoiax/ad:1/sv:meter_heating/ad:298",
"enabled": true,
"props": {
"sup_units": ["kWh", "W"]

View File

@ -1091,6 +1091,26 @@
}
],
"name": "meter_elec"
},
{
"addr": "/rt:dev/rn:cloud_adapter/ad:1/sv:parameters/ad:3_1",
"attributes": [
{
"name": "param",
"values": [
{
"parameter_id": "cable_always_locked",
"value_type": "bool",
"value": false
},
{
"parameter_id": "free_charging",
"value_type": "bool",
"value": true
}
]
}
]
}
]
},
@ -1668,7 +1688,7 @@
"id": 298,
"services": [
{
"addr": "/rt:dev/rn:hoiax/ad:1/sv:meter_heat/ad:298",
"addr": "/rt:dev/rn:hoiax/ad:1/sv:meter_heating/ad:298",
"attributes": [
{
"name": "meter",
@ -1692,7 +1712,7 @@
]
}
],
"name": "meter_heat"
"name": "meter_heating"
}
]
},

View File

@ -0,0 +1,100 @@
import { sendFimpMsg } from '../fimp/fimp';
import {
VinculumPd7Device,
VinculumPd7Service,
} from '../fimp/vinculum_pd7_device';
import { haGetCachedState } from '../ha/update_state';
import {
ServiceComponentsCreationResult,
CommandHandlers,
} from '../ha/publish_device';
import { HaMqttComponent } from '../ha/mqtt_components/_component';
export function parameters__components(
topicPrefix: string,
device: VinculumPd7Device,
svc: VinculumPd7Service,
_svcName: string,
): ServiceComponentsCreationResult | undefined {
const components: Record<string, HaMqttComponent> = {};
const commandHandlers: CommandHandlers = {};
const stateTopic = `${topicPrefix}/state`;
// Fetch cached state for this service to discover known parameters :contentReference[oaicite:2]{index=2}
const currentState = haGetCachedState({ topic: stateTopic })?.[svc.addr];
const paramMap = currentState?.param;
if (!paramMap) {
// No parameters known → nothing to expose
return;
}
// Single MQTT topic for setting any parameter
const setParamTopic = `${topicPrefix}${svc.addr}/set_param/command`;
// Iterate over each parameter in the cached state :contentReference[oaicite:3]{index=3}
for (const [paramId, param] of Object.entries(paramMap)) {
const valueType = (param as any).value_type as string;
const uniqueId = `${svc.addr}_${paramId}`;
const name = paramId.replace(/_/g, ' ');
const valueTemplate = `{{ value_json['${svc.addr}'].param.${paramId}.value }}`;
if (valueType === 'bool') {
components[uniqueId] = {
unique_id: uniqueId,
platform: 'switch',
name,
state_topic: stateTopic,
value_template: valueTemplate,
command_topic: setParamTopic,
payload_on: `{"parameter_id":"${paramId}","value_type":"${valueType}","value":true}`,
payload_off: `{"parameter_id":"${paramId}","value_type":"${valueType}","value":false}`,
};
} else if (
['int', 'float', 'double', 'uint8', 'uint16', 'uint32'].includes(
valueType,
)
) {
components[uniqueId] = {
unique_id: uniqueId,
platform: 'number',
name,
state_topic: stateTopic,
value_template: valueTemplate,
command_topic: setParamTopic,
command_template: `{"parameter_id":"${paramId}","value_type":"${valueType}","value":{{ value }}}`,
};
} else {
components[uniqueId] = {
unique_id: uniqueId,
platform: 'text',
name,
state_topic: stateTopic,
value_template: valueTemplate,
command_topic: setParamTopic,
};
}
}
// Single handler for all set_param commands
commandHandlers[setParamTopic] = async (payload: string) => {
let valObj: any;
try {
valObj = JSON.parse(payload);
} catch {
// Invalid JSON: ignore
return;
}
await sendFimpMsg({
address: svc.addr!,
service: 'parameters',
cmd: 'cmd.param.set',
val: valObj,
val_t: 'object',
});
};
return {
components,
commandHandlers,
};
}