Skip to content

Commit 2f0567d

Browse files
feat: Improve multi-endpoint support for lights (#8031)
* Add exposeEndpoints utility function * Make modernExtend and philipsLight multi-endpoint aware
1 parent 6ba63c2 commit 2f0567d

File tree

4 files changed

+31
-15
lines changed

4 files changed

+31
-15
lines changed

src/lib/modernExtend.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
assertNumber,
3434
batteryVoltageToPercentage,
3535
configureSetPowerSourceWhenUnknown,
36+
exposeEndpoints,
3637
flatten,
3738
getEndpointName,
3839
getFromLookup,
@@ -469,7 +470,7 @@ export interface OnOffArgs {
469470
export function onOff(args?: OnOffArgs): ModernExtend {
470471
args = {powerOnBehavior: true, skipDuplicateTransaction: false, configureReporting: true, ...args};
471472

472-
const exposes: Expose[] = args.endpointNames ? args.endpointNames.map((ep) => e.switch().withEndpoint(ep)) : [e.switch()];
473+
const exposes: Expose[] = exposeEndpoints(e.switch(), args.endpointNames);
473474

474475
const fromZigbee: Fz.Converter[] = [args.skipDuplicateTransaction ? fz.on_off_skip_duplicate_transaction : fz.on_off];
475476
const toZigbee: Tz.Converter[] = [tz.on_off];
@@ -943,9 +944,7 @@ export function light(args?: LightArgs): ModernExtend {
943944
}
944945
: false;
945946

946-
const lightExpose = args.endpointNames
947-
? args.endpointNames.map((ep) => e.light().withBrightness().withEndpoint(ep))
948-
: [e.light().withBrightness()];
947+
const lightExpose = exposeEndpoints(e.light().withBrightness(), args.endpointNames);
949948

950949
const fromZigbee: Fz.Converter[] = [fz.on_off, fz.brightness, fz.ignore_basic_report, fz.level_config];
951950
const toZigbee: Tz.Converter[] = [
@@ -1001,12 +1000,13 @@ export function light(args?: LightArgs): ModernExtend {
10011000
if (args.color) {
10021001
effects.values.push('colorloop', 'stop_colorloop');
10031002
}
1004-
exposes.push(effects);
1003+
1004+
exposes.push(...exposeEndpoints(effects, args.endpointNames));
10051005
toZigbee.push(tz.effect);
10061006
}
10071007

10081008
if (args.powerOnBehavior) {
1009-
exposes.push(e.power_on_behavior(['off', 'on', 'toggle', 'previous']));
1009+
exposes.push(...exposeEndpoints(e.power_on_behavior(['off', 'on', 'toggle', 'previous']), args.endpointNames));
10101010
fromZigbee.push(fz.power_on_behavior);
10111011
toZigbee.push(tz.power_on_behavior);
10121012
}

src/lib/philips.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as ota from './ota';
1010
import * as globalStore from './store';
1111
import {Fz, KeyValue, KeyValueAny, Tz} from './types';
1212
import * as utils from './utils';
13-
import {isObject} from './utils';
13+
import {exposeEndpoints, isObject} from './utils';
1414

1515
const NS = 'zhc:philips';
1616
const ea = exposes.access;
@@ -71,12 +71,15 @@ export function philipsLight(args?: modernExtend.LightArgs & {hueEffect?: boolea
7171
}
7272
result.exposes.push(
7373
// gradient_scene is deprecated, use gradient instead
74-
e.enum('gradient_scene', ea.SET, Object.keys(gradientScenes)),
75-
e
76-
.list('gradient', ea.ALL, e.text('hex', ea.ALL).withDescription('Color in RGB HEX format (eg #663399)'))
77-
.withLengthMin(1)
78-
.withLengthMax(9)
79-
.withDescription('List of RGB HEX colors'),
74+
...exposeEndpoints(e.enum('gradient_scene', ea.SET, Object.keys(gradientScenes)), args.endpointNames),
75+
...exposeEndpoints(
76+
e
77+
.list('gradient', ea.ALL, e.text('hex', ea.ALL).withDescription('Color in RGB HEX format (eg #663399)'))
78+
.withLengthMin(1)
79+
.withLengthMax(9)
80+
.withDescription('List of RGB HEX colors'),
81+
args.endpointNames,
82+
),
8083
);
8184
result.configure.push(async (device, coordinatorEndpoint, definition) => {
8285
for (const ep of device.endpoints.filter((ep) => ep.supportsInputCluster('manuSpecificPhilips2'))) {
@@ -85,7 +88,7 @@ export function philipsLight(args?: modernExtend.LightArgs & {hueEffect?: boolea
8588
});
8689
}
8790
effects.push('finish_effect', 'stop_effect', 'stop_hue_effect');
88-
result.exposes.push(e.enum('effect', ea.SET, effects));
91+
result.exposes.push(...exposeEndpoints(e.enum('effect', ea.SET, effects), args.endpointNames));
8992
}
9093
return result;
9194
}

src/lib/utils.ts

+4
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ export function postfixWithEndpointName(value: string, msg: Fz.Message, definiti
244244
return value;
245245
}
246246

247+
export function exposeEndpoints<T extends Expose>(expose: T, endpointNames?: string[]): T[] {
248+
return endpointNames ? (endpointNames.map((ep) => expose.clone().withEndpoint(ep)) as T[]) : [expose];
249+
}
250+
247251
export function enforceEndpoint(entity: Zh.Endpoint, key: string, meta: Tz.Meta) {
248252
// @ts-expect-error ignore
249253
const multiEndpointEnforce: {[s: string]: number} = getMetaValue(entity, meta.mapped, 'multiEndpointEnforce', 'allEqual', []);

test/modernExtend.test.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,16 @@ describe('ModernExtend', () => {
314314
'osram_set_transition',
315315
'osram_remember_state',
316316
],
317-
exposes: ['action', 'effect', 'light_l1(state,brightness)', 'light_l2(state,brightness)', 'light_s1(state,brightness)', 'linkquality'],
317+
exposes: [
318+
'action',
319+
'effect',
320+
'effect',
321+
'effect',
322+
'light_l1(state,brightness)',
323+
'light_l2(state,brightness)',
324+
'light_s1(state,brightness)',
325+
'linkquality',
326+
],
318327
bind: {
319328
10: ['genOnOff', 'genLevelCtrl'],
320329
11: ['genOnOff', 'genLevelCtrl'],

0 commit comments

Comments
 (0)