Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add illuminance_raw #8592

Merged
merged 10 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 29 additions & 104 deletions scripts/modernExtendRefactor.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// In the root of this repo, execute: `npx ts-node scripts/modernExtendRefactor.ts`

import {Project, QuoteKind, SyntaxKind} from 'ts-morph';

const project = new Project({
Expand All @@ -15,9 +17,12 @@ project.getSourceFiles().forEach((sourceFile) => {
if (sourceFile.getBaseName() === 'index.ts') return;
console.log(`Handling ${sourceFile.getBaseName()}`);

if (sourceFile.getBaseName().includes('philips')) {
return;
}

let changed = true;
let save = false;
const type = 'mullerLichtLight';
while (changed) {
changed = false;
const definitions = sourceFile.getVariableStatementOrThrow('definitions').getDescendantsOfKind(SyntaxKind.ObjectLiteralExpression);
Expand All @@ -27,99 +32,31 @@ project.getSourceFiles().forEach((sourceFile) => {
const childs = definition.getChildrenOfKind(SyntaxKind.PropertyAssignment);
const model = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'model');
const extend = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'extend');
// const exposes = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'exposes');
// const configure = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'configure');
const extendArray = extend?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
const exposes = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'exposes');
const exposesArray = exposes?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
const configure = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'configure');
const fromZigbee = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'fromZigbee');
const fromZigbeeArray = fromZigbee?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
const toZigbee = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'toZigbee');
// const meta = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'meta');
// const endpoint = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'endpoint');

// const ota = childs.find((c) => c.getFirstChildByKind(SyntaxKind.Identifier)?.getText() === 'ota');

if (extend?.getFullText().includes('extend.light_onoff') && !fromZigbee && toZigbee?.getFullText().includes('tint_scene')) {
console.log(`Handling ${model?.getFullText().trim()}`);
toZigbee?.remove();
const newOpts: {[s: string]: unknown} = {}; // {endpoints: eval(`(${endpoint.getFullText().split('return ')[1].split(';')[0]})`)};
// configure?.remove();
// endpoint?.remove();
const extendFeatures = extend.getFullText().split('(')[0].split('_');
if (extendFeatures.includes('colortemp')) {
newOpts.colorTemp = {range: null};
}
if (extendFeatures.includes('color')) {
newOpts.color = true;
}
if (extendFeatures.includes('gradient')) {
newOpts.gradient = true;
}
let opts = extend?.getFullText().split('(')[1].slice(0, -1).trim();
if (opts) {
if (opts[opts.length - 1] === ',') {
opts = opts.substring(0, opts.length - 1);
}
const evalOpts = Object.entries(eval(`(${opts})`));
for (const [key, value] of evalOpts) {
if (key === 'colorTempRange') {
newOpts.colorTemp = {...(newOpts.colorTemp as object), range: value};
} else if (key === 'disableColorTempStartup') {
// @ts-expect-error ignore
newOpts.colorTemp = {...newOpts.colorTemp, startup: !value};
} else if (key === 'disablePowerOnBehavior') {
newOpts.powerOnBehavior = !value;
} else if (key === 'disableEffect') {
newOpts.effect = !value;
} else if (key === 'disableHueEffects') {
newOpts.hueEffect = !value;
} else if (key === 'supportsHueAndSaturation' || key === 'preferHueAndSaturation') {
// @ts-expect-error ignore
newOpts.color = {...newOpts.color, modes: evalOpts.preferHueAndSaturation ? ['hs', 'xy'] : ['xy', 'hs']};
} else if (key === 'extraEffects') {
// @ts-expect-error ignore
newOpts.gradient = {...newOpts.gradient, extraEffects: value};
} else if (key === 'noConfigure') {
// ignore
} else {
throw new Error(`Unsupported ${key} - ${value}`);
}
}
const fzIlluminance = fromZigbeeArray?.getElements().find((el) => el.getText() === 'fz.illuminance');
if (fzIlluminance) {
fromZigbeeArray?.removeElement(fzIlluminance);
const exposesIlluminance = exposesArray?.getElements().find((el) => el.getText() === 'e.illuminance()');
if (exposesIlluminance) {
exposesArray?.removeElement(exposesIlluminance);
}
// if (meta) {
// for (const [key, value] of Object.entries(eval(`(${meta?.getFullText().replace('meta: ', '')})`))) {
// if (key === 'turnsOffAtBrightness1') {
// newOpts.turnsOffAtBrightness1 = value;
// } else if (key === 'applyRedFix') {
// // @ts-expect-error ignore
// newOpts.color = {...newOpts.color, applyRedFix: value};
// } else if (key === 'supportsEnhancedHue') {
// // @ts-expect-error ignore
// newOpts.color = {...newOpts.color, enhancedHue: value};
// } else if (key === 'multiEndpoint' || key === 'disableDefaultResponse') {
// // ignore
// } else {
// throw new Error(`Unsupported ${key} - ${value}`);
// }
// }
// // meta.remove();
// }
// if (ota) {
// ota.remove();
// }

localTotalDefinitionsWithModernExtend += 1;
extend.replaceWithText(
`extend: [${type}(${JSON.stringify(newOpts)
.split(`"`)
.join('')
.replace(`range:null`, `range:undefined`)
.replace(`xy`, `'xy'`)
.replace(`hs`, `'hs'`)
.replace(`({})`, `()`)})]`,
);
changed = true;
if (!extend) {
definition.addPropertyAssignment({
name: 'extend',
initializer: '[m.illuminance()]',
});
} else {
extendArray?.addElement('m.illuminance()');
}
save = true;
break;
} else if (extend?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression)) {
localTotalDefinitionsWithModernExtend += 1;
}
}

Expand All @@ -130,22 +67,10 @@ project.getSourceFiles().forEach((sourceFile) => {
}

if (save) {
const modernExtendImport = sourceFile
.getImportDeclarations()
.find((d) => d.getModuleSpecifierSourceFile()?.getBaseName() === 'modernExtend.ts');
if (!modernExtendImport) {
sourceFile.addImportDeclaration({moduleSpecifier: '../lib/modernExtend', namedImports: [type]});
} else {
if (!modernExtendImport.getNamedImports().find((i) => i.getName() === type)) {
modernExtendImport.addNamedImport(type);
}
}

const extendImport = sourceFile.getImportDeclarations().find((d) => d.getModuleSpecifierSourceFile()?.getBaseName() === 'extend.ts');
if (!sourceFile.getFullText().includes('extend.') && extendImport) {
extendImport.remove();
}

sourceFile.addImportDeclaration({
moduleSpecifier: '../lib/modernExtend',
namespaceImport: 'm',
});
sourceFile.saveSync();
}
});
Expand Down
9 changes: 0 additions & 9 deletions src/converters/fromZigbee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,15 +485,6 @@ const converters1 = {
return {soil_moisture: soilMoisture};
},
} satisfies Fz.Converter,
illuminance: {
cluster: 'msIlluminanceMeasurement',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
const illuminance = msg.data['measuredValue'];
const illuminanceLux = illuminance === 0 ? 0 : Math.pow(10, (illuminance - 1) / 10000);
return {illuminance: illuminanceLux};
},
} satisfies Fz.Converter,
pressure: {
cluster: 'msPressureMeasurement',
type: ['attributeReport', 'readResponse'],
Expand Down
6 changes: 0 additions & 6 deletions src/converters/toZigbee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1893,12 +1893,6 @@ const converters2 = {
await entity.read('msRelativeHumidity', ['measuredValue']);
},
} satisfies Tz.Converter,
illuminance: {
key: ['illuminance'],
convertGet: async (entity, key, meta) => {
await entity.read('msIlluminanceMeasurement', ['measuredValue']);
},
} satisfies Tz.Converter,
// #endregion

// #region Non-generic converters
Expand Down
12 changes: 4 additions & 8 deletions src/devices/aurora_lighting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fz from '../converters/fromZigbee';
import tz from '../converters/toZigbee';
import * as exposes from '../lib/exposes';
import {identify, light} from '../lib/modernExtend';
import * as m from '../lib/modernExtend';
import * as reporting from '../lib/reporting';
import {Configure, DefinitionWithExtend, Fz, OnEvent, Tz, Zh} from '../lib/types';
import * as utils from '../lib/utils';
Expand Down Expand Up @@ -176,14 +177,9 @@ const definitions: DefinitionWithExtend[] = [
model: 'AU-A1ZBPIRS',
vendor: 'Aurora Lighting',
description: 'AOne PIR sensor',
fromZigbee: [fz.ias_occupancy_alarm_1, fz.illuminance],
toZigbee: [],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(39);
await reporting.bind(endpoint, coordinatorEndpoint, ['msIlluminanceMeasurement']);
await reporting.illuminance(endpoint);
},
exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.illuminance()],
fromZigbee: [fz.ias_occupancy_alarm_1],
exposes: [e.occupancy(), e.battery_low(), e.tamper()],
extend: [m.illuminance()],
},
{
zigbeeModel: ['SingleSocket50AU'],
Expand Down
9 changes: 5 additions & 4 deletions src/devices/bosch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
onOff,
quirkCheckinInterval,
} from '../lib/modernExtend';
import * as m from '../lib/modernExtend';
import * as reporting from '../lib/reporting';
import * as globalStore from '../lib/store';
import {DefinitionWithExtend, Expose, Fz, KeyValue, ModernExtend, Tz} from '../lib/types';
Expand Down Expand Up @@ -1321,17 +1322,17 @@ const definitions: DefinitionWithExtend[] = [
model: 'RADON TriTech ZB',
vendor: 'Bosch',
description: 'Wireless motion detector',
fromZigbee: [fz.temperature, fz.battery, fz.ias_occupancy_alarm_1, fz.illuminance],
fromZigbee: [fz.temperature, fz.battery, fz.ias_occupancy_alarm_1],
toZigbee: [],
meta: {battery: {voltageToPercentage: {min: 2500, max: 3000}}},
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg', 'msIlluminanceMeasurement']);
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
await reporting.temperature(endpoint);
await reporting.batteryVoltage(endpoint);
await reporting.illuminance(endpoint);
},
exposes: [e.temperature(), e.battery(), e.occupancy(), e.battery_low(), e.tamper(), e.illuminance()],
exposes: [e.temperature(), e.battery(), e.occupancy(), e.battery_low(), e.tamper()],
extend: [m.illuminance()],
},
{
zigbeeModel: ['ISW-ZPR1-WP13'],
Expand Down
36 changes: 8 additions & 28 deletions src/devices/ctm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import tz from '../converters/toZigbee';
import * as constants from '../lib/constants';
import * as exposes from '../lib/exposes';
import {battery, identify, light, temperature} from '../lib/modernExtend';
import * as m from '../lib/modernExtend';
import * as reporting from '../lib/reporting';
import {DefinitionWithExtend, Fz, KeyValue, Tz} from '../lib/types';
import * as utils from '../lib/utils';
Expand Down Expand Up @@ -1255,17 +1256,15 @@ const definitions: DefinitionWithExtend[] = [
model: 'MBD-S',
vendor: 'CTM Lyng',
description: 'MBD-S, motion detector with 16A relay',
fromZigbee: [fz.illuminance, fz.occupancy, fzLocal.ctm_mbd_device_enabled, fzLocal.ctm_relay_state],
fromZigbee: [fz.occupancy, fzLocal.ctm_mbd_device_enabled, fzLocal.ctm_relay_state],
toZigbee: [tzLocal.ctm_mbd_device_enabled, tzLocal.ctm_relay_state],
meta: {disableDefaultResponse: true},
ota: true,
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'msIlluminanceMeasurement', 'msOccupancySensing']);
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'msOccupancySensing']);
await endpoint.read('genOnOff', ['onOff']);
await reporting.onOff(endpoint);
await endpoint.read('msIlluminanceMeasurement', ['measuredValue']);
await reporting.illuminance(endpoint);
await endpoint.read('msOccupancySensing', ['occupancy']);
await reporting.occupancy(endpoint);
// Relay State
Expand All @@ -1283,37 +1282,20 @@ const definitions: DefinitionWithExtend[] = [
{manufacturerCode: Zcl.ManufacturerCode.DATEK_WIRELESS_AS},
);
},
exposes: [
e.switch(),
e.illuminance(),
e.occupancy(),
e.binary('device_enabled', ea.ALL, 'ON', 'OFF').withDescription('Turn the device on or off'),
],
exposes: [e.switch(), e.occupancy(), e.binary('device_enabled', ea.ALL, 'ON', 'OFF').withDescription('Turn the device on or off')],
extend: [m.illuminance()],
},
{
zigbeeModel: ['MBD Dim'],
model: 'CTM_MBD_Dim',
vendor: 'CTM Lyng',
description: 'MBD Dim, motion detector with dimmer',
fromZigbee: [
fz.illuminance,
fz.occupancy,
fzLocal.ctm_mbd_device_enabled,
fzLocal.ctm_relay_state,
fz.brightness,
fz.lighting_ballast_configuration,
],
fromZigbee: [fz.occupancy, fzLocal.ctm_mbd_device_enabled, fzLocal.ctm_relay_state, fz.brightness, fz.lighting_ballast_configuration],
toZigbee: [tzLocal.ctm_mbd_device_enabled, tzLocal.ctm_relay_state, tzLocal.ctm_mbd_brightness, tz.ballast_config],
meta: {disableDefaultResponse: true},
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, [
'genOnOff',
'genLevelCtrl',
'lightingBallastCfg',
'msIlluminanceMeasurement',
'msOccupancySensing',
]);
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genLevelCtrl', 'lightingBallastCfg', 'msOccupancySensing']);
await endpoint.read('genOnOff', ['onOff']);
await reporting.onOff(endpoint);
await endpoint.read('genLevelCtrl', ['currentLevel']);
Expand Down Expand Up @@ -1343,8 +1325,6 @@ const definitions: DefinitionWithExtend[] = [
reportableChange: null,
},
]);
await endpoint.read('msIlluminanceMeasurement', ['measuredValue']);
await reporting.illuminance(endpoint);
await endpoint.read('msOccupancySensing', ['occupancy']);
await reporting.occupancy(endpoint);
// Relay State
Expand All @@ -1364,7 +1344,6 @@ const definitions: DefinitionWithExtend[] = [
},
exposes: [
e.light_brightness(),
e.illuminance(),
e.occupancy(),
e.binary('device_enabled', ea.ALL, 'ON', 'OFF').withDescription('Turn the device on or off'),
e.numeric('ballast_minimum_level', ea.ALL).withValueMin(10).withValueMax(97).withDescription('Specifies the minimum brightness value'),
Expand All @@ -1375,6 +1354,7 @@ const definitions: DefinitionWithExtend[] = [
.withValueMax(97)
.withDescription('Specifies the initialisation light level. Can not be set lower than "ballast_minimum_level"'),
],
extend: [m.illuminance()],
},
{
fingerprint: [{modelID: 'DIMMER', manufacturerName: 'NorLum Dim OP'}],
Expand Down
Loading
Loading