zigbee-herdsman-converters
Version:
Collection of device converters to be used with zigbee-herdsman
2,040 lines • 87.8 kB
JavaScript
"use strict";
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.definitions = void 0;
const node_buffer_1 = require("node:buffer");
const zigbee_herdsman_1 = require("zigbee-herdsman");
const zcl_1 = require("zigbee-herdsman/dist/zspec/zcl");
const fz = __importStar(require("../converters/fromZigbee"));
const constants_1 = require("../lib/constants");
const exposes = __importStar(require("../lib/exposes"));
const logger_1 = require("../lib/logger");
const m = __importStar(require("../lib/modernExtend"));
const reporting = __importStar(require("../lib/reporting"));
const utils = __importStar(require("../lib/utils"));
const ea = exposes.access;
const e = exposes.presets;
const NS = "zhc:lixee";
const local = {
modernExtend: {
readAttributesOnStartup: () => {
const onEvent = (event) => {
if (event.type === "start") {
event.data.device
.getEndpoint(1)
.read("liXeePrivate", ["linkyMode", "currentTarif"], { manufacturerCode: null })
.catch((e) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/11674
logger_1.logger.warning(`Failed to read Zigbee attributes during startup: ${e}`, NS);
});
}
};
return { onEvent: [onEvent], isModernExtend: true };
},
addCustomClusterManuSpecificLixee: () => m.deviceAddCustomCluster("liXeePrivate", {
name: "liXeePrivate",
ID: 0xff66,
manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.NXP_SEMICONDUCTORS,
attributes: {
currentTarif: { name: "currentTarif", ID: 0x0000, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
tomorrowColor: { name: "tomorrowColor", ID: 0x0001, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
scheduleHPHC: { name: "scheduleHPHC", ID: 0x0002, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
presencePotential: { name: "presencePotential", ID: 0x0003, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
startNoticeEJP: { name: "startNoticeEJP", ID: 0x0004, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
warnDPS: { name: "warnDPS", ID: 0x0005, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff },
warnDIR1: { name: "warnDIR1", ID: 0x0006, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff },
warnDIR2: { name: "warnDIR2", ID: 0x0007, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff },
warnDIR3: { name: "warnDIR3", ID: 0x0008, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff },
motDEtat: { name: "motDEtat", ID: 0x0009, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
tariffPeriod: { name: "tariffPeriod", ID: 0x0010, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
currentPrice: { name: "currentPrice", ID: 0x0200, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
currentIndexTarif: { name: "currentIndexTarif", ID: 0x0201, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
currentDate: { name: "currentDate", ID: 0x0202, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
activeEnergyOutD01: { name: "activeEnergyOutD01", ID: 0x0203, type: zigbee_herdsman_1.Zcl.DataType.UINT32, write: true, max: 0xffffffff },
activeEnergyOutD02: { name: "activeEnergyOutD02", ID: 0x0204, type: zigbee_herdsman_1.Zcl.DataType.UINT32, write: true, max: 0xffffffff },
activeEnergyOutD03: { name: "activeEnergyOutD03", ID: 0x0205, type: zigbee_herdsman_1.Zcl.DataType.UINT32, write: true, max: 0xffffffff },
activeEnergyOutD04: { name: "activeEnergyOutD04", ID: 0x0206, type: zigbee_herdsman_1.Zcl.DataType.UINT32, write: true, max: 0xffffffff },
injectedVA: { name: "injectedVA", ID: 0x0207, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff },
injectedVAMaxN: { name: "injectedVAMaxN", ID: 0x0208, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
injectedVAMaxN1: { name: "injectedVAMaxN1", ID: 0x0209, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
injectedActiveLoadN: { name: "injectedActiveLoadN", ID: 0x0210, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
injectedActiveLoadN1: { name: "injectedActiveLoadN1", ID: 0x0211, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
drawnVAMaxN1: { name: "drawnVAMaxN1", ID: 0x0212, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
drawnVAMaxN1P2: { name: "drawnVAMaxN1P2", ID: 0x0213, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
drawnVAMaxN1P3: { name: "drawnVAMaxN1P3", ID: 0x0214, type: zigbee_herdsman_1.Zcl.DataType.INT16, write: true, min: -32768 },
message1: { name: "message1", ID: 0x0215, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
message2: { name: "message2", ID: 0x0216, type: zigbee_herdsman_1.Zcl.DataType.CHAR_STR, write: true },
statusRegister: { name: "statusRegister", ID: 0x0217, type: zigbee_herdsman_1.Zcl.DataType.OCTET_STR, write: true },
startMobilePoint1: { name: "startMobilePoint1", ID: 0x0218, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
stopMobilePoint1: { name: "stopMobilePoint1", ID: 0x0219, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
startMobilePoint2: { name: "startMobilePoint2", ID: 0x0220, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
stopMobilePoint2: { name: "stopMobilePoint2", ID: 0x0221, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
startMobilePoint3: { name: "startMobilePoint3", ID: 0x0222, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
stopMobilePoint3: { name: "stopMobilePoint3", ID: 0x0223, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
relais: { name: "relais", ID: 0x0224, type: zigbee_herdsman_1.Zcl.DataType.UINT16, write: true, max: 0xffff },
daysNumberCurrentCalendar: { name: "daysNumberCurrentCalendar", ID: 0x0225, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
daysNumberNextCalendar: { name: "daysNumberNextCalendar", ID: 0x0226, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
daysProfileCurrentCalendar: { name: "daysProfileCurrentCalendar", ID: 0x0227, type: zigbee_herdsman_1.Zcl.DataType.LONG_OCTET_STR, write: true },
daysProfileNextCalendar: { name: "daysProfileNextCalendar", ID: 0x0228, type: zigbee_herdsman_1.Zcl.DataType.LONG_OCTET_STR, write: true },
linkyMode: { name: "linkyMode", ID: 0x0300, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff },
},
commands: {},
commandsResponse: {},
}),
},
};
/* Start ZiPulses */
const unitsZiPulses = [
"kWh",
"m3",
"ft3",
"ccf",
"US gl",
"IMP gl",
"BTUs",
"L (litre)",
"kPA (jauge)",
"kPA (absolu)",
"kPA (absolu)",
"sans unité",
"MJ",
"kVar",
];
const tzSeMetering = {
key: ["divisor", "multiplier", "unitOfMeasure"],
convertSet: async (entity, key, value, meta) => {
if (key === "unitOfMeasure") {
utils.assertString(value, "unitOfMeasure");
const val = unitsZiPulses.indexOf(value);
const payload = { 768: { value: val, type: 48 } };
await entity.write("seMetering", payload);
await entity.read("seMetering", [key]);
return { state: { unitOfMeasure: value } };
}
const payload = {
[key]: value,
};
await entity.write("seMetering", payload);
return { state: { [key]: value } };
},
// convertGet: async (entity, key, meta) => {
// await entity.read('seMetering', [key]);
// },
};
const fzZiPulses = {
cluster: "seMetering",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const payload = {};
if (msg.data.multiplier !== undefined) {
payload.multiplier = msg.data.multiplier;
}
if (msg.data.divisor !== undefined) {
payload.divisor = msg.data.divisor;
}
if (msg.data.unitOfMeasure !== undefined) {
const val = msg.data.unitOfMeasure;
payload.unitOfMeasure = unitsZiPulses[val];
}
return payload;
},
};
/* End ZiPulses */
const fzLocal = {
lixee_ha_electrical_measurement: {
cluster: "haElectricalMeasurement",
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const result = {};
const elements = [
/* 0x0305 */ "totalReactivePower",
/* 0x0306 */ "totalApparentPower",
/* 0x0505 */ "rmsVoltage",
/* 0x0508 */ "rmsCurrent",
/* 0x050A */ "rmsCurrentMax",
/* 0x050B */ "activePower",
/* 0x050D */ "activePowerMax",
/* 0x050E */ "reactivePower",
/* 0x050F */ "apparentPower",
/* 0x0511 */ "averageRmsVoltageMeasPeriod",
/* 0x0905 */ "rmsVoltagePhB",
/* 0x0908 */ "rmsCurrentPhB",
/* 0x090A */ "rmsCurrentMaxPhB",
/* 0x090B */ "activePowerPhB",
/* 0x090E */ "reactivePowerPhB",
/* 0x090D */ "activePowerMaxPhB",
/* 0x090F */ "apparentPowerPhB",
/* 0x0911 */ "averageRmsVoltageMeasurePeriodPhB",
/* 0x0A05 */ "rmsVoltagePhC",
/* 0x0A08 */ "rmsCurrentPhC",
/* 0x0A0A */ "rmsCurrentMaxPhC",
/* 0x0A0D */ "activePowerMaxPhC",
/* 0x0A0E */ "reactivePowerPhC",
/* 0x0A0F */ "apparentPowerPhC",
/* 0x0A11 */ "averageRmsVoltageMeasPeriodPhC",
];
for (const at of elements) {
const at_snake = at
.split(/(?=[A-Z])/)
.join("_")
.toLowerCase();
if (msg.data[at] != null) {
result[at_snake] = msg.data[at];
}
}
return result;
},
},
lixee_private_fz: {
cluster: "liXeePrivate", // 0xFF66
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const result = {};
const elements = [
/* 0x0000 */ "currentTarif",
/* 0x0001 */ "tomorrowColor",
/* 0x0002 */ "scheduleHPHC",
/* 0x0003 */ "presencePotential",
/* 0x0004 */ "startNoticeEJP",
/* 0x0005 */ "warnDPS",
/* 0x0006 */ "warnDIR1",
/* 0x0007 */ "warnDIR2",
/* 0x0008 */ "warnDIR3",
/* 0x0009 */ "motDEtat",
/* 0x0010 */ "tariffPeriod",
/* 0x0200 */ "currentPrice",
/* 0x0201 */ "currentIndexTarif",
/* 0x0202 */ "currentDate",
/* 0x0203 */ "activeEnergyOutD01",
/* 0x0204 */ "activeEnergyOutD02",
/* 0x0205 */ "activeEnergyOutD03",
/* 0x0206 */ "activeEnergyOutD04",
/* 0x0207 */ "injectedVA",
/* 0x0208 */ "injectedVAMaxN",
/* 0x0209 */ "injectedVAMaxN1",
/* 0x0210 */ "injectedActiveLoadN",
/* 0x0211 */ "injectedActiveLoadN1",
/* 0x0212 */ "drawnVAMaxN1",
/* 0x0213 */ "drawnVAMaxN1P2",
/* 0x0214 */ "drawnVAMaxN1P3",
/* 0x0215 */ "message1",
/* 0x0216 */ "message2",
/* 0x0217 */ "statusRegister",
/* 0x0218 */ "startMobilePoint1",
/* 0x0219 */ "stopMobilePoint1",
/* 0x0220 */ "startMobilePoint2",
/* 0x0221 */ "stopMobilePoint2",
/* 0x0222 */ "startMobilePoint3",
/* 0x0223 */ "stopMobilePoint3",
/* 0x0224 */ "relais",
/* 0x0225 */ "daysNumberCurrentCalendar",
/* 0x0226 */ "daysNumberNextCalendar",
/* 0x0227 */ "daysProfileCurrentCalendar",
/* 0x0228 */ "daysProfileNextCalendar",
];
const kWhP = options?.kWh_precision ? options.kWh_precision : 2;
utils.assertNumber(kWhP);
for (const at of elements) {
const at_snake = at
.split(/(?=[A-Z])/)
.join("_")
.toLowerCase();
// biome-ignore lint/suspicious/noExplicitAny: bad typing
let val = msg.data[at];
if (val != null) {
// TODO: this is not possible??
if (utils.isObject(val) && "type" in val && "data" in val && val.type === "Buffer") {
val = node_buffer_1.Buffer.from(val.data);
}
if (node_buffer_1.Buffer.isBuffer(val)) {
val = val.toString(); // Convert buffer to string
}
if (typeof val === "string") {
val = val.replace(/\0/g, ""); // Remove all null chars when str
val = val.replace(/\s+/g, " ").trim(); // Remove extra and leading spaces
}
switch (at) {
case "tariffPeriod":
// Store the value twice: once for when the meter
// is in standard mode and once for when it is in
// legacy mode
result.current_price = val;
result.active_register_tier_delivered = val;
break;
case "activeEnergyOutD01":
case "activeEnergyOutD02":
case "activeEnergyOutD03":
case "activeEnergyOutD04":
val = utils.precisionRound(Number.parseInt(val, 10) / 1000, kWhP); // from Wh to kWh
break;
case "relais": {
// relais is a decimal value representing the bits
// of 8 virtual dry contacts.
// 0 for an open relay
// 1 for a closed relay
// relais1 Hot water === legacy dry contact
// relais2 Main heater
// relais3 Secondary heater
// relais4 AC or Heat pump
// relais5 EV charge
// relais6 Storage or injection
// relais7 Unassigned
// relais8 Unassigned
const relais_breakout = {};
for (let i = 0; i < 8; i++) {
relais_breakout[at_snake + (i + 1)] = (Number.parseInt(val, 10) & (1 << i)) >>> i;
}
result[`${at_snake}_breakout`] = relais_breakout;
break;
}
case "statusRegister": {
// val is a String representing hex.
// Must convert
const valhex = Number(`0x${val}`);
const statusRegisterBreakout = {};
// contact sec
statusRegisterBreakout.contact_sec = (valhex & 0x1) === 1 ? "ouvert" : "ferme";
// organe de coupure
switch ((valhex >>> 1) & 0x7) {
case 0:
statusRegisterBreakout.organe_coupure = "ferme";
break;
case 1:
statusRegisterBreakout.organe_coupure = "surpuissance";
break;
case 2:
statusRegisterBreakout.organe_coupure = "surtension";
break;
case 3:
statusRegisterBreakout.organe_coupure = "delestage";
break;
case 4:
statusRegisterBreakout.organe_coupure = "ordre_CPL_Euridis";
break;
case 5:
statusRegisterBreakout.organe_coupure = "surchauffe_surcourant";
break;
case 6:
statusRegisterBreakout.organe_coupure = "surchauffe_simple";
break;
}
// etat cache borne distributeur
statusRegisterBreakout.cache_borne_dist = ((valhex >>> 4) & 0x1) === 0 ? "ferme" : "ouvert";
// bit 5 inutilise
// surtension sur une des phases
statusRegisterBreakout.surtension_phase = (valhex >>> 6) & 0x1;
// depassement puissance de reference
statusRegisterBreakout.depassement_ref_pow = (valhex >>> 7) & 0x1;
// consommateur ou producteur
statusRegisterBreakout.producteur = (valhex >>> 8) & 0x1;
// sens de l'energie active
statusRegisterBreakout.sens_energie_active = ((valhex >>> 9) & 0x1) === 0 ? "positive" : "negative";
// tarif en cours sur le contrat fourniture
statusRegisterBreakout.tarif_four = `index_${((valhex >>> 10) & 0xf) + 1}`;
// tarif en cours sur le contrat distributeur
statusRegisterBreakout.tarif_dist = `index_${((valhex >>> 14) & 0x3) + 1}`;
// mode degrade de l'horloge
statusRegisterBreakout.horloge = ((valhex >>> 16) & 0x1) === 0 ? "correcte" : "degradee";
// TIC historique ou standard
statusRegisterBreakout.type_tic = ((valhex >>> 17) & 0x1) === 0 ? "historique" : "standard";
// bit 18 inutilise
// etat sortie communicateur Euridis
switch ((valhex >>> 19) & 0x3) {
case 0:
statusRegisterBreakout.comm_euridis = "desactivee";
break;
case 1:
statusRegisterBreakout.comm_euridis = "activee sans securite";
break;
case 3:
statusRegisterBreakout.comm_euridis = "activee avec securite";
break;
}
// etat CPL
switch ((valhex >>> 21) & 0x3) {
case 0:
statusRegisterBreakout.etat_cpl = "nouveau_deverrouille";
break;
case 1:
statusRegisterBreakout.etat_cpl = "nouveau_verrouille";
break;
case 2:
statusRegisterBreakout.etat_cpl = "enregistre";
break;
}
// synchronisation CPL
statusRegisterBreakout.sync_cpl = ((valhex >>> 23) & 0x1) === 0 ? "non_synchronise" : "synchronise";
// couleur du jour contrat TEMPO historique
switch ((valhex >>> 24) & 0x3) {
case 0:
statusRegisterBreakout.tempo_jour = "UNDEF";
break;
case 1:
statusRegisterBreakout.tempo_jour = "BLEU";
break;
case 2:
statusRegisterBreakout.tempo_jour = "BLANC";
break;
case 3:
statusRegisterBreakout.tempo_jour = "ROUGE";
break;
}
// couleur demain contrat TEMPO historique
switch ((valhex >>> 26) & 0x3) {
case 0:
statusRegisterBreakout.tempo_demain = "UNDEF";
break;
case 1:
statusRegisterBreakout.tempo_demain = "BLEU";
break;
case 2:
statusRegisterBreakout.tempo_demain = "BLANC";
break;
case 3:
statusRegisterBreakout.tempo_demain = "ROUGE";
break;
}
// preavis pointe mobile
switch ((valhex >>> 28) & 0x3) {
case 0:
statusRegisterBreakout.preavis_pointe_mobile = "AUCUN";
break;
case 1:
statusRegisterBreakout.preavis_pointe_mobile = "PM1";
break;
case 2:
statusRegisterBreakout.preavis_pointe_mobile = "PM2";
break;
case 3:
statusRegisterBreakout.preavis_pointe_mobile = "PM3";
break;
}
// pointe mobile
switch ((valhex >>> 30) & 0x3) {
case 0:
statusRegisterBreakout.pointe_mobile = "AUCUN";
break;
case 1:
statusRegisterBreakout.pointe_mobile = "PM1";
break;
case 2:
statusRegisterBreakout.pointe_mobile = "PM2";
break;
case 3:
statusRegisterBreakout.pointe_mobile = "PM3";
break;
}
result[`${at_snake}_breakout`] = statusRegisterBreakout;
}
}
result[at_snake] = val;
}
}
return result;
},
},
lixee_metering: {
cluster: "seMetering", // 0x0702
type: ["attributeReport", "readResponse"],
convert: (model, msg, publish, options, meta) => {
const result = {};
const elements = [
/* 0x0000 */ "currentSummDelivered",
/* 0x0001 */ "currentSummReceived",
/* 0x0020 */ "activeRegisterTierDelivered",
/* 0x0100 */ "currentTier1SummDelivered",
/* 0x0102 */ "currentTier2SummDelivered",
/* 0x0104 */ "currentTier3SummDelivered",
/* 0x0106 */ "currentTier4SummDelivered",
/* 0x0108 */ "currentTier5SummDelivered",
/* 0x010A */ "currentTier6SummDelivered",
/* 0x010C */ "currentTier7SummDelivered",
/* 0x010E */ "currentTier8SummDelivered",
/* 0x0110 */ "currentTier9SummDelivered",
/* 0x0112 */ "currentTier10SummDelivered",
/* 0x0307 */ "siteId",
/* 0x0308 */ "meterSerialNumber",
];
const kWhP = options?.kWh_precision ? options.kWh_precision : 2;
for (const at of elements) {
const at_snake = at
.split(/(?=[A-Z])/)
.join("_")
.toLowerCase();
const val = msg.data[at];
if (val != null) {
result[at_snake] = val; // By default we assign raw value
switch (at) {
// If we receive a Buffer, transform to human readable text
case "meterSerialNumber":
case "siteId":
if (node_buffer_1.Buffer.isBuffer(val)) {
result[at_snake] = val.toString();
}
break;
case "currentSummDelivered":
case "currentSummReceived":
case "currentTier1SummDelivered":
case "currentTier2SummDelivered":
case "currentTier3SummDelivered":
case "currentTier4SummDelivered":
case "currentTier5SummDelivered":
case "currentTier6SummDelivered":
case "currentTier7SummDelivered":
case "currentTier8SummDelivered":
case "currentTier9SummDelivered":
case "currentTier10SummDelivered":
// @ts-expect-error ignore
result[at_snake] = utils.precisionRound(val / 1000, kWhP); // Wh to kWh
break;
}
}
}
// TODO: Check if all tarifs which doesn't publish "currentSummDelivered" use just Tier1 & Tier2
if (result.current_summ_delivered === 0 &&
// @ts-expect-error ignore
(result.current_tier1_summ_delivered > 0 || result.current_tier2_summ_delivered > 0)) {
// @ts-expect-error ignore
result.current_summ_delivered = result.current_tier1_summ_delivered + result.current_tier2_summ_delivered;
}
return result;
},
},
};
// we are doing it with exclusion and not inclusion because the list is dynamic (based on zlinky mode),
// and change based on that. Just some few attributes are useless, so we exclude them
const tarifsDef = {
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
histo_BASE: {
fname: "Historique - BASE",
currentTarf: "BASE",
excluded: ["HCHC", "HCHP", "HHPHC", "EJPHN", "EJPHPM", "BBRHCJB", "BBRHPJB", "BBRHCJW", "BBRHPJW", "BBRHCJR", "BBRHPJR", "DEMAIN", "PEJP"],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
histo_HCHP: {
fname: "Historique - HCHP",
currentTarf: "HC..",
excluded: ["BASE", "EJPHN", "EJPHPM", "BBRHCJB", "BBRHPJB", "BBRHCJW", "BBRHPJW", "BBRHCJR", "BBRHPJR", "DEMAIN", "PEJP"],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
histo_EJP: {
fname: "Historique - EJP",
currentTarf: "EJP.",
excluded: ["BASE", "HCHC", "HCHP", "BBRHCJB", "BBRHPJB", "BBRHCJW", "BBRHPJW", "BBRHCJR", "BBRHPJR", "DEMAIN"],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
histo_BBR: {
fname: "Historique - BBR",
currentTarf: "BBR",
excluded: ["BASE", "HCHC", "HCHP", "EJPHN", "EJPHPM", "PEJP"],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_SEM_WE_LUNDI: {
fname: "Standard - Sem WE Lundi",
currentTarf: "SEM WE LUNDI",
excluded: [
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD02",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_SEM_WE_MERCR: {
fname: "Standard - Sem WE Mercredi",
currentTarf: "SEM WE MERCREDI",
excluded: [
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD02",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_SEM_WE_VENDR: {
fname: "Standard - Sem WE Vendredi",
currentTarf: "SEM WE VENDREDI",
excluded: [
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD02",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_BASE: {
fname: "Standard - BASE",
currentTarf: "BASE",
excluded: [
"EASF03",
"EASF04",
"EASF05",
"EASF06",
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD02",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_HPHC: {
fname: "Standard - Heure Pleine Heure Creuse",
currentTarf: "H PLEINE/CREUSE",
excluded: [
"EASF03",
"EASF04",
"EASF05",
"EASF06",
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_H_SUPER_CREUSES: {
fname: "Standard - Heures Super Creuses",
currentTarf: "H SUPER CREUSES",
excluded: [
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_TEMPO: {
fname: "Standard - TEMPO",
currentTarf: "TEMPO",
excluded: [
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
"PPOINTE1",
],
},
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
stand_ZEN_FLEX: {
fname: "Standard - ZEN Flex",
currentTarf: "ZEN Flex",
excluded: [
"EASF05",
"EASF06",
"EASF07",
"EASF08",
"EASF09",
"EASF10",
"EASD03",
"EASD04",
"DPM1",
"DPM2",
"DPM3",
"FPM1",
"FPM2",
"FPM3",
"NJOURF",
"NJOURF+1",
"PJOURF+1",
],
},
};
const linkyModeDef = {
standard: "standard",
legacy: "historique",
};
const linkyPhaseDef = {
single: "single_phase",
three: "three_phase",
all: "both",
};
const clustersDef = {
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
_0xFF66: "liXeePrivate", // 0xFF66
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
_0x0B04: "haElectricalMeasurement", // 0x0B04
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
_0x0702: "seMetering", // 0x0702
// biome-ignore lint/style/useNamingConvention: ignored using `--suppress`
_0x0B01: "seMeterIdentification", // 0x0B01
};
// full list available on https://github.com/fairecasoimeme/Zlinky_TIC/blob/master/README.md
// Properties must be EXACTLY ".split(/(?=[A-Z])/).join('_').toLowerCase()" of att
const allPhaseData = [
{
cluster: clustersDef._0x0702,
att: "currentSummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("EAST", ea.STATE).withUnit("kWh").withProperty("current_summ_delivered").withDescription("Total active power delivered"),
},
{
cluster: clustersDef._0x0702,
att: "currentSummReceived",
reportable: true,
report: { change: 100 },
onlyProducer: true,
exposes: e.numeric("EAIT", ea.STATE).withUnit("kWh").withProperty("current_summ_received").withDescription("Total active power injected"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier1SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF01", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier1_summ_delivered")
.withDescription("Total provider active power delivered (index 01)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier2SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF02", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier2_summ_delivered")
.withDescription("Total provider active power delivered (index 02)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier3SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF03", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier3_summ_delivered")
.withDescription("Total provider active power delivered (index 03)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier4SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF04", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier4_summ_delivered")
.withDescription("Total provider active power delivered (index 04)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier5SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF05", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier5_summ_delivered")
.withDescription("Total provider active power delivered (index 05)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier6SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF06", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier6_summ_delivered")
.withDescription("Total provider active power delivered (index 06)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier7SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF07", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier7_summ_delivered")
.withDescription("Total provider active power delivered (index 07)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier8SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF08", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier8_summ_delivered")
.withDescription("Total provider active power delivered (index 08)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier9SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF09", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier9_summ_delivered")
.withDescription("Total provider active power delivered (index 09)"),
},
{
cluster: clustersDef._0x0702,
att: "currentTier10SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASF10", ea.STATE)
.withUnit("kWh")
.withProperty("current_tier10_summ_delivered")
.withDescription("Total provider active power delivered (index 10)"),
},
{
cluster: clustersDef._0x0702,
att: "meterSerialNumber",
reportable: false,
onlyProducer: false,
exposes: e.text("ADSC", ea.STATE).withProperty("meter_serial_number").withDescription("Serial Number"),
},
{
cluster: clustersDef._0x0702,
att: "siteId",
reportable: false,
onlyProducer: false,
exposes: e.text("PRM", ea.STATE).withProperty("site_id").withDescription("PRM number"),
},
{
cluster: clustersDef._0x0B01,
att: "availablePower",
reportable: false,
onlyProducer: false,
exposes: e.numeric("PREF", ea.STATE).withUnit("kVA").withProperty("available_power").withDescription("Apparent power of reference"),
},
{
cluster: clustersDef._0x0B01,
att: "powerThreshold",
reportable: false,
onlyProducer: false,
exposes: e.numeric("PCOUP", ea.STATE).withUnit("kVA").withProperty("power_threshold").withDescription("Apparent power threshold"),
},
{
cluster: clustersDef._0x0B01,
att: "softwareRevision",
reportable: false,
onlyProducer: false,
exposes: e.numeric("VTIC", ea.STATE).withProperty("software_revision").withDescription("Customer tele-information protocol version"),
},
{
cluster: clustersDef._0x0B04,
att: "activePower",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("CCASN", ea.STATE)
.withUnit("W")
.withProperty("active_power")
.withDescription("Current point of the active load curve drawn"),
},
{
cluster: clustersDef._0x0B04,
att: "activePowerPhB",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("CCASN-1", ea.STATE)
.withUnit("W")
.withProperty("active_power_ph_b")
.withDescription("Previous point of the active load curve drawn"),
},
{
cluster: clustersDef._0x0B04,
att: "averageRmsVoltageMeasPeriod",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("UMOY1", ea.STATE)
.withUnit("V")
.withProperty("average_rms_voltage_meas_period")
.withDescription("Average RMS voltage (phase 1)"),
},
{
cluster: clustersDef._0x0B04,
att: "totalReactivePower",
reportable: true,
onlyProducer: true,
exposes: e.numeric("ERQ1", ea.STATE).withUnit("VArh").withProperty("total_reactive_power").withDescription("Total reactive power (Q1)"),
},
{
cluster: clustersDef._0x0B04,
att: "reactivePower",
reportable: true,
onlyProducer: true,
exposes: e.numeric("ERQ2", ea.STATE).withUnit("VArh").withProperty("reactive_power").withDescription("Total reactive power (Q2)"),
},
{
cluster: clustersDef._0x0B04,
att: "reactivePowerPhB",
reportable: true,
onlyProducer: true,
exposes: e.numeric("ERQ3", ea.STATE).withUnit("VArh").withProperty("reactive_power_ph_b").withDescription("Total reactive power (Q3)"),
},
{
cluster: clustersDef._0x0B04,
att: "reactivePowerPhC",
reportable: true,
onlyProducer: true,
exposes: e.numeric("ERQ4", ea.STATE).withUnit("VArh").withProperty("reactive_power_ph_c").withDescription("Total reactive power (Q4)"),
},
{
cluster: clustersDef._0x0B04,
att: "rmsCurrent",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IRMS1", ea.STATE).withUnit("A").withProperty("rms_current").withDescription("RMS current"),
},
{
cluster: clustersDef._0x0B04,
att: "rmsVoltage",
reportable: true,
onlyProducer: false,
exposes: e.numeric("URMS1", ea.STATE).withUnit("V").withProperty("rms_voltage").withDescription("RMS voltage"),
},
{
cluster: clustersDef._0xFF66,
att: "activeEnergyOutD01",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASD01", ea.STATE)
.withUnit("kWh")
.withProperty("active_energy_out_d01")
.withDescription("Active energy withdrawn Distributor (index 01)"),
},
{
cluster: clustersDef._0xFF66,
att: "activeEnergyOutD02",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASD02", ea.STATE)
.withUnit("kWh")
.withProperty("active_energy_out_d02")
.withDescription("Active energy withdrawn Distributor (index 02)"),
},
{
cluster: clustersDef._0xFF66,
att: "activeEnergyOutD03",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASD03", ea.STATE)
.withUnit("kWh")
.withProperty("active_energy_out_d03")
.withDescription("Active energy withdrawn Distributor (index 03)"),
},
{
cluster: clustersDef._0xFF66,
att: "activeEnergyOutD04",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e
.numeric("EASD04", ea.STATE)
.withUnit("kWh")
.withProperty("active_energy_out_d04")
.withDescription("Active energy withdrawn Distributor (index 04)"),
},
{
cluster: clustersDef._0xFF66,
att: "currentDate",
reportable: false,
onlyProducer: false,
exposes: e.text("DATE", ea.STATE).withProperty("current_date").withDescription("Current date and time"),
},
{
cluster: clustersDef._0xFF66,
att: "currentIndexTarif",
reportable: false,
onlyProducer: false,
exposes: e.numeric("NTARF", ea.STATE).withProperty("current_index_tarif").withDescription("Current tariff index number"),
},
{
cluster: clustersDef._0xFF66,
att: "currentPrice",
reportable: false,
onlyProducer: false,
exposes: e.text("LTARF", ea.STATE).withProperty("current_price").withDescription("Current supplier price label"),
},
{
cluster: clustersDef._0xFF66,
att: "currentTarif",
reportable: false,
onlyProducer: false,
exposes: e.text("NGTF", ea.STATE).withProperty("current_tarif").withDescription("Supplier pricing schedule name"),
},
{
cluster: clustersDef._0xFF66,
att: "daysNumberCurrentCalendar",
reportable: false,
onlyProducer: false,
exposes: e.numeric("NJOURF", ea.STATE).withProperty("days_number_current_calendar").withDescription("Current day number supplier calendar"),
},
{
cluster: clustersDef._0xFF66,
att: "daysNumberNextCalendar",
reportable: false,
onlyProducer: false,
exposes: e.numeric("NJOURF+1", ea.STATE).withProperty("days_number_next_calendar").withDescription("Next day number supplier calendar"),
},
{
cluster: clustersDef._0xFF66,
att: "daysProfileCurrentCalendar",
reportable: false,
onlyProducer: false,
exposes: e
.text("PJOURF+1", ea.STATE)
.withProperty("days_profile_current_calendar")
.withDescription("Profile of the next supplier calendar day"),
},
{
cluster: clustersDef._0xFF66,
att: "daysProfileNextCalendar",
reportable: false,
onlyProducer: false,
exposes: e.text("PPOINTE1", ea.STATE).withProperty("days_profile_next_calendar").withDescription("Profile of the next check-in day"),
},
{
cluster: clustersDef._0xFF66,
att: "injectedActiveLoadN",
reportable: true,
onlyProducer: true,
exposes: e
.numeric("CCAIN", ea.STATE)
.withUnit("W")
.withProperty("injected_active_load_n")
.withDescription("Point n of the withdrawn active load curve"),
},
{
cluster: clustersDef._0xFF66,
att: "injectedActiveLoadN1",
reportable: false,
onlyProducer: true,
exposes: e
.numeric("CCAIN-1", ea.STATE)
.withUnit("W")
.withProperty("injected_active_load_n1")
.withDescription("Point n-1 of the withdrawn active load curve"),
},
{
cluster: clustersDef._0xFF66,
att: "injectedVA",
reportable: true,
onlyProducer: true,
exposes: e.numeric("SINSTI", ea.STATE).withUnit("VA").withProperty("injected_v_a").withDescription("Instantaneous apparent power injected"),
},
{
cluster: clustersDef._0xFF66,
att: "injectedVAMaxN",
reportable: true,
onlyProducer: true,
exposes: e.numeric("SMAXIN", ea.STATE).withUnit("VA").withProperty("injected_v_a_max_n").withDescription("Apparent power max. injected n"),
},
{
cluster: clustersDef._0xFF66,
att: "injectedVAMaxN1",
reportable: false,
onlyProducer: true,
exposes: e
.numeric("SMAXIN-1", ea.STATE)
.withUnit("VA")
.withProperty("injected_v_a_max_n1")
.withDescription("Apparent power max. injected n-1"),
},
{
cluster: clustersDef._0xFF66,
att: "message1",
reportable: false,
onlyProducer: false,
exposes: e.text("MSG1", ea.STATE).withProperty("message1").withDescription("Message short"),
},
{
cluster: clustersDef._0xFF66,
att: "message2",
reportable: false,
onlyProducer: false,
exposes: e.text("MSG2", ea.STATE).withProperty("message2").withDescription("Message ultra-short"),
},
{
cluster: clustersDef._0xFF66,
att: "relais",
reportable: false,
onlyProducer: false,
exposes: e.numeric("RELAIS", ea.STATE).withProperty("relais"),
},
{
cluster: clustersDef._0xFF66,
att: "startMobilePoint1",
reportable: false,
onlyProducer: false,
exposes: e.numeric("DPM1", ea.STATE).withProperty("start_mobile_point1").withDescription("Start mobile point 1"),
},
{
cluster: clustersDef._0xFF66,
att: "startMobilePoint2",
reportable: false,
onlyProducer: false,
exposes: e.numeric("DPM2", ea.STATE).withProperty("start_mobile_point2").withDescription("Start mobile point 2"),
},
{
cluster: clustersDef._0xFF66,
att: "startMobilePoint3",
reportable: false,
onlyProducer: false,
exposes: e.numeric("DPM3", ea.STATE).withProperty("start_mobile_point3").withDescription("Start mobile point 3"),
},
{
cluster: clustersDef._0xFF66,
att: "statusRegister",
reportable: false,
onlyProducer: false,
exposes: e.text("STGE", ea.STATE).withProperty("status_register").withDescription("Register of Statutes"),
},
{
cluster: clustersDef._0xFF66,
att: "stopMobilePoint1",
reportable: false,
onlyProducer: false,
exposes: e.numeric("FPM1", ea.STATE).withProperty("stop_mobile_point1").withDescription("Stop mobile point 1"),
},
{
cluster: clustersDef._0xFF66,
att: "stopMobilePoint2",
reportable: false,
onlyProducer: false,
exposes: e.numeric("FPM2", ea.STATE).withProperty("stop_mobile_point2").withDescription("Stop mobile point 2"),
},
{
cluster: clustersDef._0xFF66,
att: "stopMobilePoint3",
reportable: false,
onlyProducer: false,
exposes: e.numeric("FPM3", ea.STATE).withProperty("stop_mobile_point3").withDescription("Stop mobile point 3"),
},
].map((x) => {
return { ...x, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard };
});
const singlePhaseData = [
{
cluster: clustersDef._0x0B04,
att: "activePowerMax",
reportable: true,
onlyProducer: false,
exposes: e.numeric("SMAXSN", ea.STATE).withUnit("VA").withProperty("active_power_max").withDescription("Apparent power delivered peak"),
},
{
cluster: clustersDef._0x0B04,
att: "apparentPower",
reportable: true,
onlyProducer: false,
exposes: e.numeric("SINSTS", ea.STATE).withUnit("VA").withProperty("apparent_power").withDescription("Immediate apparent power delivered"),
},
{
cluster: clustersDef._0xFF66,
att: "drawnVAMaxN1",
reportable: false,
onlyProducer: false,
exposes: e.numeric("SMAXSN-1", ea.STATE).withUnit("VA").withProperty("drawn_v_a_max_n1").withDescription("Apparent power max. draw-off n-1"),
},
].map((x) => {
return { ...x, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard };
});
const threePhasesData = [
{
cluster: clustersDef._0x0B04,
att: "activePowerMax",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SMAXSN1", ea.STATE)
.withUnit("VA")
.withProperty("active_power_max")
.withDescription("Apparent power delivered peak (phase 1)"),
},
{
cluster: clustersDef._0x0B04,
att: "activePowerMaxPhB",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SMAXSN2", ea.STATE)
.withUnit("VA")
.withProperty("active_power_max_ph_b")
.withDescription("Apparent power delivered peak (phase 2)"),
},
{
cluster: clustersDef._0x0B04,
att: "activePowerMaxPhC",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SMAXSN3", ea.STATE)
.withUnit("VA")
.withProperty("active_power_max_ph_c")
.withDescription("Apparent power delivered peak (phase 3)"),
},
{
cluster: clustersDef._0x0B04,
att: "apparentPower",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SINSTS1", ea.STATE)
.withUnit("VA")
.withProperty("apparent_power")
.withDescription("Immediate apparent power delivered (phase 1)"),
},
{
cluster: clustersDef._0x0B04,
att: "apparentPowerPhB",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SINSTS2", ea.STATE)
.withUnit("VA")
.withProperty("apparent_power_ph_b")
.withDescription("Immediate apparent power delivered (phase 2)"),
},
{
cluster: clustersDef._0x0B04,
att: "apparentPowerPhC",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SINSTS3", ea.STATE)
.withUnit("VA")
.withProperty("apparent_power_ph_c")
.withDescription("Immediate apparent power delivered (phase 3)"),
},
{
cluster: clustersDef._0x0B04,
att: "totalApparentPower",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("SINSTS", ea.STATE)
.withUnit("VA")
.withProperty("total_apparent_power")
.withDescription("Total immediate apparent power delivered"),
},
{
cluster: clustersDef._0x0B04,
att: "averageRmsVoltageMeasPeriodPhC",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("UMOY3", ea.STATE)
.withUnit("V")
.withProperty("average_rms_voltage_meas_period_ph_c")
.withDescription("Average RMS voltage (phase 3)"),
},
{
cluster: clustersDef._0x0B04,
att: "averageRmsVoltageMeasurePeriodPhB",
reportable: true,
onlyProducer: false,
exposes: e
.numeric("UMOY2", ea.STATE)
.withUnit("V")
.withProperty("average_rms_voltage_measure_period_ph_b")
.withDescription("Average RMS voltage (phase 2)"),
},
{
cluster: clustersDef._0x0B04,
att: "rmsCurrentPhB",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IRMS2", ea.STATE).withUnit("A").withProperty("rms_current_ph_b").withDescription("RMS current (phase 2)"),
},
{
cluster: clustersDef._0x0B04,
att: "rmsCurrentPhC",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IRMS3", ea.STATE).withUnit("A").withProperty("rms_current_ph_c").withDescription("RMS current (phase 3)"),
},
{
cluster: clustersDef._0x0B04,
att: "rmsVoltagePhB",
reportable: true,
onlyProducer: false,
exposes: e.numeric("URMS2", ea.STATE).withUnit("V").withProperty("rms_voltage_ph_b").withDescription("RMS voltage (phase 2)"),
},
{
cluster: clustersDef._0x0B04,
att: "rmsVoltagePhC",
reportable: true,
onlyProducer: false,
exposes: e.numeric("URMS3", ea.STATE).withUnit("V").withProperty("rms_voltage_ph_c").withDescription("RMS voltage (phase 3)"),
},
{
cluster: clustersDef._0xFF66,
att: "drawnVAMaxN1",
reportable: false,
onlyProducer: false,
exposes: e
.numeric("SMAXSN1-1", ea.STATE)
.withUnit("VA")
.withProperty("drawn_v_a_max_n1")
.withDescription("Apparent power max. draw-off n-1 (phase 1)"),
},
{
cluster: clustersDef._0xFF66,
att: "drawnVAMaxN1P2",
reportable: false,
onlyProducer: false,
exposes: e
.numeric("SMAXSN2-1", ea.STATE)
.withUnit("VA")
.withProperty("drawn_v_a_max_n1_p2")
.withDescription("Apparent power max. draw-off n-1 (phase 2)"),
},
{
cluster: clustersDef._0xFF66,
att: "drawnVAMaxN1P3",
reportable: false,
onlyProducer: false,
exposes: e
.numeric("SMAXSN3-1", ea.STATE)
.withUnit("VA")
.withProperty("drawn_v_a_max_n1_p3")
.withDescription("Apparent power max. draw-off n-1 (phase 3)"),
},
].map((x) => {
return { ...x, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard };
});
const legacyData = [
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "activeRegisterTierDelivered",
reportable: false,
onlyProducer: false,
exposes: e.text("PTEC", ea.STATE).withProperty("active_register_tier_delivered").withDescription("Current pricing period"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentSummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BASE", ea.STATE).withUnit("kWh").withProperty("current_summ_delivered").withDescription("Base index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier1SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BBRHCJB", ea.STATE).withUnit("kWh").withProperty("current_tier1_summ_delivered").withDescription("BBRHCJB index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier1SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("EJPHN", ea.STATE).withUnit("kWh").withProperty("current_tier1_summ_delivered").withDescription("EJPHN index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier1SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("HCHC", ea.STATE).withUnit("kWh").withProperty("current_tier1_summ_delivered").withDescription("HCHC index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier2SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BBRHPJB", ea.STATE).withUnit("kWh").withProperty("current_tier2_summ_delivered").withDescription("BBRHPJB index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier2SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("EJPHPM", ea.STATE).withUnit("kWh").withProperty("current_tier2_summ_delivered").withDescription("EJPHPM index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier2SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("HCHP", ea.STATE).withUnit("kWh").withProperty("current_tier2_summ_delivered").withDescription("HCHP index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier3SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BBRHCJW", ea.STATE).withUnit("kWh").withProperty("current_tier3_summ_delivered").withDescription("BBRHCJW index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier4SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BBRHPJW", ea.STATE).withUnit("kWh").withProperty("current_tier4_summ_delivered").withDescription("BBRHPJW index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier5SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BBRHCJR", ea.STATE).withUnit("kWh").withProperty("current_tier5_summ_delivered").withDescription("BBRHCJR index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "currentTier6SummDelivered",
reportable: true,
report: { change: 100 },
onlyProducer: false,
exposes: e.numeric("BBRHPJR", ea.STATE).withUnit("kWh").withProperty("current_tier6_summ_delivered").withDescription("BBRHPJR index"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0702,
att: "meterSerialNumber",
reportable: false,
onlyProducer: false,
exposes: e.text("ADCO", ea.STATE).withProperty("meter_serial_number").withDescription("Serial Number"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0B01,
att: "availablePower",
reportable: false,
onlyProducer: false,
exposes: e.numeric("ISOUSC", ea.STATE).withUnit("A").withProperty("available_power").withDescription("Subscribed intensity level"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0x0B04,
att: "apparentPower",
reportable: true,
onlyProducer: false,
exposes: e.numeric("PAPP", ea.STATE).withUnit("VA").withProperty("apparent_power").withDescription("Apparent power"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0xFF66,
att: "currentTarif",
reportable: false,
onlyProducer: false,
exposes: e.text("OPTARIF", ea.STATE).withProperty("current_tarif").withDescription("Tarif option"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0xFF66,
att: "motDEtat",
reportable: false,
onlyProducer: false,
exposes: e.text("MOTDETAT", ea.STATE).withProperty("MOTDETAT").withDescription("Meter Status Word"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0xFF66,
att: "scheduleHPHC",
reportable: false,
onlyProducer: false,
exposes: e.numeric("HHPHC", ea.STATE).withProperty("schedule_h_p_h_c").withDescription("Schedule HPHC"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0xFF66,
att: "startNoticeEJP",
reportable: true,
onlyProducer: false,
exposes: e.numeric("PEJP", ea.STATE).withUnit("min").withProperty("start_notice_e_j_p").withDescription("EJP start notice (30min)"),
},
{
linkyPhase: linkyPhaseDef.all,
cluster: clustersDef._0xFF66,
att: "tomorrowColor",
reportable: true,
onlyProducer: false,
exposes: e.text("DEMAIN", ea.STATE).withProperty("tomorrow_color").withDescription("Tomorrow color"),
},
{
linkyPhase: linkyPhaseDef.single,
cluster: clustersDef._0x0B04,
att: "rmsCurrent",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IINST", ea.STATE).withUnit("A").withProperty("rms_current").withDescription("RMS current"),
},
{
linkyPhase: linkyPhaseDef.single,
cluster: clustersDef._0x0B04,
att: "rmsCurrentMax",
reportable: false,
onlyProducer: false,
exposes: e.numeric("IMAX", ea.STATE).withUnit("A").withProperty("rms_current_max").withDescription("RMS current peak"),
},
{
linkyPhase: linkyPhaseDef.single,
cluster: clustersDef._0xFF66,
att: "warnDPS",
reportable: true,
onlyProducer: false,
exposes: e.numeric("ADPS", ea.STATE).withUnit("A").withProperty("warn_d_p_s").withDescription("Subscribed Power Exceeded Warning"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "activePowerMax",
reportable: false,
onlyProducer: false,
exposes: e.numeric("PMAX", ea.STATE).withUnit("W").withProperty("active_power_max").withDescription("Three-phase power peak"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "rmsCurrent",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IINST1", ea.STATE).withUnit("A").withProperty("rms_current").withDescription("RMS current (phase 1)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "rmsCurrentMax",
reportable: false,
onlyProducer: false,
exposes: e.numeric("IMAX1", ea.STATE).withUnit("A").withProperty("rms_current_max").withDescription("RMS current peak (phase 1)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "rmsCurrentMaxPhB",
reportable: false,
onlyProducer: false,
exposes: e.numeric("IMAX2", ea.STATE).withUnit("A").withProperty("rms_current_max_ph_b").withDescription("RMS current peak (phase 2)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "rmsCurrentMaxPhC",
reportable: false,
onlyProducer: false,
exposes: e.numeric("IMAX3", ea.STATE).withUnit("A").withProperty("rms_current_max_ph_c").withDescription("RMS current peak (phase 3)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "rmsCurrentPhB",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IINST2", ea.STATE).withUnit("A").withProperty("rms_current_ph_b").withDescription("RMS current (phase 2)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0x0B04,
att: "rmsCurrentPhC",
reportable: true,
onlyProducer: false,
exposes: e.numeric("IINST3", ea.STATE).withUnit("A").withProperty("rms_current_ph_c").withDescription("RMS current (phase 3)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0xFF66,
att: "presencePotential",
reportable: false,
onlyProducer: false,
exposes: e.numeric("PPOT", ea.STATE).withProperty("presence_potential").withDescription("Presence of potentials"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0xFF66,
att: "warnDIR1",
reportable: true,
onlyProducer: false,
exposes: e.numeric("ADIR1", ea.STATE).withUnit("A").withProperty("warn_d_i_r1").withDescription("Over Current Warning (phase 1)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0xFF66,
att: "warnDIR2",
reportable: true,
onlyProducer: false,
exposes: e.numeric("ADIR2", ea.STATE).withUnit("A").withProperty("warn_d_i_r2").withDescription("Over Current Warning (phase 2)"),
},
{
linkyPhase: linkyPhaseDef.three,
cluster: clustersDef._0xFF66,
att: "warnDIR3",
reportable: true,
onlyProducer: false,
exposes: e.numeric("ADIR3", ea.STATE).withUnit("A").withProperty("warn_d_i_r3").withDescription("Over Current Warning (phase 3)"),
},
].map((x) => {
return { ...x, linkyMode: linkyModeDef.legacy };
});
const exposedData = [allPhaseData, singlePhaseData, threePhasesData, legacyData].flat();
function getCurrentConfig(device, options) {
let endpoint;
try {
endpoint = device.getEndpoint(1);
}
catch (error) {
logger_1.logger.debug(`${error.stack}`, NS);
}
// @ts-expect-error ignore
function getConfig(targetOption, bitLinkyMode, valueTrue, valueFalse) {
const valueDefault = valueFalse;
if (options && options[targetOption] != null && options[targetOption] !== "auto") {
if (options[targetOption] === "true" || options[targetOption] === "false") {
return options[targetOption] === "true"; // special case for production
}
return options[targetOption];
}
// biome-ignore lint/suspicious/noImplicitAnyLet: ignored using `--suppress`
let lMode;
try {
lMode = endpoint.clusters[clustersDef._0xFF66].attributes.linkyMode;
// @ts-expect-error ignore
lMode.raiseError; // raise if undefined
// @ts-expect-error ignore
return ((lMode >> bitLinkyMode) & 1) === 1 ? valueTrue : valueFalse;
}
catch (error) {
logger_1.logger.warning(`Was not able to detect the Linky's ${targetOption}. Defaulting to ${valueDefault}. Error: ${error}`, NS);
return valueDefault; // default value in the worst case
}
}
const linkyMode = getConfig("linky_mode", 0, linkyModeDef.standard, linkyModeDef.legacy);
const linkyPhase = getConfig("energy_phase", 1, linkyPhaseDef.three, linkyPhaseDef.single);
let linkyProduction = false; // In historique we can't be producer
if (linkyMode === linkyModeDef.standard) {
linkyProduction = getConfig("production", 2, true, false);
}
// Main filter
let myExpose = exposedData.filter((e) => e.linkyMode === linkyMode && (e.linkyPhase === linkyPhase || e.linkyPhase === linkyPhaseDef.all) && (linkyProduction || !e.onlyProducer));
if (device.applicationVersion > 15) {
// @ts-expect-error ignore
myExpose = myExpose.map((e) => {
// For recent firmwares, use the reportable tariffPeriod attribute
// instead of the old polled currentPrice and
// activeRegisterTierDelivered attributes
if (e.att === "currentPrice" || e.att === "activeRegisterTierDelivered") {
return {
...e,
cluster: clustersDef._0xFF66,
att: "tariffPeriod",
reportable: true,
report: { min: 0, max: constants_1.repInterval.HOUR, change: 0 },
};
}
return e;
});
}
// Filter even more, based on our current tarif
let currentTarf = "";
if (options?.tarif != null && options.tarif !== "auto") {
currentTarf = Object.entries(tarifsDef).find(([k, v]) => v.fname === options.tarif)[1].currentTarf;
}
else {
try {
const lixAtts = endpoint.clusters[clustersDef._0xFF66].attributes;
lixAtts.raiseIfEmpty;
// @ts-expect-error ignore
currentTarf = fzLocal.lixee_private_fz.convert({}, { data: lixAtts }).current_tarif;
}
catch {
logger_1.logger.warning("Not able to detect the current tarif. Not filtering any expose...", NS);
}
}
logger_1.logger.debug(`zlinky config: mode=${linkyMode}, phases=${linkyPhase}, production=${linkyProduction}, tariff=${currentTarf}`, NS);
switch (currentTarf) {
case linkyMode === linkyModeDef.legacy && tarifsDef.histo_BASE.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.histo_BASE.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.legacy && tarifsDef.histo_HCHP.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.histo_HCHP.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.legacy && tarifsDef.histo_EJP.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.histo_EJP.excluded.includes(a.exposes.name));
break;
// @ts-expect-error ignore
case linkyMode === linkyModeDef.legacy && currentTarf && currentTarf.startsWith(tarifsDef.histo_BBR.currentTarf):
myExpose = myExpose.filter((a) => !tarifsDef.histo_BBR.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_SEM_WE_LUNDI.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_SEM_WE_LUNDI.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_SEM_WE_MERCR.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_SEM_WE_MERCR.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_SEM_WE_VENDR.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_SEM_WE_VENDR.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_HPHC.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_HPHC.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_BASE.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_BASE.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_H_SUPER_CREUSES.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_H_SUPER_CREUSES.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_TEMPO.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_TEMPO.excluded.includes(a.exposes.name));
break;
case linkyMode === linkyModeDef.standard && tarifsDef.stand_ZEN_FLEX.currentTarf:
myExpose = myExpose.filter((a) => !tarifsDef.stand_ZEN_FLEX.excluded.includes(a.exposes.name));
break;
default:
break;
}
// Filter exposed attributes with user whitelist
if (options?.tic_command_whitelist) {
// @ts-expect-error ignore
const tic_commands_str = options.tic_command_whitelist.toUpperCase();
if (tic_commands_str !== "ALL") {
// @ts-expect-error ignore
const tic_commands = tic_commands_str.split(",").map((a) => a.trim());
myExpose = myExpose.filter((a) => tic_commands.includes(a.exposes.name));
}
}
return myExpose;
}
exports.definitions = [
{
zigbeeModel: ["ZLinky_TIC", "ZLinky_TIC\u0000"],
model: "ZLinky_TIC",
vendor: "LiXee",
description: "Lixee ZLinky",
version: "0.0.1",
fromZigbee: [fzLocal.lixee_metering, fz.meter_identification, fzLocal.lixee_ha_electrical_measurement, fzLocal.lixee_private_fz],
toZigbee: [],
exposes: (device, options) => {
// docs generation
// biome-ignore lint/suspicious/noImplicitAnyLet: ignored using `--suppress`
let exposes;
if (utils.isDummyDevice(device)) {
exposes = exposedData
.map((e) => e.exposes)
.filter((value, index, self) => index ===
self.findIndex((t) => t.property === value.property));
}
else {
exposes = getCurrentConfig(device, options).map((e) => e.exposes);
}
return exposes;
},
options: [
e
.enum("linky_mode", ea.SET, ["auto", linkyModeDef.legacy, linkyModeDef.standard])
.withDescription("Counter with TIC in mode standard or historique. May require restart (default: auto)"),
e
.enum("energy_phase", ea.SET, ["auto", linkyPhaseDef.single, linkyPhaseDef.three])
.withDescription("Power with single or three phase. May require restart (default: auto)"),
e
.enum("production", ea.SET, ["auto", "true", "false"])
.withDescription(`If you produce energy back to the grid (works ONLY when linky_mode: ${linkyModeDef.standard}, default: auto)`),
e
.enum("tarif", ea.SET, [...Object.entries(tarifsDef).map(([k, v]) => v.fname), "auto"])
.withDescription("Overrides the automatic current tarif. This option will exclude unnecessary attributes. Open an issue to support more of them. Default: auto"),
exposes.options
.precision("kWh")
.withDescription("Number of digits after decimal point for kWh, takes into effect on next report of device. Default: 2"),
e
.numeric("measurement_poll_chunk", ea.SET)
.withValueMin(1)
.withDescription("Number of attributes requested from the ZLinky in each poll to reduce Zigbee network load. " +
"Requesting too many at once may exceed the device's limit and cause read errors. Requires Z2M restart. Default: 2."),
e
.text("tic_command_whitelist", ea.SET)
.withDescription("Comma-separated list of TIC commands to expose. Requires Z2M restart. Default: all"),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, [
clustersDef._0x0702 /* seMetering */,
clustersDef._0x0B01 /* seMeterIdentification */,
clustersDef._0x0B04 /* haElectricalMeasurement */,
clustersDef._0xFF66 /* liXeePrivate */,
]);
await endpoint.read("liXeePrivate", ["linkyMode", "currentTarif"], { manufacturerCode: null }).catch((e) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/11674
logger_1.logger.warning(`Failed to read Zigbee attributes during configure: ${e}`, NS);
});
const configReportings = [];
const subscribeNew = getCurrentConfig(device, {}).filter((e) => e.reportable);
const unsubscribe = endpoint.configuredReportings.filter((e) => !subscribeNew.some((r) => e.cluster.name === r.cluster && e.attribute.name === r.att));
// Unsubscribe reports that doesn't correspond with the current config
(await Promise.allSettled(unsubscribe.map((e) => endpoint.configureReporting(e.cluster.name, reporting.payload(
// @ts-expect-error dynamic, expected correct since already applied
e.attribute.name, e.minimumReportInterval, 65535, e.reportableChange), { manufacturerCode: null }))))
.filter((e) => e.status === "rejected")
.forEach((e) => {
throw e.reason;
});
for (const e of subscribeNew) {
let params = {
att: e.att,
min: constants_1.repInterval.MINUTE,
max: constants_1.repInterval.MINUTES_15,
change: 1,
};
// Override reportings
// @ts-expect-error ignore
if (e.report !== undefined) {
// @ts-expect-error ignore
params = { ...params, ...e.report };
}
configReportings.push(endpoint.configureReporting(e.cluster, reporting.payload(
// @ts-expect-error dynamic, expected correct since already applied
params.att, params.min, params.max, params.change), {
manufacturerCode: null,
}));
}
(await Promise.allSettled(configReportings))
.filter((e) => e.status === "rejected")
.forEach((e) => {
throw e.reason;
});
},
ota: { manufacturerName: "LiXee" }, // TODO: not sure if it's set properly in device
extend: [
local.modernExtend.addCustomClusterManuSpecificLixee(),
m.poll({
key: "measurement",
defaultIntervalSeconds: 600,
option: exposes.options
.measurement_poll_interval()
.withDescription("Some attributes do not support reporting and are polled instead. " +
"The default poll interval for these is 600 seconds. Set to -1 to disable polling. " +
"Polled attributes are those marked as read-only at https://github.com/fairecasoimeme/Zlinky_TIC/"),
poll: async (device, options) => {
const endpoint = device.getEndpoint(1);
const measurement_poll_chunk = options?.measurement_poll_chunk ? options.measurement_poll_chunk : 2;
utils.assertNumber(measurement_poll_chunk);
const currentExposes = getCurrentConfig(device, options).filter((e) => !endpoint.configuredReportings.some((r) => r.cluster.name === e.cluster && r.attribute.name === e.att));
for (const key in clustersDef) {
if (Object.hasOwn(clustersDef, key)) {
// @ts-expect-error ignore
const cluster = clustersDef[key];
const targ = currentExposes.filter((e) => e.cluster === cluster).map((e) => e.att);
if (targ.length) {
logger_1.logger.debug(`Poll: trying to read from ${cluster}: ${targ}`, NS);
let i;
let j;
// Split array by chunks
for (i = 0, j = targ.length; i < j; i += measurement_poll_chunk) {
await endpoint.read(cluster, targ.slice(i, i + measurement_poll_chunk), { manufacturerCode: null }).catch((e) => {
// https://github.com/Koenkk/zigbee2mqtt/issues/11674
logger_1.logger.warning(`Failed to read Zigbee attributes during poll. If you see many of these messages, try reducing 'Measurement poll chunk'. ${e}`, NS);
});
}
}
}
}
},
}),
local.modernExtend.readAttributesOnStartup(),
],
},
{
zigbeeModel: ["ZiPulses"],
model: "ZiPulses",
vendor: "LiXee",
description: "Lixee ZiPulses",
fromZigbee: [fz.battery, fz.temperature, fz.metering, fzZiPulses],
toZigbee: [tzSeMetering],
extend: [
m.deviceAddCustomCluster("seMetering", {
name: "seMetering",
ID: 0x0702,
attributes: {
unitOfMeasure: { name: "unitOfMeasure", ID: 0x0300, type: zcl_1.DataType.ENUM8, required: true, max: 0xff, default: 0x00, write: true },
multiplier: { name: "multiplier", ID: 0x0301, type: zcl_1.DataType.UINT24, max: 0xffffff, write: true },
divisor: { name: "divisor", ID: 0x0302, type: zcl_1.DataType.UINT24, max: 0xffffff, write: true },
},
commands: {},
commandsResponse: {},
}),
],
exposes: [
e.battery(),
e.battery_voltage(),
e.temperature(),
e
.numeric("multiplier", ea.STATE_SET)
.withValueMin(1)
.withValueMax(1000)
.withDescription("It is necessary to press the link button to update"),
e
.numeric("divisor", ea.STATE_SET)
.withValueMin(1)
.withValueMax(1000)
.withDescription("It is necessary to press the link button to update"),
e.enum("unitOfMeasure", ea.STATE_SET, unitsZiPulses).withDescription("It is necessary to press the link button to update"),
e.numeric("energy", ea.STATE),
],
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
const binds = ["genPowerCfg", "seMetering", "msTemperatureMeasurement"];
await reporting.bind(endpoint, coordinatorEndpoint, binds);
await endpoint.read("seMetering", ["divisor", "unitOfMeasure", "multiplier"]);
},
},
];
//# sourceMappingURL=lixee.js.map