{"version":3,"sources":["../src/commands/setColors.ts","../src/commands/setOnOff.ts","../src/commands/createSocket.ts","../src/index.ts"],"sourcesContent":["import { colorOptions, Device, fadeOptions, stateChangedOptions } from \"..\";\nimport { hex, hsl, rgb } from \"color-convert\";\nimport * as ct from 'color-temperature';\n\n/**\n *\n * @param x Starting number\n * @param y Ending number\n * @param a percent (0-1)\n */\nconst lerp = (x: number, y: number, a: number) => x * (1 - a) + y * a;\n/**\n *\n * @param a Starting number\n * @param b Ending number\n * @param amount percent (0-1)\n */\nfunction lerpColor (a: string, b: string, amount: number)\n{\n\n    var ah = parseInt(a.replace(/#/g, ''), 16),\n        ar = ah >> 16, ag = ah >> 8 & 0xff, ab = ah & 0xff,\n        bh = parseInt(b.replace(/#/g, ''), 16),\n        br = bh >> 16, bg = bh >> 8 & 0xff, bb = bh & 0xff,\n        rr = ar + amount * (br - ar),\n        rg = ag + amount * (bg - ag),\n        rb = ab + amount * (bb - ab);\n\n    return '#' + ((1 << 24) + (rr << 16) + (rg << 8) + rb | 0).toString(16).slice(1);\n}\n\n/**\n * Returns a bezier interpolated value, using the given ranges\n * @param {number} value  Value to be interpolated\n * @param {number} s1 Source range start\n * @param {number} s2  Source range end\n * @param {number} t1  Target range start\n * @param {number} t2  Target range end\n * @param {number} [slope]  Weight of the curve (0.5 = linear, 0.1 = weighted near target start, 0.9 = weighted near target end)\n * @returns {number} Interpolated value\n */\nvar interpolate = function (value: number, s1: number, s2: number, t1: any, t2: any, slope: number)\n{\n    //Default to linear interpolation\n    slope = slope || 0.5;\n\n    //If the value is out of the source range, floor to min/max target values\n    if (value < Math.min(s1, s2))\n    {\n        return Math.min(s1, s2) === s1 ? t1 : t2;\n    }\n\n    if (value > Math.max(s1, s2))\n    {\n        return Math.max(s1, s2) === s1 ? t1 : t2;\n    }\n\n    //Reverse the value, to make it correspond to the target range (this is a side-effect of the bezier calculation)\n    value = s2 - value;\n\n    var C1 = { x: s1, y: t1 }; //Start of bezier curve\n    var C3 = { x: s2, y: t2 }; //End of bezier curve\n    var C2 = {              //Control point\n        x: C3.x,\n        y: C1.y + Math.abs(slope) * (C3.y - C1.y)\n    };\n\n    //Find out how far the value is on the curve\n    var percent = value / (C3.x - C1.x);\n\n    return C1.y * b1(percent) + C2.y * b2(percent) + C3.y * b3(percent);\n\n    function b1 (t: number) { return t * t; }\n    function b2 (t: number) { return 2 * t * (1 - t); }\n    function b3 (t: number) { return (1 - t) * (1 - t); }\n};\n\n/**\n * @description\n * Set the color of a light.\n */\nexport function setColor (this: Device, options: colorOptions): Promise<void>\n{\n    var device = this;\n    return new Promise((resolve, _reject) =>\n    {\n        var rgb = { r: 0, g: 0, b: 0 };\n        var message: string;\n\n        if (options.kelvin)\n        {\n            var kelvin = parseFloat(options.kelvin.toString().replace(/[^0-9]/g, \"\"));\n\n            message = JSON.stringify(\n                {\n                    msg: {\n                        cmd: \"colorwc\",\n                        data: {\n                            colorTemInKelvin: kelvin\n                        }\n                    }\n                }\n            );\n        } else\n        {\n            if (options.hex !== undefined)\n            {\n                var newColor = hex.rgb(options.hex);\n                rgb = {\n                    r: newColor[0],\n                    g: newColor[1],\n                    b: newColor[2]\n                };\n            } else if (options.hsl !== undefined)\n            {\n                var newColor = hsl.rgb(options.hsl);\n                rgb = {\n                    r: newColor[0],\n                    g: newColor[1],\n                    b: newColor[2]\n                };\n            } else if (options.rgb !== undefined)\n            {\n                rgb = {\n                    r: options.rgb[0],\n                    g: options.rgb[1],\n                    b: options.rgb[2]\n                };\n            }\n\n            message = JSON.stringify(\n                {\n                    msg: {\n                        cmd: \"colorwc\",\n                        data: {\n                            color: rgb\n                        }\n                    }\n                }\n            );\n        }\n\n        //! Commands have to be send twice te be caught by devstatus... annoying\n        // device.socket?.send(message, 0, message.length, 4001, device.ip, () =>\n        // {\n            device.socket?.send(message, 0, message.length, 4003, device.ip, async () =>\n            {\n                if (rgb)\n                {\n                    device.state.color = rgb;\n                    device.state.colorKelvin = ct.rgb2colorTemperature({ red: rgb.r, green: rgb.g, blue: rgb.b });\n                } else if (kelvin)\n                {\n                    var rgbColor = ct.colorTemperature2rgb(kelvin);\n                    device.state.color = { r: rgbColor.red, g: rgbColor.green, b: rgbColor.blue };\n                    device.state.colorKelvin = kelvin;\n                }\n                device.emit(\"updatedStatus\", device.state, [\"color\"])\n                resolve();\n                // await sleep(100)\n                // updateValues(device, false)\n            });\n        // });\n    });\n}\n\nexport function setBrightness (this: Device, brightness: number | string): Promise<void>\n{\n    return new Promise((resolve, _reject) =>\n    {\n        var bright = Math.round(parseFloat(brightness.toString()) * 100) / 100;\n        let message = JSON.stringify(\n            {\n                \"msg\": {\n                    \"cmd\": \"brightness\",\n                    \"data\": {\n                        \"value\": bright,\n                    }\n                }\n            }\n        );\n        //! Commands have to be send twice te be caught by devstatus... annoying\n        // this.socket?.send(message, 0, message.length, 4001, this.ip, ()=>{\n            this.socket?.send(message, 0, message.length, 4003, this.ip, async () =>\n            {\n                this.state.brightness = bright;\n                resolve();\n                await sleep(100)\n                this.emit(\"updatedStatus\", this.state, [\"brightness\"])\n                // updateValues(this, false)\n            });\n        // });\n    });\n}\n\nexport function fade (this: Device, options: fadeOptions): Promise<void>\n{\n    return new Promise(async (resolve, reject) =>\n    {\n        var device = this;\n        //? Get current value\n        await updateValues(device);\n        await sleep(100);\n\n        var curHex = rgb.hex(device.state.color.r, device.state.color.g, device.state.color.b);\n        var curKelvin = ct.rgb2colorTemperature({ red: device.state.color.r, green: device.state.color.g, blue: device.state.color.b });\n        var curBrightness = device.state.isOn == 1 ? device.state.brightness : 1;\n        var targetKelvin: number;\n        const targetBright = options.brightness;\n\n        if (options.color?.kelvin)\n        {\n            targetKelvin = parseFloat(options.color.kelvin.toString().replace(/[^0-9]/g, \"\"));\n        }\n\n        var changeColor = options.color?.hex !== undefined || options.color?.hsl !== undefined || options.color?.rgb !== undefined;\n\n        var startTime = Date.now();\n\n        var newColor = \"\";\n        if (options.color?.hsl !== undefined)\n            newColor = hsl.hex(options.color.hsl);\n        else if (options.color?.rgb !== undefined)\n            newColor = rgb.hex(options.color.rgb);\n        else if (options.color?.hex !== undefined)\n            newColor = options.color.hex.replace(/#/g, '');\n\n        async function stepBrightness (percent: number, targetBrightness: number)\n        {\n            var newBright = lerp(curBrightness, targetBrightness, Math.max(Math.min(percent, 1), 0));\n            return device.actions.setBrightness(newBright);\n        }\n\n        async function stepColor (percent: number, newColor: string)\n        {\n            var lerpedColor = lerpColor(curHex, newColor, Math.max(Math.min(percent, 1), 0));\n\n            return device.actions.setColor({ hex: \"#\" + lerpedColor });\n        }\n\n        async function stepKelvin (percent: number, targetKelvin: number)\n        {\n            var lerpedKelvin = lerp(curKelvin, targetKelvin, Math.max(Math.min(percent, 1), 0));\n            var kelvinRGB = ct.colorTemperature2rgb(lerpedKelvin);\n\n            return device.actions.setColor({ rgb: [kelvinRGB.red, kelvinRGB.green, kelvinRGB.blue] });\n        }\n\n        // Start loop\n        var running = true;\n\n        var fadeEndTimeout = setTimeout(async () =>\n        {\n            running = false;\n            this.removeListener(\"fadeCancel\", fadeCancelHandler)\n            if (changeColor)\n            {\n                setColor.call(device, {\n                    hex: newColor\n                });\n            } else if (targetKelvin)\n            {\n                var kelvinRGB = ct.colorTemperature2rgb(targetKelvin);\n                await device.actions.setColor({ rgb: [kelvinRGB.red, kelvinRGB.green, kelvinRGB.blue] });\n            }\n            if (targetBright !== undefined)\n            {\n                device.actions.setBrightness(targetBright);\n            }\n\n            await sleep(50);\n            await device.updateValues();\n            var updatedValues: stateChangedOptions = []\n            if (curBrightness !== targetBright) {\n                updatedValues.push(\"brightness\")\n            }\n            if (changeColor) {\n                updatedValues.push(\"color\")\n            }\n            device.emit(\"updatedStatus\", device.state, updatedValues)\n            resolve();\n        }, options.time - 100);\n\n        // Respond to fade cancel\n        function fadeCancelHandler(rejectPromise: boolean) {\n            running = false\n            clearTimeout(fadeEndTimeout);\n\n            if (rejectPromise) {\n                reject(\"Fade got cancelled\")\n            } else {\n                resolve();\n            }\n        }\n        this.once(\"fadeCancel\", fadeCancelHandler)\n\n        while (running)\n        {\n            var startLoopTime = Date.now();\n            var percent = interpolate((Date.now() - startTime) / (options.time - 100), 0, 1, 0, 1, 0.5);\n            // Color step\n            if (changeColor)\n            {\n                stepColor(percent, newColor);\n            }\n\n            // Kelvin step\n            if (options.color && options.color.kelvin !== undefined)\n            {\n                const targetKelvin =\n                  typeof options.color.kelvin === \"string\" ? parseFloat(options.color.kelvin) : options.color.kelvin;\n                if(!isNaN(targetKelvin)) stepKelvin(percent, targetKelvin);\n            }\n\n            // Brightness step\n            if (options.brightness !== undefined)\n            {\n                stepBrightness(percent, options.brightness);\n            }\n            await sleep(30 - (Date.now() - startLoopTime));\n        }\n    });\n}\n\nfunction sleep (ms: number): Promise<void>\n{\n    return new Promise((resolve, _reject) =>\n    {\n        setTimeout(() =>\n        {\n            resolve();\n        }, ms);\n    });\n}\n\nexport function updateValues (device?: Device, updateAll?: boolean)\n{\n    if(!device) {\n        return Promise.reject(\"No device given\");\n    }\n    return new Promise<void>((resolve, _reject) =>\n    {\n        let message = JSON.stringify(\n            {\n                \"msg\": {\n                    \"cmd\": \"devStatus\",\n                    \"data\": {}\n                }\n            }\n        );\n        if (!updateAll)\n        {\n            device.socket.send(message, 0, message.length, 4003, device.ip);\n            resolve();\n        } else\n        {\n            device.socket.send(message, 0, message.length, 4001, \"239.255.255.250\");\n            resolve();\n        }\n    });\n}\n","import { Device } from \"..\";\n\nexport function setOff (this: Device): Promise<void>\n{\n    var device = this;\n    return new Promise((resolve, _reject) =>\n    {\n        let message = JSON.stringify(\n            {\n                msg: {\n                    cmd: \"turn\",\n                    data: {\n                        value: 0\n                    }\n                }\n            }\n        );\n        device.socket?.send(message, 0, message.length, 4003, device.ip, async () =>\n        {\n            device.state.isOn = 0;\n            device.emit(\"updatedStatus\", device.state, [\"onOff\"])\n            resolve();\n        });\n    });\n}\n\n/**\n * @description\n * Turn on a light.\n */\nexport function setOn (this: Device): Promise<void>\n{\n    var device = this;\n    return new Promise((resolve, _reject) =>\n    {\n        let message = JSON.stringify(\n            {\n                msg: {\n                    cmd: \"turn\",\n                    data: {\n                        value: 1\n                    }\n                }\n            }\n        );\n        device.socket?.send(message, 0, message.length, 4003, device.ip, () =>\n        {\n            device.state.isOn = 1;\n            device.emit(\"updatedStatus\", device.state, [\"onOff\"])\n            resolve();\n        });\n    });\n}\n","import { createSocket, Socket } from 'node:dgram';\nimport { networkInterfaces } from 'os';\nconst address = '239.255.255.250';\nconst port = 4002;\n\n\n//? Loop over all network interfaces (that apply) to find one with Govee devices.\nexport function getGoveeDeviceSocket (): Promise<Socket | undefined> {\n    return new Promise((resolve, _reject) =>\n    {\n        const nets = networkInterfaces();\n        var sockets: Socket[] = []\n        var isResolved = false\n\n        //* Modified from https://stackoverflow.com/a/8440736/11186759\n        for (const name of Object.keys(nets))\n        {\n            nets[name]?.forEach((net) =>\n            {\n                const familyV4Value = typeof net.family === 'string' ? 'IPv4' : 4;\n                if (net.family === familyV4Value && !net.internal)\n                {\n                    let socket = createSocket({\n                        type: 'udp4',\n                        reuseAddr: true // for testing multiple instances on localhost\n                    });\n                    sockets.push(socket)\n\n                    socket.once('message', (_msg, _remote) =>\n                    {\n                        resolve(socket);\n                        isResolved = true\n                    });\n\n\n                    socket.bind(port, net.address);\n\n                    socket.on(\"listening\", function ()\n                    {\n                        socket.setBroadcast(true);\n                        socket.setMulticastTTL(128);\n                        socket.addMembership(address);\n                        let message = JSON.stringify(\n                            {\n                                \"msg\": {\n                                    \"cmd\": \"scan\",\n                                    \"data\": {\n                                        \"account_topic\": \"reserve\",\n                                    }\n                                }\n                            }\n                        );\n                        socket.send(message, 0, message.length, 4001, address);\n                    });\n                }\n            });\n        }\n\n        setTimeout(() => {\n            if (!isResolved) {\n                sockets.forEach((socket)=>{\n                    socket.close()\n                })\n                resolve(undefined)\n            }\n        }, 5000);\n    });\n};\n","import { RemoteInfo, Socket } from 'dgram';\nimport { fade, setBrightness, setColor, updateValues } from './commands/setColors';\nimport { setOff, setOn } from './commands/setOnOff';\nimport { getGoveeDeviceSocket } from './commands/createSocket';\nimport { EventEmitter } from 'events';\nimport * as ct from 'color-temperature';\n\nexport interface DeviceState\n{\n    isOn: number,\n    brightness: number,\n    color: { \"r\": number, \"g\": number, \"b\": number; },\n    colorKelvin: number,\n    hasReceivedUpdates: boolean;\n}\n\nexport class Device extends EventEmitter\n{\n    constructor(data: Record<string, any>, GoveeInstance: Govee, socket: Socket)\n    {\n        super();\n        deviceList.set(data.ip, this);\n\n        this.model = data.sku;\n        this.deviceID = data.device;\n        this.ip = data.ip;\n        this.versions = {\n            BLEhardware: data.bleVersionHard,\n            BLEsoftware: data.bleVersionSoft,\n            WiFiHardware: data.wifiVersionHard,\n            WiFiSoftware: data.wifiVersionSoft\n        };\n\n        this.state = {\n            isOn: 0,\n            brightness: 0,\n            color: { \"r\": 0, \"g\": 0, \"b\": 0 },\n            colorKelvin: 0,\n            hasReceivedUpdates: false\n        };\n\n        this.socket = socket;\n        this.updateTimer = setInterval(() =>\n        {\n            this.updateValues();\n        }, 6000);\n\n        // When the status gets changes, emit it on the main class aswell\n        this.on(\"updatedStatus\", (data, stateChanged) =>\n        {\n            GoveeInstance.emit(\"updatedStatus\", this, data, stateChanged);\n        });\n\n        this.goveeInstance = GoveeInstance;\n    }\n    readonly ip: string;\n    readonly deviceID: string;\n    readonly model: string;\n    readonly socket: Socket;\n    readonly goveeInstance: Govee;\n    readonly versions: {\n        BLEhardware: string;\n        BLEsoftware: string;\n        WiFiHardware: string;\n        WiFiSoftware: string;\n    };\n    public state: DeviceState;\n    readonly actions = new actions(this);\n    readonly updateValues = async () => await updateValues(this);\n    private updateTimer: NodeJS.Timer;\n    public destroy = () =>\n    {\n        this.emit(\"destroyed\");\n        clearTimeout(this.updateTimer);\n    };\n}\n\nclass actions\n{\n    constructor(device: Device)\n    {\n        this.device = device;\n    }\n    private device: Device;\n    setColor = (color: colorOptions): Promise<void> => setColor.call(this.device, color);\n\n    /**\n     * @description\n     * Pass a 0-100 value to set the brightness of the device.\n     */\n    setBrightness = (brightness: string | number): Promise<void> => setBrightness.call(this.device, brightness);\n\n    /**\n     * @description\n     * #### Fade the color and brightness of your device.\n     * **Warning**: This works by sending many many commands (At least every 10ms).\n     *\n     * Before the code gets run for sending values, the state of the device gets updated.\n     * ***\n     * Usage:\n     * ```js\n     * fadeColor({\n            time: 2000, // In milliseconds\n            color: {\n                hex: \"#282c34\" // Other options possible\n            },\n            brightness: 20 // 0-100\n        });\n     * ```\n     */\n    fadeColor = (options: fadeOptions): Promise<void> =>\n    {\n        this.cancelFade();\n\n        return fade.bind(this.device)(options)\n    };\n\n    /**\n     * @description Cancels the current fade action\n     *\n     * @param rejectPromises Reject active fade promise\n     */\n    cancelFade = (rejectPromises: boolean = false) => this.device.emit(\"fadeCancel\", rejectPromises);\n\n    /**\n     * @description\n     * Turn off a device.\n     */\n    setOff = (): Promise<void> => setOff.call(this.device);\n\n    /**\n     * @description\n     * Turn on a device.\n     */\n    setOn = (): Promise<void> => setOn.call(this.device);\n}\n\nclass GoveeConfig\n{\n    /**\n     * Automatically start searching for devices when the UDP socket is made.\n     * @default true\n     */\n    startDiscover?: boolean = true;\n    /**\n     * The interval (in ms) at which new devices will be scanned for.\n     * @default 60000 (1 minute)\n     */\n    discoverInterval?: number = 60000;\n\n    logger: (message: string) => void = console.log;\n    errorLogger: (message: string) => void = console.error;\n}\n\n//  TODO: I have no idea why i have to define the variables outside the class. But when they're inside the class, they're always undefined outside of the constructor.\n//? Edit: I do see it now (anonymous functions), but i haven't changed it yet.\nvar deviceList = new Map<string, Device>();\nlet udpSocket: Socket | undefined;\n\nclass Govee extends EventEmitter\n{\n    private config?: GoveeConfig;\n    private isReady = false;\n    constructor(config?: GoveeConfig)\n    {\n        super();\n        this.config = config;\n\n        this.getSocket().then(() =>\n        {\n            this.emit(\"ready\");\n            this.isReady = true;\n        });\n\n        let discoverInterval = 60_000;\n\n        if (config && config.discoverInterval)\n        {\n            discoverInterval = config.discoverInterval;\n        }\n\n        this.once(\"ready\", () =>\n        {\n            this.discoverInterval = setInterval(() =>\n            {\n                this.discover();\n            }, discoverInterval);\n        });\n    }\n\n    private discoverInterval: NodeJS.Timer | null = null;\n\n    private getSocket(): Promise<void> {\n        return new Promise<void>((resolve, _reject) =>\n        {\n            getGoveeDeviceSocket().then(async (socket?: Socket) =>\n            {\n                if (!socket)\n                {\n                    this.config.errorLogger(\"UDP Socket was not estabilished whilst trying to discover new devices.\\n\\nIs the server able to access UDP port 4001 and 4002 on address 239.255.255.250?\");\n                    let whileSocket = undefined;\n                    while (whileSocket == undefined)\n                    {\n                        whileSocket = await this.getSocket();\n                        if (whileSocket == undefined)\n                        {\n                            this.config.errorLogger(\"UDP Socket was not estabilished whilst trying to discover new devices.\\n\\nIs the server able to access UDP port 4001 and 4002 on address 239.255.255.250?\");\n                        }\n                    }\n                    udpSocket = whileSocket;\n                } else\n                {\n                    udpSocket = socket;\n                }\n\n                udpSocket.on(\"message\", this.receiveMessage.bind(this));\n\n                //? Now that we have a socket, we can scan (again)\n                //TODO: Creating the socket and scanning can probably combined into 1, but i don't want to risk it, seeing as i have 1 govee device\n                if (!this.config || this.config.startDiscover)\n                {\n                    this.discover();\n                }\n                if (!this.isReady)\n                {\n                    this.emit(\"ready\");\n                    this.isReady = true;\n                }\n                resolve();\n            });\n        });\n    };\n\n\n    /**\n     * @description\n     * Use this function to re-send the command to scan for devices.\n     *\n     * Note that you typically don't have to run this command yourself.\n     */\n    public discover() {\n        if (!udpSocket)\n        {\n            this.config.errorLogger(\"UDP Socket was not estabilished whilst trying to discover new devices.\\n\\nIs the server able to access UDP port 4001 and 4002 on address 239.255.255.250?\");\n            return;\n        }\n        let message = JSON.stringify(\n            {\n                \"msg\": {\n                    \"cmd\": \"scan\",\n                    \"data\": {\n                        \"account_topic\": \"reserve\",\n                    }\n                }\n            }\n        );\n        udpSocket.send(message, 0, message.length, 4001, \"239.255.255.250\");\n        deviceList.forEach((dev) =>\n        {\n            if(!udpSocket) return;\n            udpSocket.send(message, 0, message.length, 4003, dev.ip);\n            const oldCount = this.discoverTimes.get(dev.ip) ?? 0;\n            this.discoverTimes.set(dev.ip, oldCount + 1);\n\n            if (oldCount >= 4)\n            {\n                this.emit(\"deviceRemoved\", dev);\n                dev.destroy();\n                deviceList.delete(dev.ip);\n            }\n        });\n    };\n\n    private discoverTimes: Map<string, number> = new Map();\n\n    private async receiveMessage(msg: Buffer, rinfo: RemoteInfo) {\n        const msgRes: messageResponse = JSON.parse(msg.toString());\n        if (!udpSocket)\n        {\n            return;\n        }\n        const data = msgRes.msg.data;\n        switch (msgRes.msg.cmd)\n        {\n            case \"scan\":\n                this.onScanMessage(data);\n                break;\n\n            case \"devStatus\":\n                this.onDevStatusMessage(rinfo, data);\n                break;\n\n            default:\n                break;\n        }\n    };\n\n\n    private onDevStatusMessage(rinfo: RemoteInfo, data: Record<string, any>): void {\n        const device = deviceList.get(rinfo.address);\n        if (!device) {\n            return;\n        }\n\n        const oldState = JSON.parse(JSON.stringify(device.state));\n        device.state.brightness = data.brightness;\n        device.state.isOn = data.onOff;\n        device.state.color = data.color;\n\n        if (!data.color.colorTemInKelvin) {\n            device.state.colorKelvin = ct.rgb2colorTemperature({red: data.color.r, green: data.color.g, blue: data.color.b});\n        } else {\n            device.state.colorKelvin = data.color.colorTemInKelvin;\n        }\n\n        const stateChanged: stateChangedOptions = [];\n        const colorChanged = oldState.color.r !== data.color.r || oldState.color.g !== data.color.g || oldState.color.b !== data.color.b;\n        const brightnessChanged = oldState.brightness !== data.brightness;\n        const onOffChanged = oldState.isOn !== data.onOff;\n\n        //* This may seem like a weird way of doing things, but i want to first get the full state of the device, then i can say it has been added\n        if (!device.state.hasReceivedUpdates) {\n            device.state.hasReceivedUpdates = true;\n            this.emit('deviceAdded', device);\n        }\n\n        if (brightnessChanged) {\n            stateChanged.push('brightness');\n        }\n        if (colorChanged) {\n            stateChanged.push('color');\n        }\n        if (onOffChanged) {\n            stateChanged.push('onOff');\n        }\n        device.emit('updatedStatus', device.state, stateChanged as stateChangedOptions);\n        // eventEmitter.emit(\"updatedStatus\", device, device.state, stateChanged);\n    }\n\n    private onScanMessage(data: Record<string, any>): void {\n        const oldList = Array.from(deviceList.values());\n        if (!deviceList.has(data.ip)) {\n            if(!udpSocket) return;\n            var device = new Device(data, this, udpSocket);\n            device.updateValues();\n        }\n        this.discoverTimes.set(data.ip, 0);\n        oldList.forEach((device) => {\n            if (!deviceList.has(device.ip)) {\n                this.emit('deviceRemoved', device);\n                device.destroy();\n                deviceList.delete(device.ip);\n            }\n        });\n    }\n\n    /**\n     * A map of devices where the devices' IP is the key, and the Device object is the value.\n     */\n    public get devicesMap (): Map<string, Device>\n    {\n        return deviceList;\n    }\n    /**\n     * An array of all devices.\n     */\n    public get devicesArray (): Device[]\n    {\n        return Array.from(deviceList.values());\n    }\n\n    /**\n     * Retrieve the values of all devices.\n     */\n    public async updateAllDevices ()\n    {\n        const updatePromises = this.devicesArray.map((device) => device.updateValues);\n        await Promise.all(updatePromises);\n        return;\n    }\n\n    public destroy ()\n    {\n        this.removeAllListeners();\n        deviceList = new Map<string, Device>();\n        udpSocket?.close();\n        udpSocket = undefined;\n        if(this.discoverInterval !== null) {\n            clearInterval(this.discoverInterval);\n            this.discoverInterval = null;\n        }\n        //? Loop over all devices and clear their timeouts\n        deviceList.forEach((device) =>\n        {\n            device.destroy();\n        });\n    }\n}\n\nexport default Govee;\n\ninterface messageResponse\n{\n    msg: {\n        cmd: \"devStatus\" | \"scan\",\n        data: Record<string, any>;\n    };\n}\n\nexport interface DataResponseStatus\n{\n    onOff: 0 | 1;\n    brightness: number;\n    color: {\n        r: number;\n        g: number;\n        b: number;\n    };\n    colorTemInKelvin: number;\n}\n\nexport type stateChangedOptions = (\"onOff\" | \"brightness\" | \"color\" | undefined)[];\n\nexport interface fadeOptions\n{\n    time: number;\n    color?: colorOptions;\n    brightness?: number;\n}\n\ninterface colorOptionsHex\n{\n    hex: string;\n    rgb?: never;\n    hsl?: never;\n    kelvin?: never;\n}\ninterface colorOptionsRGB\n{\n    hex?: never;\n    rgb: [number, number, number];\n    hsl?: never;\n    kelvin?: never;\n}\ninterface colorOptionsHSL\n{\n    hex?: never;\n    rgb?: never;\n    hsl: [number, number, number];\n    kelvin?: never;\n}\ninterface colorOptionsKelvin\n{\n    hex?: never;\n    rgb?: never;\n    hsl?: never;\n    kelvin: string | number;\n}\nexport type colorOptions = colorOptionsHex | colorOptionsRGB | colorOptionsHSL | colorOptionsKelvin;\n\n\ntype DeviceEventTypes =\n    {\n        updatedStatus: (data: DeviceState, stateChanged: stateChangedOptions) => void;\n        fadeCancel: (rejectPromises: boolean) => void;\n        destroyed: () => void;\n    };\n\nexport declare interface Device\n{\n    addListener<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n    on<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n    once<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n    prependListener<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n    prependOnceListener<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n\n    off<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n    removeAllListeners<E extends keyof DeviceEventTypes> (event?: E): this;\n    removeListener<E extends keyof DeviceEventTypes> (event: E, listener: DeviceEventTypes[E]): this;\n\n    emit<E extends keyof DeviceEventTypes> (event: E, ...args: Parameters<DeviceEventTypes[E]>): boolean;\n    // The sloppy `eventNames()` return type is to mitigate type incompatibilities - see #5\n    eventNames (): (keyof DeviceEventTypes | string | symbol)[];\n    rawListeners<E extends keyof DeviceEventTypes> (event: E): DeviceEventTypes[E][];\n    listeners<E extends keyof DeviceEventTypes> (event: E): DeviceEventTypes[E][];\n    listenerCount<E extends keyof DeviceEventTypes> (event: E): number;\n\n    getMaxListeners (): number;\n    setMaxListeners (maxListeners: number): this;\n}\n\ntype GoveeEventTypes = {\n    ready: () => void;\n    deviceAdded: (device: Device) => void;\n    deviceRemoved: (device: Device) => void;\n    updatedStatus: (device: Device, data: DeviceState, stateChanged: stateChangedOptions) => void;\n};\n\ninterface Govee\n{\n    addListener<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n    on<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n    once<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n    prependListener<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n    prependOnceListener<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n\n    off<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n    removeAllListeners<E extends keyof GoveeEventTypes> (event?: E): this;\n    removeListener<E extends keyof GoveeEventTypes> (event: E, listener: GoveeEventTypes[E]): this;\n\n    emit<E extends keyof GoveeEventTypes> (event: E, ...args: Parameters<GoveeEventTypes[E]>): boolean;\n    // The sloppy `eventNames()` return type is to mitigate type incompatibilities - see #5\n    eventNames (): (keyof GoveeEventTypes | string | symbol)[];\n    rawListeners<E extends keyof GoveeEventTypes> (event: E): GoveeEventTypes[E][];\n    listeners<E extends keyof GoveeEventTypes> (event: E): GoveeEventTypes[E][];\n    listenerCount<E extends keyof GoveeEventTypes> (event: E): number;\n\n    getMaxListeners (): number;\n    setMaxListeners (maxListeners: number): this;\n}\n"],"mappings":"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","names":["rgb","percent","newColor","targetKelvin","ct","data","device"]}