"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 zigbee_herdsman_1 = require("zigbee-herdsman");
const fz = __importStar(require("../converters/fromZigbee"));
const tz = __importStar(require("../converters/toZigbee"));
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_1 = require("../lib/utils");
const NS = "zhc:profalux";
const e = exposes.presets;
const ea = exposes.access;
const profaluxExtend = {
    addManuSpecificProfalux1Cluster: () => m.deviceAddCustomCluster("manuSpecificProfalux1", {
        name: "manuSpecificProfalux1",
        ID: 0xfc21,
        manufacturerCode: zigbee_herdsman_1.Zcl.ManufacturerCode.PROFALUX,
        attributes: {
            motorCoverType: { name: "motorCoverType", ID: 0x0000, type: zigbee_herdsman_1.Zcl.DataType.UINT8, write: true, max: 0xff }, // 0 : rolling shutters (volet), 1 : rolling shutters with tilt (BSO), 2: shade (store)
        },
        commands: {},
        commandsResponse: {},
    }),
};
// ZTP20F sends its cover commands as genLevelCtrl groupcasts (move up/down + stop)
// which reach the coordinator, unlike other Profalux remotes bound directly to the motor.
const fzLocal = {
    cover_remote_move: {
        cluster: "genLevelCtrl",
        type: ["commandMove", "commandMoveWithOnOff"],
        convert: (model, msg) => {
            if ((0, utils_1.hasAlreadyProcessedMessage)(msg, model))
                return;
            return { action: msg.data.movemode === 1 ? "down" : "up" };
        },
    },
    cover_remote_stop: {
        cluster: "genLevelCtrl",
        type: ["commandStop", "commandStopWithOnOff"],
        convert: (model, msg) => {
            if ((0, utils_1.hasAlreadyProcessedMessage)(msg, model))
                return;
            return { action: "stop" };
        },
    },
};
const mLocal = {
    pollBatteryVoltage: () => {
        // Poll Battery voltage at most once a day
        // as the Profalux remotes do not report on battery
        return m.poll({
            key: "battery",
            defaultIntervalSeconds: 60 * 60 * 24,
            poll: (device) => {
                const endpoint = device.endpoints.find((e) => e.supportsInputCluster("genPowerCfg"));
                endpoint
                    .read("genPowerCfg", ["batteryVoltage"], { sendPolicy: "queue" })
                    .catch((error) => logger_1.logger.debug(`Failed to poll battery voltage of '${device.ieeeAddr}' (${error})`, NS));
            },
        });
    },
};
exports.definitions = [
    {
        zigbeeModel: ["MAI-ZTS"],
        fingerprint: [
            {
                manufacturerID: 4368,
                endpoints: [{ ID: 1, profileID: 260, deviceID: 513, inputClusters: [0, 3, 21], outputClusters: [3, 4, 5, 6, 8, 256, 64544, 64545] }],
            },
        ],
        model: "NB102",
        vendor: "Profalux",
        description: "Cover remote",
        fromZigbee: [],
        toZigbee: [],
        exposes: [],
    },
    {
        // Recent covers are matched by Zigbee model. Their remotes communicate
        // using cluster 0x102 "closuresWindowCovering", so use that.
        // 06/10/20/30 is the torque in Nm. 20/30 have not been seen but
        // extracted from Profalux documentation. C/F seems to be a version. D
        // and E have not been seen in the wild. I suspect A is the earlier
        // model covered below, NSAV061.
        zigbeeModel: [
            "MOT-C1Z06C\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z10C\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z20C\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z30C\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z06F\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z10F\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z20F\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C1Z30F\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C2Z10\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
            "MOT-C2Z10",
        ],
        model: "MOT-C1ZxxC/F",
        vendor: "Profalux",
        description: "Cover",
        extend: [profaluxExtend.addManuSpecificProfalux1Cluster()],
        fromZigbee: [fz.command_cover_close, fz.command_cover_open, fz.cover_position_tilt],
        toZigbee: [tz.cover_state, tz.cover_position_tilt],
        options: [],
        exposes: (device, options) => {
            // Motor can be configured using the associated remote:
            //  0: default hard cover         : 2xF Up + Down on the associated remote
            //  1: cover using tilt (aka BSO) : 2xF Stop + Up
            //  2: soft cover (aka store)     : 2xF Stop + Down
            return (0, utils_1.isDummyDevice)(device) || device?.getEndpoint(2).getClusterAttributeValue("manuSpecificProfalux1", "motorCoverType") === 1
                ? [e.cover_position_tilt()]
                : [e.cover_position()];
        },
        configure: async (device, coordinatorEndpoint) => {
            const endpoint = device.getEndpoint(2);
            await endpoint.read("manuSpecificProfalux1", ["motorCoverType"]).catch((e) => {
                logger_1.logger.warning(`Failed to read zigbee attributes: ${e}`, NS);
            });
            const coverType = endpoint.getClusterAttributeValue("manuSpecificProfalux1", "motorCoverType");
            // logger.debug(`Profalux '${device.ieeeAddr}' setup as cover type '${coverType)}'`, NS);
            await reporting.bind(endpoint, coordinatorEndpoint, ["closuresWindowCovering"]);
            await reporting.currentPositionLiftPercentage(endpoint);
            if (coverType === 1) {
                await reporting.currentPositionTiltPercentage(endpoint);
            }
        },
        endpoint: (device) => {
            return { default: 2 };
        },
        whiteLabel: [
            {
                model: "MOT-C2Z10",
                vendor: "Profalux",
                fingerprint: [{ modelID: "MOT-C2Z10\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000" }],
            },
        ],
    },
    {
        // Identify older covers based on their fingerprint. These do not
        // expose closuresWindowCovering and need to use genLevelCtrl
        // instead. Sniffing a remote would be welcome to confirm that this
        // is the right thing to do.
        fingerprint: [
            {
                manufacturerID: 4368,
                endpoints: [
                    { ID: 1, profileID: 260, deviceID: 512, inputClusters: [0, 3, 4, 5, 6, 8, 10, 21, 256, 64544, 64545], outputClusters: [3, 64544] },
                ],
            },
        ],
        model: "NSAV061",
        vendor: "Profalux",
        description: "Cover",
        fromZigbee: [fz.cover_position_via_brightness, fz.cover_state_via_onoff],
        toZigbee: [tz.cover_via_brightness],
        exposes: [e.cover_position().setAccess("state", ea.ALL)],
        configure: async (device, coordinatorEndpoint) => {
            const endpoint = device.getEndpoint(1);
            await reporting.bind(endpoint, coordinatorEndpoint, ["genLevelCtrl"]);
            await reporting.brightness(endpoint);
        },
    },
    {
        // ZTP20F emits its cover commands as genLevelCtrl groupcasts (movemode 0=up/1=down + stop)
        // that reach the coordinator, so the up/down/stop actions can be exposed.
        // Confirmed by sniffing a ZTP20F; other variants are handled below.
        zigbeeModel: ["MAI-ZTP20F"],
        model: "MAI-ZTP20F",
        vendor: "Profalux",
        description: "Cover remote",
        fromZigbee: [fzLocal.cover_remote_move, fzLocal.cover_remote_stop],
        exposes: [e.action(["up", "down", "stop"])],
        extend: [
            m.battery({ voltage: true, voltageToPercentage: { min: 2200, max: 3100 }, percentageReporting: false }),
            m.forcePowerSource({ powerSource: "Battery" }),
            // Poll battery voltage as reporting doesn't work
            mLocal.pollBatteryVoltage(),
        ],
    },
    {
        // ZTP20C/ZTP22C: these seem to be bound to the cover and the action behaviour
        // has not been verified, so only battery is exposed. The ZTP20F (above) does
        // reach the coordinator and exposes up/down/stop actions.
        zigbeeModel: ["MAI-ZTP20C", "MAI-ZTP22C"],
        model: "MAI-ZTP20",
        vendor: "Profalux",
        description: "Cover remote",
        extend: [
            m.battery({ voltage: true, voltageToPercentage: { min: 2200, max: 3100 }, percentageReporting: false }),
            m.forcePowerSource({ powerSource: "Battery" }),
            // Poll battery voltage as reporting doesn't work
            mLocal.pollBatteryVoltage(),
        ],
        whiteLabel: [{ model: "MAI-ZTP22C", vendor: "Profalux", fingerprint: [{ modelID: "MAI-ZTP22C" }] }],
    },
    {
        // Newer remotes. These expose a bunch of things but they are bound to
        // the cover and don't seem to communicate with the coordinator, so
        // nothing is likely to be doable in Z2M.
        fingerprint: [
            {
                type: "EndDevice",
                manufacturerName: "Profalux",
                modelID: "MAI-ZTS",
                manufacturerID: 4368,
                endpoints: [
                    {
                        ID: 1,
                        profileID: 260,
                        deviceID: 513,
                        inputClusters: [0, 3, 21, 64514, 64544],
                        outputClusters: [3, 4, 5, 6, 8, 256, 64544, 64545],
                    },
                    {
                        ID: 2,
                        profileID: 260,
                        deviceID: 515,
                        inputClusters: [0, 1, 3, 9, 21, 32, 64514, 64544],
                        outputClusters: [3, 4, 5, 25, 258, 64544, 64545],
                    },
                ],
            },
        ],
        model: "MAI-ZTM20C",
        zigbeeModel: ["MAI-ZTM20C"],
        vendor: "Profalux",
        description: "Cover remote",
        extend: [m.battery({ voltage: true, voltageToPercentage: { min: 2200, max: 3100 }, percentageReporting: false })],
        fromZigbee: [fz.command_cover_close, fz.command_cover_open, fz.command_cover_stop],
        exposes: [e.action(["up", "down", "stop"])],
        configure: async (device, coordinatorEndpoint, logger) => {
            const endpoint1 = device.getEndpoint(1);
            const endpoint2 = device.getEndpoint(2);
            // Bind clusters
            await reporting.bind(endpoint1, coordinatorEndpoint, ["genLevelCtrl"]);
            await reporting.bind(endpoint2, coordinatorEndpoint, ["genPowerCfg", "closureWindowCovering"]);
            // Configure battery voltage reporting from endpoint 2
            await reporting.batteryVoltage(endpoint2, { min: 3600, max: constants_1.repInterval.MAX, change: 1 });
        },
    },
];
//# sourceMappingURL=profalux.js.map