From f47a5741ee125a301ee1377baf3864ea9852885d Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 12 Jul 2026 17:29:48 +0300 Subject: [PATCH 1/7] re-use e.action() --- src/lib/modernExtend.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index 470c9f3d2e54b..9fb6dba5aabe4 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -654,7 +654,7 @@ export function commandsOnOff(args: CommandsOnOffArgs = {}): ModernExtend { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [e.enum("action", ea.STATE, actions).withDescription("Triggered action (e.g. a button click)")]; + const exposes: Expose[] = [e.action(actions)]; const actionPayloadLookup: KeyValueString = { commandOn: "on", @@ -1379,9 +1379,7 @@ export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [ - e.enum("action", ea.STATE, actions).withDescription("Triggered action (e.g. a button click)").withCategory("diagnostic"), - ]; + const exposes: Expose[] = [e.action(actions)]; const fromZigbee = [fz.command_move_to_level, fz.command_move, fz.command_step, fz.command_stop]; @@ -1447,9 +1445,7 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [ - e.enum("action", ea.STATE, actions).withDescription("Triggered action (e.g. a button click)").withCategory("diagnostic"), - ]; + const exposes: Expose[] = [e.action(actions)]; const fromZigbee = [ fz.command_move_color_temperature, @@ -1629,9 +1625,7 @@ export function commandsWindowCovering(args: CommandsWindowCoveringArgs = {}): M if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [ - e.enum("action", ea.STATE, actions).withDescription("Triggered action (e.g. a button click)").withCategory("diagnostic"), - ]; + const exposes: Expose[] = [e.action(actions)]; const actionPayloadLookup: KeyValueString = { commandUpOpen: "open", @@ -2572,7 +2566,7 @@ export function commandsScenes(args: CommandsScenesArgs = {}) { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposesArray = [e.enum("action", ea.STATE, actions).withDescription("Triggered scene action (e.g. recall a scene)")]; + const exposesArray = [e.action(actions)]; const actionPayloadLookup: {[key: string]: string} = { commandRecall: "recall", @@ -3037,7 +3031,7 @@ export function actionEnumLookup< let actions = Object.keys(lookup).flatMap((a) => (args.endpointNames ? args.endpointNames.map((e) => `${a}_${e}`) : [a])); // allows direct external input to be used by other extends in the same device if (args.extraActions) actions = actions.concat(args.extraActions); - const expose = e.enum("action", ea.STATE, actions).withDescription("Triggered action (e.g. a button click)").withCategory("diagnostic"); + const expose = e.action(actions); const fromZigbee = [ { From c3abfbebdae99be9fd6c660bd25d11dfd1e24c73 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 12 Jul 2026 17:35:11 +0300 Subject: [PATCH 2/7] expose action_level --- src/devices/eglo.ts | 2 +- src/lib/exposes.ts | 7 +++++++ src/lib/modernExtend.ts | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/devices/eglo.ts b/src/devices/eglo.ts index 9aaf1491160e9..9ec59e26da747 100644 --- a/src/devices/eglo.ts +++ b/src/devices/eglo.ts @@ -270,7 +270,7 @@ export const definitions: DefinitionWithExtend[] = [ "recall_2_long", ]), e.numeric("action_group", ea.STATE), - e.numeric("action_level", ea.STATE), + e.action_level(), e.numeric("action_color_temperature", ea.STATE), ], }, diff --git a/src/lib/exposes.ts b/src/lib/exposes.ts index e984fbfe66f17..3c1eedc24b469 100644 --- a/src/lib/exposes.ts +++ b/src/lib/exposes.ts @@ -968,6 +968,13 @@ export const presets = { action_duration: () => new Numeric("action_duration", access.STATE).withUnit("s").withDescription("Triggered action duration in seconds").withCategory("diagnostic"), action_group: () => new Numeric("action_group", access.STATE).withDescription("Group where the action was triggered on"), + action_level: () => + new Numeric("action_level", access.STATE) + .withDescription("Target brightness of Move to level command") + .withValueMin(0) + .withValueMax(255) + .withValueStep(1) + .withCategory("diagnostic"), angle: (name: string) => new Numeric(name, access.STATE).withValueMin(-360).withValueMax(360).withUnit("°"), angle_axis: (name: string) => new Numeric(name, access.STATE).withValueMin(-90).withValueMax(90).withUnit("°"), aqi: () => new Numeric("aqi", access.STATE).withDescription("Air quality index"), diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index 9fb6dba5aabe4..6256483fd9875 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -1381,6 +1381,10 @@ export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { } const exposes: Expose[] = [e.action(actions)]; + if (commands.includes("brightness_move_to_level")) { + exposes.push(e.action_level()); + } + const fromZigbee = [fz.command_move_to_level, fz.command_move, fz.command_step, fz.command_stop]; const result: ModernExtend = {exposes, fromZigbee, isModernExtend: true}; From 5eab41b499fc5f40030636d1ea5c651accb55049 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 12 Jul 2026 21:46:07 +0300 Subject: [PATCH 3/7] expose action_rate --- src/devices/iluminize.ts | 2 +- src/devices/tuya.ts | 2 +- src/lib/exposes.ts | 7 +++++++ src/lib/modernExtend.ts | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/devices/iluminize.ts b/src/devices/iluminize.ts index 9c0bcb325d399..4e1ffdf2af5cc 100644 --- a/src/devices/iluminize.ts +++ b/src/devices/iluminize.ts @@ -250,7 +250,7 @@ export const definitions: DefinitionWithExtend[] = [ e.numeric("action_group", ea.STATE).withDescription("Shows the zigbee2mqtt group bound to the active data point EP(1-4)."), e.numeric("action_transition_time", ea.STATE), e.numeric("action_step_size", ea.STATE), - e.numeric("action_rate", ea.STATE), + e.action_rate(), ], toZigbee: [], meta: {multiEndpoint: true}, diff --git a/src/devices/tuya.ts b/src/devices/tuya.ts index 52085be8e49d6..9048983ef25e3 100644 --- a/src/devices/tuya.ts +++ b/src/devices/tuya.ts @@ -13510,7 +13510,7 @@ export const definitions: DefinitionWithExtend[] = [ e.numeric("action_step_size", ea.STATE).withValueMin(0).withValueMax(255), e.numeric("action_color_temperature_delta", ea.STATE).withValueMin(-65535).withValueMax(65535), e.numeric("action_transition_time", ea.STATE).withUnit("s"), - e.numeric("action_rate", ea.STATE).withValueMin(0).withValueMax(255), + e.action_rate(), e.battery(), e .enum("operation_mode", ea.ALL, ["command", "event"]) diff --git a/src/lib/exposes.ts b/src/lib/exposes.ts index 3c1eedc24b469..c7995084baa5e 100644 --- a/src/lib/exposes.ts +++ b/src/lib/exposes.ts @@ -975,6 +975,13 @@ export const presets = { .withValueMax(255) .withValueStep(1) .withCategory("diagnostic"), + action_rate: () => + new Numeric("action_rate", access.STATE) + .withDescription("Rate parameter of brightness/color Move commands") + .withValueMin(0) + .withValueMax(255) + .withValueStep(1) + .withCategory("diagnostic"), angle: (name: string) => new Numeric(name, access.STATE).withValueMin(-360).withValueMax(360).withUnit("°"), angle_axis: (name: string) => new Numeric(name, access.STATE).withValueMin(-90).withValueMax(90).withUnit("°"), aqi: () => new Numeric("aqi", access.STATE).withDescription("Air quality index"), diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index 6256483fd9875..8544d2aa4ae6f 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -1385,6 +1385,10 @@ export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { exposes.push(e.action_level()); } + if (commands.includes("brightness_move_up") || commands.includes("brightness_move_down")) { + exposes.push(e.action_rate()); + } + const fromZigbee = [fz.command_move_to_level, fz.command_move, fz.command_step, fz.command_stop]; const result: ModernExtend = {exposes, fromZigbee, isModernExtend: true}; @@ -1451,6 +1455,16 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { } const exposes: Expose[] = [e.action(actions)]; + if ( + commands.includes("color_temperature_move_up") || + commands.includes("color_temperature_move_down") || + commands.includes("color_temperature_move") || + commands.includes("color_move") || + commands.includes("hue_move") + ) { + exposes.push(e.action_rate()); + } + const fromZigbee = [ fz.command_move_color_temperature, fz.command_step_color_temperature, From 3e354891ec91e57b94d651ad697e0708cd13d9ba Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 12 Jul 2026 21:48:44 +0300 Subject: [PATCH 4/7] de-duplicate and sort action parameters --- src/index.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/index.ts b/src/index.ts index b152fa5864fab..ed87db0a64d95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -355,6 +355,25 @@ function processExtensions(definition: DefinitionWithExtend): Definition { allExposes.push(exposesLib.presets.action(uniqueActions)); } + // De-duplicate and sort action parameters + const actionParamOrder = ["action_level", "action_rate"]; + const actionParamExposes = new Map(); + + for (const e of allExposes) { + if (typeof e !== "function" && actionParamOrder.includes(e.name)) { + actionParamExposes.set(e.name, e); + } + } + + allExposes = allExposes.filter((expose) => !actionParamOrder.includes(expose.name)); + + for (const p of actionParamOrder) { + const e = actionParamExposes.get(p); + if (e) { + allExposes.push(e); + } + } + let configure: Configure | undefined; if (configures.length !== 0) { From 441876fa8757f11fd7c311b4397b1f4702aac8cf Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 13 Jul 2026 02:42:09 +0300 Subject: [PATCH 5/7] expose action_step_size --- src/devices/iluminize.ts | 2 +- src/devices/shelly.ts | 1 - src/devices/tuya.ts | 2 +- src/index.ts | 2 +- src/lib/exposes.ts | 7 +++++++ src/lib/modernExtend.ts | 15 +++++++++++++++ 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/devices/iluminize.ts b/src/devices/iluminize.ts index 4e1ffdf2af5cc..a6794ae16cce8 100644 --- a/src/devices/iluminize.ts +++ b/src/devices/iluminize.ts @@ -249,7 +249,7 @@ export const definitions: DefinitionWithExtend[] = [ ]), e.numeric("action_group", ea.STATE).withDescription("Shows the zigbee2mqtt group bound to the active data point EP(1-4)."), e.numeric("action_transition_time", ea.STATE), - e.numeric("action_step_size", ea.STATE), + e.action_step_size(), e.action_rate(), ], toZigbee: [], diff --git a/src/devices/shelly.ts b/src/devices/shelly.ts index 3805ca3130fd6..081d470b0e6d9 100644 --- a/src/devices/shelly.ts +++ b/src/devices/shelly.ts @@ -2126,7 +2126,6 @@ export const definitions: DefinitionWithExtend[] = [ exposes: [ e.action(["on", "off", "brightness_step_up", "brightness_step_down"]), e.numeric("action_group", ea.STATE).withDescription("Group ID associated with the action command."), - e.numeric("action_step_size", ea.STATE).withDescription("Step size value used for brightness step actions."), e.numeric("action_transition_time", ea.STATE).withDescription("Transition time in seconds for the action."), ], extend: [ diff --git a/src/devices/tuya.ts b/src/devices/tuya.ts index 9048983ef25e3..086ad11674470 100644 --- a/src/devices/tuya.ts +++ b/src/devices/tuya.ts @@ -13507,7 +13507,7 @@ export const definitions: DefinitionWithExtend[] = [ "rotate_right", ]), e.numeric("action_brightness_delta", ea.STATE).withValueMin(-255).withValueMax(255), - e.numeric("action_step_size", ea.STATE).withValueMin(0).withValueMax(255), + e.action_step_size(), e.numeric("action_color_temperature_delta", ea.STATE).withValueMin(-65535).withValueMax(65535), e.numeric("action_transition_time", ea.STATE).withUnit("s"), e.action_rate(), diff --git a/src/index.ts b/src/index.ts index ed87db0a64d95..4352dfad6d516 100644 --- a/src/index.ts +++ b/src/index.ts @@ -356,7 +356,7 @@ function processExtensions(definition: DefinitionWithExtend): Definition { } // De-duplicate and sort action parameters - const actionParamOrder = ["action_level", "action_rate"]; + const actionParamOrder = ["action_level", "action_step_size", "action_rate"]; const actionParamExposes = new Map(); for (const e of allExposes) { diff --git a/src/lib/exposes.ts b/src/lib/exposes.ts index c7995084baa5e..daba4c78456a6 100644 --- a/src/lib/exposes.ts +++ b/src/lib/exposes.ts @@ -982,6 +982,13 @@ export const presets = { .withValueMax(255) .withValueStep(1) .withCategory("diagnostic"), + action_step_size: () => + new Numeric("action_step_size", access.STATE) + .withDescription("Step size parameter of brightness/color Step commands") + .withValueMin(0) + .withValueMax(255) + .withValueStep(1) + .withCategory("diagnostic"), angle: (name: string) => new Numeric(name, access.STATE).withValueMin(-360).withValueMax(360).withUnit("°"), angle_axis: (name: string) => new Numeric(name, access.STATE).withValueMin(-90).withValueMax(90).withUnit("°"), aqi: () => new Numeric("aqi", access.STATE).withDescription("Air quality index"), diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index 8544d2aa4ae6f..a056307e9a015 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -1385,6 +1385,10 @@ export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { exposes.push(e.action_level()); } + if (commands.includes("brightness_step_up") || commands.includes("brightness_step_down")) { + exposes.push(e.action_step_size()); + } + if (commands.includes("brightness_move_up") || commands.includes("brightness_move_down")) { exposes.push(e.action_rate()); } @@ -1455,6 +1459,17 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { } const exposes: Expose[] = [e.action(actions)]; + if ( + commands.includes("color_temperature_step_up") || + commands.includes("color_temperature_step_down") || + commands.includes("color_hue_step_up") || + commands.includes("color_hue_step_down") || + commands.includes("color_saturation_step_up") || + commands.includes("color_saturation_step_down") + ) { + exposes.push(e.action_step_size()); + } + if ( commands.includes("color_temperature_move_up") || commands.includes("color_temperature_move_down") || From 03e02e50bbbdbe31ececdd22c3edf6e6626c2246 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 13 Jul 2026 03:24:48 +0300 Subject: [PATCH 6/7] expose action_transition_time --- src/devices/iluminize.ts | 2 +- src/devices/shelly.ts | 1 - src/devices/tuya.ts | 4 ++-- src/index.ts | 2 +- src/lib/exposes.ts | 8 ++++++++ src/lib/modernExtend.ts | 17 ++++++++++++++++- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/devices/iluminize.ts b/src/devices/iluminize.ts index a6794ae16cce8..28716733f0b6d 100644 --- a/src/devices/iluminize.ts +++ b/src/devices/iluminize.ts @@ -248,8 +248,8 @@ export const definitions: DefinitionWithExtend[] = [ "hue_stop", ]), e.numeric("action_group", ea.STATE).withDescription("Shows the zigbee2mqtt group bound to the active data point EP(1-4)."), - e.numeric("action_transition_time", ea.STATE), e.action_step_size(), + e.action_transition_time(), e.action_rate(), ], toZigbee: [], diff --git a/src/devices/shelly.ts b/src/devices/shelly.ts index 081d470b0e6d9..534162b1cc3b5 100644 --- a/src/devices/shelly.ts +++ b/src/devices/shelly.ts @@ -2126,7 +2126,6 @@ export const definitions: DefinitionWithExtend[] = [ exposes: [ e.action(["on", "off", "brightness_step_up", "brightness_step_down"]), e.numeric("action_group", ea.STATE).withDescription("Group ID associated with the action command."), - e.numeric("action_transition_time", ea.STATE).withDescription("Transition time in seconds for the action."), ], extend: [ m.battery(), diff --git a/src/devices/tuya.ts b/src/devices/tuya.ts index 086ad11674470..5b4f8a41750c1 100644 --- a/src/devices/tuya.ts +++ b/src/devices/tuya.ts @@ -13507,9 +13507,9 @@ export const definitions: DefinitionWithExtend[] = [ "rotate_right", ]), e.numeric("action_brightness_delta", ea.STATE).withValueMin(-255).withValueMax(255), - e.action_step_size(), e.numeric("action_color_temperature_delta", ea.STATE).withValueMin(-65535).withValueMax(65535), - e.numeric("action_transition_time", ea.STATE).withUnit("s"), + e.action_step_size(), + e.action_transition_time(), e.action_rate(), e.battery(), e diff --git a/src/index.ts b/src/index.ts index 4352dfad6d516..e257d9031f184 100644 --- a/src/index.ts +++ b/src/index.ts @@ -356,7 +356,7 @@ function processExtensions(definition: DefinitionWithExtend): Definition { } // De-duplicate and sort action parameters - const actionParamOrder = ["action_level", "action_step_size", "action_rate"]; + const actionParamOrder = ["action_level", "action_step_size", "action_transition_time", "action_rate"]; const actionParamExposes = new Map(); for (const e of allExposes) { diff --git a/src/lib/exposes.ts b/src/lib/exposes.ts index daba4c78456a6..474ef19a67010 100644 --- a/src/lib/exposes.ts +++ b/src/lib/exposes.ts @@ -989,6 +989,14 @@ export const presets = { .withValueMax(255) .withValueStep(1) .withCategory("diagnostic"), + action_transition_time: () => + new Numeric("action_transition_time", access.STATE) + .withDescription("Transition parameter of level control commands") + .withValueMin(0) + .withValueMax(6553.5) + .withValueStep(0.1) + .withUnit("s") + .withCategory("diagnostic"), angle: (name: string) => new Numeric(name, access.STATE).withValueMin(-360).withValueMax(360).withUnit("°"), angle_axis: (name: string) => new Numeric(name, access.STATE).withValueMin(-90).withValueMax(90).withUnit("°"), aqi: () => new Numeric("aqi", access.STATE).withDescription("Air quality index"), diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index a056307e9a015..666b429c5ab7c 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -1365,7 +1365,7 @@ export interface CommandsLevelCtrl { export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { const { commands = [ - "brightness_move_to_level", + "brightness_move_to_level", // with on off "parameter" for all "brightness_move_up", "brightness_move_down", "brightness_step_up", @@ -1383,10 +1383,12 @@ export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { if (commands.includes("brightness_move_to_level")) { exposes.push(e.action_level()); + exposes.push(e.action_transition_time()); } if (commands.includes("brightness_step_up") || commands.includes("brightness_step_down")) { exposes.push(e.action_step_size()); + exposes.push(e.action_transition_time()); } if (commands.includes("brightness_move_up") || commands.includes("brightness_move_down")) { @@ -1449,6 +1451,7 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { "move_to_saturation", "move_to_hue", "stop_move_step", + // TODO: "move_to_color", "move_to_color_temp", "color_step", more... ], bind = true, endpointNames = undefined, @@ -1459,6 +1462,17 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { } const exposes: Expose[] = [e.action(actions)]; + // TODO: e.action_hue, e.action_enhanced_hue, e.action_direction, e.action_saturation, + // e.action_color, e.action_stepx, e.action_stepy, e.action_colortemp, e.action_minimum, e.action_maximum etc. + if ( + commands.includes("enhanced_move_to_hue_and_saturation") || + commands.includes("move_to_hue_and_saturation") || + commands.includes("move_to_saturation") || + commands.includes("move_to_hue") + ) { + exposes.push(e.action_transition_time()); + } + if ( commands.includes("color_temperature_step_up") || commands.includes("color_temperature_step_down") || @@ -1468,6 +1482,7 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { commands.includes("color_saturation_step_down") ) { exposes.push(e.action_step_size()); + exposes.push(e.action_transition_time()); } if ( From b79a7181cff69b49759bb7610677cd58fb6a27a4 Mon Sep 17 00:00:00 2001 From: Andy Date: Mon, 13 Jul 2026 12:41:09 +0300 Subject: [PATCH 7/7] expose action_group --- src/devices/eglo.ts | 2 +- src/devices/iluminize.ts | 3 +-- src/devices/ls.ts | 2 +- src/devices/shelly.ts | 4 ---- src/devices/tuya.ts | 2 +- src/index.ts | 2 +- src/lib/exposes.ts | 8 +++++++- src/lib/modernExtend.ts | 12 ++++++------ 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/devices/eglo.ts b/src/devices/eglo.ts index 9ec59e26da747..8ded4350c5ba3 100644 --- a/src/devices/eglo.ts +++ b/src/devices/eglo.ts @@ -269,7 +269,7 @@ export const definitions: DefinitionWithExtend[] = [ "recall_2", "recall_2_long", ]), - e.numeric("action_group", ea.STATE), + e.action_group(), e.action_level(), e.numeric("action_color_temperature", ea.STATE), ], diff --git a/src/devices/iluminize.ts b/src/devices/iluminize.ts index 28716733f0b6d..b5539435d99b2 100644 --- a/src/devices/iluminize.ts +++ b/src/devices/iluminize.ts @@ -6,7 +6,6 @@ import * as sunricher from "../lib/sunricher"; import type {DefinitionWithExtend} from "../lib/types"; const e = exposes.presets; -const ea = exposes.access; export const definitions: DefinitionWithExtend[] = [ { @@ -247,7 +246,7 @@ export const definitions: DefinitionWithExtend[] = [ "enhanced_move_to_hue_and_saturation", "hue_stop", ]), - e.numeric("action_group", ea.STATE).withDescription("Shows the zigbee2mqtt group bound to the active data point EP(1-4)."), + e.action_group(), e.action_step_size(), e.action_transition_time(), e.action_rate(), diff --git a/src/devices/ls.ts b/src/devices/ls.ts index bffd62e3e0edd..f1b6dc451986c 100644 --- a/src/devices/ls.ts +++ b/src/devices/ls.ts @@ -34,7 +34,7 @@ const fzLocal = { const lsModernExtend = { groupIdExpose(): ModernExtend { const result: ModernExtend = { - exposes: [e.numeric("action_group", ea.STATE).withDescription("Group where the action was triggered on")], + exposes: [e.action_group()], isModernExtend: true, }; diff --git a/src/devices/shelly.ts b/src/devices/shelly.ts index 534162b1cc3b5..f31acc2407e27 100644 --- a/src/devices/shelly.ts +++ b/src/devices/shelly.ts @@ -2123,10 +2123,6 @@ export const definitions: DefinitionWithExtend[] = [ model: "SBRC-005B-B", vendor: "Shelly", description: "BLU Remote Control ZB", - exposes: [ - e.action(["on", "off", "brightness_step_up", "brightness_step_down"]), - e.numeric("action_group", ea.STATE).withDescription("Group ID associated with the action command."), - ], extend: [ m.battery(), m.commandsOnOff({commands: ["on", "off"]}), diff --git a/src/devices/tuya.ts b/src/devices/tuya.ts index 5b4f8a41750c1..a151d110b18c8 100644 --- a/src/devices/tuya.ts +++ b/src/devices/tuya.ts @@ -23882,7 +23882,7 @@ export const definitions: DefinitionWithExtend[] = [ .withValueMax(4) .withCategory("diagnostic") .withDescription("Button number from last action"), - e.numeric("action_group", ea.STATE).withCategory("diagnostic").withDescription("Group ID from last action"), + e.action_group(), e.enum("bind_all_scene", ea.SET, ["bind"]).withCategory("config").withDescription("Bind all buttons to Scene mode (red LED)"), e.enum("bind_all_light", ea.SET, ["bind"]).withCategory("config").withDescription("Bind all buttons to Light mode (green LED)"), e.enum("bind_all_curtain", ea.SET, ["bind"]).withCategory("config").withDescription("Bind all buttons to Curtain mode (blue LED)"), diff --git a/src/index.ts b/src/index.ts index e257d9031f184..aad181b2abdb2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -356,7 +356,7 @@ function processExtensions(definition: DefinitionWithExtend): Definition { } // De-duplicate and sort action parameters - const actionParamOrder = ["action_level", "action_step_size", "action_transition_time", "action_rate"]; + const actionParamOrder = ["action_group", "action_level", "action_step_size", "action_transition_time", "action_rate"]; const actionParamExposes = new Map(); for (const e of allExposes) { diff --git a/src/lib/exposes.ts b/src/lib/exposes.ts index 474ef19a67010..87a474c72dcfc 100644 --- a/src/lib/exposes.ts +++ b/src/lib/exposes.ts @@ -967,7 +967,13 @@ export const presets = { new Enum("action", access.STATE, values).withDescription("Triggered action (e.g. a button click)").withCategory("diagnostic"), action_duration: () => new Numeric("action_duration", access.STATE).withUnit("s").withDescription("Triggered action duration in seconds").withCategory("diagnostic"), - action_group: () => new Numeric("action_group", access.STATE).withDescription("Group where the action was triggered on"), + action_group: () => + new Numeric("action_group", access.STATE) + .withDescription("Target group of the action") + .withValueMin(0) + .withValueMax(65535) + .withValueStep(1) + .withCategory("diagnostic"), action_level: () => new Numeric("action_level", access.STATE) .withDescription("Target brightness of Move to level command") diff --git a/src/lib/modernExtend.ts b/src/lib/modernExtend.ts index 666b429c5ab7c..e0d115e68934d 100644 --- a/src/lib/modernExtend.ts +++ b/src/lib/modernExtend.ts @@ -654,7 +654,7 @@ export function commandsOnOff(args: CommandsOnOffArgs = {}): ModernExtend { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [e.action(actions)]; + const exposes: Expose[] = [e.action(actions), e.action_group()]; const actionPayloadLookup: KeyValueString = { commandOn: "on", @@ -1379,7 +1379,7 @@ export function commandsLevelCtrl(args: CommandsLevelCtrl = {}): ModernExtend { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [e.action(actions)]; + const exposes: Expose[] = [e.action(actions), e.action_group()]; if (commands.includes("brightness_move_to_level")) { exposes.push(e.action_level()); @@ -1460,7 +1460,7 @@ export function commandsColorCtrl(args: CommandsColorCtrl = {}): ModernExtend { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [e.action(actions)]; + const exposes: Expose[] = [e.action(actions), e.action_group()]; // TODO: e.action_hue, e.action_enhanced_hue, e.action_direction, e.action_saturation, // e.action_color, e.action_stepx, e.action_stepy, e.action_colortemp, e.action_minimum, e.action_maximum etc. @@ -1673,7 +1673,7 @@ export function commandsWindowCovering(args: CommandsWindowCoveringArgs = {}): M if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposes: Expose[] = [e.action(actions)]; + const exposes: Expose[] = [e.action(actions), e.action_group()]; const actionPayloadLookup: KeyValueString = { commandUpOpen: "open", @@ -2614,7 +2614,7 @@ export function commandsScenes(args: CommandsScenesArgs = {}) { if (endpointNames) { actions = commands.flatMap((c) => endpointNames.map((e) => `${c}_${e}`)); } - const exposesArray = [e.action(actions)]; + const exposesArray = [e.action(actions), e.action_group()]; const actionPayloadLookup: {[key: string]: string} = { commandRecall: "recall", @@ -3103,7 +3103,7 @@ export function actionEnumLookup< } satisfies Fz.Converter, ]; - return {exposes: [expose], fromZigbee, isModernExtend: true}; + return {exposes: [expose, e.action_group()], fromZigbee, isModernExtend: true}; } export interface QuirkAddEndpointClusterArgs {