"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;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.externalDefinitions = exports.toZigbee = exports.Text = exports.Switch = exports.Numeric = exports.Lock = exports.List = exports.Light = exports.fromZigbee = exports.Fan = exports.Enum = exports.Cover = exports.Composite = exports.Climate = exports.Binary = exports.access = exports.clearGlobalStore = exports.setLogger = exports.ACTIONS = void 0;
exports.removeExternalDefinitions = removeExternalDefinitions;
exports.addExternalDefinition = addExternalDefinition;
exports.prepareDefinition = prepareDefinition;
exports.postProcessConvertedFromZigbeeMessage = postProcessConvertedFromZigbeeMessage;
exports.findByDevice = findByDevice;
exports.findDefinition = findDefinition;
exports.generateExternalDefinitionSource = generateExternalDefinitionSource;
exports.generateExternalDefinition = generateExternalDefinition;
exports.onEvent = onEvent;
const node_assert_1 = __importDefault(require("node:assert"));
const zigbee_herdsman_1 = require("zigbee-herdsman");
const fromZigbee = __importStar(require("./converters/fromZigbee"));
exports.fromZigbee = fromZigbee;
const toZigbee = __importStar(require("./converters/toZigbee"));
exports.toZigbee = toZigbee;
const exposesLib = __importStar(require("./lib/exposes"));
const exposes_1 = require("./lib/exposes");
Object.defineProperty(exports, "access", { enumerable: true, get: function () { return exposes_1.access; } });
Object.defineProperty(exports, "Binary", { enumerable: true, get: function () { return exposes_1.Binary; } });
Object.defineProperty(exports, "Climate", { enumerable: true, get: function () { return exposes_1.Climate; } });
Object.defineProperty(exports, "Composite", { enumerable: true, get: function () { return exposes_1.Composite; } });
Object.defineProperty(exports, "Cover", { enumerable: true, get: function () { return exposes_1.Cover; } });
Object.defineProperty(exports, "Enum", { enumerable: true, get: function () { return exposes_1.Enum; } });
Object.defineProperty(exports, "Fan", { enumerable: true, get: function () { return exposes_1.Fan; } });
Object.defineProperty(exports, "Light", { enumerable: true, get: function () { return exposes_1.Light; } });
Object.defineProperty(exports, "List", { enumerable: true, get: function () { return exposes_1.List; } });
Object.defineProperty(exports, "Lock", { enumerable: true, get: function () { return exposes_1.Lock; } });
Object.defineProperty(exports, "Numeric", { enumerable: true, get: function () { return exposes_1.Numeric; } });
Object.defineProperty(exports, "Switch", { enumerable: true, get: function () { return exposes_1.Switch; } });
Object.defineProperty(exports, "Text", { enumerable: true, get: function () { return exposes_1.Text; } });
const generateDefinition_1 = require("./lib/generateDefinition");
const logger_1 = require("./lib/logger");
const utils = __importStar(require("./lib/utils"));
// @ts-expect-error dynamically built
const models_index_json_1 = __importDefault(require("./models-index.json"));
const NS = "zhc";
const MODELS_INDEX = models_index_json_1.default;
var actions_1 = require("./converters/actions");
Object.defineProperty(exports, "ACTIONS", { enumerable: true, get: function () { return actions_1.ACTIONS; } });
var logger_2 = require("./lib/logger");
Object.defineProperty(exports, "setLogger", { enumerable: true, get: function () { return logger_2.setLogger; } });
var store_1 = require("./lib/store");
Object.defineProperty(exports, "clearGlobalStore", { enumerable: true, get: function () { return store_1.clear; } });
// key: zigbeeModel, value: array of definitions (most of the times 1)
const externalDefinitionsLookup = new Map();
exports.externalDefinitions = [];
// expected to be at the beginning of `definitions` array
let externalDefinitionsCount = 0;
function arrayEquals(as, bs) {
    if (as.length !== bs.length) {
        return false;
    }
    for (const a of as) {
        if (!bs.includes(a)) {
            return false;
        }
    }
    return true;
}
function addToExternalDefinitionsLookup(zigbeeModel, definition) {
    const lookupModel = zigbeeModel ? zigbeeModel.toLowerCase() : "null";
    if (!externalDefinitionsLookup.has(lookupModel)) {
        externalDefinitionsLookup.set(lookupModel, []);
    }
    // key created above
    // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
    if (!externalDefinitionsLookup.get(lookupModel).includes(definition)) {
        // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
        externalDefinitionsLookup.get(lookupModel).splice(0, 0, definition);
    }
}
function removeFromExternalDefinitionsLookup(zigbeeModel, definition) {
    const lookupModel = zigbeeModel ? zigbeeModel.toLowerCase() : "null";
    if (externalDefinitionsLookup.has(lookupModel)) {
        // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
        const i = externalDefinitionsLookup.get(lookupModel).indexOf(definition);
        if (i > -1) {
            // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
            externalDefinitionsLookup.get(lookupModel).splice(i, 1);
        }
        // biome-ignore lint/style/noNonNullAssertion: ignored using `--suppress`
        if (externalDefinitionsLookup.get(lookupModel).length === 0) {
            externalDefinitionsLookup.delete(lookupModel);
        }
    }
}
/**
 * Some devices pad `modelID` with NUL bytes or surrounding whitespace. Strip that so lookups
 * and comparisons use the same form as the value declared in `zigbeeModel`.
 */
