"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 exposes = __importStar(require("../lib/exposes"));
const m = __importStar(require("../lib/modernExtend"));
const reporting = __importStar(require("../lib/reporting"));
const e = exposes.presets;
const ea = exposes.access;
const HALO_MANUFACTURER_CODE = 0x1201;
const CLUSTER_HALO_STATUS = 0xfd00;
const CLUSTER_HALO_CONTROL = 0xfd01;
const CLUSTER_HALO_SENSORS = 0xfd02;
const CLUSTER_HALO_WEATHER = 0xfd03;
const HALO_COMMAND_TEST = 0x00;
const HALO_COMMAND_HUSH = 0x01;
const HALO_TEST_START = 0x01;
const HALO_TEST_CANCEL = 0x00;
const HALO_HUSH_START = 0x00;
const HALO_HUSH_STOP = 0x01;
const WEATHER_ALERT_CODES = [
    "NONE",
    "AVA",
    "AVW",
    "BZW",
    "CFA",
    "CFW",
    "DSW",
    "EQW",
    "FFA",
    "FFS",
    "FFW",
    "FLA",
    "FLS",
    "FLW",
    "FRW",
    "FSW",
    "FZW",
    "HLS",
    "HUA",
    "HUW",
    "HWA",
    "HWW",
    "SPS",
    "SVA",
    "SVR",
    "SVS",
    "TOA",
    "TOR",
    "TRA",
    "TRW",
    "TSA",
    "TSW",
    "VOW",
    "WSA",
    "WSW",
    "ADR",
    "NIC",
    "NMN",
    "CAE",
    "LAE",
    "TOE",
    "DMO",
    "NAT",
    "NPT",
    "NST",
    "RMT",
    "RWT",
    "CDW",
    "CEM",
    "EAN",
    "EAT",
    "EVI",
    "HMW",
    "NUW",
    "RHW",
    "SPW",
    "LEW",
    "SMW",
    "??S",
    "??M",
    "??E",
    "??A",
    "??W",
    "BHW",
    "BWW",
    "CHW",
    "CWW",
    "DBA",
    "DBW",
    "DEW",
    "EVA",
    "FCW",
    "IBW",
    "IFW",
    "LSW",
    "POS",
    "WFA",
    "WFW",
    "EWW",
    "SSA",
    "SSW",
];
const WEATHER_ALERT_STATE_CODES = [...WEATHER_ALERT_CODES, "UNKNOWN"];
const WEATHER_ALERT_CODE_SET = new Set(WEATHER_ALERT_CODES);
const WEATHER_ALERT_TO_ID = WEATHER_ALERT_CODES.reduce((acc, code, index) => {
    acc[code] = index;
    return acc;
}, {});
const WEATHER_ID_TO_ALERT = WEATHER_ALERT_CODES.reduce((acc, code, index) => {
    acc[index] = code;
    return acc;
}, {});
const WEATHER_PLAYING_STATE_VALUES = ["quiet", "playing"];
const WEATHER_PLAYBACK_ACTIONS = ["play", "stop"];
const HALO_WEATHER_COMMAND_SCAN = 0x00;
const HALO_WEATHER_COMMAND_PLAY = 0x03;
const WEATHER_STATION_MIN = 1;
const WEATHER_STATION_MAX = 7;
const WEATHER_STATION_FREQUENCIES = {
    1: "162.400 MHz",
    2: "162.425 MHz",
    3: "162.450 MHz",
    4: "162.475 MHz",
    5: "162.500 MHz",
    6: "162.525 MHz",
    7: "162.550 MHz",
};
const HALO_ALERT_STATES = [
    "safe",
    "pre_smoke",
    "smoke",
    "carbon_monoxide",
    "weather",
    "interconnect_smoke",
    "interconnect_carbon_monoxide",
    "silenced",
    "low_battery",
    "very_low_battery",
    "failed_battery",
    "end_of_life",
    "other",
    "co_test",
    "smoke_test",
];
const HALO_TEST_STATES = [
    "idle",
    "running",
    "success",
    "fail_ion",
    "fail_photo",
    "fail_co",
    "fail_temperature",
    "fail_weather",
    "fail_other",
];
const HALO_HUSH_STATES = ["ready", "success", "timeout", "disabled"];
const HALO_ROOMS = [
    "none",
    "basement",
    "bedroom",
    "den",
    "dining_room",
    "downstairs",
    "entryway",
    "family_room",
    "game_room",
    "guest_bedroom",
    "hallway",
    "kids_bedroom",
    "living_room",
    "master_bedroom",
    "office",
    "study",
    "upstairs",
    "workout_room",
];
const HALO_ROOM_ID_BY_NAME = {
    none: 0xff,
    basement: 0x00,
    bedroom: 0x01,
    den: 0x02,
    dining_room: 0x03,
    downstairs: 0x04,
    entryway: 0x05,
    family_room: 0x06,
    game_room: 0x07,
    guest_bedroom: 0x08,
    hallway: 0x09,
    kids_bedroom: 0x0a,
    living_room: 0x0b,
    master_bedroom: 0x0c,
    office: 0x0d,
    study: 0x0e,
    upstairs: 0x0f,
    workout_room: 0x10,
};
const HALO_ROOM_NAME_BY_ID = Object.entries(HALO_ROOM_ID_BY_NAME).reduce((acc, [name, id]) => {
    acc[id] = name;
    return acc;
}, {});
function ensureHaloWeatherMetaState(meta) {
    if (!meta.state.haloWeather) {
        meta.state.haloWeather = {};
    }
    return meta.state.haloWeather;
}
function normalizeWeatherStation(value) {
    const parsed = Number(value);
    if (!Number.isInteger(parsed)) {
        throw new Error("weather_station must be an integer between 1 and 7");
    }
    if (parsed < WEATHER_STATION_MIN || parsed > WEATHER_STATION_MAX) {
        throw new Error(`weather_station must be between ${WEATHER_STATION_MIN} and ${WEATHER_STATION_MAX}`);
    }
    return parsed;
}
function normalizeWeatherLocation(value) {
    const raw = typeof value === "number" ? value.toString() : String(value ?? "").trim();
    if (!/^\d{1,6}$/.test(raw)) {
        throw new Error("weather_location must be a numeric SAME code up to 6 digits");
    }
    const padded = raw.padStart(6, "0");
    return { numeric: Number(padded), padded };
}
function normalizeWeatherAlertCode(value) {
    const upper = value.toUpperCase();
    if (!WEATHER_ALERT_CODE_SET.has(upper)) {
        throw new Error(`Unsupported weather alert code: ${value}`);
    }
    return upper;
}
function normalizeHaloRoom(value) {
    if (value === undefined || value === null) {
        throw new Error("room value is required");
    }
    const normalized = String(value).trim().toLowerCase().replace(/\s+/g, "_");
    if (!(normalized in HALO_ROOM_ID_BY_NAME)) {
        throw new Error(`Unsupported room value '${value}'`);
    }
    return normalized;
}
function haloRoomIdToName(id) {
    if (id === undefined)
        return "none";
    return HALO_ROOM_NAME_BY_ID[id] ?? "none";
}
function parseWeatherAlertList(value) {
    if (value === undefined || value === null) {
        return [];
    }
    let rawList;
    if (Array.isArray(value)) {
        rawList = value.map((entry) => (typeof entry === "string" ? entry : String(entry ?? "")));
    }
    else if (typeof value === "string") {
        const trimmed = value.trim();
        if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
            try {
                const parsed = JSON.parse(trimmed);
                if (Array.isArray(parsed)) {
                    rawList = parsed.map((entry) => (typeof entry === "string" ? entry : String(entry ?? "")));
                }
            }
            catch {
                // fall back to simple splitting
            }
        }
        if (!rawList) {
            rawList = trimmed
                .split(/[,\s]+/)
                .map((entry) => entry.trim())
                .filter((entry) => entry.length > 0);
        }
    }
    else {
        rawList = [String(value)];
    }
    const unique = [];
    for (const entry of rawList) {
        const code = normalizeWeatherAlertCode(entry);
        if (!unique.includes(code)) {
            unique.push(code);
        }
    }
    return unique;
}
function encodeWeatherAlertBitmaps(alerts) {
    let event1 = 0;
    let event2 = 0;
    let event3 = 0;
    for (const alert of alerts) {
        const id = WEATHER_ALERT_TO_ID[alert];
        if (id <= 0)
            continue;
        if (id <= 32) {
            event1 = (event1 | (1 << (id - 1))) >>> 0;
        }
        else if (id <= 62) {
            event2 = (event2 | (1 << (id - 33))) >>> 0;
        }
        else if (id <= 80) {
            event3 = (event3 | (1 << (id - 63))) >>> 0;
        }
    }
    return { event1, event2, event3 };
}
function decodeWeatherAlertBitmaps(state) {
    const result = new Set();
    const addFromBitmap = (bitmap, startId) => {
        if (bitmap === undefined)
            return;
        const unsigned = bitmap >>> 0;
        for (let bit = 0; bit < 32; bit += 1) {
            if ((unsigned & (1 << bit)) !== 0) {
                const id = startId + bit;
                const code = WEATHER_ID_TO_ALERT[id];
                if (code) {
                    result.add(code);
                }
            }
        }
    };
    addFromBitmap(state.event1, 1);
    addFromBitmap(state.event2, 33);
    addFromBitmap(state.event3, 63);
    return [...result].sort((a, b) => WEATHER_ALERT_TO_ID[a] - WEATHER_ALERT_TO_ID[b]);
}
const DEVICE_STATUS_LOOKUP = {
    0: "safe",
    1: "low_battery",
    2: "end_of_life",
    4: "pre_smoke",
    5: "weather",
    6: "carbon_monoxide",
    7: "smoke",
    8: "other",
    9: "silenced",
    10: "very_low_battery",
    11: "failed_battery",
    14: "co_test",
    16: "smoke_test",
    18: "interconnect_carbon_monoxide",
    19: "interconnect_smoke",
};
const TEST_STATUS_LOOKUP = {
    0: "success",
    1: "fail_ion",
    2: "fail_photo",
    3: "fail_co",
    4: "fail_temperature",
    5: "fail_weather",
    6: "fail_other",
    7: "running",
};
const HUSH_STATUS_LOOKUP = {
    0: "success",
    1: "timeout",
    2: "ready",
    3: "disabled",
};
function haloZoneStatus() {
    return {
        exposes: [
            e.smoke(),
            e.carbon_monoxide(),
            e.tamper(),
            e.battery_low(),
            e.test(),
            e
                .binary("mains_power_connected", ea.STATE, true, false)
                .withDescription("Indicates whether mains power is currently available")
                .withCategory("diagnostic"),
        ],
        fromZigbee: [
            fz.ias_enroll,
            {
                cluster: "ssIasZone",
                type: ["commandStatusChangeNotification", "attributeReport", "readResponse"],
                convert: (model, msg, publish, options, meta) => {
                    const zoneStatus = "zonestatus" in msg.data ? msg.data.zonestatus : msg.data.zoneStatus;
                    if (zoneStatus === undefined)
                        return;
                    const payload = {};
                    if (msg.endpoint.ID === 1) {
                        payload.smoke = (zoneStatus & 1) > 0;
                        payload.tamper = (zoneStatus & (1 << 2)) > 0;
                        payload.battery_low = (zoneStatus & (1 << 3)) > 0;
                        payload.test = (zoneStatus & (1 << 8)) > 0;
                        const acFault = (zoneStatus & (1 << 7)) > 0;
                        payload.mains_power_connected = !acFault;
                    }
                    else if (msg.endpoint.ID === 3) {
                        payload.carbon_monoxide = (zoneStatus & 1) > 0;
                    }
                    if (Object.keys(payload).length > 0) {
                        return payload;
                    }
                },
            },
        ],
        configure: [
            async (device, coordinatorEndpoint) => {
                const endpoint1 = device.getEndpoint(1);
                if (endpoint1) {
                    await reporting.bind(endpoint1, coordinatorEndpoint, ["ssIasZone"]);
                    await endpoint1.read("ssIasZone", ["zoneStatus"]);
                }
                const endpoint3 = device.getEndpoint(3);
                if (endpoint3) {
                    await reporting.bind(endpoint3, coordinatorEndpoint, ["ssIasZone"]);
                    await endpoint3.read("ssIasZone", ["zoneStatus"]);
                }
            },
        ],
        isModernExtend: true,
    };
}
function haloDeviceStatus() {
    return {
        exposes: [
            e
                .enum("halo_alert_state", ea.STATE, [...HALO_ALERT_STATES])
                .withDescription("Device state reported by the manufacturer cluster")
                .withCategory("diagnostic"),
            e.enum("room", ea.STATE_SET, [...HALO_ROOMS]).withDescription("Spoken room name used in Halo announcements"),
        ],
        fromZigbee: [
            {
                cluster: "haloDeviceStatus",
                type: ["attributeReport", "readResponse"],
                convert: (model, msg, publish, options, meta) => {
                    const payload = {};
                    const status = msg.data.deviceStatus;
                    if (status !== undefined) {
                        const mapped = DEVICE_STATUS_LOOKUP[status] ?? "other";
                        payload.halo_alert_state = mapped;
                        payload.weather_alert = mapped === "weather";
                    }
                    if (msg.data.room !== undefined) {
                        payload.room = haloRoomIdToName(msg.data.room);
                    }
                    if (Object.keys(payload).length > 0) {
                        return payload;
                    }
                },
            },
        ],
        toZigbee: [
            {
                key: ["room"],
                convertSet: async (entity, key, value, meta) => {
                    const roomName = normalizeHaloRoom(value);
                    const roomId = HALO_ROOM_ID_BY_NAME[roomName];
                    const endpoint = meta.device.getEndpoint(4);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 4 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.write("haloDeviceStatus", { room: roomId }, { manufacturerCode: HALO_MANUFACTURER_CODE });
                    return { state: { room: roomName } };
                },
            },
        ],
        configure: [
            async (device, coordinatorEndpoint) => {
                const endpoint4 = device.getEndpoint(4);
                if (endpoint4) {
                    await reporting.bind(endpoint4, coordinatorEndpoint, [CLUSTER_HALO_STATUS]);
                    await endpoint4.read("haloDeviceStatus", ["deviceStatus", "room"], {
                        manufacturerCode: HALO_MANUFACTURER_CODE,
                    });
                }
            },
        ],
        isModernExtend: true,
    };
}
function haloControl() {
    return {
        exposes: [
            e
                .enum("halo_test_result", ea.STATE, [...HALO_TEST_STATES])
                .withDescription("Result of the most recent self-test")
                .withCategory("diagnostic"),
            e.binary("test_in_progress", ea.STATE, true, false).withDescription("Indicates whether a test is running").withCategory("diagnostic"),
            e
                .enum("halo_hush_state", ea.STATE, [...HALO_HUSH_STATES])
                .withDescription("Current hush status")
                .withCategory("diagnostic"),
            e.binary("hush_active", ea.STATE, true, false).withDescription("Indicates whether the alarm is hushed").withCategory("diagnostic"),
            e.enum("hush", ea.SET, ["start", "stop"]).withDescription("Start or cancel hush mode"),
            e.enum("test_cycle", ea.SET, ["start", "cancel"]).withDescription("Start or cancel the built-in test"),
        ],
        fromZigbee: [
            {
                cluster: "haloControl",
                type: ["attributeReport", "readResponse"],
                convert: (model, msg, publish, options, meta) => {
                    const payload = {};
                    if (msg.data.testStatus !== undefined) {
                        const mapped = TEST_STATUS_LOOKUP[msg.data.testStatus] ?? "idle";
                        payload.halo_test_result = mapped;
                        payload.test_in_progress = mapped === "running";
                    }
                    if (msg.data.hushStatus !== undefined) {
                        const mapped = HUSH_STATUS_LOOKUP[msg.data.hushStatus] ?? "ready";
                        payload.halo_hush_state = mapped;
                        payload.hush_active = mapped === "success";
                    }
                    if (Object.keys(payload).length > 0) {
                        return payload;
                    }
                },
            },
        ],
        toZigbee: [
            {
                key: ["hush"],
                convertSet: async (entity, key, value, meta) => {
                    if (value === undefined)
                        throw new Error("Value must be provided");
                    const normalized = String(value).toLowerCase();
                    if (!["start", "stop"].includes(normalized)) {
                        throw new Error("Value must be one of 'start' or 'stop'");
                    }
                    const payloadValue = normalized === "start" ? HALO_HUSH_START : HALO_HUSH_STOP;
                    const endpoint = meta.device.getEndpoint(4);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 4 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.command("haloControl", "haloHush", { value: payloadValue }, { manufacturerCode: HALO_MANUFACTURER_CODE, disableDefaultResponse: true });
                    return { state: { hush: normalized } };
                },
            },
            {
                key: ["test_cycle"],
                convertSet: async (entity, key, value, meta) => {
                    if (value === undefined)
                        throw new Error("Value must be provided");
                    const normalized = String(value).toLowerCase();
                    if (!["start", "cancel"].includes(normalized)) {
                        throw new Error("Value must be one of 'start' or 'cancel'");
                    }
                    const payloadValue = normalized === "start" ? HALO_TEST_START : HALO_TEST_CANCEL;
                    const endpoint = meta.device.getEndpoint(4);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 4 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.command("haloControl", "haloTest", { value: payloadValue }, { manufacturerCode: HALO_MANUFACTURER_CODE, disableDefaultResponse: true });
                    return { state: { test_cycle: normalized } };
                },
            },
        ],
        configure: [
            async (device, coordinatorEndpoint) => {
                const endpoint4 = device.getEndpoint(4);
                if (endpoint4) {
                    await reporting.bind(endpoint4, coordinatorEndpoint, [CLUSTER_HALO_CONTROL]);
                    await endpoint4.read("haloControl", ["testStatus", "hushStatus"], {
                        manufacturerCode: HALO_MANUFACTURER_CODE,
                    });
                }
            },
        ],
        isModernExtend: true,
    };
}
function haloSensors() {
    return {
        exposes: [
            e
                .numeric("co_ppm", ea.STATE)
                .withDescription("Current CO concentration reported by the detector")
                .withUnit("ppm")
                .withCategory("diagnostic"),
        ],
        fromZigbee: [
            {
                cluster: "haloSensors",
                type: ["attributeReport", "readResponse"],
                convert: (model, msg, publish, options, meta) => {
                    if (msg.data.coPpm !== undefined) {
                        return { co_ppm: msg.data.coPpm };
                    }
                },
            },
        ],
        configure: [
            async (device, coordinatorEndpoint) => {
                const endpoint4 = device.getEndpoint(4);
                if (endpoint4) {
                    await reporting.bind(endpoint4, coordinatorEndpoint, [CLUSTER_HALO_SENSORS]);
                    await endpoint4.read("haloSensors", ["coPpm"], {
                        manufacturerCode: HALO_MANUFACTURER_CODE,
                    });
                    await m.setupAttributes(endpoint4, coordinatorEndpoint, "haloSensors", [
                        { attribute: { ID: 0x0002, type: zigbee_herdsman_1.Zcl.DataType.INT16 }, min: "10_SECONDS", max: "1_HOUR", change: 1 },
                    ]);
                }
            },
        ],
        isModernExtend: true,
    };
}
function haloWeather() {
    return {
        exposes: [
            e
                .binary("weather_alert", ea.STATE, true, false)
                .withDescription("Indicates an active NOAA/SAME weather alert")
                .withCategory("diagnostic"),
            e
                .enum("current_weather_alert", ea.STATE, [...WEATHER_ALERT_STATE_CODES])
                .withDescription("Current NOAA/SAME event code reported by the detector")
                .withCategory("diagnostic"),
            e
                .list("weather_alerts_interest", ea.STATE_SET, e.enum("alert", ea.STATE_SET, [...WEATHER_ALERT_CODES]).withDescription("Alert code"))
                .withDescription("NOAA/SAME event codes that should trigger the Halo+ speaker")
                .withCategory("config"),
            e
                .text("weather_location", ea.STATE_SET)
                .withDescription("SAME location code (000000-999999) announced by the weather radio")
                .withCategory("config"),
            e
                .numeric("weather_station", ea.STATE_SET)
                .withValueMin(WEATHER_STATION_MIN)
                .withValueMax(WEATHER_STATION_MAX)
                .withDescription("Weather radio preset (1-7)")
                .withCategory("config"),
            e.text("weather_frequency", ea.STATE).withDescription("Frequency of the selected weather radio preset").withCategory("diagnostic"),
            e
                .enum("weather_playing_state", ea.STATE, [...WEATHER_PLAYING_STATE_VALUES])
                .withDescription("Current playback state of the weather radio")
                .withCategory("diagnostic"),
            e.enum("weather_playback", ea.SET, [...WEATHER_PLAYBACK_ACTIONS]).withDescription("Start or stop the weather radio audio"),
        ],
        fromZigbee: [
            {
                cluster: "haloWeather",
                type: ["attributeReport", "readResponse"],
                convert: (model, msg, publish, options, meta) => {
                    const payload = {};
                    const weatherState = ensureHaloWeatherMetaState(meta);
                    if (msg.data.weatherAlertStatus !== undefined) {
                        const code = (WEATHER_ID_TO_ALERT[msg.data.weatherAlertStatus] ?? "UNKNOWN");
                        payload.current_weather_alert = code;
                        payload.weather_alert = msg.data.weatherAlertStatus !== 0;
                    }
                    if (msg.data.weatherMute !== undefined) {
                        const playing = Number(msg.data.weatherMute) === 1;
                        payload.weather_playing_state = playing ? "playing" : "quiet";
                    }
                    if (msg.data.weatherLocation !== undefined) {
                        payload.weather_location = msg.data.weatherLocation.toString().padStart(6, "0");
                    }
                    if (msg.data.weatherStation !== undefined) {
                        const station = msg.data.weatherStation;
                        if (station >= WEATHER_STATION_MIN && station <= WEATHER_STATION_MAX) {
                            payload.weather_station = station;
                            payload.weather_frequency = WEATHER_STATION_FREQUENCIES[station];
                        }
                    }
                    let eventsChanged = false;
                    if (msg.data.weatherEvent1 !== undefined) {
                        weatherState.event1 = msg.data.weatherEvent1;
                        eventsChanged = true;
                    }
                    if (msg.data.weatherEvent2 !== undefined) {
                        weatherState.event2 = msg.data.weatherEvent2;
                        eventsChanged = true;
                    }
                    if (msg.data.weatherEvent3 !== undefined) {
                        weatherState.event3 = msg.data.weatherEvent3;
                        eventsChanged = true;
                    }
                    if (eventsChanged) {
                        payload.weather_alerts_interest = decodeWeatherAlertBitmaps(weatherState);
                    }
                    if (Object.keys(payload).length > 0) {
                        return payload;
                    }
                },
            },
        ],
        toZigbee: [
            {
                key: ["weather_playback"],
                convertSet: async (entity, key, value, meta) => {
                    if (value === undefined)
                        throw new Error("Value must be provided");
                    const normalized = typeof value === "boolean" ? (value ? "play" : "stop") : String(value).toLowerCase();
                    if (!WEATHER_PLAYBACK_ACTIONS.includes(normalized)) {
                        throw new Error("Value must be 'play' or 'stop'");
                    }
                    const commandValue = normalized === "play" ? 0x01 : 0x00;
                    const endpoint = meta.device.getEndpoint(5);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 5 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.command("haloWeather", "weatherRadioPlay", { value: commandValue }, { manufacturerCode: HALO_MANUFACTURER_CODE, disableDefaultResponse: true });
                    return { state: { weather_playback: normalized, weather_playing_state: normalized === "play" ? "playing" : "quiet" } };
                },
            },
            {
                key: ["weather_station"],
                convertSet: async (entity, key, value, meta) => {
                    if (value === undefined)
                        throw new Error("Value must be provided");
                    const station = normalizeWeatherStation(value);
                    const endpoint = meta.device.getEndpoint(5);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 5 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.write("haloWeather", { weatherStation: station }, { manufacturerCode: HALO_MANUFACTURER_CODE });
                    return { state: { weather_station: station, weather_frequency: WEATHER_STATION_FREQUENCIES[station] } };
                },
            },
            {
                key: ["weather_location"],
                convertSet: async (entity, key, value, meta) => {
                    if (value === undefined)
                        throw new Error("Value must be provided");
                    const location = normalizeWeatherLocation(value);
                    const endpoint = meta.device.getEndpoint(5);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 5 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.write("haloWeather", { weatherLocation: location.numeric }, { manufacturerCode: HALO_MANUFACTURER_CODE });
                    return { state: { weather_location: location.padded } };
                },
            },
            {
                key: ["weather_alerts_interest"],
                convertSet: async (entity, key, value, meta) => {
                    if (value === undefined)
                        throw new Error("Value must be provided");
                    const alerts = parseWeatherAlertList(value);
                    const { event1, event2, event3 } = encodeWeatherAlertBitmaps(alerts);
                    const endpoint = meta.device.getEndpoint(5);
                    if (!endpoint) {
                        throw new Error(`Failed to find endpoint 5 on Halo device ${meta.device.ieeeAddr}`);
                    }
                    await endpoint.write("haloWeather", { weatherEvent1: event1, weatherEvent2: event2, weatherEvent3: event3 }, { manufacturerCode: HALO_MANUFACTURER_CODE });
                    return { state: { weather_alerts_interest: alerts } };
                },
            },
        ],
        configure: [
            async (device, coordinatorEndpoint) => {
                const endpoint5 = device.getEndpoint(5);
                if (endpoint5) {
                    await reporting.bind(endpoint5, coordinatorEndpoint, [CLUSTER_HALO_WEATHER]);
                    await endpoint5.read("haloWeather", ["weatherAlertStatus", "weatherMute", "weatherLocation", "weatherEvent1", "weatherEvent2", "weatherEvent3", "weatherStation"], { manufacturerCode: HALO_MANUFACTURER_CODE });
                }
            },
        ],
        isModernExtend: true,
    };
}
const haloCommonExtend = [
    m.deviceEndpoints({ endpoints: { default: 1, light: 2 } }),
    m.deviceAddCustomCluster("haloDeviceStatus", {
        name: "haloDeviceStatus",
        ID: CLUSTER_HALO_STATUS,
        manufacturerCode: HALO_MANUFACTURER_CODE,
        attributes: {
            deviceStatus: { name: "deviceStatus", ID: 0x0000, type: zigbee_herdsman_1.Zcl.DataType.ENUM8 },
            room: { name: "room", ID: 0x0002, type: zigbee_herdsman_1.Zcl.DataType.ENUM8 },
        },
        commands: {},
        commandsResponse: {},
    }),
    m.deviceAddCustomCluster("haloControl", {
        name: "haloControl",
        ID: CLUSTER_HALO_CONTROL,
        manufacturerCode: HALO_MANUFACTURER_CODE,
        attributes: {
            testStatus: { name: "testStatus", ID: 0x0000, type: zigbee_herdsman_1.Zcl.DataType.ENUM8 },
            hushStatus: { name: "hushStatus", ID: 0x0001, type: zigbee_herdsman_1.Zcl.DataType.ENUM8 },
        },
        commands: {
            haloTest: { name: "haloTest", ID: HALO_COMMAND_TEST, parameters: [{ name: "value", type: zigbee_herdsman_1.Zcl.DataType.UINT8 }] },
            haloHush: { name: "haloHush", ID: HALO_COMMAND_HUSH, parameters: [{ name: "value", type: zigbee_herdsman_1.Zcl.DataType.UINT8 }] },
        },
        commandsResponse: {},
    }),
    m.deviceAddCustomCluster("haloSensors", {
        name: "haloSensors",
        ID: CLUSTER_HALO_SENSORS,
        manufacturerCode: HALO_MANUFACTURER_CODE,
        attributes: {
            coPpm: { name: "coPpm", ID: 0x0002, type: zigbee_herdsman_1.Zcl.DataType.INT16 },
        },
        commands: {},
        commandsResponse: {},
    }),
    haloZoneStatus(),
    haloDeviceStatus(),
    haloControl(),
    haloSensors(),
    m.light({
        color: { modes: ["hs"], enhancedHue: false },
        configureReporting: true,
        effect: false,
        powerOnBehavior: false,
        endpointNames: ["light"],
    }),
    m.battery({ percentage: true, voltage: true, voltageReporting: true }),
    m.temperature(),
    m.humidity(),
    m.pressure(),
];
exports.definitions = [
    {
        zigbeeModel: ["halo"],
        model: "HALO",
        vendor: "Halo Smart Labs",
        description: "Halo smart smoke & CO detector",
        extend: [...haloCommonExtend],
        meta: { disableDefaultResponse: true },
        configure: (device) => {
            const endpoint2 = device.getEndpoint(2);
            if (endpoint2) {
                endpoint2.saveClusterAttributeKeyValue("lightingColorCtrl", {
                    colorCapabilities: 0x09,
                    colorTempPhysicalMin: 153,
                    colorTempPhysicalMax: 500,
                });
            }
        },
    },
    {
        zigbeeModel: ["halo+", "haloWX", "SABDA1"],
        model: "HALO+",
        vendor: "Halo Smart Labs",
        description: "Halo+ smart smoke & CO detector with weather radio",
        extend: [
            ...haloCommonExtend,
            m.deviceAddCustomCluster("haloWeather", {
                name: "haloWeather",
                ID: CLUSTER_HALO_WEATHER,
                manufacturerCode: HALO_MANUFACTURER_CODE,
                attributes: {
                    weatherAlertStatus: { name: "weatherAlertStatus", ID: 0x0000, type: zigbee_herdsman_1.Zcl.DataType.ENUM8 },
                    weatherMute: { name: "weatherMute", ID: 0x0001, type: zigbee_herdsman_1.Zcl.DataType.BOOLEAN },
                    weatherLocation: { name: "weatherLocation", ID: 0x0002, type: zigbee_herdsman_1.Zcl.DataType.UINT32 },
                    weatherEvent1: { name: "weatherEvent1", ID: 0x0003, type: zigbee_herdsman_1.Zcl.DataType.BITMAP32 },
                    weatherEvent2: { name: "weatherEvent2", ID: 0x0004, type: zigbee_herdsman_1.Zcl.DataType.BITMAP32 },
                    weatherEvent3: { name: "weatherEvent3", ID: 0x0005, type: zigbee_herdsman_1.Zcl.DataType.BITMAP32 },
                    weatherStation: { name: "weatherStation", ID: 0x0006, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi1: { name: "weatherStationRssi1", ID: 0x0007, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi2: { name: "weatherStationRssi2", ID: 0x0008, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi3: { name: "weatherStationRssi3", ID: 0x0009, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi4: { name: "weatherStationRssi4", ID: 0x000a, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi5: { name: "weatherStationRssi5", ID: 0x000b, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi6: { name: "weatherStationRssi6", ID: 0x000c, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                    weatherStationRssi7: { name: "weatherStationRssi7", ID: 0x000d, type: zigbee_herdsman_1.Zcl.DataType.UINT8 },
                },
                commands: {
                    weatherScan: { name: "weatherScan", ID: HALO_WEATHER_COMMAND_SCAN, parameters: [] },
                    weatherRadioPlay: {
                        name: "weatherRadioPlay",
                        ID: HALO_WEATHER_COMMAND_PLAY,
                        parameters: [{ name: "value", type: zigbee_herdsman_1.Zcl.DataType.UINT8 }],
                    },
                },
                commandsResponse: {},
            }),
            haloWeather(),
        ],
        meta: { disableDefaultResponse: true },
        configure: (device) => {
            const endpoint2 = device.getEndpoint(2);
            if (endpoint2) {
                endpoint2.saveClusterAttributeKeyValue("lightingColorCtrl", {
                    colorCapabilities: 0x09,
                    colorTempPhysicalMin: 153,
                    colorTempPhysicalMax: 500,
                });
            }
        },
    },
];
//# sourceMappingURL=halo_smart_labs.js.map