2025-07-26 02:38:22 +02:00

176 lines
4.8 KiB
TypeScript

import { sendFimpMsg } from '../fimp/fimp';
import {
VinculumPd7Device,
VinculumPd7Service,
} from '../fimp/vinculum_pd7_device';
import { HaMqttComponent } from '../ha/mqtt_components/_component';
import { CoverDeviceClass } from '../ha/mqtt_components/_enums';
import { CoverComponent } from '../ha/mqtt_components/cover';
import {
CommandHandlers,
ServiceComponentsCreationResult,
} from '../ha/publish_device';
export function barrier_ctrl__components(
topicPrefix: string,
device: VinculumPd7Device,
svc: VinculumPd7Service,
_svcName: string,
): ServiceComponentsCreationResult | undefined {
const components: Record<string, HaMqttComponent> = {};
const commandHandlers: CommandHandlers = {};
// Main cover component
const commandTopic = `${topicPrefix}${svc.addr}/command`;
const positionCommandTopic = `${topicPrefix}${svc.addr}/set_position`;
const stopCommandTopic = `${topicPrefix}${svc.addr}/stop`;
// Determine device class based on device type/functionality
let deviceClass: CoverDeviceClass;
if (
device.type?.type === 'garage_door' ||
device.functionality === 'security'
) {
deviceClass = 'garage';
} else if (device.type?.type === 'gate') {
deviceClass = 'gate';
} else if (
device.type?.type === 'blinds' ||
device.functionality === 'shading'
) {
deviceClass = 'blind';
} else {
deviceClass = null;
}
const name = deviceClass ? undefined : 'Barrier';
// Check if position control is supported
const supportsPosition = svc.props?.sup_tposition === true;
const supportedTargetStates = svc.props?.sup_tstates || [];
const coverComponent: CoverComponent = {
unique_id: svc.addr,
platform: 'cover',
device_class: deviceClass,
name: name,
command_topic: commandTopic,
optimistic: false,
value_template: `{{ value_json['${svc.addr}'].state }}`,
// Standard Home Assistant cover payloads
payload_open: 'OPEN',
payload_close: 'CLOSE',
payload_stop: 'STOP',
state_open: 'open',
state_closed: 'closed',
state_opening: 'opening',
state_closing: 'closing',
state_stopped: 'stopped',
};
// Add position support if available
if (supportsPosition) {
coverComponent.set_position_topic = positionCommandTopic;
coverComponent.position_template = `{{ value_json['${svc.addr}'].position | default(0) }}`;
coverComponent.position_closed = 0;
coverComponent.position_open = 100;
}
// Add stop command if supported
if (svc.intf?.includes('cmd.op.stop')) {
coverComponent.command_topic = stopCommandTopic;
}
components[svc.addr] = coverComponent;
// Command handlers
commandHandlers[commandTopic] = async (payload: string) => {
let targetState: string;
switch (payload) {
case 'OPEN':
targetState = 'open';
break;
case 'CLOSE':
targetState = 'closed';
break;
case 'STOP':
if (svc.intf?.includes('cmd.op.stop')) {
await sendFimpMsg({
address: svc.addr,
service: 'barrier_ctrl',
cmd: 'cmd.op.stop',
val_t: 'null',
val: null,
});
}
return;
default:
return;
}
// Only send target state if it's supported
if (supportedTargetStates.includes(targetState)) {
await sendFimpMsg({
address: svc.addr,
service: 'barrier_ctrl',
cmd: 'cmd.tstate.set',
val_t: 'string',
val: targetState,
});
}
};
// Position command handler (if position control is supported)
if (supportsPosition) {
commandHandlers[positionCommandTopic] = async (payload: string) => {
const position = parseInt(payload, 10);
if (Number.isNaN(position) || position < 0 || position > 100) {
return;
}
// Determine target state based on position
let targetState: string;
if (position === 0) {
targetState = 'closed';
} else if (position === 100) {
targetState = 'open';
} else {
// For partial positions, we'll use 'open' as the target state
targetState = 'open';
}
// Only send if target state is supported
if (supportedTargetStates.includes(targetState)) {
await sendFimpMsg({
address: svc.addr,
service: 'barrier_ctrl',
cmd: 'cmd.tstate.set',
val_t: 'string',
val: targetState,
props: {
position: position.toString(),
},
});
}
};
}
// Stop command handler (separate topic if needed)
if (svc.intf?.includes('cmd.op.stop')) {
commandHandlers[stopCommandTopic] = async (_payload: string) => {
await sendFimpMsg({
address: svc.addr,
service: 'barrier_ctrl',
cmd: 'cmd.op.stop',
val_t: 'null',
val: null,
});
};
}
return {
components,
commandHandlers,
};
}