function normalizeModelID(modelID) {
    return modelID.replace(/\0(.|\n)*$/g, "").trim();
}
function getFromExternalDefinitionsLookup(zigbeeModel) {
    const lookupModel = zigbeeModel ? zigbeeModel.toLowerCase() : "null";
    if (externalDefinitionsLookup.has(lookupModel)) {
        return externalDefinitionsLookup.get(lookupModel);
    }
    return externalDefinitionsLookup.get(normalizeModelID(lookupModel));
}
function removeExternalDefinitions(converterName) {
    for (let i = 0; i < externalDefinitionsCount; i++) {
        const definition = exports.externalDefinitions[i];
        if (converterName && definition.externalConverterName !== converterName) {
            continue;
        }
        if (definition.zigbeeModel) {
            for (const zigbeeModel of definition.zigbeeModel) {
                removeFromExternalDefinitionsLookup(zigbeeModel, definition);
            }
        }
        if (definition.fingerprint) {
            for (const fingerprint of definition.fingerprint) {
                removeFromExternalDefinitionsLookup(fingerprint.modelID, definition);
            }
        }
        exports.externalDefinitions.splice(i, 1);
        externalDefinitionsCount--;
        i--;
    }
}
function addExternalDefinition(definition) {
    exports.externalDefinitions.splice(0, 0, definition);
    externalDefinitionsCount++;
    if (definition.fingerprint) {
        for (const fingerprint of definition.fingerprint) {
            addToExternalDefinitionsLookup(fingerprint.modelID, definition);
        }
    }
    if (definition.zigbeeModel) {
        for (const zigbeeModel of definition.zigbeeModel) {
            addToExternalDefinitionsLookup(zigbeeModel, definition);
        }
    }
}
async function getDefinitions(indexes) {
    const indexedDefs = [];
    // local cache for models with lots of matches (tuya...)
    const defs = {};
    for (const [moduleName, index] of indexes) {
        if (!defs[moduleName]) {
            // NOTE: modules are cached by nodejs until process is stopped
            // currently using `commonjs`, so strip `.js` file extension, XXX: creates a warning with vitest (expects static `.js`)
            const { definitions } = (await Promise.resolve(`${`./devices/${moduleName.slice(0, -3)}`}`).then(s => __importStar(require(s))));
            defs[moduleName] = definitions;
        }
        indexedDefs.push(defs[moduleName][index]);
    }
    return indexedDefs;
}
async function getFromIndex(zigbeeModel) {
    const lookupModel = zigbeeModel ? zigbeeModel.toLowerCase() : "null";
    let indexes = MODELS_INDEX[lookupModel];
    if (indexes) {
        logger_1.logger.debug(`Getting definitions for: ${indexes}`, NS);
        return await getDefinitions(indexes);
    }
    indexes = MODELS_INDEX[normalizeModelID(lookupModel)];
    if (indexes) {
        logger_1.logger.debug(`Getting definitions for: ${indexes}`, NS);
        return await getDefinitions(indexes);
    }
}
const converterRequiredFields = {
    model: "String",
    vendor: "String",
    description: "String",
    fromZigbee: "Array",
    toZigbee: "Array",
};
function validateDefinition(definition) {
    for (const [field, expectedType] of Object.entries(converterRequiredFields)) {
        const val = definition[field];
        (0, node_assert_1.default)(val !== null, `Converter field ${field} is null`);
        (0, node_assert_1.default)(val !== undefined, `Converter field ${field} is undefined`);
        (0, node_assert_1.default)(val.constructor.name === expectedType, `Converter field ${field} expected type doenst match to ${val}`);
    }
    node_assert_1.default.ok(Array.isArray(definition.exposes) || typeof definition.exposes === "function", "Exposes incorrect");
}
function processExtensions(definition) {
    if ("extend" in definition) {
        if (!Array.isArray(definition.extend)) {
            node_assert_1.default.fail(`'${definition.model}' has legacy extend which is not supported anymore`);
        }
        // Modern extend, merges properties, e.g. when both extend and definition has toZigbee, toZigbee will be combined
        let { extend, toZigbee, fromZigbee, exposes: definitionExposes, meta, endpoint, ota, configure: definitionConfigure, onEvent: definitionOnEvent, options, ...definitionWithoutExtend } = definition;
        // Exposes can be an Expose[] or DefinitionExposesFunction. In case it's only Expose[] we return an array
        // Otherwise return a DefinitionExposesFunction.
        const allExposesIsExposeOnly = (allExposes) => {
            return !allExposes.find((e) => typeof e === "function");
        };
        let allExposes = [];
        if (definitionExposes) {
            if (typeof definitionExposes === "function") {
                allExposes.push(definitionExposes);
            }
            else {
                allExposes.push(...definitionExposes);
            }
        }
        toZigbee = [...(toZigbee ?? [])];
        fromZigbee = [...(fromZigbee ?? [])];
        options = [...(options ?? [])];
        const configures = definitionConfigure ? [definitionConfigure] : [];
        const onEvents = definitionOnEvent ? [definitionOnEvent] : [];
        for (const ext of extend) {
            if (!ext.isModernExtend) {
                node_assert_1.default.fail(`'${definition.model}' has legacy extend in modern extend`);
            }
            if (ext.toZigbee) {
                toZigbee.push(...ext.toZigbee);
            }
            if (ext.fromZigbee) {
                fromZigbee.push(...ext.fromZigbee);
            }
            if (ext.options) {
                options.push(...ext.options);
            }
            if (ext.exposes) {
                allExposes.push(...ext.exposes);
            }
            if (ext.meta) {
                meta = Object.assign({}, ext.meta, meta);
            }
            // Filter `undefined` configures, e.g. returned by setupConfigureForReporting.
            if (ext.configure) {
                configures.push(...ext.configure.filter((c) => c !== undefined));
            }
            if (ext.onEvent) {
                onEvents.push(...ext.onEvent.filter((c) => c !== undefined));
            }
            if (ext.ota) {
                ota = ext.ota;
            }
            if (ext.endpoint) {
                if (endpoint) {
                    node_assert_1.default.fail(`'${definition.model}' has multiple 'endpoint', this is not allowed`);
                }
                endpoint = ext.endpoint;
            }
        }
        // Filtering out action exposes to combine them one
        const actionExposes = allExposes.filter((e) => typeof e !== "function" && e.name === "action");
        allExposes = allExposes.filter((e) => e.name !== "action");
        if (actionExposes.length > 0) {
            const actions = [];
            for (const expose of actionExposes) {
                if (expose instanceof exposes_1.Enum) {
                    for (const action of expose.values) {
                        actions.push(action.toString());
                    }
                }
            }
            const uniqueActions = actions.filter((value, index, array) => array.indexOf(value) === index);
            allExposes.push(exposesLib.presets.action(uniqueActions));
        }
        let configure;
        if (configures.length !== 0) {
            configure = async (device, coordinatorEndpoint, configureDefinition) => {
                for (const func of configures) {
                    await func(device, coordinatorEndpoint, configureDefinition);
                }
            };
        }
        let onEvent;
        if (onEvents.length !== 0) {
            onEvent = async (event) => {
                for (const func of onEvents) {
                    await func(event);
                }
            };
        }
        // In case there is a function in allExposes, return a function, otherwise just an array.
        let exposes;
        if (allExposesIsExposeOnly(allExposes)) {
            exposes = allExposes;
        }
        else {
            exposes = (device, options) => {
                const result = [];
                for (const item of allExposes) {
                    if (typeof item === "function") {
                        try {
                            const deviceExposes = item(device, options);
                            result.push(...deviceExposes);
                        }
                        catch (error) {
                            const ieeeAddr = utils.isDummyDevice(device) ? "dummy-device" : device.ieeeAddr;
                            logger_1.logger.error(`Failed to process exposes for '${ieeeAddr}' (${error.stack})`, NS);
                        }
                    }
                    else {
                        result.push(item);
                    }
                }
                return result;
            };
        }
        return { version: "0.0.0", toZigbee, fromZigbee, exposes, meta, configure, endpoint, onEvent, ota, options, ...definitionWithoutExtend };
    }
    return { version: "0.0.0", ...definition };
}
function prepareDefinition(definition) {
    const finalDefinition = processExtensions(definition);
    finalDefinition.toZigbee = [
        toZigbee.scene_store,
        toZigbee.scene_recall,
        toZigbee.scene_add,
        toZigbee.scene_remove,
        toZigbee.scene_remove_all,
        toZigbee.scene_rename,
        toZigbee.read,
        toZigbee.write,
        toZigbee.command,
        toZigbee.factory_reset,
        toZigbee.zcl_command,
        // Add device specific toZigbee converters as last, otherwise the Tuya datapoints
        // converters consume e.g. the `read` and `write`.
        ...finalDefinition.toZigbee,
    ];
    if (definition.externalConverterName) {
        validateDefinition(finalDefinition);
    }
    // Add all the options
    finalDefinition.options = [...(finalDefinition.options ?? [])];
    const optionKeys = finalDefinition.options.map((o) => o.name);
    // Add calibration/precision options based on expose
    for (const expose of Array.isArray(finalDefinition.exposes) ? finalDefinition.exposes : finalDefinition.exposes({ isDummyDevice: true }, {})) {
        if (!optionKeys.includes(expose.name) &&
            utils.isNumericExpose(expose) &&
            expose.name in utils.calibrateAndPrecisionRoundOptionsDefaultPrecision) {
            // Battery voltage is not calibratable
            if (expose.name === "voltage" && expose.unit === "mV") {
                continue;
            }
            const type = utils.calibrateAndPrecisionRoundOptionsIsPercentual(expose.name) ? "percentual" : "absolute";
            finalDefinition.options.push(exposesLib.options.calibration(expose.name, type).withValueStep(0.1));
            if (utils.calibrateAndPrecisionRoundOptionsDefaultPrecision[expose.name] !== 0) {
                finalDefinition.options.push(exposesLib.options.precision(expose.name));
            }
            optionKeys.push(expose.name);
        }
    }
    for (const converter of [...finalDefinition.toZigbee, ...finalDefinition.fromZigbee]) {
        if (converter.options) {
            const options = typeof converter.options === "function" ? converter.options(finalDefinition) : converter.options;
            for (const option of options) {
                if (!optionKeys.includes(option.name)) {
                    finalDefinition.options.push(option);
                    optionKeys.push(option.name);
                }
            }
        }
    }
    return finalDefinition;
}
function postProcessConvertedFromZigbeeMessage(definition, payload, options, device) {
    // Apply calibration/precision options
    for (const [key, value] of Object.entries(payload)) {
        const definitionExposes = Array.isArray(definition.exposes) ? definition.exposes : definition.exposes(device, {});
        const expose = definitionExposes.find((e) => e.property === key);
        if (expose?.name && expose.name in utils.calibrateAndPrecisionRoundOptionsDefaultPrecision && value !== "" && utils.isNumber(value)) {
            try {
                payload[key] = utils.calibrateAndPrecisionRoundOptions(value, options, expose.name);
            }
            catch (error) {
                logger_1.logger.error(`Failed to apply calibration to '${expose.name}': ${error.message}`, NS);
            }
        }
    }
}
async function findByDevice(device, generateForUnknown = false) {
    let definition = await findDefinition(device, generateForUnknown);
    if (definition) {
        if (definition.whiteLabel) {
            const match = definition.whiteLabel.find((w) => "fingerprint" in w && w.fingerprint.find((f) => isFingerprintMatch(f, device)));
            if (match) {
                definition = {
                    ...definition,
                    model: match.model,
                    vendor: match.vendor ?? definition.vendor,
                    description: match.description ?? definition.description,
                };
            }
        }
        return prepareDefinition(definition);
    }
}
async function findDefinition(device, generateForUnknown = false) {
    if (!device || device.type === "Coordinator") {
        return undefined;
    }
    let candidates = await getFromIndex(device.modelID);
    if (externalDefinitionsCount > 0) {
        const extCandidates = getFromExternalDefinitionsLookup(device.modelID);
        if (extCandidates) {
            if (candidates) {
                candidates.unshift(...extCandidates);
            }
            else {
                candidates = extCandidates;
            }
        }
    }
    if (candidates) {
        if (candidates.length === 1 && candidates[0].zigbeeModel) {
            return candidates[0];
        }
        logger_1.logger.debug(() => `Candidates for ${device.ieeeAddr}/${device.modelID}: ${candidates.map((c) => `${c.model}/${c.vendor}`)}`, NS);
        // First try to match based on fingerprint, return the first matching one.
        const fingerprintMatch = { priority: undefined, definition: undefined };
        for (const candidate of candidates) {
            if (candidate.fingerprint) {
                for (const fingerprint of candidate.fingerprint) {
                    const priority = fingerprint.priority ?? 0;
                    if (isFingerprintMatch(fingerprint, device) &&
                        (fingerprintMatch.priority === undefined || priority > fingerprintMatch.priority)) {
                        fingerprintMatch.definition = candidate;
                        fingerprintMatch.priority = priority;
                    }
                }
            }
        }
        if (fingerprintMatch.definition) {
            return fingerprintMatch.definition;
        }
        // Match based on fingerprint failed, return first matching definition based on zigbeeModel.
        // A candidate can be here because the lookups above matched the normalized modelID, so compare against that form too.
        if (device.modelID) {
            const normalizedModelID = normalizeModelID(device.modelID);
            for (const candidate of candidates) {
                if (candidate.zigbeeModel?.some((zigbeeModel) => zigbeeModel === device.modelID || zigbeeModel === normalizedModelID)) {
                    return candidate;
                }
            }
        }
    }
    if (!generateForUnknown) {
        return undefined;
    }
    const { definition } = await (0, generateDefinition_1.generateDefinition)(device);
    return definition;
}
async function generateExternalDefinitionSource(device) {
    return (await (0, generateDefinition_1.generateDefinition)(device)).externalDefinitionSource;
}
async function generateExternalDefinition(device) {
    const { definition } = await (0, generateDefinition_1.generateDefinition)(device);
    return prepareDefinition(definition);
}
function isFingerprintMatch(fingerprint, device) {
    let match = (fingerprint.applicationVersion === undefined || device.applicationVersion === fingerprint.applicationVersion) &&
        (fingerprint.manufacturerID === undefined || device.manufacturerID === fingerprint.manufacturerID) &&
        (!fingerprint.type || device.type === fingerprint.type) &&
        (!fingerprint.dateCode || device.dateCode === fingerprint.dateCode) &&
        (fingerprint.hardwareVersion === undefined || device.hardwareVersion === fingerprint.hardwareVersion) &&
        (!fingerprint.manufacturerName || device.manufacturerName === fingerprint.manufacturerName) &&
        (!fingerprint.modelID || device.modelID === fingerprint.modelID) &&
        (!fingerprint.powerSource || device.powerSource === fingerprint.powerSource) &&
        (!fingerprint.softwareBuildID || device.softwareBuildID === fingerprint.softwareBuildID) &&
        (fingerprint.stackVersion === undefined || device.stackVersion === fingerprint.stackVersion) &&
        (fingerprint.zclVersion === undefined || device.zclVersion === fingerprint.zclVersion) &&
        (!fingerprint.ieeeAddr || device.ieeeAddr.match(fingerprint.ieeeAddr) !== null) &&
        (!fingerprint.endpoints ||
            arrayEquals(device.endpoints.map((e) => e.ID), fingerprint.endpoints.map((e) => e.ID)));
    if (match && fingerprint.endpoints) {
        for (const fingerprintEndpoint of fingerprint.endpoints) {
            const deviceEndpoint = fingerprintEndpoint.ID !== undefined ? device.getEndpoint(fingerprintEndpoint.ID) : undefined;
            match =
                match &&
                    (fingerprintEndpoint.deviceID === undefined ||
                        (deviceEndpoint !== undefined && deviceEndpoint.deviceID === fingerprintEndpoint.deviceID)) &&
                    (fingerprintEndpoint.profileID === undefined ||
                        (deviceEndpoint !== undefined && deviceEndpoint.profileID === fingerprintEndpoint.profileID)) &&
                    (!fingerprintEndpoint.inputClusters ||
                        (deviceEndpoint !== undefined && arrayEquals(deviceEndpoint.inputClusters, fingerprintEndpoint.inputClusters))) &&
                    (!fingerprintEndpoint.outputClusters ||
                        (deviceEndpoint !== undefined && arrayEquals(deviceEndpoint.outputClusters, fingerprintEndpoint.outputClusters)));
        }
    }
    return match;
}
// Can be used to handle events for devices which are not fully paired yet (no modelID).
// Example usecase: https://github.com/Koenkk/zigbee2mqtt/issues/2399#issuecomment-570583325
function onEvent(event) {
    if (event.type === "stop") {
        return;
    }
    const { device } = event.data;
    if (device.customReadResponse === undefined) {
        if (device.manufacturerID === zigbee_herdsman_1.Zcl.ManufacturerCode.LEGRAND_GROUP) {
            // support Legrand security protocol
            // when pairing, a powered device will send a read frame to every device on the network
            // it expects at least one answer. The payload contains the number of seconds
            // since when the device is powered. If the value is too high, it will leave & not pair
            // 23 works, 200 doesn't
            device.customReadResponse = (frame, endpoint) => {
                if (frame.isCluster("genBasic") && frame.payload.some((i) => i.attrId === 61440)) {
                    // XXX: we're replying to specific attribute, which could be incorrect (not based on the request attrIds)
                    endpoint
                        .readResponse("genBasic", frame.header.transactionSequenceNumber, { 61440: { value: 23, type: zigbee_herdsman_1.Zcl.DataType.UINT32 } }, { manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.LEGRAND_GROUP, disableDefaultResponse: true })
                        .catch((e) => {
                        logger_1.logger.warning(`Legrand security read response failed: ${e}`, NS);
                    });
                    return true;
                }
                return false;
            };
        }
        else if (device.modelID === "aqara.feeder.acn001") {
            // Aqara feeder C1 polls the time during the interview, need to send back the local time instead of the UTC.
            // The device.definition has not yet been set - therefore the device.definition.onEvent method does not work.
            device.customReadResponse = (frame, endpoint) => {
                if (frame.isCluster("genTime")) {
                    const oneJanuary2000 = new Date("January 01, 2000 00:00:00 UTC+00:00").getTime();
                    const secondsUTC = Math.round((Date.now() - oneJanuary2000) / 1000);
                    const secondsLocal = secondsUTC - new Date().getTimezoneOffset() * 60;
                    // XXX: we're replying to specific attribute, which could be incorrect (not based on the request attrIds)
                    endpoint.readResponse("genTime", frame.header.transactionSequenceNumber, { time: secondsLocal }).catch((e) => {
                        logger_1.logger.warning(`ZNCWWSQ01LM custom time response failed: ${e}`, NS);
                    });
                    return true;
                }
                return false;
            };
        }
    }
    return Promise.resolve();
}
//# sourceMappingURL=index.js.map