UNPKG

@reactsaaskit/hue-node-integration

Version:

A TypeScript package for Philips Hue Bridge Api v2 integration for Node.js. Supports esm and cjs

1 lines β€’ 80.8 kB
{"version":3,"sources":["../src/index.ts","../src/HueIntegration.ts","../src/methods/connectBridge.ts","../src/methods/getBridgeInfo.ts","../src/methods/eventStream.ts","../src/methods/getTemperature.ts","../src/methods/getLightLevel.ts","../src/methods/getLights.ts","../src/methods/getLight.ts","../src/methods/getScenes.ts","../src/methods/setScene.ts","../src/methods/setLight.ts","../src/methods/setLightPower.ts","../src/methods/setLightColor.ts","../src/methods/setGradient.ts","../src/methods/setLightColorGradient.ts","../src/methods/getGroups.ts","../src/methods/setGroup.ts","../src/methods/setGroups.ts","../src/methods/getRooms.ts","../src/methods/turnoffAllLights.ts","../src/methods/turnOffAllLightsExceptPlugs.ts","../src/methods/getEntertainmentAreas.ts","../src/HueIntegrationV1.ts"],"sourcesContent":["export { HueIntegration } from \"./HueIntegration.js\";\r\nexport { HueIntegrationV1 } from \"./HueIntegrationV1.js\";","import axios from \"axios\";\r\nimport https from \"https\";\r\n\r\nimport { connectBridge } from \"./methods/connectBridge.js\";\r\nimport { getBridgeInfo } from \"./methods/getBridgeInfo.js\";\r\nimport { startEventStream } from \"./methods/eventStream.js\";\r\nimport { getTemperature } from \"./methods/getTemperature.js\";\r\nimport { getMLightLevel } from \"./methods/getLightLevel.js\";\r\nimport { getLights } from \"./methods/getLights.js\";\r\nimport { getLight } from \"./methods/getLight.js\";\r\nimport { getScenes } from \"./methods/getScenes.js\";\r\nimport { setScene } from \"./methods/setScene.js\";\r\nimport { setLight } from \"./methods/setLight.js\";\r\nimport { setLightPower } from \"./methods/setLightPower.js\";\r\nimport { setLightColor } from \"./methods/setLightColor.js\";\r\nimport { setGradient } from \"./methods/setGradient.js\";\r\nimport { setLightColorGradient } from \"./methods/setLightColorGradient.js\";\r\nimport { getGroups } from \"./methods/getGroups.js\";\r\nimport { setGroup } from \"./methods/setGroup.js\";\r\nimport { setGroups } from \"./methods/setGroups.js\";\r\nimport { getRooms } from \"./methods/getRooms.js\";\r\nimport { turnOffAllLights } from \"./methods/turnoffAllLights.js\";\r\nimport { turnOffAllLightsExceptPlugs } from \"./methods/turnOffAllLightsExceptPlugs.js\";\r\nimport { getEntertainmentAreas, EntertainmentArea } from \"./methods/getEntertainmentAreas.js\";\r\n\r\n// https://developers.meethue.com/develop/application-design-guidance/using-https/\r\nconst certificate = `-----BEGIN CERTIFICATE-----\r\nMIICMjCCAdigAwIBAgIUO7FSLbaxikuXAljzVaurLXWmFw4wCgYIKoZIzj0EAwIw\r\nOTELMAkGA1UEBhMCTkwxFDASBgNVBAoMC1BoaWxpcHMgSHVlMRQwEgYDVQQDDAty\r\nb290LWJyaWRnZTAiGA8yMDE3MDEwMTAwMDAwMFoYDzIwMzgwMTE5MDMxNDA3WjA5\r\nMQswCQYDVQQGEwJOTDEUMBIGA1UECgwLUGhpbGlwcyBIdWUxFDASBgNVBAMMC3Jv\r\nb3QtYnJpZGdlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjNw2tx2AplOf9x86\r\naTdvEcL1FU65QDxziKvBpW9XXSIcibAeQiKxegpq8Exbr9v6LBnYbna2VcaK0G22\r\njOKkTqOBuTCBtjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNV\r\nHQ4EFgQUZ2ONTFrDT6o8ItRnKfqWKnHFGmQwdAYDVR0jBG0wa4AUZ2ONTFrDT6o8\r\nItRnKfqWKnHFGmShPaQ7MDkxCzAJBgNVBAYTAk5MMRQwEgYDVQQKDAtQaGlsaXBz\r\nIEh1ZTEUMBIGA1UEAwwLcm9vdC1icmlkZ2WCFDuxUi22sYpLlwJY81Wrqy11phcO\r\nMAoGCCqGSM49BAMCA0gAMEUCIEBYYEOsa07TH7E5MJnGw557lVkORgit2Rm1h3B2\r\nsFgDAiEA1Fj/C3AN5psFMjo0//mrQebo0eKd3aWRx+pQY08mk48=\r\n-----END CERTIFICATE-----`;\r\n\r\nexport class HueIntegration {\r\n private apiKey: string;\r\n private bridgeIp: string;\r\n private axiosInstance: any;\r\n private eventSource?: { close: () => void };\r\n\r\n constructor(apiKey: string, bridgeIp: string = \"192.168.1.105\") {\r\n this.apiKey = apiKey;\r\n this.bridgeIp = bridgeIp;\r\n\r\n // Create an Axios instance with the provided certificate for secure communication\r\n this.axiosInstance = axios.create({\r\n baseURL: `https://${this.bridgeIp}/clip/v2/resource`,\r\n httpsAgent: new https.Agent({\r\n ca: certificate,\r\n rejectUnauthorized: false,\r\n }),\r\n headers: {\r\n \"hue-application-key\": this.apiKey,\r\n \"Content-Type\": \"application/json\",\r\n },\r\n });\r\n }\r\n\r\n connectBridge(appName: string): Promise<any> {\r\n return connectBridge(appName, this.bridgeIp);\r\n }\r\n\r\n async getBridgeInfo(): Promise<any> {\r\n return await getBridgeInfo(this.axiosInstance);\r\n }\r\n\r\n async getTemperature(): Promise<any> {\r\n return await getTemperature(this.axiosInstance);\r\n }\r\n\r\n async getMLightLevel(): Promise<any> {\r\n return await getMLightLevel(this.axiosInstance);\r\n }\r\n\r\n // New getLight method\r\n async getLight(lightId: string): Promise<any> {\r\n return await getLight(this.axiosInstance, lightId);\r\n }\r\n \r\n async getLights(): Promise<any> {\r\n return await getLights(this.axiosInstance);\r\n }\r\n\r\n async getRooms(): Promise<any[]> {\r\n return await getRooms(this.axiosInstance);\r\n }\r\n\r\n async getScenes(): Promise<any[]> {\r\n return await getScenes(this.axiosInstance);\r\n }\r\n\r\n async setScene(sceneId: string): Promise<boolean> {\r\n return await setScene(this.axiosInstance, sceneId);\r\n }\r\n\r\n async setLight(\r\n lightId: string,\r\n xyColor?: { x: number; y: number },\r\n isOn?: boolean,\r\n brightness?: number,\r\n transition?: number\r\n ): Promise<boolean> {\r\n return await setLight(\r\n this.axiosInstance,\r\n lightId,\r\n xyColor,\r\n isOn,\r\n brightness,\r\n transition\r\n );\r\n }\r\n\r\n async setGradient(\r\n lightId: string,\r\n gradientColors: { x: number; y: number }[],\r\n isOn: boolean,\r\n brightness: number,\r\n transition: number\r\n ): Promise<boolean> {\r\n return await setGradient(\r\n this.axiosInstance,\r\n lightId,\r\n gradientColors,\r\n isOn,\r\n brightness,\r\n transition\r\n );\r\n }\r\n\r\n async setLightPower(lightId: string, isOn: boolean): Promise<boolean> {\r\n return await setLightPower(this.axiosInstance, lightId, isOn);\r\n }\r\n\r\n async setLightColorGradient(\r\n lightId: string,\r\n gradientColors: { x: number; y: number }[],\r\n brightness: number,\r\n transition: number\r\n ): Promise<boolean> {\r\n return await setLightColorGradient(\r\n this.axiosInstance,\r\n lightId,\r\n gradientColors,\r\n brightness,\r\n transition\r\n );\r\n }\r\n\r\n async setLightColor(\r\n lightId: string,\r\n xyColor?: { x: number; y: number },\r\n brightness?: number,\r\n transition?: number\r\n ): Promise<boolean> {\r\n return await setLightColor(this.axiosInstance, lightId, xyColor, brightness, transition);\r\n }\r\n\r\n async getGroups(): Promise<any[]> {\r\n return await getGroups(this.axiosInstance);\r\n }\r\n\r\n async setGroups(\r\n groupIds: string[],\r\n brightness?: number,\r\n xyColor?: { x: number; y: number },\r\n isOn?: boolean\r\n ): Promise<boolean> {\r\n return await setGroups(\r\n this.axiosInstance,\r\n groupIds,\r\n brightness,\r\n xyColor,\r\n isOn\r\n );\r\n }\r\n\r\n async setGroup(\r\n groupId: string,\r\n brightness?: number,\r\n xyColor?: { x: number; y: number },\r\n isOn?: boolean\r\n ): Promise<boolean> {\r\n return await setGroup(\r\n this.axiosInstance,\r\n groupId,\r\n brightness,\r\n xyColor,\r\n isOn\r\n );\r\n }\r\n\r\n async turnOffAllLights(): Promise<boolean> {\r\n return await turnOffAllLights(this.axiosInstance);\r\n }\r\n async turnOffAllLightsExceptPlugs(): Promise<boolean> {\r\n return await turnOffAllLightsExceptPlugs(this.axiosInstance);\r\n }\r\n\r\n startEventStream(\r\n onMessage: (data: any) => void,\r\n onError?: (error: any) => void\r\n ): void {\r\n if (this.eventSource) {\r\n console.warn(\"Event stream is already running.\");\r\n return;\r\n }\r\n\r\n this.eventSource = startEventStream(\r\n this.bridgeIp,\r\n this.apiKey,\r\n onMessage,\r\n onError\r\n );\r\n }\r\n\r\n stopEventStream(): void {\r\n if (this.eventSource) {\r\n this.eventSource.close();\r\n this.eventSource = undefined;\r\n console.log(\"πŸ”Œ Event stream stopped.\");\r\n } else {\r\n console.warn(\"No event stream to stop.\");\r\n }\r\n }\r\n\r\n\r\n /**\r\n * Retrieve all entertainment-area configurations.\r\n */\r\n async getEntertainmentAreas(): Promise<EntertainmentArea[]> {\r\n return await getEntertainmentAreas(this.axiosInstance);\r\n }\r\n}\r\n","import axios from \"axios\";\r\nimport https from \"https\";\r\n\r\nexport interface BridgeCredentials {\r\n username: string;\r\n clientkey: string;\r\n}\r\n\r\n/**\r\n * Register with the Hue Bridge and retrieve both the CLIP API username\r\n * and the Entertainment clientkey in one request.\r\n *\r\n * @param appName – your app identifier, e.g. \"my-hue-app\"\r\n * @param bridgeIp – the Hue Bridge’s LAN IP\r\n * @returns an object containing { username, clientkey }\r\n */\r\nexport async function connectBridge(\r\n appName: string,\r\n bridgeIp: string\r\n): Promise<BridgeCredentials> {\r\n console.log(`Press the button on your Hue Bridge to proceed...`);\r\n\r\n const maxRetries = 30;\r\n let retries = 0;\r\n\r\n while (retries < maxRetries) {\r\n try {\r\n const response = await axios.post(\r\n `https://${bridgeIp}/api`,\r\n {\r\n devicetype: appName || \"my-hue-app\",\r\n generateclientkey: true\r\n },\r\n {\r\n httpsAgent: new https.Agent({ rejectUnauthorized: false })\r\n }\r\n );\r\n\r\n console.log(\"πŸ” Full response from Hue Bridge:\", response.data);\r\n const entry = response.data[0];\r\n\r\n if (entry?.success) {\r\n const { username, clientkey } = entry.success;\r\n console.log(`βœ… Registered username: ${username}`);\r\n console.log(`βœ… Received clientkey: ${clientkey}`);\r\n return { username, clientkey };\r\n }\r\n\r\n if (entry?.error?.type === 101) {\r\n console.log(` Waiting for button press... (${retries + 1}/${maxRetries})`);\r\n retries++;\r\n await new Promise((res) => setTimeout(res, 2000));\r\n continue;\r\n }\r\n\r\n throw new Error(`Unexpected response: ${JSON.stringify(entry)}`);\r\n } catch (err: any) {\r\n console.error(\"Request failed:\", err.message);\r\n throw err;\r\n }\r\n }\r\n\r\n throw new Error(\"❌ Failed to register after 30 attempts.\");\r\n}","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getBridgeInfo(axiosInstance: AxiosInstance): Promise<any> {\r\n try {\r\n // Fetch Bridge Info\r\n const response = await axiosInstance.get(\"/bridge\");\r\n const bridgeData = response.data.data[0];\r\n\r\n if (!bridgeData) {\r\n console.log(\" No bridge information found.\");\r\n return null;\r\n }\r\n\r\n // Structure the bridge info\r\n const bridgeInfo = {\r\n bridgeId: bridgeData?.bridge_id || \"N/A\",\r\n modelId: bridgeData?.model_id || \"N/A\",\r\n apiVersion: bridgeData?.apiversion || \"N/A\",\r\n };\r\n\r\n console.log(\" Successfully connected to Hue Bridge!\");\r\n console.log(\" Bridge ID:\", bridgeInfo.bridgeId);\r\n console.log(\" Model:\", bridgeInfo.modelId);\r\n console.log(\" Firmware Version:\", bridgeInfo.apiVersion);\r\n\r\n return bridgeInfo;\r\n } catch (err: any) {\r\n console.error(\" Failed to retrieve bridge info:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return null;\r\n }\r\n}\r\n","import https from \"https\";\r\n\r\nexport const startEventStream = (\r\n bridgeIp: string,\r\n apiKey: string,\r\n onMessage: (data: any) => void,\r\n onError?: (error: any) => void\r\n): { close: () => void } => {\r\n const url = `/eventstream/clip/v2`;\r\n\r\n console.log(`Connecting to EventStream at https://${bridgeIp}${url}...`);\r\n\r\n let isClosed = false;\r\n let buffer = \"\";\r\n\r\n // HTTPS request options\r\n const options = {\r\n hostname: bridgeIp,\r\n path: url,\r\n method: \"GET\",\r\n headers: {\r\n \"hue-application-key\": apiKey,\r\n \"Accept\": \"text/event-stream\",\r\n \"Cache-Control\": \"no-cache\",\r\n \"Connection\": \"keep-alive\",\r\n },\r\n rejectUnauthorized: false, // Ignore self-signed certificates\r\n };\r\n\r\n const req = https.request(options, (res) => {\r\n console.log(\"EventStream connected successfully.\");\r\n\r\n res.on(\"data\", (chunk: Buffer) => {\r\n if (isClosed) return;\r\n\r\n // Append incoming data to buffer\r\n buffer += chunk.toString();\r\n\r\n // Split buffer by newline (SSE messages are newline-separated)\r\n const lines = buffer.split(\"\\n\");\r\n\r\n let eventType = \"unknown\"; // Store `event:` value\r\n let eventId = \"unknown\"; // Store `id:` value\r\n\r\n for (const line of lines) {\r\n const trimmedLine = line.trim();\r\n\r\n if (trimmedLine.startsWith(\"event:\")) {\r\n eventType = trimmedLine.replace(\"event:\", \"\").trim();\r\n }\r\n\r\n if (trimmedLine.startsWith(\"id:\")) {\r\n eventId = trimmedLine.replace(\"id:\", \"\").trim();\r\n }\r\n\r\n if (trimmedLine.startsWith(\"data:\")) {\r\n const jsonString = trimmedLine.replace(\"data:\", \"\").trim();\r\n\r\n try {\r\n const parsedData = JSON.parse(jsonString);\r\n\r\n // Handle **multiple** events in a single batch properly\r\n if (Array.isArray(parsedData)) {\r\n parsedData.forEach((event) => {\r\n onMessage({ eventType, eventId, event });\r\n });\r\n } else {\r\n onMessage({ eventType, eventId, parsedData });\r\n }\r\n } catch (err) {\r\n console.error(\"Error parsing event data:\", err);\r\n }\r\n }\r\n }\r\n\r\n // Keep last partial event in buffer\r\n buffer = lines[lines.length - 1];\r\n });\r\n\r\n res.on(\"end\", () => {\r\n console.log(\"πŸ”Œ EventStream ended. Reconnecting...\");\r\n if (!isClosed) {\r\n setTimeout(() => startEventStream(bridgeIp, apiKey, onMessage, onError), 2000);\r\n }\r\n });\r\n\r\n res.on(\"error\", (error: any) => {\r\n console.error(\" Error in EventStream:\", error);\r\n if (onError) onError(error);\r\n });\r\n });\r\n\r\n req.on(\"error\", (error) => {\r\n console.error(\"Failed to connect to EventStream:\", error);\r\n if (onError) onError(error);\r\n\r\n // Retry connection\r\n if (!isClosed) {\r\n setTimeout(() => startEventStream(bridgeIp, apiKey, onMessage, onError), 2000);\r\n }\r\n });\r\n\r\n req.end();\r\n\r\n // Return object with a `close` method\r\n return {\r\n close: () => {\r\n isClosed = true;\r\n req.destroy();\r\n console.log(\"πŸ”Œ EventStream connection closed.\");\r\n },\r\n };\r\n};\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getTemperature(axiosInstance: AxiosInstance): Promise<any[]> {\r\n try {\r\n // Step 1: Fetch all devices to get their names\r\n const devicesResponse = await axiosInstance.get(\"/device\");\r\n const devices = devicesResponse.data.data;\r\n\r\n // Create a mapping of device IDs to their names\r\n const deviceMap: Record<string, string> = {};\r\n devices.forEach((device: any) => {\r\n deviceMap[device.id] = device.metadata?.name || \"Unnamed Device\";\r\n });\r\n\r\n // Step 2: Fetch all temperature sensors\r\n const response = await axiosInstance.get(\"/temperature\");\r\n const sensors = response.data.data;\r\n\r\n if (!sensors || sensors.length === 0) {\r\n console.log(\" No temperature sensors found on the Hue Bridge.\");\r\n return [];\r\n }\r\n\r\n console.log(` Found ${sensors.length} temperature sensor(s):`);\r\n\r\n // Build and return structured data\r\n const sensorData = sensors.map((sensor: any, index: number) => {\r\n const deviceName = deviceMap[sensor.owner?.rid] || \"Unknown Device\";\r\n\r\n const sensorObj = {\r\n id: sensor.id || \"N/A\",\r\n deviceName,\r\n temperature: sensor.temperature?.temperature ?? \"N/A\",\r\n };\r\n\r\n console.log(` Sensor ${index + 1}:`);\r\n console.log(\"ID:\", sensorObj.id);\r\n console.log(\"Device Name:\", sensorObj.deviceName);\r\n console.log(\" Temperature:\", sensorObj.temperature, \"Β°C\");\r\n console.log(\"---------------------------------------------------\");\r\n\r\n return sensorObj;\r\n });\r\n\r\n return sensorData;\r\n } catch (err: any) {\r\n console.error(\"Failed to retrieve temperature sensors:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return [];\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getMLightLevel(axiosInstance: AxiosInstance): Promise<any[]> {\r\n try {\r\n // Step 1: Fetch all devices to get their names\r\n const devicesResponse = await axiosInstance.get(\"/device\");\r\n const devices = devicesResponse.data.data;\r\n\r\n // Create a mapping of device IDs to their names\r\n const deviceMap: Record<string, string> = {};\r\n devices.forEach((device: any) => {\r\n deviceMap[device.id] = device.metadata?.name || \"Unnamed Device\";\r\n });\r\n\r\n // Step 2: Fetch all light level sensors\r\n const response = await axiosInstance.get(\"/light_level\");\r\n const sensors = response.data.data;\r\n\r\n if (!sensors || sensors.length === 0) {\r\n console.log(\"No light level sensors found on the Hue Bridge.\");\r\n return [];\r\n }\r\n\r\n console.log(`πŸ”† Found ${sensors.length} light level sensor(s):`);\r\n\r\n // Build and return structured data\r\n const sensorData = sensors.map((sensor: any, index: number) => {\r\n const deviceName = deviceMap[sensor.owner?.rid] || \"Unknown Device\";\r\n\r\n const sensorObj = {\r\n id: sensor.id || \"N/A\",\r\n deviceName,\r\n lightLevel: sensor.light?.light_level ?? \"N/A\",\r\n };\r\n\r\n console.log(`Sensor ${index + 1}:`);\r\n console.log(\"ID:\", sensorObj.id);\r\n console.log(\"Device Name:\", sensorObj.deviceName);\r\n console.log(\"Light Level:\", sensorObj.lightLevel, \"lx\");\r\n console.log(\"---------------------------------------------------\");\r\n\r\n return sensorObj;\r\n });\r\n\r\n return sensorData;\r\n } catch (err: any) {\r\n console.error(\" Failed to retrieve light level sensors:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return [];\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getLights(axiosInstance: AxiosInstance): Promise<any[]> {\r\n try {\r\n // Fetch all lights\r\n const response = await axiosInstance.get(\"/light\");\r\n const lights = response.data.data;\r\n\r\n if (!lights || lights.length === 0) {\r\n console.log(\"No lights found on the Hue Bridge.\");\r\n return [];\r\n }\r\n\r\n //console.log(`Found ${lights.length} light(s) on the Hue Bridge:`);\r\n\r\n // Build structured data\r\n const lightData = lights.map((light: any, index: number) => {\r\n const lightObj = {\r\n id: light.id || \"N/A\",\r\n name: light.metadata?.name || \"Unnamed Light\",\r\n type: light.type || \"Unknown Type\",\r\n isOn: light?.on?.on ? true : false,\r\n brightness: light?.dimming?.brightness || \"N/A\",\r\n xyColor: light.color?.xy ? { x: light.color.xy.x, y: light.color.xy.y } : null,\r\n };\r\n\r\n/* console.log(`Light ${index + 1}:`);\r\n console.log(\"ID:\", lightObj.id);\r\n console.log(\"Name:\", lightObj.name);\r\n console.log(\"Type:\", lightObj.type);\r\n console.log(\"On:\", lightObj.isOn ? \"Yes\" : \"No\");\r\n console.log(\"Brightness:\", lightObj.brightness); */\r\n\r\n/* if (lightObj.xyColor) {\r\n console.log(\"XY Color:\", `(${lightObj.xyColor.x}, ${lightObj.xyColor.y})`);\r\n } */\r\n\r\n //ANCHOR - console.log(\"---------------------------------------------------\");\r\n\r\n return lightObj;\r\n });\r\n\r\n return lightData;\r\n } catch (err: any) {\r\n console.error(\"Failed to retrieve lights:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return [];\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getLight(axiosInstance: AxiosInstance, lightId: string): Promise<any | null> {\r\n try {\r\n // Fetch a specific light by its ID.\r\n const response = await axiosInstance.get(`/light/${lightId}`);\r\n const light = response.data.data;\r\n if (!light) {\r\n console.log(`Light ${lightId} not found on the Hue Bridge.`);\r\n return null;\r\n }\r\n // Build structured data for the specific light.\r\n const lightObj = {\r\n id: light.id || \"N/A\",\r\n name: light.metadata?.name || \"Unnamed Light\",\r\n type: light.type || \"Unknown Type\",\r\n isOn: light?.on?.on ? true : false,\r\n brightness: light?.dimming?.brightness || \"N/A\",\r\n xyColor: light.color?.xy ? { x: light.color.xy.x, y: light.color.xy.y } : null,\r\n };\r\n return lightObj;\r\n } catch (err: any) {\r\n console.error(`Failed to retrieve light ${lightId}:`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return null;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getScenes(axiosInstance: AxiosInstance): Promise<any[]> {\r\n try {\r\n // Fetch all scenes\r\n const response = await axiosInstance.get(\"/scene\");\r\n const scenes = response.data.data;\r\n\r\n if (!scenes || scenes.length === 0) {\r\n console.log(\" No scenes found on the Hue Bridge.\");\r\n return [];\r\n }\r\n\r\n console.log(` Found ${scenes.length} scene(s) on the Hue Bridge:`);\r\n\r\n // Build structured data\r\n const sceneData = scenes.map((scene: any, index: number) => {\r\n const sceneObj = {\r\n id: scene.id || \"N/A\",\r\n name: scene.metadata?.name || \"Unnamed Scene\",\r\n type: scene.type || \"Unknown Type\",\r\n group: scene.group?.rid || \"N/A\",\r\n };\r\n\r\n console.log(`Scene ${index + 1}:`);\r\n console.log(\" ID:\", sceneObj.id);\r\n console.log(\" Name:\", sceneObj.name);\r\n console.log(\" Type:\", sceneObj.type);\r\n console.log(\" Group ID:\", sceneObj.group);\r\n console.log(\"---------------------------------------------------\");\r\n\r\n return sceneObj;\r\n });\r\n\r\n return sceneData;\r\n } catch (err: any) {\r\n console.error(\" Failed to retrieve scenes:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return [];\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function setScene(axiosInstance: AxiosInstance, sceneId: string): Promise<boolean> {\r\n try {\r\n console.log(` Attempting to activate Scene: ${sceneId}`);\r\n console.log(` Checking if Scene exists...`);\r\n\r\n // Step 1: Verify the Scene Exists\r\n const sceneResponse = await axiosInstance.get(\"/scene\");\r\n const scenes = sceneResponse.data.data;\r\n\r\n if (!scenes || scenes.length === 0) {\r\n console.error(\"❌ No scenes found on the Hue Bridge.\");\r\n return false;\r\n }\r\n\r\n const scene = scenes.find((s: any) => s.id === sceneId);\r\n\r\n if (!scene) {\r\n console.error(` Scene ID ${sceneId} not found.`);\r\n console.log(\" Available Scenes:\");\r\n scenes.forEach((s: any) => console.log(` - ${s.id}: ${s.metadata?.name}`));\r\n return false;\r\n }\r\n\r\n console.log(` Scene Found: ${scene.metadata?.name}`);\r\n\r\n // Step 2: Activate the Scene (Correct API Call from cURL Example)\r\n console.log(` Sending request to activate Scene: ${sceneId} using PUT /scene/{sceneId}...`);\r\n \r\n const response = await axiosInstance.put(`/scene/${sceneId}`, {\r\n recall: { action: \"active\" }\r\n });\r\n\r\n if (response.status === 200) {\r\n console.log(` Scene Activated: ${sceneId} `);\r\n return true;\r\n } else {\r\n console.warn(` Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(` Failed to activate scene (${sceneId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"πŸ“œ Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n\r\n/**\r\n * @deprecated Use `setLightPower` and `setLightColor` instead.\r\n * \r\n * Warning: Setting color and on/off state together while the light is off might not always work.\r\n * Turning on the light first and then changing its color is recommended.\r\n */\r\nexport async function setLight(\r\n axiosInstance: AxiosInstance,\r\n lightId: string,\r\n xyColor?: { x: number; y: number }, // Optional XY color\r\n isOn?: boolean, // Optional On/Off state\r\n brightness?: number, // Optional brightness (0-100)\r\n transition?: number // Optional transition time (verify if in ms or seconds)\r\n): Promise<boolean> {\r\n try {\r\n const requestBody: any = {};\r\n\r\n // If isOn is defined, handle it separately\r\n if (isOn !== undefined) {\r\n requestBody.on = { on: isOn };\r\n\r\n if (isOn) {\r\n // When turning on, include brightness, color, and dynamics if provided\r\n if (brightness !== undefined) {\r\n // Optionally, ensure brightness is an integer if required by the API\r\n requestBody.dimming = { brightness };\r\n }\r\n if (xyColor) {\r\n requestBody.color = { xy: { x: xyColor.x, y: xyColor.y } };\r\n }\r\n if (transition && transition > 0) {\r\n // If the API expects seconds, convert to the proper unit here\r\n requestBody.dynamics = { duration: transition };\r\n }\r\n }\r\n // When turning off, we intentionally omit brightness/color/dynamics to avoid conflicts\r\n } else {\r\n // If isOn is not specified, update other parameters if provided\r\n if (brightness !== undefined) {\r\n requestBody.dimming = { brightness };\r\n }\r\n if (xyColor) {\r\n requestBody.color = { xy: { x: xyColor.x, y: xyColor.y } };\r\n }\r\n if (transition && transition > 0) {\r\n requestBody.dynamics = { duration: transition };\r\n }\r\n }\r\n\r\n if (Object.keys(requestBody).length === 0) {\r\n console.error(\"No values provided for update!\");\r\n return false;\r\n }\r\n\r\n const response = await axiosInstance.put(`/light/${lightId}`, requestBody);\r\n\r\n if (response.status === 200) {\r\n return true;\r\n } else {\r\n console.warn(`Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to update light (${lightId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function setLightPower(\r\n axiosInstance: AxiosInstance,\r\n lightId: string,\r\n isOn: boolean\r\n): Promise<boolean> {\r\n try {\r\n const requestBody = {\r\n on: { on: isOn }\r\n };\r\n\r\n const response = await axiosInstance.put(`/light/${lightId}`, requestBody);\r\n\r\n if (response.status === 200) {\r\n return true;\r\n } else {\r\n console.warn(`Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to update light power (${lightId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function setLightColor(\r\n axiosInstance: AxiosInstance,\r\n lightId: string,\r\n xyColor?: { x: number; y: number },\r\n brightness?: number,\r\n transition?: number\r\n): Promise<boolean> {\r\n try {\r\n const requestBody: any = {};\r\n\r\n if (brightness !== undefined) {\r\n requestBody.dimming = { brightness };\r\n }\r\n if (xyColor) {\r\n requestBody.color = { xy: { x: xyColor.x, y: xyColor.y } };\r\n }\r\n if (transition && transition > 0) {\r\n requestBody.dynamics = { duration: transition };\r\n }\r\n\r\n if (Object.keys(requestBody).length === 0) {\r\n console.error(\"No color values provided for update!\");\r\n return false;\r\n }\r\n\r\n const response = await axiosInstance.put(`/light/${lightId}`, requestBody);\r\n\r\n if (response.status === 200) {\r\n return true;\r\n } else {\r\n console.warn(`Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to update light color (${lightId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\n\r\n/**\r\n * @deprecated Use `setLightColorGradient` instead.\r\n *\r\n * Sets the gradient on a light.\r\n * Note: The current implementation sends the on/off command along with the gradient settings.\r\n * It's recommended to separate power state updates from color/gradient updates.\r\n *\r\n * @param axiosInstance - Axios instance to use for HTTP requests.\r\n * @param lightId - ID of the light to update.\r\n * @param gradientColors - Array of XY color points (requires between 2 and 5 points).\r\n * @param isOn - The power state of the light.\r\n * @param brightness - The brightness value.\r\n * @param transition - Transition time.\r\n * @returns A promise that resolves to a boolean indicating success.\r\n */\r\nexport async function setGradient(\r\n axiosInstance: AxiosInstance,\r\n lightId: string,\r\n gradientColors: { x: number; y: number }[], // Array of XY color points\r\n isOn: boolean, // Default ON\r\n brightness: number, // Default brightness\r\n transition: number\r\n): Promise<boolean> {\r\n try {\r\n\r\n if (!gradientColors || gradientColors.length < 2 || gradientColors.length > 7) {\r\n console.error(\"Gradient requires between 2 and 7 color points.\");\r\n return false;\r\n }\r\n\r\n //console.log(`Gradient Points: ${gradientColors.length}`);\r\n gradientColors.forEach((color, index) => {\r\n console.log(`🎨 Point ${index + 1}: (${color.x}, ${color.y})`);\r\n });\r\n\r\n \r\n // Convert transition time from seconds to milliseconds if provided and greater than 0.\r\n let duration: number | undefined;\r\n if (transition && transition > 0) {\r\n duration = transition;\r\n }\r\n\r\n // Build request payload with dynamics.duration instead of a top-level transition property.\r\n const requestBody: any = {\r\n gradient: {\r\n points: gradientColors.map((xy) => ({\r\n color: { xy }\r\n }))\r\n },\r\n on: { on: isOn },\r\n dimming: { brightness },\r\n dynamics: duration ? { duration } : {}\r\n };\r\n\r\n const response = await axiosInstance.put(`/light/${lightId}`, requestBody);\r\n\r\n if (response.status === 200) {\r\n console.log(`Gradient Applied to Light: ${lightId}`);\r\n return true;\r\n } else {\r\n console.warn(`Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to set gradient on light (${lightId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function setLightColorGradient(\r\n axiosInstance: AxiosInstance,\r\n lightId: string,\r\n gradientColors: { x: number; y: number }[], // Array of XY color points\r\n brightness: number, // Brightness value\r\n transition: number // Transition time\r\n): Promise<boolean> {\r\n try {\r\n if (!gradientColors || gradientColors.length < 2 || gradientColors.length > 5) {\r\n console.error(\"Gradient requires between 2 and 5 color points.\");\r\n return false;\r\n }\r\n\r\n gradientColors.forEach((color, index) => {\r\n console.log(`🎨 Point ${index + 1}: (${color.x}, ${color.y})`);\r\n });\r\n\r\n // Use transition time if provided and greater than 0.\r\n let duration: number | undefined;\r\n if (transition && transition > 0) {\r\n duration = transition;\r\n }\r\n\r\n // Build request payload without the power state.\r\n const requestBody: any = {\r\n gradient: {\r\n points: gradientColors.map((xy) => ({\r\n color: { xy }\r\n }))\r\n },\r\n dimming: { brightness },\r\n dynamics: duration ? { duration } : {}\r\n };\r\n\r\n const response = await axiosInstance.put(`/light/${lightId}`, requestBody);\r\n\r\n if (response.status === 200) {\r\n console.log(`Gradient Applied to Light: ${lightId}`);\r\n return true;\r\n } else {\r\n console.warn(`Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to set gradient on light (${lightId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getGroups(axiosInstance: AxiosInstance): Promise<any[]> {\r\n try {\r\n console.log(\" Fetching all `grouped_light` groups...\");\r\n \r\n // Fetch grouped lights\r\n const groupResponse = await axiosInstance.get(\"/grouped_light\");\r\n const groups = groupResponse.data.data;\r\n\r\n if (!groups || groups.length === 0) {\r\n console.log(\" No groups (`grouped_light`) found on the Hue Bridge.\");\r\n return [];\r\n }\r\n\r\n console.log(\"πŸ”Ž Fetching all rooms...\");\r\n \r\n // Fetch rooms to map groups to their parent rooms\r\n const roomResponse = await axiosInstance.get(\"/room\");\r\n const rooms = roomResponse.data.data;\r\n\r\n // Create a mapping of grouped_light IDs to room names\r\n const groupToRoomMap: Record<string, string> = {};\r\n rooms.forEach((room: any) => {\r\n const groupedLightService = room.services.find((s: any) => s.rtype === \"grouped_light\");\r\n if (groupedLightService) {\r\n groupToRoomMap[groupedLightService.rid] = room.metadata?.name || \"Unnamed Room\";\r\n }\r\n });\r\n\r\n console.log(`Found ${groups.length} \\`grouped_light\\` group(s):`);\r\n\r\n // Build structured data\r\n const groupData = groups.map((group: any, index: number) => {\r\n const roomName = groupToRoomMap[group.id] || \"No Linked Room\";\r\n const groupObj = {\r\n id: group.id || \"N/A\",\r\n name: group.metadata?.name || roomName || \"Unnamed Group\",\r\n type: group.type || \"Unknown Type\",\r\n services: group.services?.map((s: any) => s.rtype).join(\", \") || \"N/A\",\r\n linkedRoom: roomName,\r\n };\r\n\r\n console.log(`Group ${index + 1}:`);\r\n console.log(\" ID:\", groupObj.id);\r\n console.log(\"Name:\", groupObj.name);\r\n console.log(\"Type:\", groupObj.type);\r\n console.log(\" Linked Room:\", groupObj.linkedRoom);\r\n console.log(\" Services:\", groupObj.services);\r\n console.log(\"---------------------------------------------------\");\r\n\r\n return groupObj;\r\n });\r\n\r\n return groupData;\r\n } catch (err: any) {\r\n console.error(\" Failed to retrieve groups:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return [];\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function setGroup(\r\n axiosInstance: AxiosInstance,\r\n groupId: string,\r\n brightness?: number, // Optional brightness (0-100)\r\n xyColor?: { x: number; y: number }, // Optional XY color\r\n isOn?: boolean // Optional On/Off state\r\n): Promise<boolean> {\r\n try {\r\n console.log(`Setting Grouped Light: ${groupId}`);\r\n \r\n // Build request payload dynamically based on provided values\r\n const requestBody: any = {};\r\n\r\n if (brightness !== undefined) {\r\n requestBody.dimming = { brightness };\r\n console.log(`Brightness: ${brightness}%`);\r\n }\r\n\r\n if (xyColor) {\r\n requestBody.color = { xy: { x: xyColor.x, y: xyColor.y } };\r\n console.log(`Color XY: (${xyColor.x}, ${xyColor.y})`);\r\n }\r\n\r\n if (isOn !== undefined) {\r\n requestBody.on = { on: isOn };\r\n console.log(`Group Light State: ${isOn ? \"ON\" : \"OFF\"}`);\r\n }\r\n\r\n if (Object.keys(requestBody).length === 0) {\r\n console.error(\" No values provided for update!\");\r\n return false;\r\n }\r\n\r\n console.log(\"Sending request to update grouped light...\");\r\n const response = await axiosInstance.put(`/grouped_light/${groupId}`, requestBody);\r\n\r\n if (response.status === 200) {\r\n console.log(`Grouped Light Updated: ${groupId}`);\r\n return true;\r\n } else {\r\n console.warn(` Unexpected response status: ${response.status}`);\r\n return false;\r\n }\r\n } catch (err: any) {\r\n console.error(`Failed to update grouped light (${groupId}):`, err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\nimport { setGroup } from \"./setGroup.js\";\r\n\r\nexport async function setGroups(\r\n axiosInstance: AxiosInstance,\r\n groupIds: string[], // Array of group IDs\r\n brightness?: number, // Optional brightness (0-100)\r\n xyColor?: { x: number; y: number }, // Optional XY color\r\n isOn?: boolean // Optional On/Off state\r\n): Promise<boolean> {\r\n try {\r\n console.log(`Setting multiple groups (${groupIds.length} groups)...`);\r\n\r\n // Track the status of all updates\r\n const results = await Promise.all(\r\n groupIds.map(async (groupId) => {\r\n console.log(`πŸ”§ Updating Group: ${groupId}`);\r\n const success = await setGroup(axiosInstance, groupId, brightness, xyColor, isOn);\r\n return { groupId, success };\r\n })\r\n );\r\n\r\n // Log results\r\n results.forEach(({ groupId, success }) => {\r\n if (success) {\r\n console.log(`Group ${groupId} updated successfully!`);\r\n } else {\r\n console.log(`❌ Failed to update Group ${groupId}.`);\r\n }\r\n });\r\n\r\n // Return overall success (true if all groups updated successfully)\r\n return results.every((result) => result.success);\r\n } catch (err: any) {\r\n console.error(\"❌ Failed to update multiple groups:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", JSON.stringify(err.response.data, null, 2));\r\n }\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport async function getRooms(axiosInstance: AxiosInstance): Promise<any[]> {\r\n try {\r\n // Fetch all rooms\r\n const response = await axiosInstance.get(\"/room\");\r\n const rooms = response.data.data;\r\n\r\n if (!rooms || rooms.length === 0) {\r\n console.log(\"πŸšͺ No rooms found on the Hue Bridge.\");\r\n return [];\r\n }\r\n\r\n console.log(`πŸšͺ Found ${rooms.length} room(s) on the Hue Bridge:`);\r\n\r\n // Build structured data\r\n const roomData = rooms.map((room: any, index: number) => {\r\n const roomObj = {\r\n id: room.id || \"N/A\",\r\n name: room.metadata?.name || \"Unnamed Room\",\r\n type: room.type || \"Unknown Type\",\r\n services: room.services?.map((s: any) => s.rtype).join(\", \") || \"N/A\",\r\n };\r\n\r\n console.log(` Room ${index + 1}:`);\r\n console.log(\" ID:\", roomObj.id);\r\n console.log(\" Name:\", roomObj.name);\r\n console.log(\" Type:\", roomObj.type);\r\n console.log(\" Services:\", roomObj.services);\r\n console.log(\"---------------------------------------------------\");\r\n\r\n return roomObj;\r\n });\r\n\r\n return roomData;\r\n } catch (err: any) {\r\n console.error(\"❌ Failed to retrieve rooms:\", err.message);\r\n if (err.response) {\r\n console.error(\"Response Data:\", err.response.data);\r\n }\r\n return [];\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\n/**\r\n * Turns off all lights by checking if a grouped_light with id_v1 \"/groups/0\" exists.\r\n * If it exists, it uses that endpoint to turn off all lights.\r\n * @param {AxiosInstance} axiosInstance - Your configured Axios instance for the Hue API.\r\n * @returns {Promise<boolean>} - Returns true if the process was successful, false otherwise.\r\n */\r\nexport async function turnOffAllLights(axiosInstance: AxiosInstance): Promise<boolean> {\r\n try {\r\n // Fetch grouped lights using the Hue API v2 endpoint\r\n const groupedResponse = await axiosInstance.get(\"/grouped_light\");\r\n const groups = groupedResponse.data.data; // assuming grouped lights are in data.data\r\n console.log(\"Grouped lights:\", groups);\r\n \r\n // Look for a group where id_v1 is \"/groups/0\"\r\n const groupZero = groups.find((group: any) => group.id_v1 === \"/groups/0\");\r\n\r\n if (groupZero) {\r\n console.log(\"Group 0 exists. Turning off all lights using grouped_light endpoint.\");\r\n const offPayload = { on: { on: false } };\r\n const offResponse = await axiosInstance.put(`/grouped_light/${groupZero.id}`, offPayload);\r\n if (offResponse.status === 200) {\r\n console.log(\"All lights turned off successfully using grouped_light group 0.\");\r\n return true;\r\n } else {\r\n console.warn(`Unexpected response status: ${offResponse.status}`);\r\n return false;\r\n }\r\n } else {\r\n console.log(\"Group 0 not found. Cannot turn off all lights using this method.\");\r\n return false;\r\n }\r\n } catch (error: any) {\r\n console.error(\"Error in turning off all lights:\", error.message);\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\n/**\r\n * Turns off all lights except those whose metadata.archetype is \"plug\".\r\n * Logs the full lights response for debugging.\r\n * Applies a 250 ms rate limit for every 2 requests.\r\n * @param {AxiosInstance} axiosInstance - Your configured Axios instance for the Hue API.\r\n * @returns {Promise<boolean>} - Returns true if the process was successful.\r\n */\r\nexport async function turnOffAllLightsExceptPlugs(axiosInstance: AxiosInstance): Promise<boolean> {\r\n try {\r\n // Fetch all lights using the Hue API v2 endpoint for individual light resources\r\n const lightsResponse = await axiosInstance.get(\"/light\");\r\n\r\n // Try to extract the array of lights:\r\n let lightsArray: any[] = [];\r\n if (Array.isArray(lightsResponse.data.data)) {\r\n lightsArray = lightsResponse.data.data;\r\n } else if (Array.isArray(lightsResponse.data)) {\r\n lightsArray = lightsResponse.data;\r\n } else {\r\n console.error(\"Unexpected lights response structure:\", lightsResponse.data);\r\n return false;\r\n }\r\n \r\n console.log(\"Full lights array:\", JSON.stringify(lightsArray, null, 2));\r\n\r\n // Arrays to keep track of non-plug lights and plugs filtered out\r\n const nonPlugLightIds: string[] = [];\r\n const filteredOutPlugIds: string[] = [];\r\n\r\n // Filter out lights based on metadata.archetype being \"plug\"\r\n lightsArray.forEach((light: any) => {\r\n const archetype = (light.metadata?.archetype || \"\").toLowerCase();\r\n if (archetype === \"plug\") {\r\n filteredOutPlugIds.push(light.id);\r\n } else {\r\n nonPlugLightIds.push(light.id);\r\n }\r\n });\r\n\r\n // Log the IDs of lights that are filtered out as plugs\r\n/* console.log(\"Filtered out plugs (not turning off):\", filteredOutPlugIds);\r\n console.log(\"Non-plug lights to turn off:\", nonPlugLightIds); */\r\n\r\n if (!nonPlugLightIds.length) {\r\n //console.warn(\"No non-plug lights found.\");\r\n return false;\r\n }\r\n\r\n // Turn off non-plug lights in batches of 2 with a 250 ms delay between batches\r\n for (let i = 0; i < nonPlugLightIds.length; i += 2) {\r\n const batch = nonPlugLightIds.slice(i, i + 2);\r\n await Promise.all(\r\n batch.map(async (lightId) => {\r\n const offPayload = { on: { on: false } };\r\n try {\r\n const offResponse = await axiosInstance.put(`/light/${lightId}`, offPayload);\r\n if (offResponse.status === 200) {\r\n console.log(`Light ${lightId} turned off successfully.`);\r\n } else {\r\n console.warn(`Failed to turn off light ${lightId}. Status: ${offResponse.status}`);\r\n }\r\n } catch (error: any) {\r\n console.error(`Error turning off light ${lightId}:`, error.message);\r\n }\r\n })\r\n );\r\n if (i + 2 < nonPlugLightIds.length) {\r\n await new Promise(resolve => setTimeout(resolve, 250));\r\n }\r\n }\r\n\r\n return true;\r\n } catch (error: any) {\r\n console.error(\"Error turning off lights except plugs:\", error.message);\r\n return false;\r\n }\r\n}\r\n","import { AxiosInstance } from \"axios\";\r\n\r\nexport interface EntertainmentArea {\r\n id: string;\r\n id_v1?: string;\r\n metadata: {\r\n name: string;\r\n };\r\n configuration_type: \"screen\" | \"monitor\" | \"music\" | \"3dspace\" | \"other\";\r\n status: \"active\" | \"inactive\";\r\n active_streamer?: { rid: string; rtype: string };\r\n stream_proxy: {\r\n mode: \"auto\" | \"manual\";\r\n node: { rid: string; rtype: string };\r\n };\r\n channels: Array<{\r\n channel_id: number;\r\n position: { x: number; y: number; z: number };\r\n members: Array<{ rid: string; rtype: string; index: number }>;\r\n }>;\r\n service_locations: Array<{\r\n service: { rid: string; rtype: string };\r\n positions: Array<{ x: number; y: number; z: number }>;\r\n equalization_factor: number;\r\n }>;\r\n}\r\n\r\nexport async function getEntertainmentAreas(\r\n axiosInstance: AxiosInstance\r\n): Promise<EntertainmentArea[]> {\r\n try {\r\n const response = await axiosInstance.get(\"/entertainment_configuration\");\r\n const areas: EntertainmentArea[] = response.data.data;\r\n return areas;\r\n } catch (err: any) {\r\n console.error(\"Failed to retrieve entertainment areas:\", err.message);\r\n return [];\r\n }\r\n}\r\n","import axios, { AxiosInstance } from \"axios\";\r\n\r\n/**\r\n * V1 version of setLight.\r\n * \r\n * - Converts brightness from a 0–100 scale to Hue API v1 brightness (1–254).\r\n * - Converts transition time from milliseconds to deciseconds (1 decisecond = 100 ms).\r\n * - Expects color as an XY array.\r\n * - Uses the /lights/{lightId}/state endpoint.\r\n */\r\nexport async function setLightV1(\r\n axiosInstance: AxiosInstance,\r\n lightId: string,\r\n xyColor?: { x: number; y: number },\r\n isOn?: boolean,\r\n brightness?: number, // expected value in 0–100 scale\r\n transition?: number // transition in milliseconds\r\n): Promise<boolean> {\r\n try {\r\n const requestBody: any = {};\r\n\r\n // Handle on/off state\r\n if (isOn !== undefined) {\r\n requestBody.on = isOn;\r\n if (isOn) {\r\n if (brightness !== undefined) {\r\n // Convert brightness from 0–100 to 1–254\r\n const bri = Math.max(1, Math.round((brightness / 100) * 254));\r\n requestBody.bri = bri;\r\n }\r\n if (xyColor) {\r\n // V1 expects an array for XY color.\r\n requestBody.xy = [xyColor.x, xyColor.y];\r\n }\r\n if (transition && transition > 0) {\r\n // Convert transition from ms to deciseconds.\r\n requestBody.transitiontime = Math.round(transition / 100);\r\n }\r\n }\r\n } else {\r\n // If isOn isn't provided, update other parameters if given.\r\n if (brightness !== undefined) {\r\n const bri = Math.max(1, Math.round((brightness / 100) * 254));\r\n requestBody.bri = bri;\r\n }\r\n if (xyColor) {\r\n req