/* eslint-disable camelcase */
/* eslint-disable max-len */
'use strict';
const exposes = require('../lib/exposes');
const globalStore = require('../lib/store');
const { repInterval } = require('../lib/constants');
const reporting = require('../lib/reporting');
const fz = require('../converters/fromZigbee');
const ea = exposes.access;
const e = exposes.presets;
const utils = require('../lib/utils');
const ota = require('../lib/ota');
const { Buffer } = require('buffer');
const herdsman = require('zigbee-herdsman');
/* 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') {
            const val = unitsZiPulses.indexOf(value);
            const payload = { 768: { value: val, type: herdsman.Zcl.DataType.enum8 } };
            await entity.write('seMetering', payload);
            await entity.read('seMetering', [key]);
            return { state: { 'unitOfMeasure': value } };
        }
        else {
            await entity.write('seMetering', {
                [key]: value,
            });
        }
        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.hasOwnProperty('multiplier')) {
            payload['multiplier'] = msg.data['multiplier'];
        }
        if (msg.data.hasOwnProperty('divisor')) {
            payload['divisor'] = msg.data['divisor'];
        }
        if (msg.data.hasOwnProperty('unitOfMeasure')) {
            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',
                /* 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',
        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',
                /* 0x0200 */ 'currentPrice',
                /* 0x0201 */ 'currentIndexTarif',
                /* 0x0202 */ 'currentDate',
                /* 0x0203 */ 'activeEnerfyOutD01',
                /* 0x0204 */ 'activeEnerfyOutD02',
                /* 0x0205 */ 'activeEnerfyOutD03',
                /* 0x0206 */ 'activeEnerfyOutD04',
                /* 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 kWh_p = options && options.kWh_precision ? options.kWh_precision : 0;
            for (const at of elements) {
                const at_snake = at.split(/(?=[A-Z])/).join('_').toLowerCase();
                let val = msg.data[at];
                if (val != null) {
                    if (val.hasOwnProperty('type') && val.type === 'Buffer') {
                        val = Buffer.from(val.data);
                    }
                    if (Buffer.isBuffer(val)) {
                        val = val.toString(); // Convert buffer to string
                    }
                    if (typeof val === 'string' || val instanceof 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 'activeEnerfyOutD01':
                        case 'activeEnerfyOutD02':
                        case 'activeEnerfyOutD03':
                        case 'activeEnerfyOutD04':
                            val = utils.precisionRound(val / 1000, kWh_p); // from Wh to kWh
                            break;
                    }
                    result[at_snake] = val;
                }
            }
            return result;
        },
    },
    lixee_metering: {
        cluster: 'seMetering',
        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 kWh_p = options && options.kWh_precision ? options.kWh_precision : 0;
            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 (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':
                            result[at_snake] = utils.precisionRound(((val[0] << 32) + val[1]) / 1000, kWh_p); // Wh to kWh
                            break;
                    }
                }
            }
            // TODO: Check if all tarifs which doesn't publish "currentSummDelivered" use just Tier1 & Tier2
            if (result['current_summ_delivered'] == 0 &&
                (result['current_tier1_summ_delivered'] > 0 || result['current_tier2_summ_delivered'] > 0)) {
                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 = {
    histo_BASE: {
        fname: 'Historique - BASE',
        currentTarf: 'BASE', excluded: [
            'HCHC',
            'HCHP',
            'HHPHC',
            'EJPHN',
            'EJPHPM',
            'BBRHCJB',
            'BBRHPJB',
            'BBRHCJW',
            'BBRHPJW',
            'BBRHCJR',
            'BBRHPJR',
            'DEMAIN',
            'PEJP',
        ]
    },
    histo_HCHP: {
        fname: 'Historique - HCHP',
        currentTarf: 'HC..', excluded: [
            'BASE',
            'EJPHN',
            'EJPHPM',
            'BBRHCJB',
            'BBRHPJB',
            'BBRHCJW',
            'BBRHPJW',
            'BBRHCJR',
            'BBRHPJR',
            'DEMAIN',
            'PEJP',
        ]
    },
    histo_EJP: {
        fname: 'Historique - EJP',
        currentTarf: 'EJP.', excluded: [
            'BASE',
            'HCHC',
            'HCHP',
            'BBRHCJB',
            'BBRHPJB',
            'BBRHCJW',
            'BBRHPJW',
            'BBRHCJR',
            'BBRHPJR',
            'DEMAIN',
        ]
    },
    histo_BBR: {
        fname: 'Historique - BBR',
        currentTarf: 'BBR', excluded: [
            'BASE',
            'HCHC',
            'HCHP',
            'EJPHN',
            'EJPHPM',
            'PEJP',
        ]
    },
    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',
        ]
    },
    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',
        ]
    },
    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',
        ]
    },
    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',
        ]
    },
    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',
        ]
    },
};
const linkyModeDef = {
    standard: 'standard',
    legacy: 'historique',
};
const linkyPhaseDef = {
    single: 'single_phase',
    three: 'three_phase',
    all: 'both',
};
const clustersDef = {
    _0xFF66: 'liXeePrivate',
    _0x0B04: 'haElectricalMeasurement',
    _0x0702: 'seMetering',
    _0x0B01: 'haMeterIdentification', // 0x0B01
};
// full list available on https://github.com/fairecasoimeme/Zlinky_TIC/blob/master/README.md
// Properties must be EAXCTLY ".split(/(?=[A-Z])/).join('_').toLowerCase()" of att
const exposedData = [
    // Historique
    { cluster: clustersDef._0x0702, att: 'meterSerialNumber', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.text('ADCO', ea.STATE).withProperty('meter_serial_number').withDescription('Serial Number') },
    { cluster: clustersDef._0x0702, att: 'currentSummDelivered', reportable: true, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BASE', ea.STATE).withUnit('kWh').withProperty('current_summ_delivered').withDescription('Base index') },
    { cluster: clustersDef._0xFF66, att: 'currentTarif', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.text('OPTARIF', ea.STATE).withProperty('current_tarif').withDescription('Tarif option') },
    { cluster: clustersDef._0x0B01, att: 'availablePower', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ISOUSC', ea.STATE).withUnit('A').withProperty('available_power').withDescription('Subscribed intensity level') },
    { cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('HCHC', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('HCHC index') },
    { cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('HCHP', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('HCHP index') },
    { cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('EJPHN', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('EJPHN index') },
    { cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('EJPHPM', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('EJPHPM index') },
    { cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHCJB', ea.STATE).withUnit('kWh').withProperty('current_tier1_summ_delivered').withDescription('BBRHCJB index') },
    { cluster: clustersDef._0x0702, att: 'currentTier2SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHPJB', ea.STATE).withUnit('kWh').withProperty('current_tier2_summ_delivered').withDescription('BBRHPJB index') },
    { cluster: clustersDef._0x0702, att: 'currentTier3SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHCJW', ea.STATE).withUnit('kWh').withProperty('current_tier3_summ_delivered').withDescription('BBRHCJW index') },
    { cluster: clustersDef._0x0702, att: 'currentTier4SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHPJW', ea.STATE).withUnit('kWh').withProperty('current_tier4_summ_delivered').withDescription('BBRHPJW index') },
    { cluster: clustersDef._0x0702, att: 'currentTier5SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHCJR', ea.STATE).withUnit('kWh').withProperty('current_tier5_summ_delivered').withDescription('BBRHCJR index') },
    { cluster: clustersDef._0x0702, att: 'currentTier6SummDelivered', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('BBRHPJR', ea.STATE).withUnit('kWh').withProperty('current_tier6_summ_delivered').withDescription('BBRHPJR index') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrent', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST', ea.STATE).withUnit('A').withProperty('rms_current').withDescription('RMS current') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrent', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST1', ea.STATE).withUnit('A').withProperty('rms_current').withDescription('RMS current (phase 1)') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST2', ea.STATE).withUnit('A').withProperty('rms_current_ph_b').withDescription('RMS current (phase 2)') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IINST3', ea.STATE).withUnit('A').withProperty('rms_current_ph_c').withDescription('RMS current (phase 3)') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentMax', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX', ea.STATE).withUnit('A').withProperty('rms_current_max').withDescription('RMS current peak') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentMax', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX1', ea.STATE).withUnit('A').withProperty('rms_current_max').withDescription('RMS current peak (phase 1)') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentMaxPhB', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX2', ea.STATE).withUnit('A').withProperty('rms_current_max_ph_b').withDescription('RMS current peak (phase 2)') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentMaxPhC', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('IMAX3', ea.STATE).withUnit('A').withProperty('rms_current_max_ph_c').withDescription('RMS current peak (phase 3)') },
    { cluster: clustersDef._0x0B04, att: 'activePowerMax', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PMAX', ea.STATE).withUnit('W').withProperty('active_power_max').withDescription('Three-phase power peak') },
    { cluster: clustersDef._0x0B04, att: 'apparentPower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PAPP', ea.STATE).withUnit('VA').withProperty('apparent_power').withDescription('Apparent power') },
    { cluster: clustersDef._0x0702, att: 'activeRegisterTierDelivered', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.text('PTEC', ea.STATE).withProperty('active_register_tier_delivered').withDescription('Current pricing period') },
    { cluster: clustersDef._0xFF66, att: 'tomorrowColor', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.text('DEMAIN', ea.STATE).withProperty('tomorrow_color').withDescription('Tomorrow color') },
    { cluster: clustersDef._0xFF66, att: 'scheduleHPHC', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('HHPHC', ea.STATE).withProperty('schedule_h_p_h_c').withDescription('Schedule HPHC') },
    { cluster: clustersDef._0xFF66, att: 'presencePotential', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PPOT', ea.STATE).withProperty('presence_potential').withDescription('Presence of potentials') },
    { cluster: clustersDef._0xFF66, att: 'startNoticeEJP', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('PEJP', ea.STATE).withUnit('min').withProperty('start_notice_e_j_p').withDescription('EJP start notice (30min)') },
    { cluster: clustersDef._0xFF66, att: 'warnDPS', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADPS', ea.STATE).withUnit('A').withProperty('warn_d_p_s').withDescription('Subscribed Power Exceeded Warning') },
    { cluster: clustersDef._0xFF66, att: 'warnDIR1', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADIR1', ea.STATE).withUnit('A').withProperty('warn_d_i_r1').withDescription('Over Current Warning (phase 1)') },
    { cluster: clustersDef._0xFF66, att: 'warnDIR2', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADIR2', ea.STATE).withUnit('A').withProperty('warn_d_i_r2').withDescription('Over Current Warning (phase 2)') },
    { cluster: clustersDef._0xFF66, att: 'warnDIR3', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.legacy, exposes: exposes.numeric('ADIR3', ea.STATE).withUnit('A').withProperty('warn_d_i_r3').withDescription('Over Current Warning (phase 3)') },
    { cluster: clustersDef._0x0702, att: 'meterSerialNumber', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('ADSC', ea.STATE).withProperty('meter_serial_number').withDescription('Serial Number') },
    { cluster: clustersDef._0xFF66, att: 'currentTarif', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('NGTF', ea.STATE).withProperty('current_tarif').withDescription('Supplier pricing schedule name') },
    { cluster: clustersDef._0xFF66, att: 'currentPrice', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('LTARF', ea.STATE).withProperty('current_price').withDescription('Current supplier price label') },
    { cluster: clustersDef._0xFF66, att: 'currentIndexTarif', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('NTARF', ea.STATE).withProperty('current_index_tarif').withDescription('Current tariff index number') },
    { cluster: clustersDef._0x0B01, att: 'softwareRevision', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('VTIC', ea.STATE).withProperty('software_revision').withDescription('Customer tele-information protocol version') },
    { cluster: clustersDef._0xFF66, att: 'currentDate', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('DATE', ea.STATE).withProperty('current_date').withDescription('Current date and time') },
    { cluster: clustersDef._0x0702, att: 'currentSummDelivered', reportable: true, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EAST', ea.STATE).withUnit('kWh').withProperty('current_summ_delivered').withDescription('Total active power delivered') },
    { cluster: clustersDef._0x0702, att: 'currentTier1SummDelivered', reportable: true, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASF10', ea.STATE).withUnit('kWh').withProperty('current_tier10_summ_delivered').withDescription('Total provider active power delivered (index 10)') },
    { cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD01', reportable: true, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD01', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d01').withDescription('Active energy withdrawn Distributor (index 01)') },
    { cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD02', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD02', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d02').withDescription('Active energy withdrawn Distributor (index 02)') },
    { cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD03', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD03', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d03').withDescription('Active energy withdrawn Distributor (index 03)') },
    { cluster: clustersDef._0xFF66, att: 'activeEnerfyOutD04', reportable: false, report: { change: 100 }, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EASD04', ea.STATE).withUnit('kWh').withProperty('active_enerfy_out_d04').withDescription('Active energy withdrawn Distributor (index 04)') },
    { cluster: clustersDef._0x0702, att: 'currentSummReceived', reportable: true, report: { change: 100 }, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('EAIT', ea.STATE).withUnit('kWh').withProperty('current_summ_received').withDescription('Total active power injected') },
    { cluster: clustersDef._0x0B04, att: 'totalReactivePower', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('ERQ1', ea.STATE).withUnit('VArh').withProperty('total_reactive_power').withDescription('Total reactive power (Q1)') },
    { cluster: clustersDef._0x0B04, att: 'reactivePower', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('ERQ2', ea.STATE).withUnit('VArh').withProperty('reactive_power').withDescription('Total reactive power (Q2)') },
    { cluster: clustersDef._0x0B04, att: 'reactivePowerPhB', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('IRMS1', ea.STATE).withUnit('A').withProperty('rms_current').withDescription('RMS current') },
    { cluster: clustersDef._0x0B04, att: 'rmsCurrentPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('IRMS3', ea.STATE).withUnit('A').withProperty('rms_current_ph_c').withDescription('RMS current (phase 3)') },
    { cluster: clustersDef._0x0B04, att: 'rmsVoltage', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('URMS1', ea.STATE).withUnit('V').withProperty('rms_voltage').withDescription('RMS voltage') },
    { cluster: clustersDef._0x0B04, att: 'rmsVoltagePhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('URMS3', ea.STATE).withUnit('V').withProperty('rms_voltage_ph_c').withDescription('RMS voltage (phase 3)') },
    { cluster: clustersDef._0x0B01, att: 'availablePower', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('PREF', ea.STATE).withUnit('kVA').withProperty('available_power').withDescription('Apparent power of reference') },
    { cluster: clustersDef._0xFF66, att: 'statusRegister', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('STGE', ea.STATE).withProperty('status_register').withDescription('Register of Statutes') },
    { cluster: clustersDef._0x0B01, att: 'powerThreshold', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('PCOUP', ea.STATE).withUnit('kVA').withProperty('power_threshold').withDescription('Apparent power threshold') },
    { cluster: clustersDef._0xFF66, att: 'injectedVA', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTI', ea.STATE).withUnit('VA').withProperty('injected_v_a').withDescription('Instantaneous apparent power injected') },
    { cluster: clustersDef._0xFF66, att: 'injectedVAMaxN', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXIN-1', ea.STATE).withUnit('VA').withProperty('injected_v_a_max_n1').withDescription('Apparent power max. injected n-1') },
    { cluster: clustersDef._0x0B04, att: 'activePower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('CCASN-1', ea.STATE).withUnit('W').withProperty('active_power_ph_b').withDescription('Previous point of the active load curve drawn') },
    { cluster: clustersDef._0xFF66, att: 'injectedActiveLoadN', reportable: true, onlyProducer: true, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('CCAIN-1', ea.STATE).withUnit('W').withProperty('injected_active_load_n1').withDescription('Point n-1 of the withdrawn active load curve') },
    { cluster: clustersDef._0x0B04, att: 'averageRmsVoltageMeasPeriod', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('UMOY1', ea.STATE).withUnit('V').withProperty('average_rms_voltage_meas_period').withDescription('Average RMS voltage (phase 1)') },
    { cluster: clustersDef._0x0B04, att: 'averageRmsVoltageMeasurePeriodPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('UMOY2', ea.STATE).withUnit('V').withProperty('average_rms_voltage_measure_period_ph_b').withDescription('Average RMS voltage (phase 2)') },
    { cluster: clustersDef._0x0B04, att: 'averageRmsVoltageMeasPeriodPhC', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('UMOY3', ea.STATE).withUnit('V').withProperty('average_rms_voltage_meas_period_ph_c').withDescription('Average RMS voltage (phase 3)') },
    { cluster: clustersDef._0x0B04, att: 'apparentPower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTS', ea.STATE).withUnit('VA').withProperty('apparent_power').withDescription('Immediate apparent power delivered') },
    { cluster: clustersDef._0x0B04, att: 'apparentPower', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SINSTS3', ea.STATE).withUnit('VA').withProperty('apparent_power_ph_c').withDescription('Immediate apparent power delivered (phase 3)') },
    { cluster: clustersDef._0x0B04, att: 'activePowerMax', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN', ea.STATE).withUnit('VA').withProperty('active_power_max').withDescription('Apparent power delivered peak') },
    { cluster: clustersDef._0x0B04, att: 'activePowerMax', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN1', ea.STATE).withUnit('VA').withProperty('active_power_max').withDescription('Apparent power delivered peak (phase 1)') },
    { cluster: clustersDef._0x0B04, att: 'activePowerMaxPhB', reportable: true, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN2', 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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN3', ea.STATE).withUnit('VA').withProperty('active_power_max_ph_c').withDescription('Apparent power delivered peak (phase 3)') },
    { cluster: clustersDef._0xFF66, att: 'drawnVAMaxN1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.single, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN-1', ea.STATE).withUnit('VA').withProperty('drawn_v_a_max_n1').withDescription('Apparent power max. draw-off n-1') },
    { cluster: clustersDef._0xFF66, att: 'drawnVAMaxN1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN1-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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN2-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, linkyPhase: linkyPhaseDef.three, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('SMAXN3-1', ea.STATE).withUnit('VA').withProperty('drawn_v_a_max_n1_p3').withDescription('Apparent power max. draw-off n-1 (phase 3)') },
    { cluster: clustersDef._0xFF66, att: 'message1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('MSG1', ea.STATE).withProperty('message1').withDescription('Message short') },
    { cluster: clustersDef._0xFF66, att: 'message2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('MSG2', ea.STATE).withProperty('message2').withDescription('Message ultra-short') },
    { cluster: clustersDef._0x0702, att: 'siteId', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('PRM', ea.STATE).withProperty('site_id').withDescription('PRM number') },
    { cluster: clustersDef._0xFF66, att: 'startMobilePoint1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('DPM1', ea.STATE).withProperty('start_mobile_point1').withDescription('Start mobile point 1') },
    { cluster: clustersDef._0xFF66, att: 'stopMobilePoint1', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('FPM1', ea.STATE).withProperty('stop_mobile_point1').withDescription('Stop mobile point 1') },
    { cluster: clustersDef._0xFF66, att: 'startMobilePoint2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('DPM2', ea.STATE).withProperty('start_mobile_point2').withDescription('Start mobile point 2') },
    { cluster: clustersDef._0xFF66, att: 'stopMobilePoint2', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('FPM2', ea.STATE).withProperty('stop_mobile_point2').withDescription('Stop mobile point 2') },
    { cluster: clustersDef._0xFF66, att: 'startMobilePoint3', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('DPM3', ea.STATE).withProperty('start_mobile_point3').withDescription('Start mobile point 3') },
    { cluster: clustersDef._0xFF66, att: 'stopMobilePoint3', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('FPM3', ea.STATE).withProperty('stop_mobile_point3').withDescription('Stop mobile point 3') },
    { cluster: clustersDef._0xFF66, att: 'relais', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('RELAIS', ea.STATE).withProperty('relais') },
    { cluster: clustersDef._0xFF66, att: 'daysNumberCurrentCalendar', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.numeric('NJOURF', ea.STATE).withProperty('days_number_current_calendar').withDescription('Current day number supplier calendar') },
    { cluster: clustersDef._0xFF66, att: 'daysNumberNextCalendar', reportable: false, onlyProducer: false, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.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, linkyPhase: linkyPhaseDef.all, linkyMode: linkyModeDef.standard, exposes: exposes.text('PPOINTE1', ea.STATE).withProperty('days_profile_next_calendar').withDescription('Profile of the next check-in day') },
];
function getCurrentConfig(device, options, logger = console) {
    let endpoint;
    try {
        endpoint = device.getEndpoint(1);
    }
    catch (error) {
        logger.debug(error);
    }
    function getConfig(targetOption, bitLinkyMode, valueTrue, valueFalse) {
        const valueDefault = valueFalse;
        if (options && options.hasOwnProperty(targetOption) && options[targetOption] != 'auto') {
            if (options[targetOption] === 'true' || options[targetOption] === 'false') {
                return options[targetOption] === 'true'; // special case for production
            }
            return options[targetOption];
        }
        let lMode;
        try {
            lMode = endpoint.clusters[clustersDef._0xFF66].attributes['linkyMode'];
            lMode.raiseError; // raise if undefined
            return (lMode >> bitLinkyMode & 1) == 1 ? valueTrue : valueFalse;
        }
        catch (err) {
            logger.warn(`Was not able to detect the Linky ` + targetOption + `. Default to ` + valueDefault);
            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));
    // Filter even more, based on our current tarif
    let currentTarf = '';
    if (options && options.hasOwnProperty('tarif') && 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;
            currentTarf = fzLocal.lixee_private_fz.convert({}, { data: lixAtts }).current_tarif;
        }
        catch (error) {
            logger.warn(`Not able to detect the current tarif. Not filtering any expose...`);
        }
    }
    logger.debug(`zlinky config: ` + linkyMode + `, ` + linkyPhase + `, ` + linkyProduction.toString() + `, ` + currentTarf);
    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;
        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;
        default:
            break;
    }
    // Filter exposed attributes with user whitelist
    if (options && options.hasOwnProperty('tic_command_whitelist')) {
        const tic_commands_str = options['tic_command_whitelist'].toUpperCase();
        if (tic_commands_str !== 'ALL') {
            const tic_commands = tic_commands_str.split(',').map((a) => a.trim());
            myExpose = myExpose.filter((a) => tic_commands.includes(a.exposes.name));
        }
    }
    return myExpose;
}
module.exports = [
    {
        zigbeeModel: ['ZLinky_TIC', 'ZLinky_TIC\u0000'],
        model: 'ZLinky_TIC',
        vendor: 'LiXee',
        description: 'Lixee ZLinky',
        fromZigbee: [fzLocal.lixee_metering, fz.meter_identification, fzLocal.lixee_ha_electrical_measurement, fzLocal.lixee_private_fz],
        toZigbee: [],
        exposes: (device, options) => {
            // docs generation
            let exposes;
            if (device == null && options == null) {
                exposes = exposedData.map((e) => e.exposes)
                    .filter((value, index, self) => index === self.findIndex((t) => (t.property === value.property // Remove duplicates
                )));
            }
            else {
                exposes = getCurrentConfig(device, options).map((e) => e.exposes);
            }
            exposes.push(e.linkquality());
            return exposes;
        },
        options: [
            exposes.options.measurement_poll_interval(),
            exposes.enum(`linky_mode`, ea.SET, ['auto', linkyModeDef.legacy, linkyModeDef.standard])
                .withDescription(`Counter with TIC in mode standard or historique. May require restart (default: auto)`),
            exposes.enum(`energy_phase`, ea.SET, ['auto', linkyPhaseDef.single, linkyPhaseDef.three])
                .withDescription(`Power with single or three phase. May require restart (default: auto)`),
            exposes.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)`),
            exposes.enum(`tarif`, ea.SET, [...Object.entries(tarifsDef).map(([k, v]) => (v.fname)), 'auto'])
                .withDescription(`Overrides the automatic current tarif. This option will exclude unnecesary attributes. Open a issue to support more of them. Default: auto`),
            exposes.options.precision(`kWh`),
            exposes.numeric(`measurement_poll_chunk`, ea.SET).withValueMin(1).withDescription(`During the poll, request multiple exposes to the Zlinky at once for reducing Zigbee network overload. Too much request at once could exceed device limit. Requieres Z2M restart. Default: 1`),
            exposes.text(`tic_command_whitelist`, ea.SET).withDescription(`List of TIC commands to be exposed (separated by comma). Reconfigure device after change. Default: all`),
        ],
        configure: async (device, coordinatorEndpoint, logger, options) => {
            const endpoint = device.getEndpoint(1);
            await reporting.bind(endpoint, coordinatorEndpoint, [
                clustersDef._0x0702,
                clustersDef._0x0B01,
                clustersDef._0x0B04,
                clustersDef._0xFF66, /* liXeePrivate */
            ]);
            await endpoint.read('liXeePrivate', ['linkyMode', 'currentTarif'], { manufacturerCode: null })
                .catch((e) => {
                // https://github.com/Koenkk/zigbee2mqtt/issues/11674
                logger.warn(`Failed to read zigbee attributes: ${e}`);
            });
            const configReportings = [];
            const suscribeNew = getCurrentConfig(device, options, logger).filter((e) => e.reportable);
            const unsuscribe = endpoint.configuredReportings
                .filter((e) => !suscribeNew.some((r) => e.cluster.name == r.cluster && e.attribute.name == r.att));
            // Unsuscribe reports that doesn't correspond with the current config
            (await Promise.allSettled(unsuscribe.map((e) => endpoint.configureReporting(e.cluster.name, reporting.payload(e.attribute.name, e.minimumReportInterval, 65535, e.reportableChange), { manufacturerCode: null }))))
                .filter((e) => e.status == 'rejected')
                .forEach((e) => {
                throw e.reason;
            });
            for (const e of suscribeNew) {
                let params = {
                    att: e.att,
                    min: repInterval.MINUTE,
                    max: repInterval.MINUTES_15,
                    change: 1,
                };
                // Override reportings
                if (e.hasOwnProperty('report')) {
                    params = { ...params, ...e.report };
                }
                configReportings.push(endpoint
                    .configureReporting(e.cluster, reporting.payload(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: ota.lixee,
        onEvent: async (type, data, device, options) => {
            const endpoint = device.getEndpoint(1);
            if (type === 'start') {
                endpoint.read('liXeePrivate', ['linkyMode', 'currentTarif'], { manufacturerCode: null })
                    .catch((e) => {
                    // https://github.com/Koenkk/zigbee2mqtt/issues/11674
                    console.warn(`Failed to read zigbee attributes: ${e}`);
                });
            }
            else if (type === 'stop') {
                clearInterval(globalStore.getValue(device, 'interval'));
                globalStore.clearValue(device, 'interval');
            }
            else if (!globalStore.hasValue(device, 'interval')) {
                const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 60;
                const measurement_poll_chunk = options && options.measurement_poll_chunk ? options.measurement_poll_chunk : 1;
                const interval = setInterval(async () => {
                    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.hasOwnProperty.call(clustersDef, key)) {
                            const cluster = clustersDef[key];
                            const targ = currentExposes.filter((e) => e.cluster == cluster).map((e) => e.att);
                            if (targ.length) {
                                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
                                        console.warn(`Failed to read zigbee attributes: ${e}`);
                                    });
                                }
                            }
                        }
                    }
                }, seconds * 1000);
                globalStore.putValue(device, 'interval', interval);
            }
        },
    },
    {
        zigbeeModel: ['ZiPulses'],
        model: 'ZiPulses',
        vendor: 'LiXee',
        description: 'Lixee ZiPulses',
        fromZigbee: [fz.battery, fz.temperature, fz.metering, fzZiPulses],
        toZigbee: [tzSeMetering],
        exposes: [e.battery_voltage(), e.temperature(),
            exposes.numeric('multiplier', ea.STATE_SET).withValueMin(1).withValueMax(1000).withDescription('It is necessary to press the link button to update'),
            exposes.numeric('divisor', ea.STATE_SET).withValueMin(1).withValueMax(1000).withDescription('It is necessary to press the link button to update'),
            exposes.enum('unitOfMeasure', ea.STATE_SET, unitsZiPulses).withDescription('It is necessary to press the link button to update'),
            exposes.numeric('energy', ea.STATE),
        ],
        configure: async (device, coordinatorEndpoint, logger) => {
            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