Skip to content
Open
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
4 changes: 2 additions & 2 deletions src/devices/eglo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ export const definitions: DefinitionWithExtend[] = [
"recall_2",
"recall_2_long",
]),
e.numeric("action_group", ea.STATE),
e.numeric("action_level", ea.STATE),
e.action_group(),
e.action_level(),
e.numeric("action_color_temperature", ea.STATE),
],
},
Expand Down
9 changes: 4 additions & 5 deletions src/devices/iluminize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = [
{
Expand Down Expand Up @@ -247,10 +246,10 @@ 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.numeric("action_transition_time", ea.STATE),
e.numeric("action_step_size", ea.STATE),
e.numeric("action_rate", ea.STATE),
e.action_group(),
e.action_step_size(),
e.action_transition_time(),
e.action_rate(),
],
toZigbee: [],
meta: {multiEndpoint: true},
Expand Down
2 changes: 1 addition & 1 deletion src/devices/ls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down
6 changes: 0 additions & 6 deletions src/devices/shelly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2123,12 +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."),
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: [
m.battery(),
m.commandsOnOff({commands: ["on", "off"]}),
Expand Down
8 changes: 4 additions & 4 deletions src/devices/tuya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13507,10 +13507,10 @@ 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.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_step_size(),
e.action_transition_time(),
e.action_rate(),
e.battery(),
e
.enum("operation_mode", ea.ALL, ["command", "event"])
Expand Down Expand Up @@ -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)"),
Expand Down
19 changes: 19 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,25 @@ function processExtensions(definition: DefinitionWithExtend): Definition {
allExposes.push(exposesLib.presets.action(uniqueActions));
}

// De-duplicate and sort action parameters
const actionParamOrder = ["action_group", "action_level", "action_step_size", "action_transition_time", "action_rate"];
const actionParamExposes = new Map<string, Expose>();

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) {
Expand Down
37 changes: 36 additions & 1 deletion src/lib/exposes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,42 @@ 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")
.withValueMin(0)
.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"),
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"),
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"),
Expand Down
70 changes: 56 additions & 14 deletions src/lib/modernExtend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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), e.action_group()];

const actionPayloadLookup: KeyValueString = {
commandOn: "on",
Expand Down Expand Up @@ -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",
Expand All @@ -1379,9 +1379,21 @@ 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), e.action_group()];

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")) {
exposes.push(e.action_rate());
}

const fromZigbee = [fz.command_move_to_level, fz.command_move, fz.command_step, fz.command_stop];

Expand Down Expand Up @@ -1439,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,
Expand All @@ -1447,9 +1460,40 @@ 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), 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.
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") ||
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());
exposes.push(e.action_transition_time());
}

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,
Expand Down Expand Up @@ -1629,9 +1673,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), e.action_group()];

const actionPayloadLookup: KeyValueString = {
commandUpOpen: "open",
Expand Down Expand Up @@ -2572,7 +2614,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), e.action_group()];

const actionPayloadLookup: {[key: string]: string} = {
commandRecall: "recall",
Expand Down Expand Up @@ -3037,7 +3079,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 = [
{
Expand All @@ -3061,7 +3103,7 @@ export function actionEnumLookup<
} satisfies Fz.Converter<Cl, Custom, Cos extends undefined ? ["attributeReport", "readResponse"] : Cos>,
];

return {exposes: [expose], fromZigbee, isModernExtend: true};
return {exposes: [expose, e.action_group()], fromZigbee, isModernExtend: true};
}

export interface QuirkAddEndpointClusterArgs {
Expand Down