node-red-contrib-huemagic 4.2.1 → 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 +95 -5
- package/README.md +511 -122
- 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 +299 -106
- 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 -7
- 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 +162 -57
- 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 -12
- 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
|
-
this.timerWatchDog = null;
|
|
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;
|
|
@@ -45,44 +53,55 @@ module.exports = function(RED)
|
|
|
45
53
|
// CREATE NODE
|
|
46
54
|
RED.nodes.createNode(scope, config);
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
56
|
+
// PERIODICALLY CHECK WETHER BRIDGE IS CONNECTED
|
|
57
|
+
this.startWatchdog = function()
|
|
58
|
+
{
|
|
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()
|
|
64
|
+
{
|
|
65
|
+
API.request({ config: config, resource: "bridge" })
|
|
66
|
+
.then(function(bridgeInformation)
|
|
67
|
+
{
|
|
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
|
}
|
|
88
|
+
|
|
72
89
|
// INITIALIZE
|
|
73
90
|
this.start = function()
|
|
74
91
|
{
|
|
75
|
-
|
|
92
|
+
if(scope.starting === true || scope.nodeActive === false) { return false; }
|
|
93
|
+
scope.starting = true;
|
|
94
|
+
scope.watchdogFailures = 0;
|
|
76
95
|
|
|
77
|
-
scope.log("
|
|
96
|
+
scope.log(RED._("hue-bridge-config.node.initializing", { bridge: config.bridge }));
|
|
78
97
|
API.init({ config: config })
|
|
79
98
|
.then(function(bridge) {
|
|
80
|
-
scope.log("
|
|
99
|
+
scope.log(RED._("hue-bridge-config.node.connected"));
|
|
81
100
|
return scope.getAllResources();
|
|
82
101
|
})
|
|
83
102
|
.then(function(allResources)
|
|
84
103
|
{
|
|
85
|
-
scope.log("
|
|
104
|
+
scope.log(RED._("hue-bridge-config.node.processing"));
|
|
86
105
|
return API.processResources(allResources);
|
|
87
106
|
})
|
|
88
107
|
.then(function(allResources)
|
|
@@ -91,21 +110,27 @@ module.exports = function(RED)
|
|
|
91
110
|
scope.resources = allResources;
|
|
92
111
|
|
|
93
112
|
// EMIT INITIAL STATES -> NODES
|
|
94
|
-
scope.log("
|
|
113
|
+
scope.log(RED._("hue-bridge-config.node.initial-emit"));
|
|
95
114
|
return scope.emitInitialStates();
|
|
96
115
|
})
|
|
97
116
|
.then(function(emitted)
|
|
98
117
|
{
|
|
118
|
+
scope.starting = false;
|
|
119
|
+
|
|
99
120
|
// START REFRESHING STATES
|
|
100
121
|
scope.keepUpdated();
|
|
101
122
|
|
|
102
123
|
// START LOOKING FOR FIRMWARE-UPDATES
|
|
103
124
|
scope.autoUpdateFirmware();
|
|
125
|
+
|
|
126
|
+
// START WATCHDOG
|
|
127
|
+
scope.startWatchdog();
|
|
104
128
|
return true;
|
|
105
129
|
})
|
|
106
130
|
.catch(function(error)
|
|
107
131
|
{
|
|
108
132
|
// RETRY AFTER 30 SECONDS
|
|
133
|
+
scope.starting = false;
|
|
109
134
|
scope.log(error);
|
|
110
135
|
if(scope.nodeActive == true) { setTimeout(function(){ scope.start(); }, 30000); }
|
|
111
136
|
});
|
|
@@ -147,8 +172,13 @@ module.exports = function(RED)
|
|
|
147
172
|
{
|
|
148
173
|
var allResources = [];
|
|
149
174
|
|
|
150
|
-
// GET BRIDGE INFORMATION
|
|
175
|
+
// GET BRIDGE INFORMATION (LEGACY API / MAY BE UNAVAILABLE)
|
|
151
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
|
+
})
|
|
152
182
|
.then(function(bridgeInformation)
|
|
153
183
|
{
|
|
154
184
|
// PUSH TO RESOURCES
|
|
@@ -162,13 +192,16 @@ module.exports = function(RED)
|
|
|
162
192
|
// MERGE RESOURCES
|
|
163
193
|
allResources = allResources.concat(v2Resources);
|
|
164
194
|
|
|
165
|
-
// GET RULES (LEGACY API)
|
|
166
|
-
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 {}; });
|
|
167
197
|
})
|
|
168
198
|
.then(function(rules)
|
|
169
199
|
{
|
|
170
200
|
for (var [id, rule] of Object.entries(rules))
|
|
171
201
|
{
|
|
202
|
+
// SKIP ERROR RESPONSES OF THE LEGACY API
|
|
203
|
+
if(!rule || typeof rule !== 'object' || rule["error"]) { continue; }
|
|
204
|
+
|
|
172
205
|
// "RENAME" OWNER
|
|
173
206
|
rule["_owner"] = rule["owner"];
|
|
174
207
|
delete rule["owner"];
|
|
@@ -201,6 +234,7 @@ module.exports = function(RED)
|
|
|
201
234
|
// PUSH ALL STATES
|
|
202
235
|
for (const [id, resource] of Object.entries(scope.resources))
|
|
203
236
|
{
|
|
237
|
+
if(id === "_groupsOf") { continue; }
|
|
204
238
|
scope.pushUpdatedState(resource, resource.type, true);
|
|
205
239
|
}
|
|
206
240
|
|
|
@@ -214,7 +248,7 @@ module.exports = function(RED)
|
|
|
214
248
|
{
|
|
215
249
|
if(!config.disableupdates)
|
|
216
250
|
{
|
|
217
|
-
scope.log("
|
|
251
|
+
scope.log(RED._("hue-bridge-config.node.keep-updated"));
|
|
218
252
|
|
|
219
253
|
// REFRESH STATES (SSE)
|
|
220
254
|
this.refreshStatesSSE();
|
|
@@ -224,11 +258,17 @@ module.exports = function(RED)
|
|
|
224
258
|
// GET UPDATED STATES (SSE)
|
|
225
259
|
this.refreshStatesSSE = function()
|
|
226
260
|
{
|
|
227
|
-
scope.log("
|
|
228
|
-
API.subscribe(config, function(updates)
|
|
261
|
+
scope.log(RED._("hue-bridge-config.node.subscribing"));
|
|
262
|
+
API.subscribe(config, function(updates, eventType)
|
|
229
263
|
{
|
|
230
264
|
const currentDateTime = dayjs().format();
|
|
231
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
|
+
|
|
232
272
|
for(let resource of updates)
|
|
233
273
|
{
|
|
234
274
|
let id = resource.id;
|
|
@@ -240,18 +280,19 @@ module.exports = function(RED)
|
|
|
240
280
|
if(resource["owner"])
|
|
241
281
|
{
|
|
242
282
|
let targetId = resource["owner"]["rid"];
|
|
283
|
+
const services = scope.resources[targetId] ? scope.resources[targetId]["services"] : false;
|
|
243
284
|
|
|
244
|
-
if(
|
|
285
|
+
if(services && services[type])
|
|
245
286
|
{
|
|
246
287
|
// GET PREVIOUS STATE
|
|
247
|
-
previousState =
|
|
288
|
+
previousState = services[type][id];
|
|
248
289
|
|
|
249
|
-
// IS BUTTON? -> REMOVE PREVIOUS STATES
|
|
250
|
-
if(type === "button")
|
|
290
|
+
// IS BUTTON OR DIAL? -> REMOVE PREVIOUS STATES
|
|
291
|
+
if(type === "button" || type === "relative_rotary")
|
|
251
292
|
{
|
|
252
|
-
for (const [
|
|
293
|
+
for (const [oneServiceID, oneService] of Object.entries(services[type]))
|
|
253
294
|
{
|
|
254
|
-
delete
|
|
295
|
+
delete services[type][oneServiceID][type];
|
|
255
296
|
}
|
|
256
297
|
}
|
|
257
298
|
}
|
|
@@ -262,8 +303,8 @@ module.exports = function(RED)
|
|
|
262
303
|
previousState = scope.resources[id];
|
|
263
304
|
}
|
|
264
305
|
|
|
265
|
-
// NO PREVIOUS STATE?
|
|
266
|
-
if(!previousState) {
|
|
306
|
+
// NO PREVIOUS STATE? -> UNKNOWN RESOURCE, CONTINUE WITH THE NEXT ONE
|
|
307
|
+
if(!previousState) { continue; }
|
|
267
308
|
|
|
268
309
|
// CHECK DIFFERENCES
|
|
269
310
|
const mergedState = merge.deep(previousState, resource);
|
|
@@ -291,23 +332,59 @@ module.exports = function(RED)
|
|
|
291
332
|
}
|
|
292
333
|
}
|
|
293
334
|
}
|
|
335
|
+
},
|
|
336
|
+
function(reason, seconds)
|
|
337
|
+
{
|
|
338
|
+
scope.log(RED._("hue-bridge-config.node.connection-lost", { reason: reason, seconds: seconds }));
|
|
294
339
|
});
|
|
295
340
|
}
|
|
296
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
|
+
|
|
297
365
|
// PUSH UPDATED STATE
|
|
298
366
|
this.pushUpdatedState = function(resource, updatedType, suppressMessage = false)
|
|
299
367
|
{
|
|
300
|
-
|
|
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 };
|
|
301
376
|
this.events.emit(config.id + "_" + resource.id, msg);
|
|
302
377
|
this.events.emit(config.id + "_" + "globalResourceUpdates", msg);
|
|
303
378
|
|
|
304
379
|
// RESOURCE CONTAINS SERVICES? -> SERVICE IN GROUP? -> EMIT CHANGES TO GROUPS ALSO
|
|
305
|
-
|
|
380
|
+
const groupsOfResource = this.resources["_groupsOf"] ? this.resources["_groupsOf"][resource.id] : false;
|
|
381
|
+
|
|
382
|
+
if(groupsOfResource)
|
|
306
383
|
{
|
|
307
|
-
for (var g =
|
|
384
|
+
for (var g = groupsOfResource.length - 1; g >= 0; g--)
|
|
308
385
|
{
|
|
309
|
-
const groupID =
|
|
310
|
-
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 };
|
|
311
388
|
|
|
312
389
|
this.events.emit(config.id + "_" + groupID, groupMessage);
|
|
313
390
|
this.events.emit(config.id + "_" + "globalResourceUpdates", groupMessage);
|
|
@@ -326,7 +403,7 @@ module.exports = function(RED)
|
|
|
326
403
|
{
|
|
327
404
|
// RESOLVE LINKS
|
|
328
405
|
const targetResource = scope.resources[id];
|
|
329
|
-
const lastState = scope.lastStates[type+targetResource.id] ?
|
|
406
|
+
const lastState = scope.lastStates[type+targetResource.id] ? structuredClone(scope.lastStates[type+targetResource.id]) : false;
|
|
330
407
|
|
|
331
408
|
if(type == "bridge")
|
|
332
409
|
{
|
|
@@ -335,11 +412,11 @@ module.exports = function(RED)
|
|
|
335
412
|
|
|
336
413
|
// GET CURRENT STATE MESSAGE
|
|
337
414
|
let currentState = message.msg;
|
|
338
|
-
return currentState;
|
|
415
|
+
return currentState;
|
|
339
416
|
} catch (error) {
|
|
340
417
|
return false;
|
|
341
418
|
}
|
|
342
|
-
|
|
419
|
+
|
|
343
420
|
}
|
|
344
421
|
else if(type == "light")
|
|
345
422
|
{
|
|
@@ -348,7 +425,7 @@ module.exports = function(RED)
|
|
|
348
425
|
|
|
349
426
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
350
427
|
let currentState = message.msg;
|
|
351
|
-
scope.lastStates[type+targetResource.id] =
|
|
428
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
352
429
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
353
430
|
currentState.lastState = lastState;
|
|
354
431
|
|
|
@@ -365,7 +442,7 @@ module.exports = function(RED)
|
|
|
365
442
|
|
|
366
443
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
367
444
|
let currentState = message.msg;
|
|
368
|
-
scope.lastStates[type+targetResource.id] =
|
|
445
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
369
446
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
370
447
|
currentState.lastState = lastState;
|
|
371
448
|
|
|
@@ -381,7 +458,7 @@ module.exports = function(RED)
|
|
|
381
458
|
|
|
382
459
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
383
460
|
let currentState = message.msg;
|
|
384
|
-
scope.lastStates[type+targetResource.id] =
|
|
461
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
385
462
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
386
463
|
currentState.lastState = lastState;
|
|
387
464
|
|
|
@@ -397,7 +474,23 @@ module.exports = function(RED)
|
|
|
397
474
|
|
|
398
475
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
399
476
|
let currentState = message.msg;
|
|
400
|
-
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);
|
|
401
494
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
402
495
|
currentState.lastState = lastState;
|
|
403
496
|
|
|
@@ -413,7 +506,7 @@ module.exports = function(RED)
|
|
|
413
506
|
|
|
414
507
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
415
508
|
let currentState = message.msg;
|
|
416
|
-
scope.lastStates[type+targetResource.id] =
|
|
509
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
417
510
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
418
511
|
currentState.lastState = lastState;
|
|
419
512
|
|
|
@@ -429,7 +522,39 @@ module.exports = function(RED)
|
|
|
429
522
|
|
|
430
523
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
431
524
|
let currentState = message.msg;
|
|
432
|
-
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);
|
|
433
558
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
434
559
|
currentState.lastState = lastState;
|
|
435
560
|
|
|
@@ -445,7 +570,7 @@ module.exports = function(RED)
|
|
|
445
570
|
|
|
446
571
|
// GET & SAVE LAST STATE AND DIFFERENCES
|
|
447
572
|
let currentState = message.msg;
|
|
448
|
-
scope.lastStates[type+targetResource.id] =
|
|
573
|
+
scope.lastStates[type+targetResource.id] = structuredClone(currentState);
|
|
449
574
|
currentState.updated = (lastState === false) ? {} : diff(lastState, currentState);
|
|
450
575
|
currentState.lastState = lastState;
|
|
451
576
|
|
|
@@ -473,13 +598,15 @@ module.exports = function(RED)
|
|
|
473
598
|
{
|
|
474
599
|
const isGroup = (resource["type"] == "room" || resource["type"] == "zone" || resource["type"] == "bridge_home");
|
|
475
600
|
|
|
601
|
+
// AUTOMATIONS ARE NOT DEVICES
|
|
602
|
+
if(type === "automation")
|
|
603
|
+
{
|
|
604
|
+
if(resource["type"] === "behavior_instance") { allFilteredResources[rootID] = scope.get(type, rootID); }
|
|
605
|
+
}
|
|
476
606
|
// NORMAL DEVICES
|
|
477
|
-
if(!isGroup && resource
|
|
607
|
+
else if(!isGroup && servesType(resource, type))
|
|
478
608
|
{
|
|
479
|
-
|
|
480
|
-
{
|
|
481
|
-
allFilteredResources[rootID] = scope.get(type, rootID);
|
|
482
|
-
}
|
|
609
|
+
allFilteredResources[rootID] = scope.get(type, rootID);
|
|
483
610
|
}
|
|
484
611
|
// GROUPED RESOURCES
|
|
485
612
|
else if(isGroup && type === "group")
|
|
@@ -497,7 +624,7 @@ module.exports = function(RED)
|
|
|
497
624
|
{
|
|
498
625
|
return new Promise(function(resolve, reject)
|
|
499
626
|
{
|
|
500
|
-
if(!scope.patchQueue) { return
|
|
627
|
+
if(!scope.patchQueue) { return reject({ status: "ECONNRESET", errors: RED._("hue-bridge-config.node.not-connected") }); }
|
|
501
628
|
scope.patchQueue.push({ type: type, id: id, patch: patch, version: version }, function (error, response)
|
|
502
629
|
{
|
|
503
630
|
if(error)
|
|
@@ -512,7 +639,22 @@ module.exports = function(RED)
|
|
|
512
639
|
});
|
|
513
640
|
}
|
|
514
641
|
|
|
515
|
-
//
|
|
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)
|
|
516
658
|
this.patchQueue = fastq(function({ type, id, patch, version }, callback)
|
|
517
659
|
{
|
|
518
660
|
// GET SERVICE ID
|
|
@@ -522,14 +664,17 @@ module.exports = function(RED)
|
|
|
522
664
|
id = targetResource.id;
|
|
523
665
|
}
|
|
524
666
|
|
|
525
|
-
// ACTION!
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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));
|
|
533
678
|
}, config.worker ? parseInt(config.worker) : 10);
|
|
534
679
|
|
|
535
680
|
// RE-FETCH RULE (RECEIVES NO UPDATES VIA SSE)
|
|
@@ -579,23 +724,34 @@ module.exports = function(RED)
|
|
|
579
724
|
// PUSH WHITELIST
|
|
580
725
|
const messageWhitelist = {
|
|
581
726
|
"light": ["light", "zigbee_connectivity", "zgp_connectivity", "device"],
|
|
582
|
-
"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"],
|
|
583
729
|
"temperature": ["temperature", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
584
|
-
"light_level": ["light_level", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
585
|
-
"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"],
|
|
586
732
|
"group": ["group", "light", "grouped_light"],
|
|
733
|
+
"speaker": ["speaker", "zigbee_connectivity", "zgp_connectivity", "device_power", "device"],
|
|
734
|
+
"automation": ["behavior_instance"],
|
|
587
735
|
"rule": ["rule"]
|
|
588
736
|
};
|
|
589
737
|
|
|
738
|
+
let eventName;
|
|
739
|
+
let listener;
|
|
740
|
+
|
|
590
741
|
if(!id)
|
|
591
742
|
{
|
|
592
743
|
// UNIVERSAL MODE
|
|
593
|
-
|
|
744
|
+
eventName = config.id + "_" + "globalResourceUpdates";
|
|
745
|
+
listener = function(info)
|
|
594
746
|
{
|
|
595
747
|
if(type === "bridge")
|
|
596
748
|
{
|
|
597
749
|
callback(info);
|
|
598
750
|
}
|
|
751
|
+
else if(!messageWhitelist[type])
|
|
752
|
+
{
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
599
755
|
else if(info.services.includes(type) && messageWhitelist[type].includes(info.updatedType))
|
|
600
756
|
{
|
|
601
757
|
callback(info);
|
|
@@ -604,19 +760,27 @@ module.exports = function(RED)
|
|
|
604
760
|
{
|
|
605
761
|
callback(info);
|
|
606
762
|
}
|
|
607
|
-
}
|
|
763
|
+
};
|
|
608
764
|
}
|
|
609
765
|
else
|
|
610
766
|
{
|
|
611
767
|
// SPECIFIC RESOURCE MODE
|
|
612
|
-
|
|
768
|
+
eventName = config.id + "_" + id;
|
|
769
|
+
listener = function(info)
|
|
613
770
|
{
|
|
771
|
+
if(type !== "bridge" && !messageWhitelist[type]) { return false; }
|
|
772
|
+
|
|
614
773
|
if(type === "bridge" || messageWhitelist[type].includes(info.updatedType))
|
|
615
774
|
{
|
|
616
775
|
callback(info);
|
|
617
776
|
}
|
|
618
|
-
}
|
|
777
|
+
};
|
|
619
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); };
|
|
620
784
|
}
|
|
621
785
|
|
|
622
786
|
// AUTO UPDATES?
|
|
@@ -658,7 +822,7 @@ module.exports = function(RED)
|
|
|
658
822
|
//
|
|
659
823
|
// START THE MAGIC
|
|
660
824
|
this.start();
|
|
661
|
-
|
|
825
|
+
|
|
662
826
|
//
|
|
663
827
|
// CLOSE NODE / REMOVE EVENT LISTENER
|
|
664
828
|
this.on('close', function()
|
|
@@ -666,14 +830,16 @@ module.exports = function(RED)
|
|
|
666
830
|
scope.nodeActive = false;
|
|
667
831
|
|
|
668
832
|
// UNSUBSCRIBE FROM BRIDGE EVENTS
|
|
669
|
-
scope.log("
|
|
833
|
+
scope.log(RED._("hue-bridge-config.node.unsubscribing"));
|
|
670
834
|
API.unsubscribe(config);
|
|
671
835
|
|
|
672
836
|
// UNSUBSCRIBE FROM "READY" EVENTS
|
|
673
837
|
scope.events.removeAllListeners();
|
|
674
838
|
|
|
675
|
-
// REMOVE
|
|
839
|
+
// REMOVE ALL TIMEOUTS
|
|
676
840
|
if(scope.firmwareUpdateTimeout !== null) { clearTimeout(scope.firmwareUpdateTimeout); }
|
|
841
|
+
if(scope.timerWatchDog !== null) { clearTimeout(scope.timerWatchDog); }
|
|
842
|
+
if(scope.refetchTimeout !== null) { clearTimeout(scope.refetchTimeout); }
|
|
677
843
|
|
|
678
844
|
// KILL QUEUE
|
|
679
845
|
scope.patchQueue.kill();
|
|
@@ -684,7 +850,7 @@ module.exports = function(RED)
|
|
|
684
850
|
|
|
685
851
|
//
|
|
686
852
|
// DISCOVER HUE BRIDGES ON LOCAL NETWORK
|
|
687
|
-
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)
|
|
688
854
|
{
|
|
689
855
|
axios({
|
|
690
856
|
"method": "GET",
|
|
@@ -692,6 +858,7 @@ module.exports = function(RED)
|
|
|
692
858
|
"headers": {
|
|
693
859
|
"Content-Type": "application/json; charset=utf-8"
|
|
694
860
|
},
|
|
861
|
+
"timeout": 10000,
|
|
695
862
|
})
|
|
696
863
|
.then(function(response)
|
|
697
864
|
{
|
|
@@ -699,20 +866,24 @@ module.exports = function(RED)
|
|
|
699
866
|
var bridges = {};
|
|
700
867
|
for (var i = response.data.length - 1; i >= 0; i--)
|
|
701
868
|
{
|
|
702
|
-
|
|
703
|
-
|
|
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 };
|
|
704
875
|
}
|
|
705
876
|
|
|
706
877
|
res.end(JSON.stringify(Object.values(bridges)));
|
|
707
878
|
})
|
|
708
879
|
.catch(function(error) {
|
|
709
|
-
res.send(error);
|
|
880
|
+
res.status(500).send(JSON.stringify({ error: error.message }));
|
|
710
881
|
});
|
|
711
882
|
});
|
|
712
883
|
|
|
713
884
|
//
|
|
714
885
|
// GET BRIDGE NAME
|
|
715
|
-
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)
|
|
716
887
|
{
|
|
717
888
|
if(!req.query.ip)
|
|
718
889
|
{
|
|
@@ -725,14 +896,14 @@ module.exports = function(RED)
|
|
|
725
896
|
res.end(bridge.name);
|
|
726
897
|
})
|
|
727
898
|
.catch(function(error) {
|
|
728
|
-
res.send(error);
|
|
899
|
+
res.status(500).send(error.message ? error.message : JSON.stringify(error));
|
|
729
900
|
});
|
|
730
901
|
}
|
|
731
902
|
});
|
|
732
903
|
|
|
733
904
|
//
|
|
734
905
|
// REGISTER A HUE BRIDGE
|
|
735
|
-
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)
|
|
736
907
|
{
|
|
737
908
|
if(!req.query.ip)
|
|
738
909
|
{
|
|
@@ -740,21 +911,27 @@ module.exports = function(RED)
|
|
|
740
911
|
}
|
|
741
912
|
else
|
|
742
913
|
{
|
|
914
|
+
// MODERN BRIDGES (AND THE BRIDGE PRO) NO LONGER ANSWER ON PLAIN HTTP
|
|
743
915
|
axios({
|
|
744
916
|
"method": "POST",
|
|
745
|
-
"url": "
|
|
917
|
+
"url": "https://"+req.query.ip+"/api",
|
|
746
918
|
"httpsAgent": new https.Agent({ rejectUnauthorized: false }),
|
|
919
|
+
"proxy": false, // THE BRIDGE IS ON THE LOCAL NETWORK, NEVER GO THROUGH A PROXY
|
|
747
920
|
"headers": {
|
|
748
921
|
"Content-Type": "application/json; charset=utf-8"
|
|
749
922
|
},
|
|
923
|
+
"timeout": 10000,
|
|
750
924
|
"data": {
|
|
751
|
-
"devicetype": "
|
|
925
|
+
"devicetype": "huemagic#node-red " + Math.floor((Math.random() * 100) + 1),
|
|
926
|
+
"generateclientkey": true
|
|
752
927
|
}
|
|
753
928
|
})
|
|
754
929
|
.then(function(response)
|
|
755
930
|
{
|
|
756
931
|
var bridge = response.data;
|
|
757
|
-
|
|
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)
|
|
758
935
|
{
|
|
759
936
|
rescope.end("error");
|
|
760
937
|
}
|
|
@@ -764,14 +941,14 @@ module.exports = function(RED)
|
|
|
764
941
|
}
|
|
765
942
|
})
|
|
766
943
|
.catch(function(error) {
|
|
767
|
-
rescope.status(500).send(error);
|
|
944
|
+
rescope.status(500).send(error.message ? error.message : JSON.stringify(error));
|
|
768
945
|
});
|
|
769
946
|
}
|
|
770
947
|
});
|
|
771
948
|
|
|
772
949
|
//
|
|
773
950
|
// DISCOVER RESOURCES
|
|
774
|
-
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)
|
|
775
952
|
{
|
|
776
953
|
const targetType = req.query.type;
|
|
777
954
|
|
|
@@ -785,6 +962,9 @@ module.exports = function(RED)
|
|
|
785
962
|
|
|
786
963
|
for (var [id, rule] of Object.entries(rules))
|
|
787
964
|
{
|
|
965
|
+
// SKIP ERROR RESPONSES OF THE LEGACY API
|
|
966
|
+
if(!rule || typeof rule !== 'object' || rule["error"]) { continue; }
|
|
967
|
+
|
|
788
968
|
var oneDevice = {};
|
|
789
969
|
oneDevice.id = id;
|
|
790
970
|
oneDevice.name = rule.name;
|
|
@@ -819,19 +999,29 @@ module.exports = function(RED)
|
|
|
819
999
|
{
|
|
820
1000
|
const isGroup = (resource["type"] == "room" || resource["type"] == "zone" || resource["type"] == "bridge_home");
|
|
821
1001
|
|
|
822
|
-
//
|
|
823
|
-
if(
|
|
1002
|
+
// AUTOMATIONS OF THE HUE APP
|
|
1003
|
+
if(targetType === "automation")
|
|
824
1004
|
{
|
|
825
|
-
|
|
1005
|
+
if(resource["type"] === "behavior_instance")
|
|
826
1006
|
{
|
|
827
1007
|
var oneDevice = {};
|
|
828
1008
|
oneDevice.id = id;
|
|
829
|
-
oneDevice.name = resource.metadata ? resource.metadata.name :
|
|
830
|
-
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;
|
|
831
1011
|
|
|
832
1012
|
targetDevices[id] = oneDevice;
|
|
833
1013
|
}
|
|
834
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
|
+
}
|
|
835
1025
|
// GROUPED (LIGHT) RESOURCES
|
|
836
1026
|
else if(isGroup && targetType === "group")
|
|
837
1027
|
{
|
|
@@ -846,12 +1036,15 @@ module.exports = function(RED)
|
|
|
846
1036
|
}
|
|
847
1037
|
}
|
|
848
1038
|
// SCENES
|
|
849
|
-
else if(targetType === "scene" && resource["type"] == "scene")
|
|
1039
|
+
else if(targetType === "scene" && (resource["type"] == "scene" || resource["type"] == "smart_scene"))
|
|
850
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
|
+
|
|
851
1044
|
var oneDevice = {};
|
|
852
1045
|
oneDevice.id = id;
|
|
853
1046
|
oneDevice.name = resource.metadata ? resource.metadata.name : false;
|
|
854
|
-
oneDevice.group =
|
|
1047
|
+
oneDevice.group = (sceneGroup && sceneGroup.metadata) ? sceneGroup.metadata.name : "–";
|
|
855
1048
|
|
|
856
1049
|
targetDevices[id] = oneDevice;
|
|
857
1050
|
}
|
|
@@ -868,4 +1061,4 @@ module.exports = function(RED)
|
|
|
868
1061
|
});
|
|
869
1062
|
}
|
|
870
1063
|
});
|
|
871
|
-
};
|
|
1064
|
+
};
|