matterbridge-example-dynamic-platform
Version:
Matterbridge dynamic plugin
693 lines • 111 kB
JavaScript
import { MatterbridgeEndpoint, MatterbridgeDynamicPlatform, airQualitySensor, bridgedNode, colorTemperatureLight, coverDevice, dimmableLight, doorLockDevice, fanDevice, flowSensor, humiditySensor, onOffLight, onOffOutlet, onOffSwitch, powerSource, rainSensor, smokeCoAlarm, temperatureSensor, thermostatDevice, waterFreezeDetector, waterLeakDetector, airPurifier, pumpDevice, waterValve, genericSwitch, airConditioner, cooktop, microwaveOven, oven, refrigerator, onOffMountedSwitch, dimmableMountedSwitch, extendedColorLight, } from 'matterbridge';
import { RoboticVacuumCleaner, LaundryWasher, WaterHeater, Evse, SolarPower, BatteryStorage, LaundryDryer, HeatPump, Dishwasher, ExtractorHood } from 'matterbridge/devices';
import { isValidBoolean, isValidNumber, isValidString } from 'matterbridge/utils';
import { debugStringify } from 'matterbridge/logger';
import { AreaNamespaceTag, LocationTag, NumberTag, PositionTag, SwitchesTag, UINT16_MAX, UINT32_MAX } from 'matterbridge/matter';
import { PowerSource, BooleanState, OnOff, LevelControl, AirQuality, CarbonDioxideConcentrationMeasurement, CarbonMonoxideConcentrationMeasurement, FlowMeasurement, ColorControl, DoorLock, FanControl, FormaldehydeConcentrationMeasurement, NitrogenDioxideConcentrationMeasurement, OzoneConcentrationMeasurement, Pm10ConcentrationMeasurement, Pm1ConcentrationMeasurement, Pm25ConcentrationMeasurement, RadonConcentrationMeasurement, RelativeHumidityMeasurement, RelativeHumidityMeasurementCluster, SmokeCoAlarm, TemperatureMeasurement, Thermostat, ThermostatCluster, TotalVolatileOrganicCompoundsConcentrationMeasurement, WindowCovering, EnergyEvseMode, EnergyEvse, RvcRunMode, RvcCleanMode, ConcentrationMeasurement, Descriptor, BridgedDeviceBasicInformation, } from 'matterbridge/matter/clusters';
import { Appliances } from './appliances.js';
export class ExampleMatterbridgeDynamicPlatform extends MatterbridgeDynamicPlatform {
switch;
mountedOnOffSwitch;
mountedDimmerSwitch;
lightOnOff;
dimmer;
light;
lightXY;
lightHS;
lightCT;
outlet;
coverLift;
coverLiftTilt;
lock;
thermoAuto;
thermoHeat;
thermoCool;
fanBase;
fanOnHigh;
fanDefault;
fanComplete;
waterLeak;
waterFreeze;
rain;
smokeCo;
smokeOnly;
coOnly;
airQuality;
airConditioner;
airPurifier;
pump;
valve;
momentarySwitch;
latchingSwitch;
vacuum;
roboticVacuum;
waterHeater;
evse;
laundryWasher;
laundryDryer;
dishwasher;
extractorHood;
solarPower;
batteryStorage;
heatPump;
switchInterval;
lightInterval;
outletInterval;
coverInterval;
lockInterval;
thermoInterval;
fanInterval;
waterLeakInterval;
waterFreezeInterval;
rainInterval;
smokeInterval;
airQualityInterval;
airConditionerInterval;
genericSwitchInterval;
genericSwitchLastEvent = 'Release';
intervalOnOff = false;
intervalLevel = 0;
intervalColorTemperature = 147;
bridgedDevices = new Map();
fanModeLookup = ['Off', 'Low', 'Medium', 'High', 'On', 'Auto', 'Smart'];
fanDirectionLookup = ['Forward', 'Reverse'];
constructor(matterbridge, log, config) {
super(matterbridge, log, config);
if (this.verifyMatterbridgeVersion === undefined || typeof this.verifyMatterbridgeVersion !== 'function' || !this.verifyMatterbridgeVersion('3.1.7')) {
throw new Error(`This plugin requires Matterbridge version >= "3.1.7". Please update Matterbridge from ${this.matterbridge.matterbridgeVersion} to the latest version in the frontend.`);
}
this.log.info('Initializing platform:', this.config.name);
if (config.whiteList === undefined)
config.whiteList = [];
if (config.blackList === undefined)
config.blackList = [];
if (config.enableRVC !== undefined)
delete config.enableRVC;
if (config.enableServerRvc === undefined)
config.enableServerRvc = true;
}
async onStart(reason) {
this.log.info('onStart called with reason:', reason ?? 'none');
await this.ready;
await this.clearSelect();
this.switch = new MatterbridgeEndpoint([onOffSwitch, bridgedNode, powerSource], { uniqueStorageKey: 'Switch' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Switch', '0x23452164', 0xfff1, 'Matterbridge', 'Matterbridge Switch')
.createDefaultOnOffClusterServer()
.createDefaultPowerSourceRechargeableBatteryClusterServer(70);
this.switch = await this.addDevice(this.switch);
this.switch?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.switch?.addCommandHandler('on', async () => {
await this.switch?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.switch.log);
this.switch?.log.info('Command on called');
});
this.switch?.addCommandHandler('off', async () => {
await this.switch?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.switch.log);
this.switch?.log.info('Command off called');
});
this.mountedOnOffSwitch = new MatterbridgeEndpoint([onOffMountedSwitch, bridgedNode, powerSource], { uniqueStorageKey: 'OnOffMountedSwitch' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('OnOff Mounted Switch', '0x298242164', 0xfff1, 'Matterbridge', 'Matterbridge OnOff Mounted Switch')
.createDefaultOnOffClusterServer()
.createDefaultPowerSourceRechargeableBatteryClusterServer(70);
this.mountedOnOffSwitch = await this.addDevice(this.mountedOnOffSwitch);
this.mountedOnOffSwitch?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.mountedOnOffSwitch?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.mountedOnOffSwitch?.addCommandHandler('on', async () => {
await this.mountedOnOffSwitch?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.mountedOnOffSwitch.log);
this.mountedOnOffSwitch?.log.info('Command on called');
});
this.mountedOnOffSwitch?.addCommandHandler('off', async () => {
await this.mountedOnOffSwitch?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.mountedOnOffSwitch.log);
this.mountedOnOffSwitch?.log.info('Command off called');
});
this.mountedDimmerSwitch = new MatterbridgeEndpoint([dimmableMountedSwitch, bridgedNode, powerSource], { uniqueStorageKey: 'DimmerMountedSwitch' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Dimmer Mounted Switch', '0x22145578864', 0xfff1, 'Matterbridge', 'Matterbridge Dimmer Mounted Switch')
.createDefaultOnOffClusterServer()
.createDefaultLevelControlClusterServer()
.createDefaultPowerSourceWiredClusterServer()
.addRequiredClusterServers();
this.mountedDimmerSwitch = await this.addDevice(this.mountedDimmerSwitch);
this.mountedDimmerSwitch?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.mountedDimmerSwitch?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.mountedDimmerSwitch?.addCommandHandler('on', async () => {
await this.mountedDimmerSwitch?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.mountedDimmerSwitch.log);
this.mountedDimmerSwitch?.log.info('Command on called');
});
this.mountedDimmerSwitch?.addCommandHandler('off', async () => {
await this.mountedDimmerSwitch?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.mountedDimmerSwitch.log);
this.mountedDimmerSwitch?.log.info('Command off called');
});
this.mountedDimmerSwitch?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
await this.mountedDimmerSwitch?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.mountedDimmerSwitch.log);
this.mountedDimmerSwitch?.log.debug(`Command moveToLevel called request: ${level}`);
});
this.mountedDimmerSwitch?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
await this.mountedDimmerSwitch?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.mountedDimmerSwitch.log);
this.mountedDimmerSwitch?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.lightOnOff = new MatterbridgeEndpoint([onOffLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (on/off)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Light (on/off)', '0x2342375564', 0xfff1, 'Matterbridge', 'Matterbridge Light on/off')
.createDefaultOnOffClusterServer()
.createDefaultPowerSourceWiredClusterServer();
this.lightOnOff = await this.addDevice(this.lightOnOff);
this.lightOnOff?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.lightOnOff?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.lightOnOff?.addCommandHandler('on', async () => {
await this.lightOnOff?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.lightOnOff?.log);
this.lightOnOff?.log.info('Command on called');
});
this.lightOnOff?.addCommandHandler('off', async () => {
await this.lightOnOff?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.lightOnOff?.log);
this.lightOnOff?.log.info('Command off called');
});
this.dimmer = new MatterbridgeEndpoint([dimmableLight, bridgedNode, powerSource], { uniqueStorageKey: 'Dimmer' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Dimmer', '0x234554564', 0xfff1, 'Matterbridge', 'Matterbridge Dimmer')
.createDefaultOnOffClusterServer()
.createDefaultLevelControlClusterServer()
.createDefaultPowerSourceReplaceableBatteryClusterServer(70, PowerSource.BatChargeLevel.Ok, 2990, '2 x AA', 2);
this.dimmer = await this.addDevice(this.dimmer);
this.dimmer?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.dimmer?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.dimmer?.addCommandHandler('on', async () => {
await this.dimmer?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.dimmer.log);
this.dimmer?.log.info('Command on called');
});
this.dimmer?.addCommandHandler('off', async () => {
await this.dimmer?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.dimmer.log);
this.dimmer?.log.info('Command off called');
});
this.dimmer?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
await this.dimmer?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.dimmer.log);
this.dimmer?.log.debug(`Command moveToLevel called request: ${level}`);
});
this.dimmer?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
await this.dimmer?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.dimmer.log);
this.dimmer?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.light = new MatterbridgeEndpoint([extendedColorLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (XY, HS and CT)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Light (XY, HS and CT)', '0x23480564', 0xfff1, 'Matterbridge', 'Matterbridge Light')
.createDefaultOnOffClusterServer()
.createDefaultLevelControlClusterServer()
.createDefaultColorControlClusterServer()
.createDefaultPowerSourceReplaceableBatteryClusterServer(70);
this.light = await this.addDevice(this.light);
this.light?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.light?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.light?.addCommandHandler('on', async () => {
await this.light?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.light?.log);
this.light?.log.info('Command on called');
});
this.light?.addCommandHandler('off', async () => {
await this.light?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.light?.log);
this.light?.log.info('Command off called');
});
this.light?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
await this.light?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.light?.log);
this.light?.log.debug(`Command moveToLevel called request: ${level}`);
});
this.light?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
await this.light?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.light?.log);
this.light?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.light?.addCommandHandler('moveToColor', async ({ request: { colorX, colorY } }) => {
await this.light?.setAttribute(ColorControl.Cluster.id, 'currentX', colorX, this.light?.log);
await this.light?.setAttribute(ColorControl.Cluster.id, 'currentY', colorY, this.light?.log);
this.light?.log.debug(`Command moveToColor called request: X ${colorX / 65536} Y ${colorY / 65536}`);
});
this.light?.addCommandHandler('moveToHueAndSaturation', async ({ request: { hue, saturation } }) => {
await this.light?.setAttribute(ColorControl.Cluster.id, 'currentHue', hue, this.light?.log);
await this.light?.setAttribute(ColorControl.Cluster.id, 'currentSaturation', saturation, this.light?.log);
this.light?.log.debug(`Command moveToHueAndSaturation called request: hue ${hue} saturation ${saturation}`);
});
this.light?.addCommandHandler('moveToHue', async ({ request: { hue } }) => {
await this.light?.setAttribute(ColorControl.Cluster.id, 'currentHue', hue, this.light?.log);
this.light?.log.debug(`Command moveToHue called request: hue ${hue}`);
});
this.light?.addCommandHandler('moveToSaturation', async ({ request: { saturation } }) => {
await this.light?.setAttribute(ColorControl.Cluster.id, 'currentSaturation', saturation, this.light?.log);
this.light?.log.debug(`Command moveToSaturation called request: saturation ${saturation}}`);
});
this.light?.addCommandHandler('moveToColorTemperature', async ({ request: { colorTemperatureMireds } }) => {
await this.light?.setAttribute(ColorControl.Cluster.id, 'colorTemperatureMireds', colorTemperatureMireds, this.light?.log);
this.light?.log.debug(`Command moveToColorTemperature called request: ${colorTemperatureMireds}`);
});
this.lightHS = new MatterbridgeEndpoint([colorTemperatureLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (HS, CT)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Light (HS, CT)', '0x25097564', 0xfff1, 'Matterbridge', 'Matterbridge Light')
.createDefaultOnOffClusterServer()
.createDefaultLevelControlClusterServer()
.createHsColorControlClusterServer()
.createDefaultPowerSourceWiredClusterServer();
this.lightHS = await this.addDevice(this.lightHS);
this.lightHS?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.lightHS?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.lightHS?.addCommandHandler('on', async () => {
await this.lightHS?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.lightHS?.log);
this.lightHS?.log.info('Command on called');
});
this.lightHS?.addCommandHandler('off', async () => {
await this.lightHS?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.lightHS?.log);
this.lightHS?.log.info('Command off called');
});
this.lightHS?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
await this.lightHS?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.lightHS?.log);
this.lightHS?.log.debug(`Command moveToLevel called request: ${level}`);
});
this.lightHS?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
await this.lightHS?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.lightHS?.log);
this.lightHS?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.lightHS?.addCommandHandler('moveToHueAndSaturation', async ({ request: { hue, saturation } }) => {
await this.lightHS?.setAttribute(ColorControl.Cluster.id, 'currentHue', hue, this.lightHS?.log);
await this.lightHS?.setAttribute(ColorControl.Cluster.id, 'currentSaturation', saturation, this.lightHS?.log);
this.lightHS?.log.debug(`Command moveToHueAndSaturation called request: hue ${hue} saturation ${saturation}}`);
});
this.lightHS?.addCommandHandler('moveToHue', async ({ request: { hue } }) => {
await this.lightHS?.setAttribute(ColorControl.Cluster.id, 'currentHue', hue, this.lightHS?.log);
this.lightHS?.log.debug(`Command moveToHue called request: hue ${hue}`);
});
this.lightHS?.addCommandHandler('moveToSaturation', async ({ request: { saturation } }) => {
await this.lightHS?.setAttribute(ColorControl.Cluster.id, 'currentSaturation', saturation, this.lightHS?.log);
this.lightHS?.log.debug(`Command moveToSaturation called request: saturation ${saturation}`);
});
this.lightHS?.addCommandHandler('moveToColorTemperature', async ({ request: { colorTemperatureMireds } }) => {
await this.lightHS?.setAttribute(ColorControl.Cluster.id, 'colorTemperatureMireds', colorTemperatureMireds, this.lightHS?.log);
this.lightHS?.log.debug(`Command moveToColorTemperature called request: ${colorTemperatureMireds}`);
});
this.lightXY = new MatterbridgeEndpoint([extendedColorLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (XY, CT)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Light (XY, CT)', '0x23497564', 0xfff1, 'Matterbridge', 'Matterbridge Light')
.createDefaultOnOffClusterServer()
.createDefaultLevelControlClusterServer()
.createXyColorControlClusterServer()
.createDefaultPowerSourceWiredClusterServer();
this.lightXY = await this.addDevice(this.lightXY);
this.lightXY?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.lightXY?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.lightXY?.addCommandHandler('on', async () => {
await this.lightXY?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.lightXY?.log);
this.lightXY?.log.info('Command on called');
});
this.lightXY?.addCommandHandler('off', async () => {
await this.lightXY?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.lightXY?.log);
this.lightXY?.log.info('Command off called');
});
this.lightXY?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
await this.lightXY?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.lightXY?.log);
this.lightXY?.log.debug(`Command moveToLevel called request: ${level}`);
});
this.lightXY?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
await this.lightXY?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.lightXY?.log);
this.lightXY?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.lightXY?.addCommandHandler('moveToColor', async ({ request: { colorX, colorY } }) => {
await this.lightXY?.setAttribute(ColorControl.Cluster.id, 'currentX', colorX, this.lightXY?.log);
await this.lightXY?.setAttribute(ColorControl.Cluster.id, 'currentY', colorY, this.lightXY?.log);
this.lightXY?.log.debug(`Command moveToColor called request: X ${colorX / 65536} Y ${colorY / 65536}`);
});
this.lightXY?.addCommandHandler('moveToColorTemperature', async ({ request: { colorTemperatureMireds } }) => {
await this.lightXY?.setAttribute(ColorControl.Cluster.id, 'colorTemperatureMireds', colorTemperatureMireds, this.lightXY?.log);
this.lightXY?.log.debug(`Command moveToColorTemperature called request: ${colorTemperatureMireds}`);
});
this.lightCT = new MatterbridgeEndpoint([colorTemperatureLight, bridgedNode, powerSource], { uniqueStorageKey: 'Light (CT)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Light (CT)', '0x23480749', 0xfff1, 'Matterbridge', 'Matterbridge Light')
.createDefaultOnOffClusterServer()
.createDefaultLevelControlClusterServer()
.createCtColorControlClusterServer()
.createDefaultPowerSourceReplaceableBatteryClusterServer(70);
this.lightCT = await this.addDevice(this.lightCT);
this.lightCT?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.lightCT?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.lightCT?.addCommandHandler('on', async () => {
await this.lightCT?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.lightCT?.log);
this.lightCT?.log.info('Command on called');
});
this.lightCT?.addCommandHandler('off', async () => {
await this.lightCT?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.lightCT?.log);
this.lightCT?.log.info('Command off called');
});
this.lightCT?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
await this.lightCT?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.lightCT?.log);
this.lightCT?.log.debug(`Command moveToLevel called request: ${level}`);
});
this.lightCT?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
await this.lightCT?.setAttribute(LevelControl.Cluster.id, 'currentLevel', level, this.lightCT?.log);
this.lightCT?.log.debug(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.lightCT?.addCommandHandler('moveToColorTemperature', async ({ request: { colorTemperatureMireds } }) => {
await this.lightCT?.setAttribute(ColorControl.Cluster.id, 'colorTemperatureMireds', colorTemperatureMireds, this.lightCT?.log);
this.lightCT?.log.debug(`Command moveToColorTemperature called request: ${colorTemperatureMireds}`);
});
this.outlet = new MatterbridgeEndpoint([onOffOutlet, bridgedNode, powerSource], { uniqueStorageKey: 'Outlet' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Outlet', '0x29252164', 0xfff1, 'Matterbridge', 'Matterbridge Outlet')
.createDefaultOnOffClusterServer()
.createDefaultPowerSourceWiredClusterServer();
this.outlet = await this.addDevice(this.outlet);
this.outlet?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.outlet?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.outlet?.addCommandHandler('on', async () => {
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', true, this.outlet?.log);
this.outlet?.log.info('Command on called');
});
this.outlet?.addCommandHandler('off', async () => {
await this.outlet?.setAttribute(OnOff.Cluster.id, 'onOff', false, this.outlet?.log);
this.outlet?.log.info('Command off called');
});
this.coverLift = new MatterbridgeEndpoint([coverDevice, bridgedNode, powerSource], { uniqueStorageKey: 'CoverLift' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Cover lift', 'CL01020564', 0xfff1, 'Matterbridge', 'Matterbridge Cover')
.createDefaultWindowCoveringClusterServer()
.createDefaultPowerSourceRechargeableBatteryClusterServer(86);
this.coverLift = await this.addDevice(this.coverLift);
this.coverLift?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.coverLift?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.coverLift?.addCommandHandler('stopMotion', async () => {
await this.coverLift?.setWindowCoveringTargetAsCurrentAndStopped();
this.coverLift?.log.info(`Command stopMotion called`);
});
this.coverLift?.addCommandHandler('downOrClose', async () => {
await this.coverLift?.setWindowCoveringCurrentTargetStatus(10000, 10000, WindowCovering.MovementStatus.Stopped);
this.coverLift?.log.info(`Command downOrClose called`);
});
this.coverLift?.addCommandHandler('upOrOpen', async () => {
await this.coverLift?.setWindowCoveringCurrentTargetStatus(0, 0, WindowCovering.MovementStatus.Stopped);
this.coverLift?.log.info(`Command upOrOpen called`);
});
this.coverLift?.addCommandHandler('goToLiftPercentage', async ({ request: { liftPercent100thsValue } }) => {
await this.coverLift?.setWindowCoveringCurrentTargetStatus(liftPercent100thsValue, liftPercent100thsValue, WindowCovering.MovementStatus.Stopped);
this.coverLift?.log.info(`Command goToLiftPercentage ${liftPercent100thsValue} called`);
});
this.coverLiftTilt = new MatterbridgeEndpoint([coverDevice, bridgedNode, powerSource], { uniqueStorageKey: 'CoverLiftTilt' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Cover lift and tilt', 'CLT01020554', 0xfff1, 'Matterbridge', 'Matterbridge Cover')
.createDefaultLiftTiltWindowCoveringClusterServer()
.createDefaultPowerSourceRechargeableBatteryClusterServer(86);
this.coverLiftTilt = await this.addDevice(this.coverLiftTilt);
this.coverLiftTilt?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.coverLiftTilt?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.coverLiftTilt?.addCommandHandler('stopMotion', async () => {
await this.coverLiftTilt?.setWindowCoveringTargetAsCurrentAndStopped();
this.coverLiftTilt?.log.info(`Command stopMotion called`);
});
this.coverLiftTilt?.addCommandHandler('downOrClose', async () => {
await this.coverLiftTilt?.setWindowCoveringCurrentTargetStatus(10000, 10000, WindowCovering.MovementStatus.Stopped);
this.coverLiftTilt?.log.info(`Command downOrClose called`);
});
this.coverLiftTilt?.addCommandHandler('upOrOpen', async () => {
await this.coverLiftTilt?.setWindowCoveringCurrentTargetStatus(0, 0, WindowCovering.MovementStatus.Stopped);
this.coverLiftTilt?.log.info(`Command upOrOpen called`);
});
this.coverLiftTilt?.addCommandHandler('goToLiftPercentage', async ({ request: { liftPercent100thsValue } }) => {
await this.coverLiftTilt?.setWindowCoveringCurrentTargetStatus(liftPercent100thsValue, liftPercent100thsValue, WindowCovering.MovementStatus.Stopped);
this.coverLiftTilt?.log.info(`Command goToLiftPercentage ${liftPercent100thsValue} called`);
});
this.coverLiftTilt?.addCommandHandler('goToTiltPercentage', async ({ request: { tiltPercent100thsValue } }) => {
const position = this.coverLiftTilt?.getAttribute(WindowCovering.Cluster.id, 'currentPositionLiftPercent100ths', this.coverLiftTilt?.log);
await this.coverLiftTilt?.setWindowCoveringTargetAndCurrentPosition(position, tiltPercent100thsValue);
this.coverLiftTilt?.log.info(`Command goToTiltPercentage ${tiltPercent100thsValue} called`);
});
this.lock = new MatterbridgeEndpoint([doorLockDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Lock' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Lock', '0x96352164', 0xfff1, 'Matterbridge', 'Matterbridge Lock')
.createDefaultDoorLockClusterServer()
.createDefaultPowerSourceRechargeableBatteryClusterServer(30);
this.lock = await this.addDevice(this.lock);
this.lock?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.lock?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.lock?.addCommandHandler('lockDoor', async () => {
await this.lock?.setAttribute(DoorLock.Cluster.id, 'lockState', DoorLock.LockState.Locked, this.lock?.log);
this.lock?.log.info('Command lockDoor called');
});
this.lock?.addCommandHandler('unlockDoor', async () => {
await this.lock?.setAttribute(DoorLock.Cluster.id, 'lockState', DoorLock.LockState.Unlocked, this.lock?.log);
this.lock?.log.info('Command unlockDoor called');
});
this.thermoAuto = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (AutoMode)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (AutoMode)', '0x96382164A', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
.createDefaultThermostatClusterServer(20, 18, 22)
.createDefaultPowerSourceRechargeableBatteryClusterServer(70, PowerSource.BatChargeLevel.Ok, 4700);
this.thermoAuto
.addChildDeviceType('Flow', flowSensor)
.createDefaultFlowMeasurementClusterServer(1 * 10)
.addRequiredClusterServers();
this.thermoAuto
.addChildDeviceType('Temperature', temperatureSensor)
.createDefaultTemperatureMeasurementClusterServer(21 * 100)
.addRequiredClusterServers();
this.thermoAuto
.addChildDeviceType('Humidity', humiditySensor)
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
.addRequiredClusterServers();
this.thermoAuto = await this.addDevice(this.thermoAuto);
this.thermoAuto?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.thermoAuto?.log.info(`Command identify called identifyTime ${identifyTime}`);
});
this.thermoAuto?.addCommandHandler('triggerEffect', async ({ request: { effectIdentifier, effectVariant } }) => {
this.thermoAuto?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
});
this.thermoAuto?.addCommandHandler('setpointRaiseLower', async ({ request: { mode, amount } }) => {
const lookupSetpointAdjustMode = ['Heat', 'Cool', 'Both'];
this.thermoAuto?.log.info(`Command setpointRaiseLower called with mode: ${lookupSetpointAdjustMode[mode]} amount: ${amount / 10}`);
if (mode === Thermostat.SetpointRaiseLowerMode.Heat || mode === Thermostat.SetpointRaiseLowerMode.Both) {
const setpoint = this.thermoAuto?.getAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', this.thermoAuto?.log) / 100 + amount / 10;
await this.thermoAuto?.setAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', setpoint * 100, this.thermoAuto?.log);
this.thermoAuto?.log.info('Set occupiedHeatingSetpoint:', setpoint);
}
if (mode === Thermostat.SetpointRaiseLowerMode.Cool || mode === Thermostat.SetpointRaiseLowerMode.Both) {
const setpoint = this.thermoAuto?.getAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', this.thermoAuto?.log) / 100 + amount / 10;
await this.thermoAuto?.setAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', setpoint * 100, this.thermoAuto?.log);
this.thermoAuto?.log.info('Set occupiedCoolingSetpoint:', setpoint);
}
});
await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
this.thermoAuto?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
}, this.thermoAuto.log);
await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', (value) => {
this.thermoAuto?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
}, this.thermoAuto.log);
await this.thermoAuto?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
this.thermoAuto?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
}, this.thermoAuto.log);
this.thermoHeat = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (Heat)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (Heat)', '0x96382164H', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
.createDefaultHeatingThermostatClusterServer(20, 18, 5, 35)
.createDefaultPowerSourceReplaceableBatteryClusterServer(70, PowerSource.BatChargeLevel.Ok, 6010, 'AA 1.5V', 4);
this.thermoHeat
.addChildDeviceType('TemperatureIN', [temperatureSensor], {
tagList: [
{ mfgCode: null, namespaceId: LocationTag.Indoor.namespaceId, tag: LocationTag.Indoor.tag, label: null },
{ mfgCode: null, namespaceId: NumberTag.One.namespaceId, tag: NumberTag.One.tag, label: null },
],
})
.createDefaultIdentifyClusterServer()
.createDefaultTemperatureMeasurementClusterServer(21 * 100);
this.thermoHeat
.addChildDeviceType('TemperatureOUT', [temperatureSensor], {
tagList: [
{ mfgCode: null, namespaceId: LocationTag.Outdoor.namespaceId, tag: LocationTag.Outdoor.tag, label: null },
{ mfgCode: null, namespaceId: NumberTag.Two.namespaceId, tag: NumberTag.Two.tag, label: null },
],
})
.createDefaultIdentifyClusterServer()
.createDefaultTemperatureMeasurementClusterServer(15 * 100);
this.thermoHeat = await this.addDevice(this.thermoHeat);
this.thermoHeat?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.thermoHeat?.log.info(`Command identify called identifyTime ${identifyTime}`);
});
this.thermoHeat?.addCommandHandler('triggerEffect', async ({ request: { effectIdentifier, effectVariant } }) => {
this.thermoHeat?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
});
await this.thermoHeat?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
this.thermoHeat?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
}, this.thermoHeat.log);
await this.thermoHeat?.subscribeAttribute(ThermostatCluster.id, 'occupiedHeatingSetpoint', (value) => {
this.thermoHeat?.log.info('Subscribe occupiedHeatingSetpoint called with:', value / 100);
}, this.thermoHeat.log);
this.thermoCool = new MatterbridgeEndpoint([thermostatDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Thermostat (Cool)' }, this.config.debug)
.createDefaultIdentifyClusterServer()
.createDefaultGroupsClusterServer()
.createDefaultBridgedDeviceBasicInformationClusterServer('Thermostat (Cool)', '0x96382164C', 0xfff1, 'Matterbridge', 'Matterbridge Thermostat')
.createDefaultCoolingThermostatClusterServer(20, 18, 5, 35)
.createDefaultPowerSourceReplaceableBatteryClusterServer(40, PowerSource.BatChargeLevel.Ok, 5080, 'AA 1.5V', 4);
this.thermoCool = await this.addDevice(this.thermoCool);
this.thermoCool?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.thermoCool?.log.info(`Command identify called identifyTime ${identifyTime}`);
});
this.thermoCool?.addCommandHandler('triggerEffect', async ({ request: { effectIdentifier, effectVariant } }) => {
this.thermoCool?.log.info(`Command identify called effectIdentifier ${effectIdentifier} effectVariant ${effectVariant}`);
});
await this.thermoCool?.subscribeAttribute(ThermostatCluster.id, 'systemMode', (value) => {
const lookupSystemMode = ['Off', 'Auto', '', 'Cool', 'Heat', 'EmergencyHeat', 'Precooling', 'FanOnly', 'Dry', 'Sleep'];
this.thermoCool?.log.info('Subscribe systemMode called with:', lookupSystemMode[value]);
}, this.thermoCool.log);
await this.thermoCool?.subscribeAttribute(ThermostatCluster.id, 'occupiedCoolingSetpoint', (value) => {
this.thermoCool?.log.info('Subscribe occupiedCoolingSetpoint called with:', value / 100);
}, this.thermoCool.log);
this.airPurifier = new MatterbridgeEndpoint([airPurifier, temperatureSensor, humiditySensor, bridgedNode, powerSource], { uniqueStorageKey: 'Air purifier' }, this.config.debug)
.createDefaultBridgedDeviceBasicInformationClusterServer('Air purifier', '0x96584864AP', 0xfff1, 'Matterbridge', 'Matterbridge Air purifier')
.createDefaultIdentifyClusterServer()
.createDefaultFanControlClusterServer()
.createDefaultTemperatureMeasurementClusterServer(20 * 100)
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
.createDefaultPowerSourceWiredClusterServer()
.createDefaultActivatedCarbonFilterMonitoringClusterServer()
.createDefaultHepaFilterMonitoringClusterServer();
this.airPurifier = await this.addDevice(this.airPurifier);
this.airPurifier?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.airPurifier?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
await this.airPurifier?.subscribeAttribute(FanControl.Cluster.id, 'fanMode', (newValue, oldValue, context) => {
this.airPurifier?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.offline === true ? 'offline' : 'online'}`);
if (context.offline === true)
return;
if (newValue === FanControl.FanMode.Off) {
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentSettings', 0, this.airPurifier?.log);
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 0, this.airPurifier?.log);
}
else if (newValue === FanControl.FanMode.Low) {
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentSettings', 33, this.airPurifier?.log);
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 33, this.airPurifier?.log);
}
else if (newValue === FanControl.FanMode.Medium) {
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentSettings', 66, this.airPurifier?.log);
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 66, this.airPurifier?.log);
}
else if (newValue === FanControl.FanMode.High) {
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentSettings', 100, this.airPurifier?.log);
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.airPurifier?.log);
}
else if (newValue === FanControl.FanMode.On) {
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentSettings', 100, this.airPurifier?.log);
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 100, this.airPurifier?.log);
}
}, this.airPurifier.log);
await this.airPurifier?.subscribeAttribute(FanControl.Cluster.id, 'percentSetting', (newValue, oldValue, context) => {
this.airPurifier?.log.info(`Percent setting changed from ${oldValue} to ${newValue} context: ${context.offline === true ? 'offline' : 'online'}`);
if (context.offline === true)
return;
if (isValidNumber(newValue, 0, 100))
this.airPurifier?.setAttribute(FanControl.Cluster.id, 'percentCurrent', newValue, this.airPurifier?.log);
}, this.airPurifier.log);
this.airConditioner = new MatterbridgeEndpoint([airConditioner, bridgedNode, powerSource], { uniqueStorageKey: 'Air Conditioner' }, this.config.debug)
.createDefaultBridgedDeviceBasicInformationClusterServer('Air Conditioner', '0x96382864AC', 0xfff1, 'Matterbridge', 'Matterbridge Air Conditioner')
.createDefaultIdentifyClusterServer()
.createDeadFrontOnOffClusterServer(true)
.createDefaultThermostatClusterServer(20, 18, 22)
.createDefaultThermostatUserInterfaceConfigurationClusterServer()
.createDefaultFanControlClusterServer(FanControl.FanMode.Auto)
.createDefaultTemperatureMeasurementClusterServer(20 * 100)
.createDefaultRelativeHumidityMeasurementClusterServer(50 * 100)
.createDefaultPowerSourceWiredClusterServer()
.addRequiredClusterServers();
this.airConditioner = await this.addDevice(this.airConditioner);
this.airConditioner?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.airConditioner?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.airConditioner?.addCommandHandler('on', async () => {
this.airConditioner?.log.info('Command on called');
await this.airConditioner?.setAttribute(ThermostatCluster.id, 'localTemperature', 20 * 100, this.airConditioner?.log);
await this.airConditioner?.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', 20 * 100, this.airConditioner?.log);
await this.airConditioner?.setAttribute(RelativeHumidityMeasurementCluster.id, 'measuredValue', 50 * 100, this.airConditioner?.log);
await this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', 50, this.airConditioner?.log);
});
this.airConditioner?.addCommandHandler('off', async () => {
this.airConditioner?.log.info('Command off called');
await this.airConditioner?.setAttribute(ThermostatCluster.id, 'localTemperature', null, this.airConditioner?.log);
await this.airConditioner?.setAttribute(TemperatureMeasurement.Cluster.id, 'measuredValue', null, this.airConditioner?.log);
await this.airConditioner?.setAttribute(RelativeHumidityMeasurementCluster.id, 'measuredValue', null, this.airConditioner?.log);
await this.airConditioner?.setAttribute(FanControl.Cluster.id, 'percentSetting', null, this.airConditioner?.log);
});
this.pump = new MatterbridgeEndpoint([pumpDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Pump' }, this.config.debug)
.createDefaultBridgedDeviceBasicInformationClusterServer('Pump', '0x96382864PUMP', 0xfff1, 'Matterbridge', 'Matterbridge Pump')
.createDefaultIdentifyClusterServer()
.createOnOffClusterServer()
.createLevelControlClusterServer()
.createDefaultPumpConfigurationAndControlClusterServer()
.createDefaultPowerSourceWiredClusterServer();
this.pump = await this.addDevice(this.pump);
this.pump?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.pump?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.pump?.addCommandHandler('on', async () => {
this.pump?.log.info('Command on called');
});
this.pump?.addCommandHandler('off', async () => {
this.pump?.log.info('Command off called');
});
this.pump?.addCommandHandler('moveToLevel', async ({ request: { level } }) => {
this.pump?.log.info(`Command moveToLevel called request: ${level}`);
});
this.pump?.addCommandHandler('moveToLevelWithOnOff', async ({ request: { level } }) => {
this.pump?.log.info(`Command moveToLevelWithOnOff called request: ${level}`);
});
this.valve = new MatterbridgeEndpoint([waterValve, bridgedNode, powerSource], { uniqueStorageKey: 'Water valve' }, this.config.debug)
.createDefaultBridgedDeviceBasicInformationClusterServer('Water valve', '0x96382864WV', 0xfff1, 'Matterbridge', 'Matterbridge Water valve')
.createDefaultIdentifyClusterServer()
.createDefaultValveConfigurationAndControlClusterServer()
.createDefaultPowerSourceWiredClusterServer();
this.valve = await this.addDevice(this.valve);
this.valve?.addCommandHandler('identify', async ({ request: { identifyTime } }) => {
this.valve?.log.info(`Command identify called identifyTime:${identifyTime}`);
});
this.fanDefault = new MatterbridgeEndpoint([fanDevice, bridgedNode, powerSource], { uniqueStorageKey: 'Fan off low medium high auto' }, this.config.debug)
.createDefaultBridgedDeviceBasicInformationClusterServer('Fan', 'FAN_980545631228', 0xfff1, 'Matterbridge', 'Matterbridge Fan')
.createDefaultPowerSourceWiredClusterServer()
.addRequiredClusterServers();
this.fanDefault = await this.addDevice(this.fanDefault);
await this.fanDefault?.subscribeAttribute(FanControl.Cluster.id, 'fanMode', (newValue, oldValue, context) => {
this.fanDefault?.log.info(`Fan mode changed from ${this.fanModeLookup[oldValue]} to ${this.fanModeLookup[newValue]} context: ${context.offline === true ? 'offline' : 'online'}`);
if (context.offline === true)
return;
if (newValue === FanControl.FanMode.Off) {
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentSetting', 0, this.fanDefault?.log);
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 0, this.fanDefault?.log);
}
else if (newValue === FanControl.FanMode.Low) {
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentSetting', 33, this.fanDefault?.log);
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 33, this.fanDefault?.log);
}
else if (newValue === FanControl.FanMode.Medium) {
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentSetting', 66, this.fanDefault?.log);
this.fanDefault?.setAttribute(FanControl.Cluster.id, 'percentCurrent', 66, this.fanDefault?.log);
}
else if (newValue === FanControl.FanMode.High) {
this.fanDefault?.setAttr