matterbridge
Version:
Matterbridge plugin manager for Matter
142 lines • 7.12 kB
JavaScript
/**
* This file contains the helpers functions of Matterbridge.
*
* @file helpers.ts
* @author Luca Liguori
* @date 2025-05-12
* @version 1.0.0
*
* Copyright 2025, 2026, 2027 Luca Liguori.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. *
*/
// @matter module
import { OnOff } from '@matter/main/clusters/on-off';
import { Endpoint } from '@matter/node';
import { BridgedDeviceBasicInformationServer } from '@matter/node/behaviors/bridged-device-basic-information';
import { OnOffBaseServer } from '@matter/node/behaviors/on-off';
import { OnOffPlugInUnitDevice } from '@matter/node/devices/on-off-plug-in-unit';
import { hasParameter } from './utils/commandLine.js';
import { MountedOnOffControlDevice } from '@matter/node/devices/mounted-on-off-control';
import { OnOffLightDevice } from '@matter/node/devices/on-off-light';
import { OnOffLightSwitchDevice } from '@matter/node/devices/on-off-light-switch';
/**
* Adds a virtual device to the provided endpoint, sets up an event listener for device state changes,
* and ensures the device is initialized in the off state.
*
* @param {Endpoint<AggregatorEndpoint>} aggregatorEndpoint - The aggragator endpoint to which the virtual device will be added.
* @param {string} name - The name of the virtual device. Spaces in the name are removed to form the device ID.
* @param {'light' | 'outlet' | 'switch' | 'mounted_switch'} type - The type of the virtual device. Can be 'light', 'outlet', 'switch', or 'mounted_switch'.
* @param {() => Promise<void>} callback - A callback function that gets executed when the device's on/off state changes to true.
* @returns {Promise<Endpoint>} A promise that resolves with the created virtual device.
* @remark The virtual device is created as an instance of `Endpoint` with the `OnOffPlugInUnitDevice` device type.
* The onOff state always reverts to false when the device is turned on.
*/
export async function addVirtualDevice(aggregatorEndpoint, name, type, callback) {
// Create a new virtual device by instantiating `Endpoint` with device information.
// The device ID is created by replacing all spaces in the name with an empty string.
// The node label of the bridged device basic information is set to the given name.
let deviceType;
switch (type) {
case 'light':
deviceType = OnOffLightDevice.with(BridgedDeviceBasicInformationServer);
break;
case 'outlet':
deviceType = OnOffPlugInUnitDevice.with(BridgedDeviceBasicInformationServer);
break;
case 'switch':
deviceType = OnOffLightSwitchDevice.with(BridgedDeviceBasicInformationServer, OnOffBaseServer);
break;
case 'mounted_switch':
deviceType = MountedOnOffControlDevice.with(BridgedDeviceBasicInformationServer);
break;
}
const device = new Endpoint(deviceType, {
id: name.replaceAll(' ', '') + ':' + type,
bridgedDeviceBasicInformation: { nodeLabel: name.slice(0, 32) },
onOff: { onOff: false, startUpOnOff: OnOff.StartUpOnOff.Off },
});
// Set up an event listener for when the `onOff` state changes.
device.events.onOff.onOff$Changed.on((value) => {
// If the `onOff` state becomes true, turn off the virtual device and execute the callback.
if (value) {
callback();
process.nextTick(async () => {
try {
await device.setStateOf(OnOffBaseServer, { onOff: false });
}
catch (_error) {
// Not necessary to handle the error
}
});
}
});
// Add the created device to the given endpoint.
await aggregatorEndpoint.add(device);
// Initially set the state of the virtual device's `OnOffBaseServer` to false (off).
await device.setStateOf(OnOffBaseServer, { onOff: false });
return device;
}
/**
* Creates and add the virtual devices to the aggregator.
*
* @param {Matterbridge} matterbridge - The Matterbridge instance.
* @param {Endpoint<AggregatorEndpoint>} aggregatorEndpoint - The aggregator node to add the virtual devices to.
* @returns {Promise<void>} A promise that resolves when the virtual devices are added.
*/
export async function addVirtualDevices(matterbridge, aggregatorEndpoint) {
if (matterbridge.matterbridgeInformation.virtualMode !== 'disabled' && matterbridge.bridgeMode === 'bridge' && aggregatorEndpoint) {
matterbridge.log.notice(`Creating virtual devices for Matterbridge server node...`);
await addVirtualDevice(aggregatorEndpoint, 'Restart Matterbridge', matterbridge.matterbridgeInformation.virtualMode, async () => {
if (matterbridge.restartMode === '')
await matterbridge.restartProcess();
else
await matterbridge.shutdownProcess();
});
await addVirtualDevice(aggregatorEndpoint, 'Update Matterbridge', matterbridge.matterbridgeInformation.virtualMode, async () => {
if (hasParameter('shelly')) {
const { getShelly } = await import('./shelly.js');
getShelly('/api/updates/sys/perform', 10 * 1000)
.then(() => {
matterbridge.log.notice('Shelly system updated successfully');
})
.catch((error) => {
matterbridge.log.error(`Error updating shelly system: ${error}`);
});
getShelly('/api/updates/main/perform', 10 * 1000)
.then(() => {
matterbridge.log.notice('Shelly software updated successfully');
})
.catch((error) => {
matterbridge.log.error(`Error updating shelly software: ${error}`);
});
}
else {
await matterbridge.updateProcess();
}
});
if (hasParameter('shelly')) {
await addVirtualDevice(aggregatorEndpoint, 'Reboot Matterbridge', matterbridge.matterbridgeInformation.virtualMode, async () => {
const { postShelly } = await import('./shelly.js');
postShelly('/api/system/reboot', {}, 60 * 1000)
.then(() => {
matterbridge.log.notice('Rebooting shelly board...');
})
.catch((error) => {
matterbridge.log.error(`Error rebooting shelly board: ${error}`);
});
});
}
}
}
//# sourceMappingURL=helpers.js.map