Skip to content

Instantly share code, notes, and snippets.

@Koenkk

Koenkk/ext.js Secret

Last active July 29, 2024 18:44
Show Gist options
  • Save Koenkk/3d766bc346c74cb985b75cbb13eb7c6e to your computer and use it in GitHub Desktop.
Save Koenkk/3d766bc346c74cb985b75cbb13eb7c6e to your computer and use it in GitHub Desktop.
const fz = require('zigbee-herdsman-converters/converters/fromZigbee');
const tz = require('zigbee-herdsman-converters/converters/toZigbee');
const exposes = require('zigbee-herdsman-converters/lib/exposes');
const reporting = require('zigbee-herdsman-converters/lib/reporting');
const tuya = require('zigbee-herdsman-converters/lib/tuya');
const e = exposes.presets;
const ea = exposes.access;
const legacy = require('zigbee-herdsman-converters/lib/legacy');
const lumi = require('zigbee-herdsman-converters/lib/lumi');
const utils = require('zigbee-herdsman-converters/lib/utils');
const fzLocal = {
battery: {
cluster: 'genPowerCfg',
type: ['attributeReport', 'readResponse'],
convert: (model, msg, publish, options, meta) => {
const payload = {};
if (msg.data.hasOwnProperty('batteryPercentageRemaining') && (msg.data['batteryPercentageRemaining'] < 255)) {
// Some devices do not comply to the ZCL and report a
// batteryPercentageRemaining of 100 when the battery is full (should be 200).
//
// IKEA corrected this on newer remote fw version, but many people are still
// 2.2.010 which is the last version supporting group bindings. We try to be
// smart and pick the correct one for IKEA remotes.
let dontDividePercentage = false;
let percentage = msg.data['batteryPercentageRemaining'];
const fwVer = meta.device.softwareBuildID.split('.').map((e) => Number(e));
if ((fwVer[0] < 2) || (fwVer[0] == 2 && fwVer[1] <= 3)) {
dontDividePercentage = true;
}
percentage = dontDividePercentage ? percentage : percentage / 2;
payload.battery = precisionRound(percentage, 2);
}
return payload;
},
},
styrbar_on: {
cluster: 'genOnOff',
type: 'commandOn',
convert: (model, msg, publish, options, meta) => {
if (utils.hasAlreadyProcessedMessage(msg, model)) return;
const arrowReleaseAgo = Date.now() - globalStore.getValue(msg.endpoint, 'arrow_release', 0);
if (arrowReleaseAgo > 700) {
return {action: 'on'};
}
},
},
styrbar_arrow_release: {
cluster: 'genScenes',
type: 'commandTradfriArrowRelease',
options: [exposes.options.legacy()],
convert: (model, msg, publish, options, meta) => {
if (utils.hasAlreadyProcessedMessage(msg, model)) return;
globalStore.putValue(msg.endpoint, 'arrow_release', Date.now());
const direction = globalStore.getValue(msg.endpoint, 'direction');
if (direction) {
globalStore.clearValue(msg.endpoint, 'direction');
const duration = msg.data.value / 1000;
const result = {action: `arrow_${direction}_release`, duration, action_duration: duration};
if (!utils.isLegacyEnabled(options)) delete result.duration;
return result;
}
},
},
ikea_arrow_click: {
cluster: 'genScenes',
type: 'commandTradfriArrowSingle',
convert: (model, msg, publish, options, meta) => {
if (hasAlreadyProcessedMessage(msg, model)) return;
if (msg.data.value === 2) {
// This is send on toggle hold, ignore it as a toggle_hold is already handled above.
return;
}
const direction = msg.data.value === 257 ? 'left' : 'right';
return {action: `arrow_${direction}_click`};
},
}
}
const definition = {
zigbeeModel: ['Remote Control N2'],
model: 'E2001/E2002',
vendor: 'IKEA',
description: 'STYRBAR remote control CUSTOM',
fromZigbee: [fzLocal.battery, fzLocal.styrbar_on, fz.command_off, fz.command_move, fz.command_stop, fzLocal.ikea_arrow_click,
fz.ikea_arrow_hold, fzLocal.styrbar_arrow_release],
exposes: [e.battery().withAccess(ea.STATE_GET), e.action(['on', 'off', 'brightness_move_up', 'brightness_move_down',
'brightness_stop', 'arrow_left_click', 'arrow_right_click', 'arrow_left_hold',
'arrow_right_hold', 'arrow_left_release', 'arrow_right_release'])],
toZigbee: [tz.battery_percentage_remaining],
// ota: ota.tradfri,
configure: async (device, coordinatorEndpoint, logger) => {
// Binding genOnOff is not required to make device send events.
const endpoint = device.getEndpoint(1);
const version = device.softwareBuildID.split('.').map((n) => Number(n));
// https://github.com/Koenkk/zigbee2mqtt/issues/15725
const v245OrLater = version[0] > 2 || (version[0] == 2 && version[1] >= 4);
const binds = v245OrLater ? ['genPowerCfg', 'genOnOff', 'genLevelCtrl', 'genScenes'] : ['genPowerCfg'];
await reporting.bind(endpoint, coordinatorEndpoint, binds);
await reporting.batteryPercentageRemaining(endpoint);
},
};
module.exports = definition;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment