mirror of
https://github.com/adrianjagielak/home-assistant-futurehome.git
synced 2025-09-13 07:37:09 +00:00
Inclusion/exclusion improvements
This commit is contained in:
parent
d131297f2a
commit
1aad80ed38
@ -1,3 +1,61 @@
|
|||||||
|
export type DeviceFunctionality =
|
||||||
|
| 'appliance'
|
||||||
|
| 'climate'
|
||||||
|
| 'energy'
|
||||||
|
| 'ev_charger'
|
||||||
|
| 'lighting'
|
||||||
|
| 'media'
|
||||||
|
| 'other'
|
||||||
|
| 'power'
|
||||||
|
| 'safety'
|
||||||
|
| 'security'
|
||||||
|
| 'shading'
|
||||||
|
| string;
|
||||||
|
|
||||||
|
export type DeviceType =
|
||||||
|
| 'appliance'
|
||||||
|
| 'battery'
|
||||||
|
| 'blinds'
|
||||||
|
| 'boiler'
|
||||||
|
| 'chargepoint'
|
||||||
|
| 'door_lock'
|
||||||
|
| 'energy_storage'
|
||||||
|
| 'fan'
|
||||||
|
| 'fire_detector'
|
||||||
|
| 'garage_door'
|
||||||
|
| 'gas_detector'
|
||||||
|
| 'gate'
|
||||||
|
| 'heat_detector'
|
||||||
|
| 'heat_pump'
|
||||||
|
| 'heater'
|
||||||
|
| 'input'
|
||||||
|
| 'inverter'
|
||||||
|
| 'leak_detector'
|
||||||
|
| 'light'
|
||||||
|
| 'media_player'
|
||||||
|
| 'meter'
|
||||||
|
| 'none'
|
||||||
|
| 'sensor'
|
||||||
|
| 'siren'
|
||||||
|
| 'thermostat'
|
||||||
|
| 'water_valve'
|
||||||
|
| string;
|
||||||
|
|
||||||
|
export type DeviceSubType =
|
||||||
|
| 'car_charger'
|
||||||
|
| 'door'
|
||||||
|
| 'door_lock'
|
||||||
|
| 'garage'
|
||||||
|
| 'lock'
|
||||||
|
| 'main_elec'
|
||||||
|
| 'none'
|
||||||
|
| 'other'
|
||||||
|
| 'presence'
|
||||||
|
| 'scene'
|
||||||
|
| 'window'
|
||||||
|
| 'window_lock'
|
||||||
|
| string;
|
||||||
|
|
||||||
export type VinculumPd7Device = {
|
export type VinculumPd7Device = {
|
||||||
client?: {
|
client?: {
|
||||||
// User-defined device name
|
// User-defined device name
|
||||||
@ -5,75 +63,29 @@ export type VinculumPd7Device = {
|
|||||||
} | null;
|
} | null;
|
||||||
// FIMP Device ID.
|
// FIMP Device ID.
|
||||||
id: number;
|
id: number;
|
||||||
|
fimp?: {
|
||||||
|
adapter?: 'zigbee' | 'zwave-ad' | string | null;
|
||||||
|
// FIMP Device address (ID) in the context of its adapter.
|
||||||
|
address?: string | null;
|
||||||
|
} | null;
|
||||||
// FIMP Thing Address (ID).
|
// FIMP Thing Address (ID).
|
||||||
thing?: number | null;
|
thing?: string | null;
|
||||||
// "Model" string, e.g. "zb - _TZ3040_bb6xaihh - TS0202"
|
// "Model" string, e.g. "zb - _TZ3040_bb6xaihh - TS0202"
|
||||||
// The first one is the adapter, the second one is the manufacturer, the third one is the device model.
|
// The first one is the adapter, the second one is the manufacturer, the third one is the device model.
|
||||||
model?: string | null;
|
model?: string | null;
|
||||||
// Device model, e.g. "TS0202"
|
// Device model, e.g. "TS0202"
|
||||||
modelAlias?: string | null;
|
modelAlias?: string | null;
|
||||||
functionality?:
|
functionality?: DeviceFunctionality | null;
|
||||||
| 'appliance'
|
|
||||||
| 'climate'
|
|
||||||
| 'energy'
|
|
||||||
| 'ev_charger'
|
|
||||||
| 'lighting'
|
|
||||||
| 'media'
|
|
||||||
| 'other'
|
|
||||||
| 'power'
|
|
||||||
| 'safety'
|
|
||||||
| 'security'
|
|
||||||
| 'shading'
|
|
||||||
| string
|
|
||||||
| null;
|
|
||||||
services?: Record<string, VinculumPd7Service> | null;
|
services?: Record<string, VinculumPd7Service> | null;
|
||||||
type?: {
|
type?: {
|
||||||
// User-defined device type
|
// User-defined device type
|
||||||
type?:
|
type?: DeviceType | null;
|
||||||
| 'appliance'
|
|
||||||
| 'battery'
|
|
||||||
| 'blinds'
|
|
||||||
| 'boiler'
|
|
||||||
| 'chargepoint'
|
|
||||||
| 'door_lock'
|
|
||||||
| 'energy_storage'
|
|
||||||
| 'fan'
|
|
||||||
| 'fire_detector'
|
|
||||||
| 'garage_door'
|
|
||||||
| 'gas_detector'
|
|
||||||
| 'gate'
|
|
||||||
| 'heat_detector'
|
|
||||||
| 'heat_pump'
|
|
||||||
| 'heater'
|
|
||||||
| 'input'
|
|
||||||
| 'inverter'
|
|
||||||
| 'leak_detector'
|
|
||||||
| 'light'
|
|
||||||
| 'media_player'
|
|
||||||
| 'meter'
|
|
||||||
| 'none'
|
|
||||||
| 'sensor'
|
|
||||||
| 'siren'
|
|
||||||
| 'thermostat'
|
|
||||||
| 'water_valve'
|
|
||||||
| string
|
|
||||||
| null;
|
|
||||||
// User-defined device subtype
|
// User-defined device subtype
|
||||||
subtype?:
|
subtype?: DeviceSubType | null;
|
||||||
| 'car_charger'
|
// Supported device types and subtypes for this device
|
||||||
| 'door'
|
supported?: {
|
||||||
| 'door_lock'
|
[key: DeviceType]: DeviceSubType[];
|
||||||
| 'garage'
|
} | null;
|
||||||
| 'lock'
|
|
||||||
| 'main_elec'
|
|
||||||
| 'none'
|
|
||||||
| 'other'
|
|
||||||
| 'presence'
|
|
||||||
| 'scene'
|
|
||||||
| 'window'
|
|
||||||
| 'window_lock'
|
|
||||||
| string
|
|
||||||
| null;
|
|
||||||
} | null;
|
} | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -340,21 +340,9 @@ export function handleInclusionStatusReport(hubId: string, msg: FimpResponse) {
|
|||||||
case 'ADD_NODE_GET_NODE_INFO':
|
case 'ADD_NODE_GET_NODE_INFO':
|
||||||
case 'ADD_NODE_PROTOCOL_DONE':
|
case 'ADD_NODE_PROTOCOL_DONE':
|
||||||
localizedStatus = 'Device added successfully!';
|
localizedStatus = 'Device added successfully!';
|
||||||
pollVinculum('device').catch((e) =>
|
|
||||||
log.warn('Failed to request devices', e),
|
|
||||||
);
|
|
||||||
pollVinculum('state').catch((e) =>
|
|
||||||
log.warn('Failed to request state', e),
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case 'ADD_NODE_DONE':
|
case 'ADD_NODE_DONE':
|
||||||
localizedStatus = 'Done';
|
localizedStatus = 'Done';
|
||||||
pollVinculum('device').catch((e) =>
|
|
||||||
log.warn('Failed to request devices', e),
|
|
||||||
);
|
|
||||||
pollVinculum('state').catch((e) =>
|
|
||||||
log.warn('Failed to request state', e),
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case 'NET_NODE_INCL_CTRL_OP_FAILED':
|
case 'NET_NODE_INCL_CTRL_OP_FAILED':
|
||||||
localizedStatus = "Operation failed. The device can't be included.";
|
localizedStatus = "Operation failed. The device can't be included.";
|
||||||
@ -389,12 +377,6 @@ export function handleExclusionStatusReport(hubId: string, msg: FimpResponse) {
|
|||||||
break;
|
break;
|
||||||
case 'REMOVE_NODE_DONE':
|
case 'REMOVE_NODE_DONE':
|
||||||
localizedStatus = 'Done';
|
localizedStatus = 'Done';
|
||||||
pollVinculum('device').catch((e) =>
|
|
||||||
log.warn('Failed to request devices', e),
|
|
||||||
);
|
|
||||||
pollVinculum('state').catch((e) =>
|
|
||||||
log.warn('Failed to request state', e),
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case 'NET_NODE_REMOVE_FAILED':
|
case 'NET_NODE_REMOVE_FAILED':
|
||||||
localizedStatus = "Operation failed. The device can't be excluded.";
|
localizedStatus = "Operation failed. The device can't be excluded.";
|
||||||
@ -415,6 +397,11 @@ export function handleExclusionStatusReport(hubId: string, msg: FimpResponse) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function handleInclusionReport() {
|
||||||
|
pollVinculum('device').catch((e) => log.warn('Failed to request devices', e));
|
||||||
|
pollVinculum('state').catch((e) => log.warn('Failed to request state', e));
|
||||||
|
}
|
||||||
|
|
||||||
export function handleExclusionReport() {
|
export function handleExclusionReport() {
|
||||||
pollVinculum('device').catch((e) => log.warn('Failed to request devices', e));
|
pollVinculum('device').catch((e) => log.warn('Failed to request devices', e));
|
||||||
pollVinculum('state').catch((e) => log.warn('Failed to request state', e));
|
pollVinculum('state').catch((e) => log.warn('Failed to request state', e));
|
||||||
|
@ -31,7 +31,10 @@ import { sound_switch__components } from '../services/sound_switch';
|
|||||||
import { thermostat__components } from '../services/thermostat';
|
import { thermostat__components } from '../services/thermostat';
|
||||||
import { user_code__components } from '../services/user_code';
|
import { user_code__components } from '../services/user_code';
|
||||||
import { water_heater__components } from '../services/water_heater';
|
import { water_heater__components } from '../services/water_heater';
|
||||||
import { connectThingsplexWebSocketAndSend, loginToThingsplex } from '../thingsplex/thingsplex';
|
import {
|
||||||
|
connectThingsplexWebSocketAndSend,
|
||||||
|
loginToThingsplex,
|
||||||
|
} from '../thingsplex/thingsplex';
|
||||||
import { abbreviateHaMqttKeys } from './abbreviate_ha_mqtt_keys';
|
import { abbreviateHaMqttKeys } from './abbreviate_ha_mqtt_keys';
|
||||||
import { ha, haCommandHandlers } from './globals';
|
import { ha, haCommandHandlers } from './globals';
|
||||||
import { HaDeviceConfig } from './ha_device_config';
|
import { HaDeviceConfig } from './ha_device_config';
|
||||||
@ -258,35 +261,26 @@ export function haPublishDevice(parameters: {
|
|||||||
Object.assign(handlers, result.commandHandlers);
|
Object.assign(handlers, result.commandHandlers);
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstSvcAddr =
|
|
||||||
Object.entries(parameters.vinculumDeviceData.services ?? {})?.[0]?.[1]
|
|
||||||
.addr ?? '';
|
|
||||||
if (
|
if (
|
||||||
parameters.thingsplexUsername &&
|
parameters.thingsplexUsername &&
|
||||||
parameters.thingsplexPassword &&
|
parameters.thingsplexPassword &&
|
||||||
parameters.vinculumDeviceData.thing &&
|
parameters.vinculumDeviceData.fimp?.address &&
|
||||||
(firstSvcAddr.includes('/rn:zigbee/ad:1/') ||
|
(parameters.vinculumDeviceData.fimp?.adapter === 'zigbee' ||
|
||||||
firstSvcAddr.includes('/rn:zw/ad:1/'))
|
parameters.vinculumDeviceData.fimp?.adapter === 'zwave-ad')
|
||||||
) {
|
) {
|
||||||
const deleteCommandTopic = `${topicPrefix}/delete/command`;
|
const deleteCommandTopic = `${topicPrefix}/delete/command`;
|
||||||
const availabilityTopic = `${topicPrefix}/delete/availability`;
|
|
||||||
components[`${topicPrefix}_delete_button`] = {
|
components[`${topicPrefix}_delete_button`] = {
|
||||||
unique_id: `${topicPrefix}_delete_button`,
|
unique_id: `${topicPrefix}_delete_button`,
|
||||||
platform: 'button',
|
platform: 'button',
|
||||||
entity_category: 'diagnostic',
|
entity_category: 'diagnostic',
|
||||||
name: firstSvcAddr.includes('/rn:zigbee/ad:1/')
|
name:
|
||||||
? 'ZigBee: Unpair Device'
|
parameters.vinculumDeviceData.fimp?.adapter === 'zigbee'
|
||||||
: 'Z-Wave: Unpair Device',
|
? 'ZigBee: Unpair Device'
|
||||||
|
: 'Z-Wave: Unpair Device',
|
||||||
icon: 'mdi:delete-forever',
|
icon: 'mdi:delete-forever',
|
||||||
command_topic: deleteCommandTopic,
|
command_topic: deleteCommandTopic,
|
||||||
availability_topic: availabilityTopic,
|
|
||||||
availability_template: `{% if value == "online" or value == "" %}online{% else %}offline{% endif %}`,
|
|
||||||
} as any;
|
} as any;
|
||||||
handlers[deleteCommandTopic] = async (_payload: string) => {
|
handlers[deleteCommandTopic] = async (_payload: string) => {
|
||||||
ha?.publish(availabilityTopic, 'offline', {
|
|
||||||
retain: true,
|
|
||||||
qos: 2,
|
|
||||||
});
|
|
||||||
try {
|
try {
|
||||||
const token = await loginToThingsplex({
|
const token = await loginToThingsplex({
|
||||||
host: parameters.hubIp,
|
host: parameters.hubIp,
|
||||||
@ -300,25 +294,24 @@ export function haPublishDevice(parameters: {
|
|||||||
},
|
},
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
address: firstSvcAddr.includes('/rn:zigbee/ad:1/')
|
address:
|
||||||
? 'pt:j1/mt:cmd/rt:ad/rn:zigbee/ad:1'
|
parameters.vinculumDeviceData.fimp?.adapter === 'zigbee'
|
||||||
: 'pt:j1/mt:evt/rt:ad/rn:zw/ad:1',
|
? 'pt:j1/mt:cmd/rt:ad/rn:zigbee/ad:1'
|
||||||
service: firstSvcAddr.includes('/rn:zigbee/ad:1/')
|
: 'pt:j1/mt:evt/rt:ad/rn:zw/ad:1',
|
||||||
? 'zigbee'
|
service:
|
||||||
: 'zwave-ad',
|
parameters.vinculumDeviceData.fimp?.adapter === 'zigbee'
|
||||||
|
? 'zigbee'
|
||||||
|
: 'zwave-ad',
|
||||||
cmd: 'cmd.thing.delete',
|
cmd: 'cmd.thing.delete',
|
||||||
val_t: 'str_map',
|
val_t: 'str_map',
|
||||||
val: {
|
val: {
|
||||||
address: parameters.vinculumDeviceData.thing,
|
address: parameters.vinculumDeviceData.fimp?.address,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ha?.publish(availabilityTopic, 'online', {
|
log.error('Failed to delete device:', e);
|
||||||
retain: true,
|
|
||||||
qos: 2,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,13 @@ import { haUpdateState, haUpdateStateValueReport } from './ha/update_state';
|
|||||||
import { VinculumPd7Device } from './fimp/vinculum_pd7_device';
|
import { VinculumPd7Device } from './fimp/vinculum_pd7_device';
|
||||||
import { haUpdateAvailability } from './ha/update_availability';
|
import { haUpdateAvailability } from './ha/update_availability';
|
||||||
import { delay } from './utils';
|
import { delay } from './utils';
|
||||||
import { exposeSmarthubTools, handleExclusionReport, handleExclusionStatusReport, handleInclusionStatusReport } from './ha/admin';
|
import {
|
||||||
|
exposeSmarthubTools,
|
||||||
|
handleExclusionReport,
|
||||||
|
handleExclusionStatusReport,
|
||||||
|
handleInclusionReport,
|
||||||
|
handleInclusionStatusReport,
|
||||||
|
} from './ha/admin';
|
||||||
import { pollVinculum } from './fimp/vinculum';
|
import { pollVinculum } from './fimp/vinculum';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
@ -264,12 +270,17 @@ import { pollVinculum } from './fimp/vinculum';
|
|||||||
handleInclusionStatusReport(hubId, msg);
|
handleInclusionStatusReport(hubId, msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'evt.thing.exclusion_status_report': {
|
case 'evt.thing.exclusion_status_report': {
|
||||||
handleExclusionStatusReport(hubId, msg);
|
handleExclusionStatusReport(hubId, msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'evt.thing.inclusion_report': {
|
||||||
|
handleInclusionReport();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'evt.thing.exclusion_report': {
|
case 'evt.thing.exclusion_report': {
|
||||||
handleExclusionReport();
|
handleExclusionReport();
|
||||||
break;
|
break;
|
||||||
|
@ -7,6 +7,11 @@ import { v4 as uuidv4 } from 'uuid';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs in to the Thingsplex and extracts the tplex token.
|
* Logs in to the Thingsplex and extracts the tplex token.
|
||||||
|
*
|
||||||
|
* The use of Thingsplex is required for including and excluding devices,
|
||||||
|
* as the regular Local API (SmartHub MQTT broker on port 1884)
|
||||||
|
* does not support inclusion or exclusion commands.
|
||||||
|
*
|
||||||
* @param username - The login username
|
* @param username - The login username
|
||||||
* @param password - The login password
|
* @param password - The login password
|
||||||
* @returns The tplex token if login is successful
|
* @returns The tplex token if login is successful
|
||||||
@ -54,6 +59,11 @@ export async function loginToThingsplex(parameters: {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to the Thingsplex websocket with the tplex token and sends the messages.
|
* Connects to the Thingsplex websocket with the tplex token and sends the messages.
|
||||||
|
*
|
||||||
|
* The use of Thingsplex is required for including and excluding devices,
|
||||||
|
* as the regular Local API (SmartHub MQTT broker on port 1884)
|
||||||
|
* does not support inclusion or exclusion commands.
|
||||||
|
*
|
||||||
* @param token - The tplex token from login
|
* @param token - The tplex token from login
|
||||||
*/
|
*/
|
||||||
export function connectThingsplexWebSocketAndSend(
|
export function connectThingsplexWebSocketAndSend(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user