zigbee-herdsman-converters
Version:
Collection of device converters to be used with zigbee-herdsman
739 lines • 29.1 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.calibrateAndPrecisionRoundOptionsDefaultPrecision = void 0;
exports.flatten = flatten;
exports.onEventPoll = onEventPoll;
exports.precisionRound = precisionRound;
exports.toLocalISOString = toLocalISOString;
exports.numberWithinRange = numberWithinRange;
exports.mapNumberRange = mapNumberRange;
exports.hasAlreadyProcessedMessage = hasAlreadyProcessedMessage;
exports.calibrateAndPrecisionRoundOptionsIsPercentual = calibrateAndPrecisionRoundOptionsIsPercentual;
exports.calibrateAndPrecisionRoundOptions = calibrateAndPrecisionRoundOptions;
exports.toPercentage = toPercentage;
exports.addActionGroup = addActionGroup;
exports.getEndpointName = getEndpointName;
exports.postfixWithEndpointName = postfixWithEndpointName;
exports.exposeEndpoints = exposeEndpoints;
exports.enforceEndpoint = enforceEndpoint;
exports.getKey = getKey;
exports.batteryVoltageToPercentage = batteryVoltageToPercentage;
exports.getMetaValue = getMetaValue;
exports.hasEndpoints = hasEndpoints;
exports.isInRange = isInRange;
exports.replaceToZigbeeConvertersInArray = replaceToZigbeeConvertersInArray;
exports.filterObject = filterObject;
exports.sleep = sleep;
exports.toSnakeCase = toSnakeCase;
exports.toCamelCase = toCamelCase;
exports.getLabelFromName = getLabelFromName;
exports.saveSceneState = saveSceneState;
exports.deleteSceneState = deleteSceneState;
exports.getSceneState = getSceneState;
exports.getEntityOrFirstGroupMember = getEntityOrFirstGroupMember;
exports.getTransition = getTransition;
exports.getOptions = getOptions;
exports.getMetaValues = getMetaValues;
exports.getObjectProperty = getObjectProperty;
exports.validateValue = validateValue;
exports.getClusterAttributeValue = getClusterAttributeValue;
exports.normalizeCelsiusVersionOfFahrenheit = normalizeCelsiusVersionOfFahrenheit;
exports.noOccupancySince = noOccupancySince;
exports.attachOutputCluster = attachOutputCluster;
exports.printNumberAsHex = printNumberAsHex;
exports.printNumbersAsHexSequence = printNumbersAsHexSequence;
exports.assertObject = assertObject;
exports.assertArray = assertArray;
exports.assertString = assertString;
exports.isNumber = isNumber;
exports.isObject = isObject;
exports.isString = isString;
exports.isBoolean = isBoolean;
exports.assertNumber = assertNumber;
exports.toNumber = toNumber;
exports.getFromLookup = getFromLookup;
exports.getFromLookupByValue = getFromLookupByValue;
exports.configureSetPowerSourceWhenUnknown = configureSetPowerSourceWhenUnknown;
exports.assertEndpoint = assertEndpoint;
exports.assertGroup = assertGroup;
exports.isEndpoint = isEndpoint;
exports.isDevice = isDevice;
exports.isGroup = isGroup;
exports.isNumericExpose = isNumericExpose;
exports.isLightExpose = isLightExpose;
exports.splitArrayIntoChunks = splitArrayIntoChunks;
const zigbee_herdsman_1 = require("zigbee-herdsman");
const logger_1 = require("./logger");
const globalStore = __importStar(require("./store"));
const NS = "zhc:utils";
function flatten(arr) {
return [].concat(...arr);
}
function onEventPoll(type, data, device, options, key, defaultIntervalSeconds, poll) {
if (type === "stop") {
clearTimeout(globalStore.getValue(device, key));
globalStore.clearValue(device, key);
}
else if (!globalStore.hasValue(device, key)) {
const optionsKey = `${key}_poll_interval`;
const seconds = toNumber(options[optionsKey] || defaultIntervalSeconds, optionsKey);
if (seconds <= 0) {
logger_1.logger.debug(`Not polling '${key}' for '${device.ieeeAddr}' since poll interval is <= 0 (got ${seconds})`, NS);
}
else {
logger_1.logger.debug(`Polling '${key}' for '${device.ieeeAddr}' at an interval of ${seconds}`, NS);
const setTimer = () => {
const timer = setTimeout(async () => {
try {
await poll();
}
catch {
/* Do nothing*/
}
setTimer();
}, seconds * 1000);
globalStore.putValue(device, key, timer);
};
setTimer();
}
}
}
function precisionRound(number, precision) {
if (typeof precision === "number") {
const factor = 10 ** precision;
return Math.round(number * factor) / factor;
}
if (typeof precision === "object") {
const thresholds = Object.keys(precision)
.map(Number)
.sort((a, b) => b - a);
for (const t of thresholds) {
if (!Number.isNaN(t) && number >= t) {
return precisionRound(number, precision[t]);
}
}
}
return number;
}
function toLocalISOString(dDate) {
const tzOffset = -dDate.getTimezoneOffset();
const plusOrMinus = tzOffset >= 0 ? "+" : "-";
const pad = (num) => {
const norm = Math.floor(Math.abs(num));
return (norm < 10 ? "0" : "") + norm;
};
return `${dDate.getFullYear()}-${pad(dDate.getMonth() + 1)}-${pad(dDate.getDate())}T${pad(dDate.getHours())}:${pad(dDate.getMinutes())}:${pad(dDate.getSeconds())}${plusOrMinus}${pad(tzOffset / 60)}:${pad(tzOffset % 60)}`;
}
function numberWithinRange(number, min, max) {
if (number > max) {
return max;
}
if (number < min) {
return min;
}
return number;
}
/**
* Maps number from one range to another. In other words it performs a linear interpolation.
* Note that this function can interpolate values outside source range (linear extrapolation).
* @param value - value to map
* @param fromLow - source range lower value
* @param fromHigh - source range upper value
* @param toLow - target range lower value
* @param toHigh - target range upper value
* @param number - of decimal places to which result should be rounded
* @returns value mapped to new range
*/
function mapNumberRange(value, fromLow, fromHigh, toLow, toHigh, precision = 0) {
const mappedValue = toLow + ((value - fromLow) * (toHigh - toLow)) / (fromHigh - fromLow);
return precisionRound(mappedValue, precision);
}
const transactionStore = {};
function hasAlreadyProcessedMessage(msg, model, id = null, key = null) {
if (model.meta?.publishDuplicateTransaction)
return false;
const currentID = id !== null ? id : msg.meta.zclTransactionSequenceNumber;
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
key = key || `${msg.device.ieeeAddr}-${msg.endpoint.ID}`;
if (transactionStore[key]?.includes(currentID))
return true;
// Keep last 5, as they might come in different order: https://github.com/Koenkk/zigbee2mqtt/issues/20024
transactionStore[key] = [currentID, ...(transactionStore[key] ?? [])].slice(0, 5);
return false;
}
exports.calibrateAndPrecisionRoundOptionsDefaultPrecision = {
ac_frequency: 2,
temperature: 2,
humidity: 2,
pressure: 1,
pm25: 0,
power: 2,
current: 2,
current_phase_b: 2,
current_phase_c: 2,
current_neutral: 2,
voltage: 2,
voltage_phase_b: 2,
voltage_phase_c: 2,
power_phase_b: 2,
power_phase_c: 2,
energy: 2,
device_temperature: 0,
soil_moisture: 2,
co2: 0,
illuminance: 0,
voc: 0,
formaldehyd: 0,
co: 0,
};
function calibrateAndPrecisionRoundOptionsIsPercentual(type) {
return (type.startsWith("current") ||
type.startsWith("energy") ||
type.startsWith("voltage") ||
type.startsWith("power") ||
type.startsWith("illuminance"));
}
function calibrateAndPrecisionRoundOptions(number, options, type) {
// Calibrate
const calibrateKey = `${type}_calibration`;
let calibrationOffset = toNumber(options?.[calibrateKey] != null ? options[calibrateKey] : 0, calibrateKey);
if (calibrateAndPrecisionRoundOptionsIsPercentual(type)) {
// linear calibration because measured value is zero based
// +/- percent
calibrationOffset = (number * calibrationOffset) / 100;
}
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
number = number + calibrationOffset;
// Precision round
const precisionKey = `${type}_precision`;
const defaultValue = exports.calibrateAndPrecisionRoundOptionsDefaultPrecision[type] || 0;
const precision = toNumber(options?.[precisionKey] != null ? options[precisionKey] : defaultValue, precisionKey);
return precisionRound(number, precision);
}
function toPercentage(value, min, max) {
if (value > max) {
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
value = max;
}
else if (value < min) {
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
value = min;
}
const normalised = (value - min) / (max - min);
return Math.round(normalised * 100);
}
function addActionGroup(payload, msg, definition) {
const disableActionGroup = definition.meta?.disableActionGroup;
if (!disableActionGroup && msg.groupID) {
payload.action_group = msg.groupID;
}
}
function getEndpointName(msg, definition, meta) {
if (!definition.endpoint) {
throw new Error(`Definition '${definition.model}' has not endpoint defined`);
}
return getKey(definition.endpoint(meta.device), msg.endpoint.ID);
}
function postfixWithEndpointName(value, msg, definition, meta) {
// Prevent breaking change https://github.com/Koenkk/zigbee2mqtt/issues/13451
if (!meta) {
logger_1.logger.warning("No meta passed to postfixWithEndpointName, update your external converter!", NS);
// @ts-expect-error ignore
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
meta = { device: null };
}
if (definition.meta?.multiEndpoint && (!definition.meta.multiEndpointSkip || !definition.meta.multiEndpointSkip.includes(value))) {
const endpointName = definition.endpoint !== undefined ? getKey(definition.endpoint(meta.device), msg.endpoint.ID) : msg.endpoint.ID;
// NOTE: endpointName can be undefined if we have a definition.endpoint and the endpoint is
// not listed.
if (endpointName)
return `${value}_${endpointName}`;
}
return value;
}
function exposeEndpoints(expose, endpointNames) {
return endpointNames ? endpointNames.map((ep) => expose.clone().withEndpoint(ep)) : [expose];
}
function enforceEndpoint(entity, key, meta) {
// @ts-expect-error ignore
const multiEndpointEnforce = getMetaValue(entity, meta.mapped, "multiEndpointEnforce", "allEqual", []);
if (multiEndpointEnforce && isObject(multiEndpointEnforce) && multiEndpointEnforce[key] !== undefined) {
const endpoint = entity.getDevice().getEndpoint(multiEndpointEnforce[key]);
if (endpoint)
return endpoint;
}
return entity;
}
function getKey(object, value, fallback, convertTo) {
for (const key in object) {
// @ts-expect-error ignore
if (object[key] === value) {
return convertTo ? convertTo(key) : key;
}
}
return fallback;
}
function batteryVoltageToPercentage(voltage, option) {
if (option === "3V_2100") {
let percentage = 100; // >= 3000
if (voltage < 2100) {
percentage = 0;
}
else if (voltage < 2440) {
percentage = 6 - ((2440 - voltage) * 6) / 340;
}
else if (voltage < 2740) {
percentage = 18 - ((2740 - voltage) * 12) / 300;
}
else if (voltage < 2900) {
percentage = 42 - ((2900 - voltage) * 24) / 160;
}
else if (voltage < 3000) {
percentage = 100 - ((3000 - voltage) * 58) / 100;
}
return Math.round(percentage);
}
if (option === "3V_1500_2800") {
const percentage = 235 - 370000 / (voltage + 1);
return Math.round(Math.min(Math.max(percentage, 0), 100));
}
if (typeof option === "object") {
// Generic converter that expects an option object with min and max values
// I.E. meta: {battery: {voltageToPercentage: {min: 1900, max: 3000}}}
return toPercentage(voltage + (option.vOffset ?? 0), option.min, option.max);
}
// only to cover case where a BatteryVoltage is missing in this switch
throw new Error(`Unhandled battery voltage to percentage option: ${option}`);
}
// groupStrategy: allEqual: return only if all members in the groups have the same meta property value
// first: return the first property
// {atLeastOnce}: returns `atLeastOnce` value when at least one of the group members has this value
function getMetaValue(entity, definition, key, groupStrategy = "first", defaultValue = undefined) {
// In case meta is a function, the first argument should be a `Zh.Entity`.
if (isGroup(entity) && entity.members.length > 0) {
const values = [];
for (let i = 0; i < entity.members.length; i++) {
const memberMetaMeta = getMetaValues(definition[i], entity.members[i]);
if (memberMetaMeta?.[key] !== undefined) {
const value = typeof memberMetaMeta[key] === "function" ? memberMetaMeta[key](entity.members[i]) : memberMetaMeta[key];
if (groupStrategy === "first") {
return value;
}
if (typeof groupStrategy === "object" && value === groupStrategy.atLeastOnce) {
return groupStrategy.atLeastOnce;
}
values.push(value);
}
else {
values.push(defaultValue);
}
}
if (groupStrategy === "allEqual" && new Set(values).size === 1) {
return values[0];
}
}
else {
const definitionMeta = getMetaValues(definition, entity);
if (definitionMeta?.[key] !== undefined) {
return typeof definitionMeta[key] === "function" ? definitionMeta[key](entity) : definitionMeta[key];
}
}
return defaultValue;
}
function hasEndpoints(device, endpoints) {
const eps = device.endpoints.map((e) => e.ID);
for (const endpoint of endpoints) {
if (!eps.includes(endpoint)) {
return false;
}
}
return true;
}
function isInRange(min, max, value) {
return value >= min && value <= max;
}
function replaceToZigbeeConvertersInArray(arr, oldElements, newElements, errorIfNotInArray = true) {
const clone = [...arr];
for (let i = 0; i < oldElements.length; i++) {
const index = clone.findIndex((t) => t.key === oldElements[i].key);
if (index !== -1) {
clone[index] = newElements[i];
}
else {
if (errorIfNotInArray) {
throw new Error("Element not in array");
}
}
}
return clone;
}
function filterObject(obj, keys) {
const result = {};
for (const [key, value] of Object.entries(obj)) {
if (keys.includes(key)) {
result[key] = value;
}
}
return result;
}
async function sleep(ms) {
return await new Promise((resolve) => setTimeout(resolve, ms));
}
function toSnakeCase(value) {
if (typeof value === "object") {
for (const key of Object.keys(value)) {
const keySnakeCase = toSnakeCase(key);
if (key !== keySnakeCase) {
// @ts-expect-error ignore
value[keySnakeCase] = value[key];
delete value[key];
}
}
return value;
}
return value
.replace(/\.?([A-Z])/g, (x, y) => `_${y.toLowerCase()}`)
.replace(/^_/, "")
.replace("_i_d", "_id");
}
function toCamelCase(value) {
if (typeof value === "object") {
for (const key of Object.keys(value)) {
const keyCamelCase = toCamelCase(key);
if (key !== keyCamelCase) {
// @ts-expect-error ignore
value[keyCamelCase] = value[key];
delete value[key];
}
}
return value;
}
return value.replace(/_([a-z])/g, (x, y) => y.toUpperCase());
}
function getLabelFromName(name) {
const label = name.replace(/_/g, " ");
return label[0].toUpperCase() + label.slice(1);
}
function saveSceneState(entity, sceneID, groupID, state, name) {
const attributes = ["state", "brightness", "color", "color_temp", "color_mode"];
if (entity.meta.scenes === undefined)
entity.meta.scenes = {};
const metaKey = `${sceneID}_${groupID}`;
entity.meta.scenes[metaKey] = { name, state: filterObject(state, attributes) };
entity.save();
}
function deleteSceneState(entity, sceneID = null, groupID = null) {
if (entity.meta.scenes) {
if (sceneID == null && groupID == null) {
entity.meta.scenes = {};
}
else {
const metaKey = `${sceneID}_${groupID}`;
if (entity.meta.scenes[metaKey] !== undefined) {
delete entity.meta.scenes[metaKey];
}
}
entity.save();
}
}
function getSceneState(entity, sceneID, groupID) {
const metaKey = `${sceneID}_${groupID}`;
if (entity.meta.scenes !== undefined && entity.meta.scenes[metaKey] !== undefined) {
return entity.meta.scenes[metaKey].state;
}
return null;
}
function getEntityOrFirstGroupMember(entity) {
if (isGroup(entity)) {
return entity.members.length > 0 ? entity.members[0] : null;
}
return entity;
}
function getTransition(entity, key, meta) {
const { options, message } = meta;
let manufacturerIDs = [];
if (isGroup(entity)) {
manufacturerIDs = entity.members.map((m) => m.getDevice().manufacturerID);
}
else if (isEndpoint(entity)) {
manufacturerIDs = [entity.getDevice().manufacturerID];
}
if (manufacturerIDs.includes(zigbee_herdsman_1.Zcl.ManufacturerCode.IKEA_OF_SWEDEN)) {
/**
* When setting both brightness and color temperature with a transition, the brightness is skipped
* for IKEA TRADFRI bulbs.
* To workaround this we skip the transition for the brightness as it is applied first.
* https://github.com/Koenkk/zigbee2mqtt/issues/1810
*/
if (key === "brightness" && (message.color != null || message.color_temp != null)) {
return { time: 0, specified: false };
}
}
if (message.transition != null) {
const time = toNumber(message.transition, "transition");
return { time: time * 10, specified: true };
}
if (options.transition != null && options.transition !== "") {
const transition = toNumber(options.transition, "transition");
return { time: transition * 10, specified: true };
}
return { time: 0, specified: false };
}
function getOptions(definition, entity, options = {}) {
const allowed = ["disableDefaultResponse", "timeout"];
return getMetaValues(definition, entity, allowed, options);
}
function getMetaValues(definitions, entity, allowed, options = {}) {
const result = { ...options };
for (const definition of Array.isArray(definitions) ? definitions : [definitions]) {
if (definition?.meta) {
for (const key of Object.keys(definition.meta)) {
if (allowed == null || allowed.includes(key)) {
// @ts-expect-error ignore
const value = definition.meta[key];
if (typeof value === "function") {
if (isEndpoint(entity)) {
result[key] = value(entity);
}
}
else {
result[key] = value;
}
}
}
}
}
return result;
}
function getObjectProperty(object, key, defaultValue) {
return object && object[key] !== undefined ? object[key] : defaultValue;
}
function validateValue(value, allowed) {
if (!allowed.includes(value)) {
throw new Error(`'${value}' not allowed, choose between: ${allowed}`);
}
}
async function getClusterAttributeValue(endpoint, cluster, attribute, fallback = undefined) {
try {
if (endpoint.getClusterAttributeValue(cluster, attribute) == null) {
await endpoint.read(cluster, [attribute], { sendPolicy: "immediate", disableRecovery: true });
}
return endpoint.getClusterAttributeValue(cluster, attribute);
}
catch (error) {
if (fallback !== undefined)
return fallback;
throw error;
}
}
function normalizeCelsiusVersionOfFahrenheit(value) {
const fahrenheit = value * 1.8 + 32;
const roundedFahrenheit = Number((Math.round(Number((fahrenheit * 2).toFixed(1))) / 2).toFixed(1));
return Number(((roundedFahrenheit - 32) / 1.8).toFixed(2));
}
function noOccupancySince(endpoint, options, publish, action) {
if (options?.no_occupancy_since) {
if (action === "start") {
// biome-ignore lint/complexity/noForEach: ignored using `--suppress`
globalStore.getValue(endpoint, "no_occupancy_since_timers", []).forEach((t) => clearTimeout(t));
globalStore.putValue(endpoint, "no_occupancy_since_timers", []);
// biome-ignore lint/complexity/noForEach: ignored using `--suppress`
options.no_occupancy_since.forEach((since) => {
const timer = setTimeout(() => {
publish({ no_occupancy_since: since });
}, since * 1000);
globalStore.getValue(endpoint, "no_occupancy_since_timers").push(timer);
});
}
else if (action === "stop") {
// biome-ignore lint/complexity/noForEach: ignored using `--suppress`
globalStore.getValue(endpoint, "no_occupancy_since_timers", []).forEach((t) => clearTimeout(t));
globalStore.putValue(endpoint, "no_occupancy_since_timers", []);
}
}
}
function attachOutputCluster(device, clusterKey) {
const clusterId = zigbee_herdsman_1.Zcl.Utils.getCluster(clusterKey, device.manufacturerID, device.customClusters).ID;
const endpoint = device.getEndpoint(1);
if (!endpoint.outputClusters.includes(clusterId)) {
endpoint.outputClusters.push(clusterId);
device.save();
}
}
function printNumberAsHex(value, hexLength) {
const hexValue = value.toString(16).padStart(hexLength, "0");
return `0x${hexValue}`;
}
function printNumbersAsHexSequence(numbers, hexLength) {
return numbers.map((v) => v.toString(16).padStart(hexLength, "0")).join(":");
}
// biome-ignore lint/suspicious/noExplicitAny: ignored using `--suppress`
function assertObject(value, property) {
const isObject = typeof value === "object" && !Array.isArray(value) && value !== null;
if (!isObject) {
throw new Error(`${property} is not a object, got ${typeof value} (${JSON.stringify(value)})`);
}
}
function assertArray(value, property) {
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
property = property ? `'${property}'` : "Value";
if (!Array.isArray(value))
throw new Error(`${property} is not an array, got ${typeof value} (${value.toString()})`);
}
function assertString(value, property) {
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
property = property ? `'${property}'` : "Value";
if (typeof value !== "string")
throw new Error(`${property} is not a string, got ${typeof value} (${value.toString()})`);
}
function isNumber(value) {
return typeof value === "number";
}
// biome-ignore lint/suspicious/noExplicitAny: ignored using `--suppress`
function isObject(value) {
return typeof value === "object" && !Array.isArray(value);
}
function isString(value) {
return typeof value === "string";
}
function isBoolean(value) {
return typeof value === "boolean";
}
function assertNumber(value, property) {
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
property = property ? `'${property}'` : "Value";
if (typeof value !== "number" || Number.isNaN(value))
throw new Error(`${property} is not a number, got ${typeof value} (${value?.toString()})`);
}
function toNumber(value, property) {
// biome-ignore lint/style/noParameterAssign: ignored using `--suppress`
property = property ? `'${property}'` : "Value";
// @ts-expect-error ignore
const result = Number.parseFloat(value);
if (Number.isNaN(result)) {
throw new Error(`${property} is not a number, got ${typeof value} (${value.toString()})`);
}
return result;
}
function getFromLookup(value, lookup, defaultValue = undefined, keyIsBool = false) {
if (!keyIsBool) {
if (typeof value === "string") {
for (const key of [value, value.toLowerCase(), value.toUpperCase()]) {
if (lookup[key] !== undefined) {
return lookup[key];
}
}
}
else if (typeof value === "number") {
if (lookup[value] !== undefined) {
return lookup[value];
}
}
else {
throw new Error(`Expected string or number, got: ${typeof value}`);
}
}
else {
// Silly hack, but boolean is not supported as index
if (typeof value === "boolean") {
const stringValue = value.toString();
for (const key of [stringValue, stringValue.toLowerCase(), stringValue.toUpperCase()]) {
if (lookup[key] !== undefined) {
return lookup[key];
}
}
}
else {
throw new Error(`Expected boolean, got: ${typeof value}`);
}
}
if (defaultValue === undefined) {
throw new Error(`Value: '${value}' not found in: [${Object.keys(lookup).join(", ")}]`);
}
return defaultValue;
}
function getFromLookupByValue(value, lookup, defaultValue = undefined) {
for (const entry of Object.entries(lookup)) {
if (entry[1] === value) {
return entry[0];
}
}
if (defaultValue === undefined) {
throw new Error(`Expected one of: ${Object.values(lookup).join(", ")}, got: '${value}'`);
}
return defaultValue;
}
function configureSetPowerSourceWhenUnknown(powerSource) {
return (device) => {
if (!device.powerSource || device.powerSource === "Unknown") {
logger_1.logger.debug(`Device has no power source, forcing to '${powerSource}'`, NS);
device.powerSource = powerSource;
device.save();
}
};
}
function assertEndpoint(obj) {
if (obj?.constructor?.name?.toLowerCase() !== "endpoint")
throw new Error("Not an endpoint");
}
function assertGroup(obj) {
if (obj?.constructor?.name?.toLowerCase() !== "group")
throw new Error("Not a group");
}
function isEndpoint(obj) {
return obj.constructor.name.toLowerCase() === "endpoint";
}
function isDevice(obj) {
return obj.constructor.name.toLowerCase() === "device";
}
function isGroup(obj) {
return obj.constructor.name.toLowerCase() === "group";
}
function isNumericExpose(expose) {
return expose?.type === "numeric";
}
function isLightExpose(expose) {
return expose?.type === "light";
}
function splitArrayIntoChunks(arr, chunkSize) {
const result = [];
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
result.push(chunk);
}
return result;
}
//# sourceMappingURL=utils.js.map
;