node-red-contrib-huemagic 4.2.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -5
- package/README.md +506 -123
- package/examples/Deutsch/Hue Automation.json +176 -0
- package/examples/Deutsch/Hue Bridge.json +256 -0
- package/examples/Deutsch/Hue Brightness.json +150 -0
- package/examples/Deutsch/Hue Buttons.json +88 -0
- package/examples/Deutsch/Hue Contact.json +150 -0
- package/examples/Deutsch/Hue Group.json +658 -0
- package/examples/Deutsch/Hue Light.json +893 -0
- package/examples/Deutsch/Hue Magic.json +148 -0
- package/examples/Deutsch/Hue Motion.json +150 -0
- package/examples/Deutsch/Hue Rules.json +150 -0
- package/examples/Deutsch/Hue Scene.json +178 -0
- package/examples/Deutsch/Hue Speaker.json +274 -0
- package/examples/Deutsch/Hue Sync Box.json +378 -0
- package/examples/Deutsch/Hue Temperature.json +150 -0
- package/examples/English/Hue Automation.json +176 -0
- package/examples/{Hue Bridge.json → English/Hue Bridge.json } +1 -1
- package/examples/{Hue Brightness.json → English/Hue Brightness.json } +1 -1
- package/examples/{Hue Buttons.json → English/Hue Buttons.json } +1 -1
- package/examples/English/Hue Contact.json +150 -0
- package/examples/{Hue Group.json → English/Hue Group.json } +1 -1
- package/examples/{Hue Light.json → English/Hue Light.json } +1 -1
- package/examples/{Hue Magic.json → English/Hue Magic.json } +1 -1
- package/examples/{Hue Motion.json → English/Hue Motion.json } +1 -1
- package/examples/{Hue Rules.json → English/Hue Rules.json } +1 -1
- package/examples/{Hue Scene.json → English/Hue Scene.json } +1 -1
- package/examples/English/Hue Speaker.json +274 -0
- package/examples/English/Hue Sync Box.json +378 -0
- package/examples/{Hue Temperature.json → English/Hue Temperature.json } +1 -1
- package/examples/Espa/303/261ol/Hue Automation.json" +176 -0
- package/examples/Espa/303/261ol/Hue Bridge.json" +256 -0
- package/examples/Espa/303/261ol/Hue Brightness.json" +150 -0
- package/examples/Espa/303/261ol/Hue Buttons.json" +88 -0
- package/examples/Espa/303/261ol/Hue Contact.json" +150 -0
- package/examples/Espa/303/261ol/Hue Group.json" +658 -0
- package/examples/Espa/303/261ol/Hue Light.json" +893 -0
- package/examples/Espa/303/261ol/Hue Magic.json" +148 -0
- package/examples/Espa/303/261ol/Hue Motion.json" +150 -0
- package/examples/Espa/303/261ol/Hue Rules.json" +150 -0
- package/examples/Espa/303/261ol/Hue Scene.json" +178 -0
- package/examples/Espa/303/261ol/Hue Speaker.json" +274 -0
- package/examples/Espa/303/261ol/Hue Sync Box.json" +378 -0
- package/examples/Espa/303/261ol/Hue Temperature.json" +150 -0
- package/examples/Fran/303/247ais/Hue Automation.json" +176 -0
- package/examples/Fran/303/247ais/Hue Bridge.json" +256 -0
- package/examples/Fran/303/247ais/Hue Brightness.json" +150 -0
- package/examples/Fran/303/247ais/Hue Buttons.json" +88 -0
- package/examples/Fran/303/247ais/Hue Contact.json" +150 -0
- package/examples/Fran/303/247ais/Hue Group.json" +658 -0
- package/examples/Fran/303/247ais/Hue Light.json" +893 -0
- package/examples/Fran/303/247ais/Hue Magic.json" +148 -0
- package/examples/Fran/303/247ais/Hue Motion.json" +150 -0
- package/examples/Fran/303/247ais/Hue Rules.json" +150 -0
- package/examples/Fran/303/247ais/Hue Scene.json" +178 -0
- package/examples/Fran/303/247ais/Hue Speaker.json" +274 -0
- package/examples/Fran/303/247ais/Hue Sync Box.json" +378 -0
- package/examples/Fran/303/247ais/Hue Temperature.json" +150 -0
- package/examples/Italiano/Hue Automation.json +176 -0
- package/examples/Italiano/Hue Bridge.json +256 -0
- package/examples/Italiano/Hue Brightness.json +150 -0
- package/examples/Italiano/Hue Buttons.json +88 -0
- package/examples/Italiano/Hue Contact.json +150 -0
- package/examples/Italiano/Hue Group.json +658 -0
- package/examples/Italiano/Hue Light.json +893 -0
- package/examples/Italiano/Hue Magic.json +148 -0
- package/examples/Italiano/Hue Motion.json +150 -0
- package/examples/Italiano/Hue Rules.json +150 -0
- package/examples/Italiano/Hue Scene.json +178 -0
- package/examples/Italiano/Hue Speaker.json +274 -0
- package/examples/Italiano/Hue Sync Box.json +378 -0
- package/examples/Italiano/Hue Temperature.json +150 -0
- package/examples/Nederlands/Hue Automation.json +176 -0
- package/examples/Nederlands/Hue Bridge.json +256 -0
- package/examples/Nederlands/Hue Brightness.json +150 -0
- package/examples/Nederlands/Hue Buttons.json +88 -0
- package/examples/Nederlands/Hue Contact.json +150 -0
- package/examples/Nederlands/Hue Group.json +658 -0
- package/examples/Nederlands/Hue Light.json +893 -0
- package/examples/Nederlands/Hue Magic.json +148 -0
- package/examples/Nederlands/Hue Motion.json +150 -0
- package/examples/Nederlands/Hue Rules.json +150 -0
- package/examples/Nederlands/Hue Scene.json +178 -0
- package/examples/Nederlands/Hue Speaker.json +274 -0
- package/examples/Nederlands/Hue Sync Box.json +378 -0
- package/examples/Nederlands/Hue Temperature.json +150 -0
- package/examples/Polski/Hue Automation.json +176 -0
- package/examples/Polski/Hue Bridge.json +256 -0
- package/examples/Polski/Hue Brightness.json +150 -0
- package/examples/Polski/Hue Buttons.json +88 -0
- package/examples/Polski/Hue Contact.json +150 -0
- package/examples/Polski/Hue Group.json +658 -0
- package/examples/Polski/Hue Light.json +893 -0
- package/examples/Polski/Hue Magic.json +148 -0
- package/examples/Polski/Hue Motion.json +150 -0
- package/examples/Polski/Hue Rules.json +150 -0
- package/examples/Polski/Hue Scene.json +178 -0
- package/examples/Polski/Hue Speaker.json +274 -0
- package/examples/Polski/Hue Sync Box.json +378 -0
- package/examples/Polski/Hue Temperature.json +150 -0
- package/examples/Portugu/303/252s/Hue Automation.json" +176 -0
- package/examples/Portugu/303/252s/Hue Bridge.json" +256 -0
- package/examples/Portugu/303/252s/Hue Brightness.json" +150 -0
- package/examples/Portugu/303/252s/Hue Buttons.json" +88 -0
- package/examples/Portugu/303/252s/Hue Contact.json" +150 -0
- package/examples/Portugu/303/252s/Hue Group.json" +658 -0
- package/examples/Portugu/303/252s/Hue Light.json" +893 -0
- package/examples/Portugu/303/252s/Hue Magic.json" +148 -0
- package/examples/Portugu/303/252s/Hue Motion.json" +150 -0
- package/examples/Portugu/303/252s/Hue Rules.json" +150 -0
- package/examples/Portugu/303/252s/Hue Scene.json" +178 -0
- package/examples/Portugu/303/252s/Hue Speaker.json" +274 -0
- package/examples/Portugu/303/252s/Hue Sync Box.json" +378 -0
- package/examples/Portugu/303/252s/Hue Temperature.json" +150 -0
- package/examples/T/303/274rk/303/247e/Hue Automation.json" +176 -0
- package/examples/T/303/274rk/303/247e/Hue Bridge.json" +256 -0
- package/examples/T/303/274rk/303/247e/Hue Brightness.json" +150 -0
- package/examples/T/303/274rk/303/247e/Hue Buttons.json" +88 -0
- package/examples/T/303/274rk/303/247e/Hue Contact.json" +150 -0
- package/examples/T/303/274rk/303/247e/Hue Group.json" +658 -0
- package/examples/T/303/274rk/303/247e/Hue Light.json" +893 -0
- package/examples/T/303/274rk/303/247e/Hue Magic.json" +148 -0
- package/examples/T/303/274rk/303/247e/Hue Motion.json" +150 -0
- package/examples/T/303/274rk/303/247e/Hue Rules.json" +150 -0
- package/examples/T/303/274rk/303/247e/Hue Scene.json" +178 -0
- package/examples/T/303/274rk/303/247e/Hue Speaker.json" +274 -0
- package/examples/T/303/274rk/303/247e/Hue Sync Box.json" +378 -0
- package/examples/T/303/274rk/303/247e/Hue Temperature.json" +150 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Automation.json" +176 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Bridge.json" +256 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Brightness.json" +150 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Buttons.json" +88 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Contact.json" +150 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Group.json" +658 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Light.json" +893 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Magic.json" +148 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Motion.json" +150 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Rules.json" +150 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Scene.json" +178 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Speaker.json" +274 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Sync Box.json" +378 -0
- package/examples//316/225/316/273/316/273/316/267/316/275/316/271/316/272/316/254/Hue Temperature.json" +150 -0
- package/huemagic/assets/huemagic-examples.gif +0 -0
- package/huemagic/hue-automation.html +218 -0
- package/huemagic/hue-automation.js +173 -0
- package/huemagic/hue-bridge-config.html +39 -32
- package/huemagic/hue-bridge-config.js +290 -99
- package/huemagic/hue-bridge.html +8 -8
- package/huemagic/hue-bridge.js +29 -4
- package/huemagic/hue-brightness.html +21 -9
- package/huemagic/hue-brightness.js +20 -10
- package/huemagic/hue-buttons.html +16 -9
- package/huemagic/hue-buttons.js +90 -27
- package/huemagic/hue-contact.html +218 -0
- package/huemagic/hue-contact.js +209 -0
- package/huemagic/hue-group.html +16 -9
- package/huemagic/hue-group.js +141 -179
- package/huemagic/hue-light.html +19 -12
- package/huemagic/hue-light.js +222 -167
- package/huemagic/hue-magic.html +3 -5
- package/huemagic/hue-motion.html +16 -9
- package/huemagic/hue-motion.js +37 -8
- package/huemagic/hue-rules.html +16 -9
- package/huemagic/hue-rules.js +16 -8
- package/huemagic/hue-scene.html +9 -5
- package/huemagic/hue-scene.js +52 -16
- package/huemagic/hue-speaker.html +218 -0
- package/huemagic/hue-speaker.js +257 -0
- package/huemagic/hue-syncbox-config.html +123 -0
- package/huemagic/hue-syncbox-config.js +179 -0
- package/huemagic/hue-syncbox.html +82 -0
- package/huemagic/hue-syncbox.js +274 -0
- package/huemagic/hue-temperature.html +21 -9
- package/huemagic/hue-temperature.js +18 -10
- package/huemagic/icons/hue-automation.png +0 -0
- package/huemagic/icons/hue-automation.svg +3 -0
- package/huemagic/icons/hue-contact.png +0 -0
- package/huemagic/icons/hue-contact.svg +4 -0
- package/huemagic/icons/hue-speaker.png +0 -0
- package/huemagic/icons/hue-speaker.svg +6 -0
- package/huemagic/icons/hue-syncbox.png +0 -0
- package/huemagic/icons/hue-syncbox.svg +7 -0
- package/huemagic/locales/de/hue-automation.html +59 -0
- package/huemagic/locales/de/hue-automation.json +33 -0
- package/huemagic/locales/de/hue-bridge-config.json +23 -12
- package/huemagic/locales/de/hue-bridge.html +7 -4
- package/huemagic/locales/de/hue-bridge.json +9 -10
- package/huemagic/locales/de/hue-brightness.html +9 -6
- package/huemagic/locales/de/hue-brightness.json +13 -9
- package/huemagic/locales/de/hue-buttons.html +5 -4
- package/huemagic/locales/de/hue-buttons.json +22 -8
- package/huemagic/locales/de/hue-contact.html +67 -0
- package/huemagic/locales/de/hue-contact.json +35 -0
- package/huemagic/locales/de/hue-group.html +17 -6
- package/huemagic/locales/de/hue-group.json +16 -9
- package/huemagic/locales/de/hue-light.html +6 -6
- package/huemagic/locales/de/hue-light.json +17 -9
- package/huemagic/locales/de/hue-magic.html +1 -1
- package/huemagic/locales/de/hue-magic.json +6 -8
- package/huemagic/locales/de/hue-motion.html +4 -4
- package/huemagic/locales/de/hue-motion.json +14 -9
- package/huemagic/locales/de/hue-rules.html +2 -2
- package/huemagic/locales/de/hue-rules.json +10 -9
- package/huemagic/locales/de/hue-scene.html +11 -3
- package/huemagic/locales/de/hue-scene.json +9 -9
- package/huemagic/locales/de/hue-speaker.html +80 -0
- package/huemagic/locales/de/hue-speaker.json +38 -0
- package/huemagic/locales/de/hue-syncbox-config.html +19 -0
- package/huemagic/locales/de/hue-syncbox-config.json +25 -0
- package/huemagic/locales/de/hue-syncbox.html +86 -0
- package/huemagic/locales/de/hue-syncbox.json +30 -0
- package/huemagic/locales/de/hue-temperature.html +7 -5
- package/huemagic/locales/de/hue-temperature.json +13 -9
- package/huemagic/locales/el/hue-automation.html +59 -0
- package/huemagic/locales/el/hue-automation.json +33 -0
- package/huemagic/locales/el/hue-bridge-config.html +31 -0
- package/huemagic/locales/el/hue-bridge-config.json +40 -0
- package/huemagic/locales/el/hue-bridge.html +96 -0
- package/huemagic/locales/el/hue-bridge.json +26 -0
- package/huemagic/locales/el/hue-brightness.html +70 -0
- package/huemagic/locales/el/hue-brightness.json +37 -0
- package/huemagic/locales/el/hue-buttons.html +59 -0
- package/huemagic/locales/el/hue-buttons.json +42 -0
- package/huemagic/locales/el/hue-contact.html +67 -0
- package/huemagic/locales/el/hue-contact.json +35 -0
- package/huemagic/locales/el/hue-group.html +87 -0
- package/huemagic/locales/el/hue-group.json +46 -0
- package/huemagic/locales/el/hue-light.html +97 -0
- package/huemagic/locales/el/hue-light.json +44 -0
- package/huemagic/locales/el/hue-magic.html +68 -0
- package/huemagic/locales/el/hue-magic.json +26 -0
- package/huemagic/locales/el/hue-motion.html +64 -0
- package/huemagic/locales/el/hue-motion.json +36 -0
- package/huemagic/locales/el/hue-rules.html +69 -0
- package/huemagic/locales/el/hue-rules.json +30 -0
- package/huemagic/locales/el/hue-scene.html +43 -0
- package/huemagic/locales/el/hue-scene.json +32 -0
- package/huemagic/locales/el/hue-speaker.html +80 -0
- package/huemagic/locales/el/hue-speaker.json +38 -0
- package/huemagic/locales/el/hue-syncbox-config.html +19 -0
- package/huemagic/locales/el/hue-syncbox-config.json +25 -0
- package/huemagic/locales/el/hue-syncbox.html +86 -0
- package/huemagic/locales/el/hue-syncbox.json +30 -0
- package/huemagic/locales/el/hue-temperature.html +69 -0
- package/huemagic/locales/el/hue-temperature.json +33 -0
- package/huemagic/locales/en/hue-automation.html +59 -0
- package/huemagic/locales/en/hue-automation.json +33 -0
- package/huemagic/locales/en/hue-bridge-config.json +40 -0
- package/huemagic/locales/{en-US → en}/hue-bridge.html +5 -2
- package/huemagic/locales/{en-US → en}/hue-bridge.json +8 -9
- package/huemagic/locales/{en-US → en}/hue-brightness.html +6 -3
- package/huemagic/locales/{en-US → en}/hue-brightness.json +11 -9
- package/huemagic/locales/{en-US → en}/hue-buttons.html +4 -3
- package/huemagic/locales/en/hue-buttons.json +42 -0
- package/huemagic/locales/en/hue-contact.html +67 -0
- package/huemagic/locales/en/hue-contact.json +35 -0
- package/huemagic/locales/{en-US → en}/hue-group.html +16 -5
- package/huemagic/locales/{en-US → en}/hue-group.json +15 -10
- package/huemagic/locales/{en-US → en}/hue-light.html +3 -3
- package/huemagic/locales/en/hue-light.json +44 -0
- package/huemagic/locales/{en-US → en}/hue-magic.html +1 -1
- package/huemagic/locales/{en-US → en}/hue-motion.html +2 -2
- package/huemagic/locales/{en-US → en}/hue-motion.json +12 -9
- package/huemagic/locales/{en-US → en}/hue-rules.html +2 -2
- package/huemagic/locales/{en-US → en}/hue-rules.json +10 -9
- package/huemagic/locales/{en-US → en}/hue-scene.html +11 -3
- package/huemagic/locales/{en-US → en}/hue-scene.json +9 -9
- package/huemagic/locales/en/hue-speaker.html +80 -0
- package/huemagic/locales/en/hue-speaker.json +38 -0
- package/huemagic/locales/en/hue-syncbox-config.html +19 -0
- package/huemagic/locales/en/hue-syncbox-config.json +25 -0
- package/huemagic/locales/en/hue-syncbox.html +86 -0
- package/huemagic/locales/en/hue-syncbox.json +30 -0
- package/huemagic/locales/{en-US → en}/hue-temperature.html +4 -2
- package/huemagic/locales/{en-US → en}/hue-temperature.json +11 -9
- package/huemagic/locales/es/hue-automation.html +59 -0
- package/huemagic/locales/es/hue-automation.json +33 -0
- package/huemagic/locales/es/hue-bridge-config.html +31 -0
- package/huemagic/locales/es/hue-bridge-config.json +40 -0
- package/huemagic/locales/es/hue-bridge.html +96 -0
- package/huemagic/locales/es/hue-bridge.json +26 -0
- package/huemagic/locales/es/hue-brightness.html +70 -0
- package/huemagic/locales/es/hue-brightness.json +37 -0
- package/huemagic/locales/es/hue-buttons.html +59 -0
- package/huemagic/locales/es/hue-buttons.json +42 -0
- package/huemagic/locales/es/hue-contact.html +67 -0
- package/huemagic/locales/es/hue-contact.json +35 -0
- package/huemagic/locales/es/hue-group.html +87 -0
- package/huemagic/locales/es/hue-group.json +46 -0
- package/huemagic/locales/es/hue-light.html +97 -0
- package/huemagic/locales/es/hue-light.json +44 -0
- package/huemagic/locales/es/hue-magic.html +68 -0
- package/huemagic/locales/es/hue-magic.json +26 -0
- package/huemagic/locales/es/hue-motion.html +64 -0
- package/huemagic/locales/es/hue-motion.json +36 -0
- package/huemagic/locales/es/hue-rules.html +69 -0
- package/huemagic/locales/es/hue-rules.json +30 -0
- package/huemagic/locales/es/hue-scene.html +43 -0
- package/huemagic/locales/es/hue-scene.json +32 -0
- package/huemagic/locales/es/hue-speaker.html +80 -0
- package/huemagic/locales/es/hue-speaker.json +38 -0
- package/huemagic/locales/es/hue-syncbox-config.html +19 -0
- package/huemagic/locales/es/hue-syncbox-config.json +25 -0
- package/huemagic/locales/es/hue-syncbox.html +86 -0
- package/huemagic/locales/es/hue-syncbox.json +30 -0
- package/huemagic/locales/es/hue-temperature.html +69 -0
- package/huemagic/locales/es/hue-temperature.json +33 -0
- package/huemagic/locales/fr/hue-automation.html +59 -0
- package/huemagic/locales/fr/hue-automation.json +33 -0
- package/huemagic/locales/fr/hue-bridge-config.html +31 -0
- package/huemagic/locales/fr/hue-bridge-config.json +40 -0
- package/huemagic/locales/fr/hue-bridge.html +96 -0
- package/huemagic/locales/fr/hue-bridge.json +26 -0
- package/huemagic/locales/fr/hue-brightness.html +70 -0
- package/huemagic/locales/fr/hue-brightness.json +37 -0
- package/huemagic/locales/fr/hue-buttons.html +59 -0
- package/huemagic/locales/fr/hue-buttons.json +42 -0
- package/huemagic/locales/fr/hue-contact.html +67 -0
- package/huemagic/locales/fr/hue-contact.json +35 -0
- package/huemagic/locales/fr/hue-group.html +87 -0
- package/huemagic/locales/fr/hue-group.json +46 -0
- package/huemagic/locales/fr/hue-light.html +97 -0
- package/huemagic/locales/fr/hue-light.json +44 -0
- package/huemagic/locales/fr/hue-magic.html +68 -0
- package/huemagic/locales/fr/hue-magic.json +26 -0
- package/huemagic/locales/fr/hue-motion.html +64 -0
- package/huemagic/locales/fr/hue-motion.json +36 -0
- package/huemagic/locales/fr/hue-rules.html +69 -0
- package/huemagic/locales/fr/hue-rules.json +30 -0
- package/huemagic/locales/fr/hue-scene.html +43 -0
- package/huemagic/locales/fr/hue-scene.json +32 -0
- package/huemagic/locales/fr/hue-speaker.html +80 -0
- package/huemagic/locales/fr/hue-speaker.json +38 -0
- package/huemagic/locales/fr/hue-syncbox-config.html +19 -0
- package/huemagic/locales/fr/hue-syncbox-config.json +25 -0
- package/huemagic/locales/fr/hue-syncbox.html +86 -0
- package/huemagic/locales/fr/hue-syncbox.json +30 -0
- package/huemagic/locales/fr/hue-temperature.html +69 -0
- package/huemagic/locales/fr/hue-temperature.json +33 -0
- package/huemagic/locales/it/hue-automation.html +59 -0
- package/huemagic/locales/it/hue-automation.json +33 -0
- package/huemagic/locales/it/hue-bridge-config.html +31 -0
- package/huemagic/locales/it/hue-bridge-config.json +40 -0
- package/huemagic/locales/it/hue-bridge.html +96 -0
- package/huemagic/locales/it/hue-bridge.json +26 -0
- package/huemagic/locales/it/hue-brightness.html +70 -0
- package/huemagic/locales/it/hue-brightness.json +37 -0
- package/huemagic/locales/it/hue-buttons.html +59 -0
- package/huemagic/locales/it/hue-buttons.json +42 -0
- package/huemagic/locales/it/hue-contact.html +67 -0
- package/huemagic/locales/it/hue-contact.json +35 -0
- package/huemagic/locales/it/hue-group.html +87 -0
- package/huemagic/locales/it/hue-group.json +46 -0
- package/huemagic/locales/it/hue-light.html +97 -0
- package/huemagic/locales/it/hue-light.json +44 -0
- package/huemagic/locales/it/hue-magic.html +68 -0
- package/huemagic/locales/it/hue-magic.json +26 -0
- package/huemagic/locales/it/hue-motion.html +64 -0
- package/huemagic/locales/it/hue-motion.json +36 -0
- package/huemagic/locales/it/hue-rules.html +69 -0
- package/huemagic/locales/it/hue-rules.json +30 -0
- package/huemagic/locales/it/hue-scene.html +43 -0
- package/huemagic/locales/it/hue-scene.json +32 -0
- package/huemagic/locales/it/hue-speaker.html +80 -0
- package/huemagic/locales/it/hue-speaker.json +38 -0
- package/huemagic/locales/it/hue-syncbox-config.html +19 -0
- package/huemagic/locales/it/hue-syncbox-config.json +25 -0
- package/huemagic/locales/it/hue-syncbox.html +86 -0
- package/huemagic/locales/it/hue-syncbox.json +30 -0
- package/huemagic/locales/it/hue-temperature.html +69 -0
- package/huemagic/locales/it/hue-temperature.json +33 -0
- package/huemagic/locales/nl/hue-automation.html +59 -0
- package/huemagic/locales/nl/hue-automation.json +33 -0
- package/huemagic/locales/nl/hue-bridge-config.html +31 -0
- package/huemagic/locales/nl/hue-bridge-config.json +40 -0
- package/huemagic/locales/nl/hue-bridge.html +96 -0
- package/huemagic/locales/nl/hue-bridge.json +26 -0
- package/huemagic/locales/nl/hue-brightness.html +70 -0
- package/huemagic/locales/nl/hue-brightness.json +37 -0
- package/huemagic/locales/nl/hue-buttons.html +59 -0
- package/huemagic/locales/nl/hue-buttons.json +42 -0
- package/huemagic/locales/nl/hue-contact.html +67 -0
- package/huemagic/locales/nl/hue-contact.json +35 -0
- package/huemagic/locales/nl/hue-group.html +87 -0
- package/huemagic/locales/nl/hue-group.json +46 -0
- package/huemagic/locales/nl/hue-light.html +97 -0
- package/huemagic/locales/nl/hue-light.json +44 -0
- package/huemagic/locales/nl/hue-magic.html +68 -0
- package/huemagic/locales/nl/hue-magic.json +26 -0
- package/huemagic/locales/nl/hue-motion.html +64 -0
- package/huemagic/locales/nl/hue-motion.json +36 -0
- package/huemagic/locales/nl/hue-rules.html +69 -0
- package/huemagic/locales/nl/hue-rules.json +30 -0
- package/huemagic/locales/nl/hue-scene.html +43 -0
- package/huemagic/locales/nl/hue-scene.json +32 -0
- package/huemagic/locales/nl/hue-speaker.html +80 -0
- package/huemagic/locales/nl/hue-speaker.json +38 -0
- package/huemagic/locales/nl/hue-syncbox-config.html +19 -0
- package/huemagic/locales/nl/hue-syncbox-config.json +25 -0
- package/huemagic/locales/nl/hue-syncbox.html +86 -0
- package/huemagic/locales/nl/hue-syncbox.json +30 -0
- package/huemagic/locales/nl/hue-temperature.html +69 -0
- package/huemagic/locales/nl/hue-temperature.json +33 -0
- package/huemagic/locales/pl/hue-automation.html +59 -0
- package/huemagic/locales/pl/hue-automation.json +33 -0
- package/huemagic/locales/pl/hue-bridge-config.html +31 -0
- package/huemagic/locales/pl/hue-bridge-config.json +40 -0
- package/huemagic/locales/pl/hue-bridge.html +96 -0
- package/huemagic/locales/pl/hue-bridge.json +26 -0
- package/huemagic/locales/pl/hue-brightness.html +70 -0
- package/huemagic/locales/pl/hue-brightness.json +37 -0
- package/huemagic/locales/pl/hue-buttons.html +59 -0
- package/huemagic/locales/pl/hue-buttons.json +42 -0
- package/huemagic/locales/pl/hue-contact.html +67 -0
- package/huemagic/locales/pl/hue-contact.json +35 -0
- package/huemagic/locales/pl/hue-group.html +87 -0
- package/huemagic/locales/pl/hue-group.json +46 -0
- package/huemagic/locales/pl/hue-light.html +97 -0
- package/huemagic/locales/pl/hue-light.json +44 -0
- package/huemagic/locales/pl/hue-magic.html +68 -0
- package/huemagic/locales/pl/hue-magic.json +26 -0
- package/huemagic/locales/pl/hue-motion.html +64 -0
- package/huemagic/locales/pl/hue-motion.json +36 -0
- package/huemagic/locales/pl/hue-rules.html +69 -0
- package/huemagic/locales/pl/hue-rules.json +30 -0
- package/huemagic/locales/pl/hue-scene.html +43 -0
- package/huemagic/locales/pl/hue-scene.json +32 -0
- package/huemagic/locales/pl/hue-speaker.html +80 -0
- package/huemagic/locales/pl/hue-speaker.json +38 -0
- package/huemagic/locales/pl/hue-syncbox-config.html +19 -0
- package/huemagic/locales/pl/hue-syncbox-config.json +25 -0
- package/huemagic/locales/pl/hue-syncbox.html +86 -0
- package/huemagic/locales/pl/hue-syncbox.json +30 -0
- package/huemagic/locales/pl/hue-temperature.html +69 -0
- package/huemagic/locales/pl/hue-temperature.json +33 -0
- package/huemagic/locales/pt/hue-automation.html +59 -0
- package/huemagic/locales/pt/hue-automation.json +33 -0
- package/huemagic/locales/pt/hue-bridge-config.html +31 -0
- package/huemagic/locales/pt/hue-bridge-config.json +40 -0
- package/huemagic/locales/pt/hue-bridge.html +96 -0
- package/huemagic/locales/pt/hue-bridge.json +26 -0
- package/huemagic/locales/pt/hue-brightness.html +70 -0
- package/huemagic/locales/pt/hue-brightness.json +37 -0
- package/huemagic/locales/pt/hue-buttons.html +59 -0
- package/huemagic/locales/pt/hue-buttons.json +42 -0
- package/huemagic/locales/pt/hue-contact.html +67 -0
- package/huemagic/locales/pt/hue-contact.json +35 -0
- package/huemagic/locales/pt/hue-group.html +87 -0
- package/huemagic/locales/pt/hue-group.json +46 -0
- package/huemagic/locales/pt/hue-light.html +97 -0
- package/huemagic/locales/pt/hue-light.json +44 -0
- package/huemagic/locales/pt/hue-magic.html +68 -0
- package/huemagic/locales/pt/hue-magic.json +26 -0
- package/huemagic/locales/pt/hue-motion.html +64 -0
- package/huemagic/locales/pt/hue-motion.json +36 -0
- package/huemagic/locales/pt/hue-rules.html +69 -0
- package/huemagic/locales/pt/hue-rules.json +30 -0
- package/huemagic/locales/pt/hue-scene.html +43 -0
- package/huemagic/locales/pt/hue-scene.json +32 -0
- package/huemagic/locales/pt/hue-speaker.html +80 -0
- package/huemagic/locales/pt/hue-speaker.json +38 -0
- package/huemagic/locales/pt/hue-syncbox-config.html +19 -0
- package/huemagic/locales/pt/hue-syncbox-config.json +25 -0
- package/huemagic/locales/pt/hue-syncbox.html +86 -0
- package/huemagic/locales/pt/hue-syncbox.json +30 -0
- package/huemagic/locales/pt/hue-temperature.html +69 -0
- package/huemagic/locales/pt/hue-temperature.json +33 -0
- package/huemagic/locales/tr/hue-automation.html +59 -0
- package/huemagic/locales/tr/hue-automation.json +33 -0
- package/huemagic/locales/tr/hue-bridge-config.html +31 -0
- package/huemagic/locales/tr/hue-bridge-config.json +40 -0
- package/huemagic/locales/tr/hue-bridge.html +96 -0
- package/huemagic/locales/tr/hue-bridge.json +26 -0
- package/huemagic/locales/tr/hue-brightness.html +70 -0
- package/huemagic/locales/tr/hue-brightness.json +37 -0
- package/huemagic/locales/tr/hue-buttons.html +59 -0
- package/huemagic/locales/tr/hue-buttons.json +42 -0
- package/huemagic/locales/tr/hue-contact.html +67 -0
- package/huemagic/locales/tr/hue-contact.json +35 -0
- package/huemagic/locales/tr/hue-group.html +87 -0
- package/huemagic/locales/tr/hue-group.json +46 -0
- package/huemagic/locales/tr/hue-light.html +97 -0
- package/huemagic/locales/tr/hue-light.json +44 -0
- package/huemagic/locales/tr/hue-magic.html +68 -0
- package/huemagic/locales/tr/hue-magic.json +26 -0
- package/huemagic/locales/tr/hue-motion.html +64 -0
- package/huemagic/locales/tr/hue-motion.json +36 -0
- package/huemagic/locales/tr/hue-rules.html +69 -0
- package/huemagic/locales/tr/hue-rules.json +30 -0
- package/huemagic/locales/tr/hue-scene.html +43 -0
- package/huemagic/locales/tr/hue-scene.json +32 -0
- package/huemagic/locales/tr/hue-speaker.html +80 -0
- package/huemagic/locales/tr/hue-speaker.json +38 -0
- package/huemagic/locales/tr/hue-syncbox-config.html +19 -0
- package/huemagic/locales/tr/hue-syncbox-config.json +25 -0
- package/huemagic/locales/tr/hue-syncbox.html +86 -0
- package/huemagic/locales/tr/hue-syncbox.json +30 -0
- package/huemagic/locales/tr/hue-temperature.html +69 -0
- package/huemagic/locales/tr/hue-temperature.json +33 -0
- package/huemagic/utils/api.js +158 -54
- package/huemagic/utils/color.js +20 -2
- package/huemagic/utils/merge.js +3 -2
- package/huemagic/utils/messages.js +506 -120
- package/huemagic/utils/sse.js +51 -0
- package/huemagic/utils/syncbox.js +84 -0
- package/package.json +19 -11
- package/.github/FUNDING.yml +0 -2
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -30
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/.github/workflows/npm.yml +0 -18
- package/huemagic/locales/en-US/hue-bridge-config.json +0 -29
- package/huemagic/locales/en-US/hue-buttons.json +0 -34
- package/huemagic/locales/en-US/hue-light.json +0 -38
- /package/huemagic/locales/{en-US → en}/hue-bridge-config.html +0 -0
- /package/huemagic/locales/{en-US → en}/hue-magic.json +0 -0
|
@@ -16,10 +16,14 @@ module.exports = function(RED)
|
|
|
16
16
|
HueLightMessage,
|
|
17
17
|
HueGroupMessage,
|
|
18
18
|
HueMotionMessage,
|
|
19
|
+
HueContactMessage,
|
|
19
20
|
HueTemperatureMessage,
|
|
20
21
|
HueBrightnessMessage,
|
|
21
22
|
HueButtonsMessage,
|
|
22
|
-
HueRulesMessage
|
|
23
|
+
HueRulesMessage,
|
|
24
|
+
HueSpeakerMessage,
|
|
25
|
+
HueAutomationMessage,
|
|
26
|
+
servesType
|
|
23
27
|
} = require('./utils/messages');
|
|
24
28
|
|
|
25
29
|
function HueBridge(config)
|
|
@@ -33,11 +37,15 @@ module.exports = function(RED)
|
|
|
33
37
|
this.resourcesInGroups = {};
|
|
34
38
|
this.lastStates = {};
|
|
35
39
|
this.events = new events.EventEmitter();
|
|
40
|
+
this.events.setMaxListeners(0);
|
|
36
41
|
this.patchQueue = null;
|
|
37
42
|
this.timerWatchDog = null;
|
|
43
|
+
this.watchdogFailures = 0;
|
|
44
|
+
this.starting = false;
|
|
45
|
+
this.refetchTimeout = null;
|
|
38
46
|
|
|
39
|
-
// RESOURCE ID PATTERN
|
|
40
|
-
this.validResourceID =
|
|
47
|
+
// RESOURCE ID PATTERN (NEVER GLOBAL, "test" WOULD BECOME STATEFUL)
|
|
48
|
+
this.validResourceID = /^[a-zA-Z0-9-]+$/i;
|
|
41
49
|
|
|
42
50
|
// FIRMWARE UPDATE TIMEOUT
|
|
43
51
|
this.firmwareUpdateTimeout = null;
|
|
@@ -48,40 +56,52 @@ module.exports = function(RED)
|
|
|
48
56
|
// PERIODICALLY CHECK WETHER BRIDGE IS CONNECTED
|
|
49
57
|
this.startWatchdog = function()
|
|
50
58
|
{
|
|
51
|
-
if
|
|
52
|
-
|
|
59
|
+
if(scope.timerWatchDog !== null) { clearTimeout(scope.timerWatchDog); }
|
|
60
|
+
if(scope.nodeActive === false) { return false; }
|
|
61
|
+
|
|
62
|
+
// THE BRIDGE SENDS NO KEEP-ALIVE ON THE EVENT STREAM, SO KEEP ASKING - JUST RARELY
|
|
63
|
+
scope.timerWatchDog = setTimeout(function()
|
|
53
64
|
{
|
|
54
|
-
|
|
65
|
+
API.request({ config: config, resource: "bridge" })
|
|
66
|
+
.then(function(bridgeInformation)
|
|
55
67
|
{
|
|
56
|
-
|
|
57
|
-
.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
scope.
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
scope.
|
|
68
|
-
scope.
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
scope.watchdogFailures = 0;
|
|
69
|
+
scope.startWatchdog();
|
|
70
|
+
})
|
|
71
|
+
.catch(function(error)
|
|
72
|
+
{
|
|
73
|
+
// BRIDGE IS OVERLOADED (429) OR BUSY (503) BUT STILL ALIVE
|
|
74
|
+
if(error.status === 429 || error.status === 503)
|
|
75
|
+
{
|
|
76
|
+
return scope.startWatchdog();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
scope.watchdogFailures += 1;
|
|
80
|
+
scope.log(RED._("hue-bridge-config.node.request-error", { error: JSON.stringify(error.errors ? error.errors : error) }));
|
|
81
|
+
|
|
82
|
+
// ONLY RECONNECT AFTER THREE FAILED ATTEMPTS IN A ROW
|
|
83
|
+
if(scope.watchdogFailures >= 3) { scope.start(); }
|
|
84
|
+
else { scope.startWatchdog(); }
|
|
85
|
+
});
|
|
86
|
+
}, API.connected(config) ? 60000 : 15000);
|
|
71
87
|
}
|
|
72
88
|
|
|
73
89
|
// INITIALIZE
|
|
74
90
|
this.start = function()
|
|
75
91
|
{
|
|
76
|
-
scope.
|
|
92
|
+
if(scope.starting === true || scope.nodeActive === false) { return false; }
|
|
93
|
+
scope.starting = true;
|
|
94
|
+
scope.watchdogFailures = 0;
|
|
95
|
+
|
|
96
|
+
scope.log(RED._("hue-bridge-config.node.initializing", { bridge: config.bridge }));
|
|
77
97
|
API.init({ config: config })
|
|
78
98
|
.then(function(bridge) {
|
|
79
|
-
scope.log("
|
|
99
|
+
scope.log(RED._("hue-bridge-config.node.connected"));
|
|
80
100
|
return scope.getAllResources();
|
|
81
101
|
})
|
|
82
102
|
.then(function(allResources)
|
|
83
103
|
{
|
|
84
|
-
scope.log("
|
|
104
|
+
scope.log(RED._("hue-bridge-config.node.processing"));
|
|
85
105
|
return API.processResources(allResources);
|
|
86
106
|
})
|
|
87
107
|
.then(function(allResources)
|
|
@@ -90,11 +110,13 @@ module.exports = function(RED)
|
|
|
90
110
|
scope.resources = allResources;
|
|
91
111
|
|
|
92
112
|
// EMIT INITIAL STATES -> NODES
|
|
93
|
-
scope.log("
|
|
113
|
+
scope.log(RED._("hue-bridge-config.node.initial-emit"));
|
|
94
114
|
return scope.emitInitialStates();
|
|
95
115
|
})
|
|
96
116
|
.then(function(emitted)
|
|
97
117
|
{
|
|
118
|
+
scope.starting = false;
|
|
119
|
+
|
|
98
120
|
// START REFRESHING STATES
|
|
99
121
|
scope.keepUpdated();
|
|
100
122
|
|
|
@@ -108,6 +130,7 @@ module.exports = function(RED)
|
|
|
108
130
|
.catch(function(error)
|
|
109
131
|
{
|
|
110
132
|
// RETRY AFTER 30 SECONDS
|
|
133
|
+
scope.starting = false;
|
|
111
134
|
scope.log(error);
|
|
112
135
|
if(scope.nodeActive == true) { setTimeout(function(){ scope.start(); }, 30000); }
|
|
113
136
|
});
|
|
@@ -149,8 +172,13 @@ module.exports = function(RED)
|
|
|
149
172
|
{
|
|
150
173
|
var allResources = [];
|
|
151
174
|
|
|
152
|
-
// GET BRIDGE INFORMATION
|
|
175
|
+
// GET BRIDGE INFORMATION (LEGACY API / MAY BE UNAVAILABLE)
|
|
153
176
|
scope.getBridgeInformation()
|
|
177
|
+
.catch(function(error)
|
|
178
|
+
{
|
|
179
|
+
scope.log(RED._("hue-bridge-config.node.no-legacy-api"));
|
|
180
|
+
return { id: "bridge", id_v1: "/config", updated: dayjs().format() };
|
|
181
|
+
})
|
|
154
182
|
.then(function(bridgeInformation)
|
|
155
183
|
{
|
|
156
184
|
// PUSH TO RESOURCES
|
|
@@ -164,13 +192,16 @@ module.exports = function(RED)
|
|
|
164
192
|
// MERGE RESOURCES
|
|
165
193
|
allResources = allResources.concat(v2Resources);
|
|
166
194
|
|
|
167
|
-
// GET RULES (LEGACY API)
|
|
168
|
-
return API.request({ config: config, resource: "/rules", version: 1 });
|
|
195
|
+
// GET RULES (LEGACY API / MAY BE UNAVAILABLE)
|
|
196
|
+
return API.request({ config: config, resource: "/rules", version: 1 }).catch(function(error) { return {}; });
|
|
169
197
|
})
|
|
170
198
|
.then(function(rules)
|
|
171
199
|
{
|
|
172
200
|
for (var [id, rule] of Object.entries(rules))
|
|
173
201
|
{
|
|
202
|
+
// SKIP ERROR RESPONSES OF THE LEGACY API
|
|
203
|
+
if(!rule || typeof rule !== 'object' || rule["error"]) { continue; }
|
|
204
|
+
|
|
174
205
|
// "RENAME" OWNER
|
|
175
206
|
rule["_owner"] = rule["owner"];
|
|
176
207
|
delete rule["owner"];
|
|
@@ -203,6 +234,7 @@ module.exports = function(RED)
|
|
|
203
234
|
// PUSH ALL STATES
|
|
204
235
|
for (const [id, resource] of Object.entries(scope.resources))
|
|
205
236
|
{
|
|
237
|
+
if(id === "_groupsOf") { continue; }
|
|
206
238
|
scope.pushUpdatedState(resource, resource.type, true);
|
|
207
239
|
}
|
|
208
240
|
|
|
@@ -216,7 +248,7 @@ module.exports = function(RED)
|
|
|
216
248
|
{
|
|
217
249
|
if(!config.disableupdates)
|
|
218
250
|
{
|
|
219
|
-
scope.log("
|
|
251
|
+
scope.log(RED._("hue-bridge-config.node.keep-updated"));
|
|
220
252
|
|
|
221
253
|
// REFRESH STATES (SSE)
|
|
222
254
|
this.refreshStatesSSE();
|
|
@@ -226,11 +258,17 @@ module.exports = function(RED)
|
|
|
226
258
|
// GET UPDATED STATES (SSE)
|
|
227
259
|
this.refreshStatesSSE = function()
|
|
228
260
|
{
|
|
229
|
-
scope.log("
|
|
230
|
-
API.subscribe(config, function(updates)
|
|
261
|
+
scope.log(RED._("hue-bridge-config.node.subscribing"));
|
|
262
|
+
API.subscribe(config, function(updates, eventType)
|
|
231
263
|
{
|
|
232
264
|
const currentDateTime = dayjs().format();
|
|
233
265
|
|
|
266
|
+
// DEVICE ADDED/REMOVED OR EVENTS MISSED? -> RE-READ ALL RESOURCES
|
|
267
|
+
if(eventType === "add" || eventType === "delete" || eventType === "reconnect")
|
|
268
|
+
{
|
|
269
|
+
return scope.refetchResources();
|
|
270
|
+
}
|
|
271
|
+
|
|
234
272
|
for(let resource of updates)
|
|
235
273
|
{
|
|
236
274
|
let id = resource.id;
|
|
@@ -242,18 +280,19 @@ module.exports = function(RED)
|
|
|
242
280
|
if(resource["owner"])
|
|
243
281
|
{
|
|
244
282
|
let targetId = resource["owner"]["rid"];
|
|
283
|
+
const services = scope.resources[targetId] ? scope.resources[targetId]["services"] : false;
|
|
245
284
|
|
|
246
|
-
if(
|
|
285
|
+
if(services && services[type])
|
|
247
286
|
{
|
|
248
287
|
// GET PREVIOUS STATE
|
|
249
|
-
previousState =
|
|
288
|
+
previousState = services[type][id];
|
|
250
289
|
|
|
251
|
-
// IS BUTTON? -> REMOVE PREVIOUS STATES
|
|
252
|
-
if(type === "button")
|
|
290
|
+
// IS BUTTON OR DIAL? -> REMOVE PREVIOUS STATES
|
|
291
|
+
if(type === "button" || type === "relative_rotary")
|
|
253
292
|
{
|
|
254
|
-
for (const [
|
|
293
|
+
for (const [oneServiceID, oneService] of Object.entries(services[type]))
|
|
255
294
|
{
|
|
256
|
-
delete
|
|
295
|
+
delete services[type][oneServiceID][type];
|
|
257
296
|
}
|
|
258
297
|
}
|
|
259
298
|
}
|
|
@@ -264,8 +303,8 @@ module.exports = function(RED)
|
|
|
264
303
|
previousState = scope.resources[id];
|
|
265
304
|
}
|
|
266
305
|
|
|
267
|
-
// NO PREVIOUS STATE?
|
|
268
|
-
if(!previousState) {
|
|
306
|
+
// NO PREVIOUS STATE? -> UNKNOWN RESOURCE, CONTINUE WITH THE NEXT ONE
|
|
307
|
+
if(!previousState) { continue; }
|
|
269
308
|
|
|
270
309
|
// CHECK DIFFERENCES
|
|
271
310
|
const mergedState = merge.deep(previousState, resource);
|
|
@@ -293,23 +332,59 @@ module.exports = function(RED)
|
|
|
293
332
|
}
|
|
294
333
|
}
|
|
295
334
|
}
|
|
335
|
+
},
|
|
336
|
+
function(reason, seconds)
|
|
337
|
+
{
|
|
338
|
+
scope.log(RED._("hue-bridge-config.node.connection-lost", { reason: reason, seconds: seconds }));
|
|
296
339
|
});
|
|
297
340
|
}
|
|
298
341
|
|
|
342
|
+
// RE-READ ALL RESOURCES (DEVICE ADDED / REMOVED ON THE BRIDGE)
|
|
343
|
+
this.refetchResources = function()
|
|
344
|
+
{
|
|
345
|
+
if(scope.refetchTimeout !== null) { clearTimeout(scope.refetchTimeout); }
|
|
346
|
+
scope.refetchTimeout = setTimeout(function()
|
|
347
|
+
{
|
|
348
|
+
scope.refetchTimeout = null;
|
|
349
|
+
scope.log(RED._("hue-bridge-config.node.resources-changed"));
|
|
350
|
+
|
|
351
|
+
scope.getAllResources()
|
|
352
|
+
.then(function(allResources)
|
|
353
|
+
{
|
|
354
|
+
return API.processResources(allResources);
|
|
355
|
+
})
|
|
356
|
+
.then(function(allResources)
|
|
357
|
+
{
|
|
358
|
+
scope.resources = allResources;
|
|
359
|
+
return scope.emitInitialStates();
|
|
360
|
+
})
|
|
361
|
+
.catch(function(error) { scope.log(error); });
|
|
362
|
+
}, 5000);
|
|
363
|
+
}
|
|
364
|
+
|
|
299
365
|
// PUSH UPDATED STATE
|
|
300
366
|
this.pushUpdatedState = function(resource, updatedType, suppressMessage = false)
|
|
301
367
|
{
|
|
302
|
-
|
|
368
|
+
if(!resource || !resource.id) { return false; }
|
|
369
|
+
|
|
370
|
+
let services = resource["services"] ? Object.keys(resource["services"]) : [];
|
|
371
|
+
|
|
372
|
+
// ROOMS, ZONES AND THE BRIDGE HOME ARE ADDRESSED AS GROUPS
|
|
373
|
+
if(resource["type"] === "room" || resource["type"] === "zone" || resource["type"] === "bridge_home") { services.push("group"); }
|
|
374
|
+
|
|
375
|
+
const msg = { id: resource.id, type: resource.type, updatedType: updatedType, services: services, suppressMessage: suppressMessage };
|
|
303
376
|
this.events.emit(config.id + "_" + resource.id, msg);
|
|
304
377
|
this.events.emit(config.id + "_" + "globalResourceUpdates", msg);
|
|
305
378
|
|
|
306
379
|
// RESOURCE CONTAINS SERVICES? -> SERVICE IN GROUP? -> EMIT CHANGES TO GROUPS ALSO
|
|
307
|
-
|
|
380
|
+
const groupsOfResource = this.resources["_groupsOf"] ? this.resources["_groupsOf"][resource.id] : false;
|
|
381
|
+
|
|
382
|
+
if(groupsOfResource)
|
|
308
383
|
{
|
|
309
|
-
for (var g =
|
|
384
|
+
for (var g = groupsOfResource.length - 1; g >= 0; g--)
|
|
310
385
|
{
|
|
311
|
-
const groupID =
|
|
312
|
-
const groupMessage = { id: groupID, type: "group", updatedType: updatedType, services: [], suppressMessage: suppressMessage };
|
|
386
|
+
const groupID = groupsOfResource[g];
|
|
387
|
+
const groupMessage = { id: groupID, type: "group", updatedType: updatedType, services: ["group"], suppressMessage: suppressMessage };
|
|
313
388
|
|
|
314
389
|
this.events.emit(config.id + "_" + groupID, groupMessage);
|
|
315
390
|
this.events.emit(config.id + "_" + "globalResourceUpdates", groupMessage);
|
|
@@ -328,7 +403,7 @@ module.exports = function(RED)
|
|
|
328
403
|
{
|
|
329
404
|
// RESOLVE LINKS
|
|
330
405
|
const targetResource = scope.resources[id];
|
|
331
|
-
const lastState = scope.lastStates[type+targetResource.id] ?
|
|
406
|
+
const lastState = scope.lastStates[type+targetResource.id] ? structuredClone(scope.lastStates[type+targetResource.id]) : false;
|
|
332
407
|
|
|
333
408
|
if(type == "bridge")
|
|
334
409
|
{
|
|
@@ -337,11 +412,11 @@ module.exports = function(RED)
|
|
|
337
412
|
|
|
338
413
|
// GET CURRENT STATE MESSAGE
|
|
339
414
|
let currentState = message.msg;
|
|
340
|
-
return currentState;
|
|
415
|
+
return currentState;
|
|
341
416
|
} catch (error) {
|
|
342
417
|
return false;
|
|
343
418
|
}
|
|
344
|
-
|
|
419
|
+
|
|
345
420
|
}
|
|
346
421
|
else if(type == "light")
|
|
347
422
|
{
|
|
@@ -350,7 +425,7 @@ module.exports = function(RED)
|
|
|
350
425
|
|
|
351
426
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
352
427
|
let currentState = message.msg;
|
|
353
|
-
scope.lastStates[type+targetResource.id] =
|
|
428
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
354
429
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
355
430
|
currentState.lastState = lastState;
|
|
356
431
|
|
|
@@ -367,7 +442,7 @@ module.exports = function(RED)
|
|
|
367
442
|
|
|
368
443
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
369
444
|
let currentState = message.msg;
|
|
370
|
-
scope.lastStates[type+targetResource.id] =
|
|
445
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
371
446
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
372
447
|
currentState.lastState = lastState;
|
|
373
448
|
|
|
@@ -383,7 +458,7 @@ module.exports = function(RED)
|
|
|
383
458
|
|
|
384
459
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
385
460
|
let currentState = message.msg;
|
|
386
|
-
scope.lastStates[type+targetResource.id] =
|
|
461
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
387
462
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
388
463
|
currentState.lastState = lastState;
|
|
389
464
|
|
|
@@ -399,7 +474,23 @@ module.exports = function(RED)
|
|
|
399
474
|
|
|
400
475
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
401
476
|
let currentState = message.msg;
|
|
402
|
-
scope.lastStates[type+targetResource.id] =
|
|
477
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
478
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
479
|
+
currentState.lastState = lastState;
|
|
480
|
+
|
|
481
|
+
return currentState;
|
|
482
|
+
} catch (error) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
else if(type == "contact")
|
|
487
|
+
{
|
|
488
|
+
try {
|
|
489
|
+
const message = new HueContactMessage(targetResource, options);
|
|
490
|
+
|
|
491
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
492
|
+
let currentState = message.msg;
|
|
493
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
403
494
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
404
495
|
currentState.lastState = lastState;
|
|
405
496
|
|
|
@@ -415,7 +506,7 @@ module.exports = function(RED)
|
|
|
415
506
|
|
|
416
507
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
417
508
|
let currentState = message.msg;
|
|
418
|
-
scope.lastStates[type+targetResource.id] =
|
|
509
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
419
510
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
420
511
|
currentState.lastState = lastState;
|
|
421
512
|
|
|
@@ -431,7 +522,39 @@ module.exports = function(RED)
|
|
|
431
522
|
|
|
432
523
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
433
524
|
let currentState = message.msg;
|
|
434
|
-
scope.lastStates[type+targetResource.id] =
|
|
525
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
526
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
527
|
+
currentState.lastState = lastState;
|
|
528
|
+
|
|
529
|
+
return currentState;
|
|
530
|
+
} catch (error) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
else if(type == "speaker")
|
|
535
|
+
{
|
|
536
|
+
try {
|
|
537
|
+
const message = new HueSpeakerMessage(targetResource, options);
|
|
538
|
+
|
|
539
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
540
|
+
let currentState = message.msg;
|
|
541
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
542
|
+
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
543
|
+
currentState.lastState = lastState;
|
|
544
|
+
|
|
545
|
+
return currentState;
|
|
546
|
+
} catch (error) {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
else if(type == "automation")
|
|
551
|
+
{
|
|
552
|
+
try {
|
|
553
|
+
const message = new HueAutomationMessage(targetResource, options);
|
|
554
|
+
|
|
555
|
+
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
556
|
+
let currentState = message.msg;
|
|
557
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
435
558
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
436
559
|
currentState.lastState = lastState;
|
|
437
560
|
|
|
@@ -447,7 +570,7 @@ module.exports = function(RED)
|
|
|
447
570
|
|
|
448
571
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
449
572
|
let currentState = message.msg;
|
|
450
|
-
scope.lastStates[type+targetResource.id] =
|
|
573
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
451
574
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
452
575
|
currentState.lastState = lastState;
|
|
453
576
|
|
|
@@ -475,13 +598,15 @@ module.exports = function(RED)
|
|
|
475
598
|
{
|
|
476
599
|
const isGroup = (resource["type"] == "room" || resource["type"] == "zone" || resource["type"] == "bridge_home");
|
|
477
600
|
|
|
601
|
+
// AUTOMATIONS ARE NOT DEVICES
|
|
602
|
+
if(type === "automation")
|
|
603
|
+
{
|
|
604
|
+
if(resource["type"] === "behavior_instance") { allFilteredResources[rootID] = scope.get(type, rootID); }
|
|
605
|
+
}
|
|
478
606
|
// NORMAL DEVICES
|
|
479
|
-
if(!isGroup && resource
|
|
607
|
+
else if(!isGroup && servesType(resource, type))
|
|
480
608
|
{
|
|
481
|
-
|
|
482
|
-
{
|
|
483
|
-
allFilteredResources[rootID] = scope.get(type, rootID);
|
|
484
|
-
}
|
|
609
|
+
allFilteredResources[rootID] = scope.get(type, rootID);
|
|
485
610
|
}
|
|
486
611
|
// GROUPED RESOURCES
|
|
487
612
|
else if(isGroup && type === "group")
|
|
@@ -499,7 +624,7 @@ module.exports = function(RED)
|
|
|
499
624
|
{
|
|
500
625
|
return new Promise(function(resolve, reject)
|
|
501
626
|
{
|
|
502
|
-
if(!scope.patchQueue) { return
|
|
627
|
+
if(!scope.patchQueue) { return reject({ status: "ECONNRESET", errors: RED._("hue-bridge-config.node.not-connected") }); }
|
|
503
628
|
scope.patchQueue.push({ type: type, id: id, patch: patch, version: version }, function (error, response)
|
|
504
629
|
{
|
|
505
630
|
if(error)
|
|
@@ -514,7 +639,22 @@ module.exports = function(RED)
|
|
|
514
639
|
});
|
|
515
640
|
}
|
|
516
641
|
|
|
517
|
-
//
|
|
642
|
+
// THE BRIDGE ACCEPTS ABOUT 10 LIGHT COMMANDS BUT ONLY 1 GROUP COMMAND PER SECOND
|
|
643
|
+
this.rateLimits = { light: 100, group: 1000 };
|
|
644
|
+
this.nextSlot = { light: 0, group: 0 };
|
|
645
|
+
|
|
646
|
+
// RESERVE THE NEXT FREE TIME SLOT / GIVE BACK HOW LONG TO WAIT FOR IT
|
|
647
|
+
this.reserveSlot = function(type)
|
|
648
|
+
{
|
|
649
|
+
const channel = (type === "group" || type === "grouped_light" || type === "scene" || type === "smart_scene") ? "group" : "light";
|
|
650
|
+
const now = Date.now();
|
|
651
|
+
const slot = Math.max(now, scope.nextSlot[channel]);
|
|
652
|
+
|
|
653
|
+
scope.nextSlot[channel] = slot + scope.rateLimits[channel];
|
|
654
|
+
return slot - now;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// PATCH RESOURCE (WORKER)
|
|
518
658
|
this.patchQueue = fastq(function({ type, id, patch, version }, callback)
|
|
519
659
|
{
|
|
520
660
|
// GET SERVICE ID
|
|
@@ -524,14 +664,17 @@ module.exports = function(RED)
|
|
|
524
664
|
id = targetResource.id;
|
|
525
665
|
}
|
|
526
666
|
|
|
527
|
-
// ACTION!
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
667
|
+
// ACTION! (BUT NEVER FASTER THAN THE BRIDGE CAN TAKE IT)
|
|
668
|
+
setTimeout(function()
|
|
669
|
+
{
|
|
670
|
+
API.request({ config: config, method: "PUT", resource: (version === 2) ? (type+"/"+id) : id, data: patch, version: version })
|
|
671
|
+
.then(function(response) {
|
|
672
|
+
callback(null, response);
|
|
673
|
+
})
|
|
674
|
+
.catch(function(error) {
|
|
675
|
+
callback(error, null);
|
|
676
|
+
});
|
|
677
|
+
}, scope.reserveSlot(type));
|
|
535
678
|
}, config.worker ? parseInt(config.worker) : 10);
|
|
536
679
|
|
|
537
680
|
// RE-FETCH RULE (RECEIVES NO UPDATES VIA SSE)
|
|
@@ -581,23 +724,34 @@ module.exports = function(RED)
|
|
|
581
724
|
// PUSH WHITELIST
|
|
582
725
|
const messageWhitelist = {
|
|
583
726
|
"light": ["light", "zigbee_connectivity", "zgp_connectivity", "device"],
|
|
584
|
-
"motion": ["motion", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
727
|
+
"motion": ["motion", "camera_motion", "grouped_motion", "convenience_area_motion", "security_area_motion", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
728
|
+
"contact": ["contact", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
585
729
|
"temperature": ["temperature", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
586
|
-
"light_level": ["light_level", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
587
|
-
"button": ["button", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
730
|
+
"light_level": ["light_level", "grouped_light_level", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
731
|
+
"button": ["button", "bell_button", "relative_rotary", "switch_input_configuration", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
588
732
|
"group": ["group", "light", "grouped_light"],
|
|
733
|
+
"speaker": ["speaker", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
734
|
+
"automation": ["behavior_instance"],
|
|
589
735
|
"rule": ["rule"]
|
|
590
736
|
};
|
|
591
737
|
|
|
738
|
+
let eventName;
|
|
739
|
+
let listener;
|
|
740
|
+
|
|
592
741
|
if(!id)
|
|
593
742
|
{
|
|
594
743
|
// UNIVERSAL MODE
|
|
595
|
-
|
|
744
|
+
eventName = config.id + "_" + "globalResourceUpdates";
|
|
745
|
+
listener = function(info)
|
|
596
746
|
{
|
|
597
747
|
if(type === "bridge")
|
|
598
748
|
{
|
|
599
749
|
callback(info);
|
|
600
750
|
}
|
|
751
|
+
else if(!messageWhitelist[type])
|
|
752
|
+
{
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
601
755
|
else if(info.services.includes(type) && messageWhitelist[type].includes(info.updatedType))
|
|
602
756
|
{
|
|
603
757
|
callback(info);
|
|
@@ -606,19 +760,27 @@ module.exports = function(RED)
|
|
|
606
760
|
{
|
|
607
761
|
callback(info);
|
|
608
762
|
}
|
|
609
|
-
}
|
|
763
|
+
};
|
|
610
764
|
}
|
|
611
765
|
else
|
|
612
766
|
{
|
|
613
767
|
// SPECIFIC RESOURCE MODE
|
|
614
|
-
|
|
768
|
+
eventName = config.id + "_" + id;
|
|
769
|
+
listener = function(info)
|
|
615
770
|
{
|
|
771
|
+
if(type !== "bridge" && !messageWhitelist[type]) { return false; }
|
|
772
|
+
|
|
616
773
|
if(type === "bridge" || messageWhitelist[type].includes(info.updatedType))
|
|
617
774
|
{
|
|
618
775
|
callback(info);
|
|
619
776
|
}
|
|
620
|
-
}
|
|
777
|
+
};
|
|
621
778
|
}
|
|
779
|
+
|
|
780
|
+
scope.events.on(eventName, listener);
|
|
781
|
+
|
|
782
|
+
// THE CONFIG NODE OUTLIVES A REDEPLOY, SO EVERY NODE HAS TO DETACH ITSELF AGAIN
|
|
783
|
+
return function() { scope.events.removeListener(eventName, listener); };
|
|
622
784
|
}
|
|
623
785
|
|
|
624
786
|
// AUTO UPDATES?
|
|
@@ -660,7 +822,7 @@ module.exports = function(RED)
|
|
|
660
822
|
//
|
|
661
823
|
// START THE MAGIC
|
|
662
824
|
this.start();
|
|
663
|
-
|
|
825
|
+
|
|
664
826
|
//
|
|
665
827
|
// CLOSE NODE / REMOVE EVENT LISTENER
|
|
666
828
|
this.on('close', function()
|
|
@@ -668,14 +830,16 @@ module.exports = function(RED)
|
|
|
668
830
|
scope.nodeActive = false;
|
|
669
831
|
|
|
670
832
|
// UNSUBSCRIBE FROM BRIDGE EVENTS
|
|
671
|
-
scope.log("
|
|
833
|
+
scope.log(RED._("hue-bridge-config.node.unsubscribing"));
|
|
672
834
|
API.unsubscribe(config);
|
|
673
835
|
|
|
674
836
|
// UNSUBSCRIBE FROM "READY" EVENTS
|
|
675
837
|
scope.events.removeAllListeners();
|
|
676
838
|
|
|
677
|
-
// REMOVE
|
|
839
|
+
// REMOVE ALL TIMEOUTS
|
|
678
840
|
if(scope.firmwareUpdateTimeout !== null) { clearTimeout(scope.firmwareUpdateTimeout); }
|
|
841
|
+
if(scope.timerWatchDog !== null) { clearTimeout(scope.timerWatchDog); }
|
|
842
|
+
if(scope.refetchTimeout !== null) { clearTimeout(scope.refetchTimeout); }
|
|
679
843
|
|
|
680
844
|
// KILL QUEUE
|
|
681
845
|
scope.patchQueue.kill();
|
|
@@ -686,7 +850,7 @@ module.exports = function(RED)
|
|
|
686
850
|
|
|
687
851
|
//
|
|
688
852
|
// DISCOVER HUE BRIDGES ON LOCAL NETWORK
|
|
689
|
-
RED.httpAdmin.get('/hue/bridges', async function(req, res, next)
|
|
853
|
+
RED.httpAdmin.get('/hue/bridges', RED.auth.needsPermission('hue-bridge.read'), async function(req, res, next)
|
|
690
854
|
{
|
|
691
855
|
axios({
|
|
692
856
|
"method": "GET",
|
|
@@ -694,6 +858,7 @@ module.exports = function(RED)
|
|
|
694
858
|
"headers": {
|
|
695
859
|
"Content-Type": "application/json; charset=utf-8"
|
|
696
860
|
},
|
|
861
|
+
"timeout": 10000,
|
|
697
862
|
})
|
|
698
863
|
.then(function(response)
|
|
699
864
|
{
|
|
@@ -701,20 +866,24 @@ module.exports = function(RED)
|
|
|
701
866
|
var bridges = {};
|
|
702
867
|
for (var i = response.data.length - 1; i >= 0; i--)
|
|
703
868
|
{
|
|
704
|
-
|
|
705
|
-
|
|
869
|
+
// THE DISCOVERY SERVICE ALSO ANSWERS WITH A PORT SINCE THE BRIDGE PRO
|
|
870
|
+
const ipAddress = response.data[i].internalipaddress;
|
|
871
|
+
const port = response.data[i].port;
|
|
872
|
+
const target = (port && port !== 443) ? (ipAddress + ":" + port) : ipAddress;
|
|
873
|
+
|
|
874
|
+
bridges[target] = { ip: target, name: target };
|
|
706
875
|
}
|
|
707
876
|
|
|
708
877
|
res.end(JSON.stringify(Object.values(bridges)));
|
|
709
878
|
})
|
|
710
879
|
.catch(function(error) {
|
|
711
|
-
res.send(error);
|
|
880
|
+
res.status(500).send(JSON.stringify({ error: error.message }));
|
|
712
881
|
});
|
|
713
882
|
});
|
|
714
883
|
|
|
715
884
|
//
|
|
716
885
|
// GET BRIDGE NAME
|
|
717
|
-
RED.httpAdmin.get('/hue/name', function(req, res, next)
|
|
886
|
+
RED.httpAdmin.get('/hue/name', RED.auth.needsPermission('hue-bridge.read'), function(req, res, next)
|
|
718
887
|
{
|
|
719
888
|
if(!req.query.ip)
|
|
720
889
|
{
|
|
@@ -727,14 +896,14 @@ module.exports = function(RED)
|
|
|
727
896
|
res.end(bridge.name);
|
|
728
897
|
})
|
|
729
898
|
.catch(function(error) {
|
|
730
|
-
res.send(error);
|
|
899
|
+
res.status(500).send(error.message ? error.message : JSON.stringify(error));
|
|
731
900
|
});
|
|
732
901
|
}
|
|
733
902
|
});
|
|
734
903
|
|
|
735
904
|
//
|
|
736
905
|
// REGISTER A HUE BRIDGE
|
|
737
|
-
RED.httpAdmin.get('/hue/register', function(req, rescope, next)
|
|
906
|
+
RED.httpAdmin.get('/hue/register', RED.auth.needsPermission('hue-bridge.read'), function(req, rescope, next)
|
|
738
907
|
{
|
|
739
908
|
if(!req.query.ip)
|
|
740
909
|
{
|
|
@@ -742,21 +911,27 @@ module.exports = function(RED)
|
|
|
742
911
|
}
|
|
743
912
|
else
|
|
744
913
|
{
|
|
914
|
+
// MODERN BRIDGES (AND THE BRIDGE PRO) NO LONGER ANSWER ON PLAIN HTTP
|
|
745
915
|
axios({
|
|
746
916
|
"method": "POST",
|
|
747
|
-
"url": "
|
|
917
|
+
"url": "https://"+req.query.ip+"/api",
|
|
748
918
|
"httpsAgent": new https.Agent({ rejectUnauthorized: false }),
|
|
919
|
+
"proxy": false, // THE BRIDGE IS ON THE LOCAL NETWORK, NEVER GO THROUGH A PROXY
|
|
749
920
|
"headers": {
|
|
750
921
|
"Content-Type": "application/json; charset=utf-8"
|
|
751
922
|
},
|
|
923
|
+
"timeout": 10000,
|
|
752
924
|
"data": {
|
|
753
|
-
"devicetype": "
|
|
925
|
+
"devicetype": "huemagic#node-red " + Math.floor((Math.random() * 100) + 1),
|
|
926
|
+
"generateclientkey": true
|
|
754
927
|
}
|
|
755
928
|
})
|
|
756
929
|
.then(function(response)
|
|
757
930
|
{
|
|
758
931
|
var bridge = response.data;
|
|
759
|
-
|
|
932
|
+
|
|
933
|
+
// LINK BUTTON NOT PRESSED (ERROR TYPE 101) OR ANYTHING ELSE WENT WRONG
|
|
934
|
+
if(!Array.isArray(bridge) || !bridge[0] || bridge[0].error || !bridge[0].success)
|
|
760
935
|
{
|
|
761
936
|
rescope.end("error");
|
|
762
937
|
}
|
|
@@ -766,14 +941,14 @@ module.exports = function(RED)
|
|
|
766
941
|
}
|
|
767
942
|
})
|
|
768
943
|
.catch(function(error) {
|
|
769
|
-
rescope.status(500).send(error);
|
|
944
|
+
rescope.status(500).send(error.message ? error.message : JSON.stringify(error));
|
|
770
945
|
});
|
|
771
946
|
}
|
|
772
947
|
});
|
|
773
948
|
|
|
774
949
|
//
|
|
775
950
|
// DISCOVER RESOURCES
|
|
776
|
-
RED.httpAdmin.get('/hue/resources', function(req, res, next)
|
|
951
|
+
RED.httpAdmin.get('/hue/resources', RED.auth.needsPermission('hue-bridge.read'), function(req, res, next)
|
|
777
952
|
{
|
|
778
953
|
const targetType = req.query.type;
|
|
779
954
|
|
|
@@ -787,6 +962,9 @@ module.exports = function(RED)
|
|
|
787
962
|
|
|
788
963
|
for (var [id, rule] of Object.entries(rules))
|
|
789
964
|
{
|
|
965
|
+
// SKIP ERROR RESPONSES OF THE LEGACY API
|
|
966
|
+
if(!rule || typeof rule !== 'object' || rule["error"]) { continue; }
|
|
967
|
+
|
|
790
968
|
var oneDevice = {};
|
|
791
969
|
oneDevice.id = id;
|
|
792
970
|
oneDevice.name = rule.name;
|
|
@@ -821,19 +999,29 @@ module.exports = function(RED)
|
|
|
821
999
|
{
|
|
822
1000
|
const isGroup = (resource["type"] == "room" || resource["type"] == "zone" || resource["type"] == "bridge_home");
|
|
823
1001
|
|
|
824
|
-
//
|
|
825
|
-
if(
|
|
1002
|
+
// AUTOMATIONS OF THE HUE APP
|
|
1003
|
+
if(targetType === "automation")
|
|
826
1004
|
{
|
|
827
|
-
|
|
1005
|
+
if(resource["type"] === "behavior_instance")
|
|
828
1006
|
{
|
|
829
1007
|
var oneDevice = {};
|
|
830
1008
|
oneDevice.id = id;
|
|
831
|
-
oneDevice.name = resource.metadata ? resource.metadata.name :
|
|
832
|
-
oneDevice.model = resource.
|
|
1009
|
+
oneDevice.name = (resource.metadata && resource.metadata.name) ? resource.metadata.name : id;
|
|
1010
|
+
oneDevice.model = resource.script_id ? resource.script_id : false;
|
|
833
1011
|
|
|
834
1012
|
targetDevices[id] = oneDevice;
|
|
835
1013
|
}
|
|
836
1014
|
}
|
|
1015
|
+
// NORMAL DEVICES
|
|
1016
|
+
else if(!isGroup && servesType(resource, targetType))
|
|
1017
|
+
{
|
|
1018
|
+
var oneDevice = {};
|
|
1019
|
+
oneDevice.id = id;
|
|
1020
|
+
oneDevice.name = resource.metadata ? resource.metadata.name : (resource.name ? resource.name : false);
|
|
1021
|
+
oneDevice.model = resource.product_data ? resource.product_data.product_name : false;
|
|
1022
|
+
|
|
1023
|
+
targetDevices[id] = oneDevice;
|
|
1024
|
+
}
|
|
837
1025
|
// GROUPED (LIGHT) RESOURCES
|
|
838
1026
|
else if(isGroup && targetType === "group")
|
|
839
1027
|
{
|
|
@@ -848,12 +1036,15 @@ module.exports = function(RED)
|
|
|
848
1036
|
}
|
|
849
1037
|
}
|
|
850
1038
|
// SCENES
|
|
851
|
-
else if(targetType === "scene" && resource["type"] == "scene")
|
|
1039
|
+
else if(targetType === "scene" && (resource["type"] == "scene" || resource["type"] == "smart_scene"))
|
|
852
1040
|
{
|
|
1041
|
+
// THE GROUP OF A SCENE MAY BE UNKNOWN OR ALREADY DELETED
|
|
1042
|
+
const sceneGroup = (resource["group"] && processedResources[resource["group"]["rid"]]) ? processedResources[resource["group"]["rid"]] : false;
|
|
1043
|
+
|
|
853
1044
|
var oneDevice = {};
|
|
854
1045
|
oneDevice.id = id;
|
|
855
1046
|
oneDevice.name = resource.metadata ? resource.metadata.name : false;
|
|
856
|
-
oneDevice.group =
|
|
1047
|
+
oneDevice.group = (sceneGroup && sceneGroup.metadata) ? sceneGroup.metadata.name : "–";
|
|
857
1048
|
|
|
858
1049
|
targetDevices[id] = oneDevice;
|
|
859
1050
|
}
|
|
@@ -870,4 +1061,4 @@ module.exports = function(RED)
|
|
|
870
1061
|
});
|
|
871
1062
|
}
|
|
872
1063
|
});
|
|
873
|
-
};
|
|
1064
|
+
};
|