├── .gitignore ├── edomoticz.png ├── lib ├── constants.js ├── mqtt.js ├── helper.js ├── domoticz.js ├── services.js └── domoticz_accessory.js ├── LICENSE ├── InstallGuide ├── CHANGELOG ├── config.schema.json ├── package.json ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.log 3 | node_modules 4 | -------------------------------------------------------------------------------- /edomoticz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paveltrpan/prnt/HEAD/edomoticz.png -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | global.Service; 2 | global.Characteristic; 3 | global.Categories; 4 | global.Types; 5 | global.UUID; 6 | 7 | module.exports = { 8 | DeviceTypeSwitch: 0, 9 | DeviceTypeDoorbell: 1, 10 | DeviceTypeContact: 2, 11 | DeviceTypeBlinds: 3, 12 | DeviceTypeSmoke: 5, 13 | DeviceTypeBlindsInverted: 6, 14 | DeviceTypeDimmer: 7, 15 | DeviceTypeMotion: 8, 16 | DeviceTypePushOn: 9, 17 | DeviceTypeDoorContact: 11, 18 | DeviceTypeBlindsPercentage: 13, 19 | DeviceTypeBlindsVenetianUS: 14, 20 | DeviceTypeBlindsVenetianEU: 15, 21 | DeviceTypeBlindsPercentageInverted: 16, 22 | DeviceTypeMedia: 17, 23 | DeviceTypeSelector: 18, 24 | DeviceTypeDoorLock: 19, 25 | DeviceTypeDoorLockInverted: 20, 26 | DeviceTypeBlindsPlusStop: 21, 27 | 28 | /* Made up, internal types */ 29 | DeviceTypeSecuritySystem: 254, // Has HardwareTypeVal 67 w/o any SwitchTypeVal 30 | 31 | /* 32 | DeviceTypeNotSupportedYet: 4, //x10siren 33 | DeviceTypeNotSupportedYet: 10, //pushoff 34 | DeviceTypeNotSupportedYet: 12, //dusk 35 | */ 36 | DeviceTypeHoneywellHGI80: 39, 37 | HardwareTypeMQTT: 43, 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ____ _ _ 2 | ___| _ \ ___ _ __ ___ ___ | |_(_) ___ ____ 3 | / _ | | | |/ _ \| '_ ` _ \ / _ \| __| |/ __|_ / 4 | | __| |_| | (_) | | | | | | (_) | |_| | (__ / / 5 | \___|____/ \___/|_| |_| |_|\___/ \__|_|\___/___| 6 | www.npmjs.com/package/homebridge-edomoticz 7 | 8 | A Platform Plugin for HomeBridge by Marci & TheRamon 9 | [http://twitter.com/marcisshadow] 10 | [http://domoticz.com/forum/memberlist.php?mode=viewprofile&u=10884] 11 | 12 | Copyright (c) 2016, Marci (aka PatchworkBoy) & TheRamon 13 | 14 | Permission to use, copy, modify, and/or distribute this software for any 15 | purpose with or without fee is hereby granted, provided that the above 16 | copyright notice and this permission notice appear in all copies. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 19 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 20 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 21 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 24 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 | -------------------------------------------------------------------------------- /InstallGuide: -------------------------------------------------------------------------------- 1 | ____ _ _ 2 | ___| _ \ ___ _ __ ___ ___ | |_(_) _v0.2.3 3 | / _ | | | |/ _ \| '_ ` _ \ / _ \| __| |/ __|_ / 4 | | __| |_| | (_) | | | | | | (_) | |_| | (__ / / 5 | \___|____/ \___/|_| |_| |_|\___/ \__|_|\___/___| 6 | www.npmjs.com/package/homebridge-edomoticz 7 | 8 | A Platform Plugin for HomeBridge by Marci & TheRamon 9 | [http://twitter.com/marcisshadow] 10 | [http://domoticz.com/forum/memberlist.php?mode=viewprofile&u=10884] 11 | 12 | From a clean install of Jessie on Raspberry Pi, booted up and connected to WLAN... 13 | 14 | sudo apt-get update 15 | sudo apt-get upgrade 16 | sudo reboot 17 | 18 | sudo apt-get install rpi-update 19 | sudo BRANCH=next rpi-update [fixes Wifi Ch12/13 issue with rPi3 WiFi] 20 | iwconfig wlan0 power off [fixes powermanagement issue with WiFi on all Raspberry Pi] 21 | 22 | sudo touch /etc/network/if-up.d/wlan0 [these lines make the powermanagement fix permanent] 23 | sudo chmod +x /etc/network/if-up.d/wlan0 24 | sudo chmod 777 /etc/network/if-up.d/wlan0 25 | sudo echo -e '#!/bin/bash\niwconfig wlan0 power off' > /etc/network/if-up.d/wlan0 26 | sudo chmod 755 /etc/network/if-up.d/wlan0 27 | 28 | sudo reboot 29 | 30 | [Installing Domoticz] 31 | sudo curl -L install.domoticz.com | bash 32 | 33 | [Only need to do the following lines if on RaspberryPi Model B / B+ / nonARM7 CPU] 34 | sudo rm -rf /usr/local/{lib/node{,/.npm,_modules},bin,share/man}/{npm*,node*,man1/node*} /var/db/receipts/org.nodejs.* 35 | hash -r 36 | sudo su -c 'echo "deb https://deb.nodesource.com/armv6l-node/ weezy main" >> /etc/apt/sources.list' 37 | sudo curl -sL https://deb.nodesource.com/setup_0.12 | sudo bash - 38 | 39 | [otherwise continue from here] 40 | sudo apt-get install -y build-essential python-rpi.gpio nodejs 41 | sudo apt-get install libavahi-compat-libdnssd-dev 42 | sudo apt-get install git 43 | sudo apt-get install mosquitto 44 | sudo npm install -g node-red --unsafe-perm 45 | sudo wget https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/nodered.service -O /lib/systemd/system/nodered.service 46 | sudo wget https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-start -O /usr/bin/node-red-start 47 | sudo wget https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/node-red-stop -O /usr/bin/node-red-stop 48 | sudo chmod +x /usr/bin/node-red-st* 49 | 50 | sudo npm install -g homebridge --unsafe-perm 51 | sudo npm install -g homebridge-edomoticz --unsafe-perm 52 | 53 | mkdir ~/.homebridge 54 | pico ~/.homebridge/config.json [refer to https://github.com/PatchworkBoy/homebridge-eDomoticz, ctrl-o to save, ctrl-x to exit] 55 | 56 | sudo pico /lib/systemd/system/homebridge.service 57 | 58 | #---Start Copy---# 59 | [Unit] 60 | Description=HomeBridge Service 61 | After=multi-user.target 62 | 63 | [Service] 64 | User=pi 65 | Type=idle 66 | ExecStart=/usr/bin/homebridge 67 | 68 | [Install] 69 | WantedBy=multi-user.target 70 | #---END Copy---# 71 | 72 | [Paste (ctrl-v from win clients, cmd-v from Mac clients) 73 | ctrl-o to save, ctrl-x to exit] 74 | 75 | sudo chmod 644 /lib/systemd/system/homebridge.service 76 | sudo systemctl daemon-reload 77 | sudo systemctl enable homebridge.service 78 | sudo systemctl enable nodered.service 79 | sudo systemctl enable mosquitto.service 80 | 81 | sudo apt-get install pi-bluetooth bluetooth bluez blueman [RaspberryPi 3 only] 82 | 83 | sudo reboot 84 | 85 | [done - navigate to the device in a web browser on port 8080, configure Domoticz, add sensors, reboot. Pair to the Homebridge from your iOS device.] 86 | -------------------------------------------------------------------------------- /lib/mqtt.js: -------------------------------------------------------------------------------- 1 | var mqtt = require('mqtt'); 2 | var platform; 3 | var client; 4 | var config = {host: "", port: 0, credentials: false, channel: ""}; 5 | 6 | module.exports = { 7 | Mqtt: Mqtt 8 | } 9 | 10 | function Mqtt(aPlatform, host, port, channel, credentials) { 11 | platform = aPlatform; 12 | 13 | config = {host: host, port: port, credentials: credentials, channel: channel}; 14 | if (typeof config.credentials === 'undefined' || typeof config.credentials.username === 'undefined' || config.credentials.username.length == 0) { 15 | config.credentials = false; 16 | } 17 | this.connect(); 18 | } 19 | 20 | Mqtt.prototype.connect = function() { 21 | var connectOptions = { 22 | host: config.host, 23 | port: config.port 24 | }; 25 | 26 | if (config.credentials) 27 | { 28 | connectOptions.username = config.credentials.username; 29 | connectOptions.password = config.credentials.password; 30 | } 31 | 32 | client = mqtt.connect(connectOptions); 33 | 34 | client.on('connect', function() { 35 | platform.forceLog("Successfully connected to MQTT broker."); 36 | client.subscribe(config.channel); 37 | }); 38 | 39 | client.on('close', function(error) { 40 | client.end(true, function() { 41 | this.error("Retrying in 5 seconds..."); 42 | setTimeout(function() { 43 | platform.forceLog("Retrying connection to MQTT broker..."); 44 | this.connect(); 45 | }.bind(this), 5000); 46 | }.bind(this)); 47 | 48 | }.bind(this)); 49 | 50 | client.on('error', function(error) { 51 | client.end(true, function() { 52 | this.error(error); 53 | }.bind(this)); 54 | }.bind(this)); 55 | 56 | client.on('message', function (topic, buffer) { 57 | var message; 58 | try { 59 | message = JSON.parse(buffer.toString()); 60 | } catch (e) { 61 | if (e instanceof SyntaxError) { 62 | platform.log('[ERR] JSON Syntax Error - misconstructed MQTT message received'); 63 | platform.log(e); 64 | platform.log('[ERR] The offending message follows:'); 65 | platform.log(buffer.toString()); 66 | } else { 67 | platform.log(e); 68 | platform.log('[ERR] The offending message follows:'); 69 | platform.log(buffer.toString()); 70 | } 71 | message = !1; 72 | } 73 | if (message !== !1) { 74 | if (typeof message.nvalue !== 'undefined' || typeof message.svalue1 !== 'undefined') { 75 | var accessory = platform.accessories.find(function(acc) { 76 | return acc.idx == message.idx; 77 | }); 78 | 79 | if (!accessory) { 80 | return; 81 | } 82 | 83 | accessory.handleMQTTMessage(message, function(characteristic, value) { 84 | if (typeof value !== 'undefined' && typeof characteristic !== 'undefined') { 85 | characteristic.setValue(value, null, "eDomoticz-MQTT"); 86 | } 87 | }); 88 | } else { 89 | platform.log('[ERR] MQTT message received, but no nvalue or svalue1 was found:'); 90 | platform.log(message); 91 | } 92 | } 93 | }); 94 | } 95 | 96 | Mqtt.prototype.send = function(message) { 97 | if (client) 98 | { 99 | var payload = message; 100 | if (typeof payload !== 'string') { 101 | payload = JSON.stringify(payload); 102 | } 103 | client.publish('domoticz/in', payload); 104 | } 105 | } 106 | 107 | Mqtt.prototype.error = function(error) { 108 | var logMessage = "Could not connect to MQTT broker! (" + config.host + ":" + config.port + ")\n"; 109 | 110 | if (config.credentials !== false) { 111 | logMessage += "Note: You're using a username and password to connect. Please verify your username and password too.\n"; 112 | } 113 | 114 | if (error) { 115 | logMessage += error; 116 | } 117 | 118 | platform.forceLog(logMessage); 119 | }; -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | ____ _ _ 2 | ___| _ \ ___ _ __ ___ ___ | |_(_) ________ 3 | / _ | | | |/ _ \| '_ ` _ \ / _ \| __| |/ __|_ / 4 | | __| |_| | (_) | | | | | | (_) | |_| | (__ / / 5 | \___|____/ \___/|_| |_| |_|\___/ \__|_|\___/___| 6 | www.npmjs.com/package/homebridge-edomoticz 7 | 8 | A Platform Plugin for HomeBridge by Marci & TheRamon 9 | [http://twitter.com/marcisshadow] 10 | [http://domoticz.com/forum/memberlist.php?mode=viewprofile&u=10884] 11 | 12 | V1.0.1 - see https://github.com/PatchworkBoy/homebridge-edomoticz/commits/master 13 | V1.0.0 - MQTT Merge 14 | V0.2.3 - 2016/10/26 15 | - MQTT Integration 16 | - Switch and dimmer values caching 17 | - Support for Domoticz Security panel 18 | - Dedicated waterflow handling 19 | - Improved response times 20 | - Improved handling of characteristics (iOS 10) 21 | V0.2.2 - 2016/08/19 22 | - Release Candidate for MQTT Integration 23 | V0.2.1 - 2016/06/21 24 | - Added handling for sensors of type 'Lux' - cheers @100hz 25 | - Hue/RGB support - cheers @xTheRamon 26 | - Improved BlindSupport (iOS10 compatible) - cheers @xTheRamon 27 | V0.1.32 - 2016/04/04 28 | - Add Occupancy Sensor support - power switches in Domotics 29 | featuring the word "Occupied" (case sensitive) in the Name 30 | will be created in HomeKit as an Occupancy Sensor 31 | V0.1.31 - 2016/04/01 32 | - Revert blind support 33 | V0.1.28 - 2016/04/01 34 | - Tweak to EvoHome support 35 | - Add Blind (switchType 3) support 36 | V0.1.27 - 2016/03/12 37 | - Tweak to EvoHome support 38 | V0.1.26 - 2016/03/02 39 | - Added CurrentCost USB support (introduced to stable in v3.4834) 40 | - Type: Usage, SubType: Electric 41 | V0.1.25 - 2016/02/26 42 | - Revision history moved to CHANGELOG 43 | V0.1.24 - 2016/02/26 44 | - fixed batterysensor for Motion Detectors (was: get before it was added = err thrown) 45 | - merge @gerard33/patch-1 pull request: Add smoke detector status Normal 46 | V0.1.23 - 2016/02/20 47 | - merge in bugfixes by @EddyK69 - commit/1ae1020146b5761f1aaa9bd69b6675210a777290 48 | - consistent that/this 49 | - removed some fluff 50 | - globally switched roundToHalf to OneDP 51 | V0.1.21 & 22 - 2016/02/20 52 | - More work on Thermostat / SetPoint support 53 | V0.1.20 - 2016/02/19 54 | - Dimmers reflect power state 55 | V0.1.19 - 2016/02/19 56 | - Corrected UV Type checking (@EddyK69) 57 | V0.1.16 - 18 - 2016/02/19 58 | - added P1 Smart Meter Energy subtype support 59 | - more work on Evohome 60 | V0.1.14 & 15 - 2016/02/19 61 | - added P1 Smart Meter kWh & Gas type / subtype support 62 | - added UVN800 support (@EddyK69) 63 | - added preliminary EvoHom / OpenTherm Gateway Thermostat / SetPoint support 64 | V0.1.11 & 12 - 2016/02/10 65 | - rewritten switch detection to use SwitchTypeVal=0>17 66 | - de-verbosed object selectors & jshint'd end-to-end 67 | - added: smoke detector, motion detector 68 | - fixed: dimmmer allocation, contact sensors 69 | V0.1.10 - 2016/02/08 70 | - more work relating to dimmers and contact sensors 71 | V0.1.9 - 2016/02/07 72 | - hopefully fixes an oopsie related to brightness on EVERY switch. 73 | V0.1.8 - 2016/02/07 74 | - add support for SwitchType: Contact (basic open / closed) 75 | V0.1.6 - 2016/02/07 76 | - add another identifier for Current 77 | V0.1.5 - 2016/02/07 78 | - add another identifier for a dimming light 79 | V0.1.4 - 2016/02/06 80 | - removed extraneous cruft from Base64 81 | - enable dimming 82 | V0.1.2 - 2016/02/05 83 | - Added SSL Protocol support 84 | - authorization header rather than within URL 85 | V0.0.7 - 2016/02/05 86 | - Fixed Today counter and WindChill characteristic 87 | V0.0.6 - 2016/02/03 88 | - Full DarkSkies Virtual Sensor support (Rain, Wind, Barometer, Solar Radiation, Visibility 89 | V0.0.5 - 2016/02/03 90 | - Added YouLess counter support (Type: YouLess Meter, SubType: YouLess counter) 91 | - Expanded Temp sensor to include humidity & pressure (if present) 92 | - fixed UUID generation 93 | V0.0.4 - 2016/01/31 94 | - Fixed 'Siri Name' disappearance 95 | V0.0.3 - 2016/01/31 96 | - Added General Usage Sensors (Type: General, SubType: Percentage) 97 | V0.0.2 - 2016/01/31 98 | - Added Electric Consumption sensors (Type: General, SubType: kWh) 99 | V0.0.1 - 2016/01/31 100 | - Initial version 101 | - I make no claims to the quality of this shim. Function over form! 102 | -------------------------------------------------------------------------------- /lib/helper.js: -------------------------------------------------------------------------------- 1 | var inherits = require('util').inherits; 2 | 3 | module.exports = { 4 | Helper: Helper 5 | } 6 | 7 | function Helper() { 8 | 9 | } 10 | 11 | if (!Date.prototype.toISOString) { 12 | (function() { 13 | 14 | function pad(number) { 15 | if (number < 10) { 16 | return '0' + number; 17 | } 18 | return number; 19 | } 20 | 21 | Date.prototype.toISOString = function() { 22 | return this.getUTCFullYear() + 23 | '-' + pad(this.getUTCMonth() + 1) + 24 | '-' + pad(this.getUTCDate()) + 25 | 'T' + pad(this.getUTCHours()) + 26 | ':' + pad(this.getUTCMinutes()) + 27 | ':' + pad(this.getUTCSeconds()) + 28 | '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + 29 | 'Z'; 30 | }; 31 | 32 | }()); 33 | } 34 | 35 | Date.prototype.addMinutes = function(h) { 36 | this.setTime(this.getTime() + (h*60*1000)); 37 | return this; 38 | }; 39 | 40 | Helper.sortByKey = function(array, key) { 41 | return array.sort(function(a, b) { 42 | var x = a[key]; 43 | var y = b[key]; 44 | return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 45 | }); 46 | }; 47 | 48 | Helper.oneDP = function(value) { 49 | var converted = value ? Math.round(value*10)/10 : 0; 50 | var fixed = converted.toFixed(1); 51 | return parseFloat(fixed); 52 | }; 53 | 54 | Helper.cleanFloat = function(value) { 55 | var stringval = value ? value.toString() : ""; 56 | stringval = stringval.replace(/[^0-9\.-]+/g,'') 57 | return parseFloat(stringval); 58 | }; 59 | 60 | Helper.fixInheritance = function(subclass, superclass) { 61 | var proto = subclass.prototype; 62 | inherits(subclass, superclass); 63 | subclass.prototype.parent = superclass.prototype; 64 | for (var mn in proto) { 65 | subclass.prototype[mn] = proto[mn]; 66 | } 67 | }; 68 | 69 | Helper.HSVtoRGB = function(hsb) { 70 | var br = Math.round(hsb[2] / 100 * 254); 71 | var rgb = false; 72 | if (hsb[1] == 0){ 73 | rgb = [br, br, br]; 74 | } else { 75 | var hue = hsb[0] % 360; 76 | var f = hue % 60; 77 | var p = Math.round((hsb[2] * (100 - hsb[1])) / 10000 * 254); 78 | var q = Math.round((hsb[2] * (6000 - hsb[1] * f)) / 600000 * 254); 79 | var t = Math.round((hsb[2] * (6000 - hsb[1] * (60 - f))) / 600000 * 254); 80 | switch (Math.floor(hue / 60)){ 81 | case 0: rgb = [br, t, p]; break; 82 | case 1: rgb = [q, br, p]; break; 83 | case 2: rgb = [p, br, t]; break; 84 | case 3: rgb = [p, q, br]; break; 85 | case 4: rgb = [t, p, br]; break; 86 | case 5: rgb = [br, p, q]; break; 87 | } 88 | } 89 | 90 | if (rgb) 91 | { 92 | var hex = ""; 93 | for (var i = 0; i < 3; i++){ 94 | var bit = (rgb[i] - 0).toString(16); 95 | hex += (bit.length == 1) ? '0' + bit : bit; 96 | } 97 | return hex; 98 | } 99 | 100 | return "FFFFFF"; 101 | }; 102 | 103 | Helper.Base64 = { 104 | _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 105 | encode: function(e) { 106 | var t = ""; 107 | var n, r, i, s, o, u, a; 108 | var f = 0; 109 | e = Helper.Base64._utf8_encode(e); 110 | while (f < e.length) { 111 | n = e.charCodeAt(f++); 112 | r = e.charCodeAt(f++); 113 | i = e.charCodeAt(f++); 114 | s = n >> 2; 115 | o = (n & 3) << 4 | r >> 4; 116 | u = (r & 15) << 2 | i >> 6; 117 | a = i & 63; 118 | if (isNaN(r)) { 119 | u = a = 64; 120 | } else if (isNaN(i)) { 121 | a = 64; 122 | } 123 | t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a); 124 | } 125 | return t; 126 | }, 127 | _utf8_encode: function(e) { 128 | e = e.replace(/\r\n/g, "\n"); 129 | var t = ""; 130 | for (var n = 0; n < e.length; n++) { 131 | var r = e.charCodeAt(n); 132 | if (r < 128) { 133 | t += String.fromCharCode(r); 134 | } else if (r > 127 && r < 2048) { 135 | t += String.fromCharCode(r >> 6 | 192); 136 | t += String.fromCharCode(r & 63 | 128); 137 | } else { 138 | t += String.fromCharCode(r >> 12 | 224); 139 | t += String.fromCharCode(r >> 6 & 63 | 128); 140 | t += String.fromCharCode(r & 63 | 128); 141 | } 142 | } 143 | return t; 144 | } 145 | }; 146 | 147 | Helper.LogConnectionError = function(platform, response, err) 148 | { 149 | var errorMessage = "There was a problem connecting to Domoticz."; 150 | 151 | if (response && response.statusCode) { 152 | errorMessage += " (HTTP Status code " + response.statusCode + ")\n\n" + response.body; 153 | } 154 | 155 | if (err) { 156 | errorMessage += "\n- " + err; 157 | } 158 | 159 | platform.forceLog(errorMessage); 160 | } -------------------------------------------------------------------------------- /config.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginAlias": "eDomoticz", 3 | "pluginType": "platform", 4 | "singular": false, 5 | "headerDisplay": "Homebridge plugin for Domoticz.\n\n1. Open the Home app on your device.\n2. Tap the Home tab, then tap .\n3. Tap *Add Accessory*, and scan the QR code, alternatively select *I Don't Have a Code or Cannot Scan*.\n4. Enter the Homebridge PIN, this can be found under the QR code in Homebridge UI or your Homebridge logs.", 6 | "footerDisplay": "For help visit [eDomoticz on GitHub](https://github.com/PatchworkBoy/homebridge-edomoticz) or [Domoticz forum thread](https://www.domoticz.com/forum/viewtopic.php?f=36&t=10272)", 7 | "schema": { 8 | "type": "object", 9 | "properties": { 10 | "name": { 11 | "title": "Name", 12 | "type": "string", 13 | "default": "Domoticz", 14 | "required": true 15 | }, 16 | "server": { 17 | "title": "Server", 18 | "type": "string", 19 | "default": "127.0.0.1", 20 | "required": true, 21 | "description": "If Domoticz is set up to use basic or form login authentication, set Server to 'user:pass@ipadress'." 22 | }, 23 | "port": { 24 | "title": "Port", 25 | "type": "string", 26 | "default": "8080", 27 | "required": true 28 | }, 29 | "webroot": { 30 | "title": "Webroot", 31 | "type": "string", 32 | "default": "", 33 | "required": false 34 | }, 35 | "roomid": { 36 | "title": "Room ID", 37 | "type": "integer", 38 | "default": 0, 39 | "required": true, 40 | "description": "If Room ID is set to 0 homebridge loads ALL sensors. Room ID is domoticz roomplan’s idx number" 41 | }, 42 | "mqtt": { 43 | "title": "Enable MQTT", 44 | "type": "boolean", 45 | "default": 1, 46 | "description": "By default, the plugin will grab hardware information regarding MQTT from Domoticz if MQTT is checked. Advanced users can override their MQTT. In config, \"mqtt\": true can be changed to:
\"mqtt\": {
\"host\":\"alternate.mgtt.com\",
\"port\": 1234,
\"topic\": \"domoticz/out\",
\"username\": \"username\",
\"password\": \"password\"
}
" 47 | }, 48 | "ssl": { 49 | "title": "Enable SSL", 50 | "type": "boolean", 51 | "default": 0, 52 | "description": "You will need to specify your SSL port - usually Port 443 by default." 53 | }, 54 | "dimFix": { 55 | "title": "Dim Offset", 56 | "type": "integer", 57 | "default": 0, 58 | "description": "The dimFix variable relates to an early issue between HomeKit and Domoticz regarding scaling of dimmer values. If you find that you can never set your dimmers to 100%, then set this variable to 1. If you find that, when you set your dimmers, this starts a never ending loop of brightness increasing by 1%, then you MUST omit this variable or set it to 0." 59 | }, 60 | "legacyBlinds": { 61 | "title": "Use legacy blind support", 62 | "type": "integer", 63 | "default": 0, 64 | "description": "If you use blinds, set this option to 1 if you use an older version of domoticz (until 2022-beta.14535). If using a more recent version, set to 0. When set to 0, the new reverse state and position will be used" 65 | }, 66 | "excludedDevices": { 67 | "title": "Exluded Devices", 68 | "type": "array", 69 | "items": { 70 | "title": "Excluded Device IDX", 71 | "type": "string", 72 | "pattern": "^[0-9]" 73 | } 74 | } 75 | } 76 | }, 77 | "form": [ 78 | "name", { 79 | "type": "flex", 80 | "items": [ 81 | "server", 82 | "port", 83 | "webroot", 84 | "roomid" 85 | ] 86 | }, { 87 | "type": "fieldset", 88 | "title": "Exclude Devices", 89 | "expandable": true, 90 | "expanded": false, 91 | "items": [{ 92 | "type": "help", 93 | "helpvalue": "
Exclude Devices
To prevent certain Domoticz devices from showing up in HomeBridge, add IDX of the device." 94 | }, { 95 | "nodescription": true, 96 | "notitle": true, 97 | "key": "excludedDevices", 98 | "type": "array", 99 | "items": [{ 100 | "type": "div", 101 | "displayFlex": true, 102 | "flex-direction": "row", 103 | "items": [{ 104 | "key": "excludedDevices[]", 105 | "flex": "1 1 50px", 106 | "notitle": true, 107 | "placeholder": "Enter device IDX..." 108 | } 109 | ] 110 | } 111 | ] 112 | } 113 | ] 114 | }, { 115 | "type": "fieldset", 116 | "expandable": true, 117 | "title": "Advanced Settings", 118 | "items": [ 119 | 120 | "dimFix", 121 | "legacyBlinds", 122 | "mqtt", 123 | "ssl" 124 | ] 125 | } 126 | ] 127 | } 128 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "homebridge-edomoticz", 3 | "version": "2.1.48", 4 | "description": "homebridge-plugin for Domoticz https://github.com/nfarina/homebridge", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/patchworkboy/homebridge-eDomoticz.git" 12 | }, 13 | "preferGlobal": true, 14 | "keywords": [ 15 | "homebridge-plugin", 16 | "eDomoticz", 17 | "Domoticz" 18 | ], 19 | "engines": { 20 | "node": ">=0.12.0", 21 | "homebridge": ">=0.2.5" 22 | }, 23 | "dependencies": { 24 | "inherits": "^2.0.1", 25 | "mqtt": "^2.15.0", 26 | "request": "^2.81.0" 27 | }, 28 | "author": { 29 | "name": "PatchworkBoy", 30 | "url": "aka Marci" 31 | }, 32 | "license": "GPL-3.0", 33 | "bugs": { 34 | "url": "https://github.com/patchworkboy/homebridge-eDomoticz/issues" 35 | }, 36 | "homepage": "https://github.com/patchworkboy/homebridge-eDomoticz#readme", 37 | "readme": "# homebridge-eDomoticz\nA fully-fledged up-to-date Homebridge-Plugin\nfor use with [Homebridge](https://github.com/nfarina/homebridge) v0.2.1+\nand [Domoticz](https://github.com/domoticz/domoticz)\n\n##Supports:\n###Standard HomeKit Types:\n- Sockets (on/off) - Domoticz SwitchTypeVal: 0\n- Lamps (on/off) - Domoticz SwitchTypeVal: 0\n- Contact Sensors - Domoticz SwitchTypeVal: 2\n- Blinds - Domoticz SwitchTypeVal: 3\n- Smoke Detectors - Domoticz SwitchTypeVal: 5\n- Blinds (inverted) - Domoticz SwitchTypeVal: 6\n- Lamps (dimmer) - Domoticz SwitchTypeVal: 7\n- Motion Sensors - Domoticz SwitchTypeVal: 8\n- Push Switches - Domoticz SwitchTypeVal: 9\n- Lock Mechanisms - Domoticz SwitchTypeVal: 11\n- Blinds (%) - Domoticz SwitchTypeVal: 13\n- Blinds (& inverted) - Domoticz SwitchTypeVal: 16\n\n##Provides:\n###Custom HomeKit Types:\n- General kWh power meters - Types: General, Current; SubType: kWh, mapped to Eve chars where possible\n- CurrentCost USB power meter - Type: Usage, SubType: Electric, mapped to Eve chars where possible\n- P1 Smart Meter (Electric & Gas), mapped to Eve chars where possible\n- EvoHome** / OpenTherm Thermostat support - Types: Heating, Thermostat; SubTypes: Zone, SetPoint\n- YouLess Meter (Current, Total and Today Total Consumption) - Type: YouLess Meter; SubType: YouLess counter, mapped to Eve chars where possible\n- General Usage % meters (eg: Motherboard Sensors Hardware Device - CPU %, Mem %, HDD % etc) - Type: General; SubType: Percentage\n- Temperature, Temp + Humidity, Temp + Humidity + Baro (Current Temperature, Current Humidity, Current Pressure in hPA) - Type: Temp, Temp + Humidty, Temp + Humidity + Baro [id'd as Eve Weather]\n- DarkSkies Virtual Weather Station Sensors (Wind, Solar Radiation, Rainfall, Visibility, Barometer [id'd as Eve Weather])\n\n** assumes the EvoHome has been setup according to [this script method](https://www.domoticz.com/wiki/Evohome#Scripting_for_RFG100).\n\n###Todo:\n- [ ] homebridge [plugin 2.0](https://github.com/nfarina/homebridge/pull/497) support\n- [x] MQTT-based realtime updates\n- [x] Hue/RGB\n- [x] Blinds\n- [x] m3 (gas usage)\n- [x] Motion sensors\n- [x] Smoke Detectors\n- [x] Brightness/Dimming\n- [x] kWh (electricity usage)\n- [x] General % usage\n- [x] Humidity\n- [x] Pressure\n- [x] YouLess Meter\n- [x] Open/Closed contact sensors\n- [ ] ...more sensors (ongoing)!\n\n## Installation\n```\nsudo npm install -g homebridge-edomoticz\n```\n\n## Update\n```\nsudo npm update -g homebridge-edomoticz\n```\n\n## Configuration\n\n~/.homebridge/config.json example:\n```\n{\n \"bridge\": {\n \"name\": \"Homebridge\",\n \"username\": \"CC:21:3E:E4:DE:33\",\n \"port\": 51826,\n \"pin\": \"031-45-154\"\n },\n \"description\": \"Configuration file for (e)xtended Domoticz platform.\",\n \"platforms\": [\n {\n \"platform\": \"eDomoticz\",\n \"name\": \"eDomoticz\",\n \"server\": \"127.0.0.1\",\n \"port\": \"8080\",\n \"ssl\": 0,\n \"roomid\": 0,\n \"mqttenable\": 1,\n \"mqttserver\": \"127.0.0.1\",\n \"mqttport\": \"1883\",\n \"mqttauth\": 0,\n \"mqttuser\": \"\",\n \"mqttpass\": \"\"\n }\n ],\n \"accessories\": []\n}\n```\n\n## Tips\n\n### Authentication\nIf Domoticz is set up to use basic or form login authentication, set \"server\":\"user:pass@ip\" within config.json. The plugin will internally extract the username and password, base64 encode it and send it as a http authorization header whenever it talks to your Domoticz server.\n\n### SSL\nSet \"ssl\":1 in config.json to turn on SSL (ie: server connects with https:// rather than http://). You will need to specify your SSL port - usually \"port\":\"443\" by default.\n\n### Issues pairing to Homebridge when you have a lot of Domoticz sensors...\nIf you have more than 100 devices in Domoticz, you need to limit the number of devices exposed to HomeKit (HomeKit only supports 100 Accessories on a single bridge - whilst we could combine multiple sensors into a single homekit accessory within the plugin, the possible combinations out there are endless, so we won't).\n\nTherefore, to reduce the number of devices exposed from Domoticz, create a roomplan within Domoticz via Setup > More Options > Plans > roomplan. Add only the devices you wish to be exposed to HomeKit to this new roomplan within Domoticz, and then get it's roomidx number. Set \"roomid\" in your config.json file to this room number.\n\n### Is my <> supported??\nSee [Domoticz API Reference](https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's#Retrieve_status_of_specific_device) - query your device as per the instructions there, and if your device’s SwitchTypeVal isn't in the 'Supports:' list or Type/SubType aren’t in the ’Provides:' list above then it'll just appear as an On/Off switch. [Open a new issue](https://github.com/PatchworkBoy/homebridge-eDomoticz/issues/new) including the output from the json api and I’ll get look into supporting that particular device more fully!\n\n### What does the Override slider represent on the EvoHome Thermostat?\nOverride-Until time in minutes from the current time. Allows setting an override-until time upto 8 hours in the future. Setting this slider to 0 will set the heating mode to Auto. Setting it to 481 will set the override as a PermanentOverride.\n\n### Logging\nComplies with Homebridge's native logging & debugging methodology - see https://github.com/nfarina/homebridge/wiki/Basic-Trouble-Shooting\n", 38 | "readmeFilename": "README.md", 39 | "_id": "homebridge-edomoticz@2.1.8", 40 | "_from": "homebridge-edomoticz", 41 | "_resolved": "file:homebridge-edomoticz" 42 | } 43 | -------------------------------------------------------------------------------- /lib/domoticz.js: -------------------------------------------------------------------------------- 1 | var request = require("request"); 2 | var Helper = require('./helper.js').Helper; 3 | var extend = require('util')._extend; 4 | 5 | module.exports = { 6 | Domoticz: Domoticz 7 | } 8 | 9 | var baseHttpRequest = false; 10 | 11 | function Domoticz() { 12 | 13 | } 14 | 15 | Domoticz.initialize = function(useSSL, requestHeaders) { 16 | var defaultRequestOptions = { 17 | headers: requestHeaders, 18 | json: true 19 | }; 20 | 21 | if (useSSL) 22 | { 23 | defaultRequestOptions.agentOptions = { 24 | rejectUnauthorized: false 25 | }; 26 | } 27 | 28 | baseHttpRequest = request.defaults(defaultRequestOptions); 29 | }; 30 | 31 | Domoticz.settings = function(accessory, completion, error) { 32 | if (baseHttpRequest === false) { 33 | return; 34 | } 35 | 36 | var url = accessory.platform.apiBaseURL + "type=command¶m=getsettings"; 37 | baseHttpRequest.get({ 38 | url: url 39 | }, function(err, response, json) { 40 | if (!err && response.statusCode == 200 && json !== undefined) 41 | { 42 | if (typeof completion !== 'undefined' && completion !== false) { 43 | completion(json); 44 | } 45 | } 46 | else 47 | { 48 | Helper.LogConnectionError(this.platform, response, err); 49 | if (typeof error !== 'undefined' && error !== false) { 50 | error(); 51 | callback(); 52 | } 53 | } 54 | }.bind(accessory)); 55 | }; 56 | 57 | Domoticz.devices = function(baseURL, roomID, completion, error) { 58 | if (baseHttpRequest === false) { 59 | return; 60 | } 61 | 62 | var url = baseURL + "type=command¶m=getdevices&used=true&order=Name"; 63 | if (roomID) { 64 | url += "&plan=" + roomID; 65 | } 66 | 67 | baseHttpRequest.get({ 68 | url: url 69 | }, function(err, response, json) { 70 | if (!err && response.statusCode == 200) 71 | { 72 | var devices = []; 73 | 74 | if (json.result === undefined) 75 | { 76 | if (typeof completion !== 'undefined' && completion !== false) { 77 | completion(devices); 78 | } 79 | return; 80 | } 81 | 82 | var sArray = Helper.sortByKey(json.result, "Name"); 83 | sArray.map(function(s) { 84 | devices.push(s); 85 | }); 86 | 87 | if (typeof completion !== 'undefined' && completion !== false) { 88 | completion(devices); 89 | } 90 | } 91 | else 92 | { 93 | if (typeof error !== 'undefined' && error !== false) { 94 | error(response, err); 95 | } 96 | } 97 | }); 98 | }; 99 | 100 | Domoticz.hardware = function(baseURL, completion, error) { 101 | if (baseHttpRequest === false) { 102 | return; 103 | } 104 | 105 | var url = baseURL + "type=command¶m=gethardware"; 106 | 107 | baseHttpRequest.get({ 108 | url: url 109 | }, function(err, response, json) { 110 | if (!err && response.statusCode == 200 && json.result !== undefined) 111 | { 112 | var hardware = []; 113 | var sArray = Helper.sortByKey(json.result, "Name"); 114 | sArray.map(function(s) { 115 | hardware.push(s); 116 | }); 117 | 118 | if (typeof completion !== 'undefined' && completion !== false) { 119 | completion(hardware); 120 | } 121 | } 122 | else 123 | { 124 | if (typeof error !== 'undefined' && error !== false) { 125 | error(response, err); 126 | } 127 | } 128 | }); 129 | }; 130 | 131 | Domoticz.deviceStatus = function(accessory, completion, error) { 132 | if (baseHttpRequest === false) { 133 | return; 134 | } 135 | 136 | var url = accessory.platform.apiBaseURL + "type=command¶m=getdevices&rid=" + accessory.idx; 137 | baseHttpRequest.get({ 138 | url: url 139 | }, function(err, response, json) { 140 | if (!err && response.statusCode == 200 && json !== undefined) 141 | { 142 | if (!json.result) 143 | { 144 | this.platform.forceLog("Could not fetch data for " + this.name + ". (Device might have been removed?)"); 145 | if (typeof error !== 'undefined' && error !== false) { 146 | error(); 147 | } 148 | 149 | // Powerstate failed.. Device has probably been removed. Trigger a sync. 150 | if (accessory && accessory.platform) { 151 | accessory.platform.synchronizeAccessories(); 152 | } 153 | return; 154 | } 155 | 156 | this.platform.log("Data received for " + this.name + "."); 157 | if (typeof completion !== 'undefined' && completion !== false) { 158 | completion(json); 159 | } 160 | } 161 | else 162 | { 163 | Helper.LogConnectionError(this.platform, response, err); 164 | if (typeof error !== 'undefined' && error !== false) { 165 | error(); 166 | } 167 | } 168 | }.bind(accessory)); 169 | }; 170 | 171 | Domoticz.updateDeviceStatus = function(accessory, command, parameters, completion) { 172 | if (accessory.platform.mqtt && this.isMQTTSupportedCommand(command, parameters)) 173 | { 174 | var message = {"command": command, "idx": parseInt(accessory.idx)}; 175 | extend(message, parameters); 176 | 177 | accessory.platform.mqtt.send(message); 178 | if (typeof completion !== 'undefined' && completion !== false) { 179 | completion(true); 180 | } 181 | return; 182 | } 183 | 184 | var url = accessory.platform.apiBaseURL + "type=command¶m=" + encodeURI(command) + "&idx=" + accessory.idx; 185 | 186 | for (var key in parameters) { 187 | url += "&" + encodeURI(key) + "=" + encodeURI(parameters[key]); 188 | } 189 | 190 | Domoticz.updateWithURL(accessory, url, completion); 191 | }; 192 | 193 | Domoticz.updateWithURL = function(accessory, url, completion) { 194 | if (baseHttpRequest === false) { 195 | return; 196 | } 197 | 198 | baseHttpRequest.put({ 199 | url: url, 200 | header: this.requestHeaders, 201 | json: true 202 | }, 203 | function(err, response) { 204 | var success = (typeof err === 'undefined' || !err); 205 | 206 | if (success) { 207 | this.platform.log(this.name + " sent command succesfully."); 208 | } 209 | else { 210 | Helper.LogConnectionError(this.platform, response, err); 211 | callback(); 212 | } 213 | 214 | if (typeof completion !== 'undefined' && completion !== false) { 215 | completion(success); 216 | } 217 | }.bind(accessory)); 218 | }; 219 | 220 | Domoticz.isMQTTSupportedCommand = function(command, parameters) { 221 | if (command == "setcolbrightnessvalue" || command == "setkelvinlevel" || command == "kodimediacommand") { 222 | return false; 223 | } 224 | 225 | return true; 226 | }; 227 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![npm (tag)](https://img.shields.io/npm/v/homebridge-edomoticz/latest) 2 | ![npm](https://img.shields.io/npm/dt/homebridge-edomoticz?label=Downloads&style=flat-square) 3 | [![verified-by-homebridge](https://badgen.net/badge/homebridge/verified/purple)](https://github.com/homebridge/homebridge/wiki/Verified-Plugins) 4 | 5 | # Homebridge-eDomoticz 6 | This is a plugin for [Homebridge](https://github.com/nfarina/homebridge) and [Homebridge Config UI X Support](https://github.com/oznu/homebridge-config-ui-x) and [Domoticz](https://github.com/domoticz/domoticz). 7 | 8 | ## Supports: 9 |
10 | Standard HomeKit Types (supported by Home.app): 11 | 12 | - Sockets (on/off) 13 | - Lamps (on/off) 14 | - Contact Sensors 15 | - Blinds 16 | - Smoke Detectors 17 | - Blinds (inverted) 18 | - Lamps (dimmer) 19 | - Motion Sensors 20 | - Push Switches 21 | - Lock Contact 22 | - Blinds (%) 23 | - Blinds (& inverted) 24 | - Push Buttons (selectors) 25 | - Lock Mechanisms 26 | - Lock Mechanisms (inverted) 27 | - Temperature sensors (only temperature characteristic in case of T+H / T+H+B) 28 | - Thermostat SetPoints 29 | - TV 30 |
31 | 32 | ## Provides: 33 |
Custom HomeKit Types (supported by 3rd Party HomeKit Apps only - eg: Elgato Eve): 34 | 35 | - General kWh power meters - Types: General, Current; SubType: kWh, mapped to Eve chars where possible 36 | - General Current, Voltage - Types: General, SubType: Current,Voltage, mapped to Eve chars where possible 37 | - CurrentCost USB power meter - Type: Usage, SubType: Electric, mapped to Eve chars where possible 38 | - P1 Smart Meter (Electric & Gas), mapped to Eve chars where possible 39 | - EvoHome** / OpenTherm Thermostat support - Types: Heating, Thermostat; SubTypes: Zone, SetPoint 40 | - YouLess Meter (Current, Total and Today Total Consumption) - Type: YouLess Meter; SubType: YouLess counter, mapped to Eve chars where possible 41 | - General Usage % meters (eg: Motherboard Sensors Hardware Device - CPU %, Mem %, HDD % etc) - Type: General; SubType: Percentage 42 | - Temperature, Temp + Humidity, Temp + Humidity + Baro (Current Temperature, Current Humidity, Current Pressure in hPA) - Type: Temp, Temp + Humidty, Temp + Humidity + Baro [id'd as Eve Weather] 43 | - DarkSkies Virtual Weather Station Sensors (Wind, Solar Radiation, Rainfall, Visibility, Barometer [id'd as Eve Weather]) 44 | 45 | ** assumes the EvoHome has been setup according to [this script method](https://www.domoticz.com/wiki/Evohome#Scripting_for_RFG100). 46 |
47 | 48 | ## Installation 49 | 50 | **Option 1: Install via Homebridge Config UI X:** 51 | 52 | 1. Navigate to the Plugins page in in [homebridge-config-ui-x](https://github.com/oznu/homebridge-config-ui-x). 53 | 2. Search for "domoticz" and install homebridge-edomoticz. 54 | 55 | **Option 2: Manually Install:** 56 | ``` 57 | sudo npm install -g homebridge-edomoticz 58 | ``` 59 | 60 | ## Update 61 | 62 | **Option 1: Update via Homebridge Config UI X:** 63 | 64 | 1. Navigate to the Plugins page in [homebridge-config-ui-x](https://github.com/oznu/homebridge-config-ui-x). 65 | 2. Click the Update button for the eDomoticz plugin. 66 | 67 | **Option 2: Manually Update:** 68 | ``` 69 | sudo npm update -g homebridge-edomoticz 70 | ``` 71 | 72 | ## Configuration 73 | 74 | To configure homebridge-eDomoticz you must also be running [homebridge-config-ui-x](https://github.com/oznu/homebridge-config-ui-x). 75 | 76 | 1. Navigate to the Plugins page in homebridge-config-ui-x. 77 | 2. Click the Settings button for the eDomoticz plugin. 78 | 79 | ![sDomoticz](edomoticz.png) 80 | 81 | ### Manual Settings 82 | 83 |
Manual Configuration 84 | 85 | ~/.homebridge/config.json example: 86 | ```js 87 | { 88 | "bridge": { 89 | "name": "Homebridge", 90 | "username": "CC:21:3E:E4:DE:33", 91 | "port": 51826, 92 | "pin": "031-45-154" 93 | }, 94 | "platforms": [ 95 | { 96 | "platform": "eDomoticz", 97 | "name": "Domoticz", 98 | "server": "127.0.0.1", 99 | "port": "8080", 100 | "ssl": false, 101 | "roomid": 0, 102 | "mqtt": true, 103 | "debuglog":false, 104 | "excludedDevices": [], 105 | "dimFix": 0 106 | } 107 | ], 108 | "accessories": [] 109 | } 110 | ``` 111 | To prevent certain Domoticz devices from showing up in HomeBridge it is possible to exclude them by setting the "excludedDevices" parameter. 112 | Provide an array of Domoticz Device IDX's, which can be found in the Domoticz dashboard on the "Setup > Devices" page and look for the "idx" column. 113 | 114 | ```js 115 | "excludedDevices": ["12","30","129"] 116 | ``` 117 | 118 | The dimFix variable relates to an early issue between HomeKit and Domoticz regarding scaling of dimmer values. These days, for the majority of setups this variable can be set to 0 or omitted entirely. If you find that you can never set your dimmers to 100%, then set this variable to 1. If you find that, when you set your dimmers, this starts a never ending loop of brightness increasing by 1%, then you MUST omit this variable or set it to 0. 119 | ```js 120 | "dimFix": 0 121 | ``` 122 | 123 |
124 | 125 |
Advanced Configuration 126 | 127 | ### Dim Offset 128 | The dimFix variable relates to an early issue between HomeKit and Domoticz regarding scaling of dimmer values. If you find that you can never set your dimmers to 100%, then set this variable to 1. If you find that, when you set your dimmers, this starts a never ending loop of brightness increasing by 1%, then you MUST omit this variable or set it to 0. 129 | 130 | ### Use legacy blind support 131 | If you use blinds, set this option to 1 if you use an older version of domoticz (until 2022-beta.14535). If using a more recent version, set to 0. When set to 0, the new reverse state and position will be used 132 | 133 | 134 | ### MQTT 135 | By default, the plugin will grab hardware information regarding MQTT from Domoticz if `mqtt` is 1 or true in the configuration file. 136 | Advanced users can override their MQTT configuration as follows: 137 | 138 | ```js 139 | "mqtt": { 140 | "host": "alternate.mqtt.com", 141 | "port": 1234, 142 | "topic": "domoticz/out", 143 | "username": "username", 144 | "password": "password" 145 | } 146 | ``` 147 | 148 | Values can be omitted from this dictionary, and the values that need overriding can be kept, e.g. 149 | 150 | ```js 151 | "mqtt": { 152 | "port": 1234 153 | } 154 | ``` 155 | 156 | to only override the port value. 157 | 158 | ### SSL 159 | Set "ssl":1 or true in config.json to turn on SSL (ie: server connects with https:// rather than http://). You will need to specify your SSL port - usually "port":"443" by default. 160 | 161 |
162 | 163 | ## Tips 164 | 165 | ### Authentication 166 | If Domoticz is set up to use basic or form login authentication, set "server":"user:pass@ip" within config.json. The plugin will internally extract the username and password, base64 encode it and send it as a http authorization header whenever it talks to your Domoticz server. 167 | 168 | ### Issues pairing to Homebridge when you have a lot of Domoticz sensors... 169 | If you have more than 99 devices in Domoticz, you need to limit the number of devices exposed to HomeKit (Homebridge only supports 99 Accessories on a single bridge - whilst we could combine multiple sensors into a single homekit accessory within the plugin, the possible combinations out there are endless, so we won't). 170 | 171 | Therefore, to reduce the number of devices exposed from Domoticz, create a roomplan within Domoticz via Setup > More Options > Plans > roomplan. Add only the devices you wish to be exposed to HomeKit to this new roomplan within Domoticz, and then get it's roomidx number. Set "roomid" in your config.json file to this room number. 172 | 173 | ### Is my device supported?? 174 | See [Domoticz API Reference](https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's#Retrieve_status_of_specific_device) - query your device as per the instructions there, and if your device’s SwitchTypeVal isn't in the 'Supports:' list or Type/SubType aren’t in the ’Provides:' list above then it'll just appear as an On/Off switch. [Open a new issue](https://github.com/PatchworkBoy/homebridge-edomoticz/issues/new) including the output from the json api and I’ll get look into supporting that particular device more fully! 175 | 176 | ### What does the Override slider represent on the EvoHome Thermostat? 177 | Override-Until time in minutes from the current time. Allows setting an override-until time upto 8 hours in the future. Setting this slider to 0 will set the heating mode to Auto. Setting it to 481 will set the override as a PermanentOverride. 178 | 179 | ### Why does my iOS10 > iOS12 iPad no longer work as a HomeHub? 180 | You've added a new 'TV' device type. This is unsupported on < iOS13, and breaks the ability for (for example) an iOS 10.3.4 iPad 4th Gen from being used as a HomeHub. Removing the TV accessory does not resolve the issue. You MUST remove / disable the accessory, and then delete and recreate your home from scratch to continue using non iOS13 devices as HomeHubs. This is not unique to this plugin's implementation of the TV device type. If you (for instance) add the Sky-Q-Experimental platform plugin alongside eDomoticz, this will break non iOS13 homehubs. 181 | 182 | In short, if you do not have an AppleTV4, HomePod, or iPad running iOS13 on your home network and you wish to retain remote control abilities from off-LAN, you cannot use the new HomeKit TV device type in ANY homebridge plugin. 183 | 184 | ### Logging 185 | Complies with Homebridge's native logging & debugging methodology - see https://github.com/nfarina/homebridge/wiki/Basic-Troubleshooting 186 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // ____ _ _ 2 | // ___| _ \ ___ _ __ ___ ___ | |_(_) ___ ____ 3 | // / _ | | | |/ _ \| '_ ` _ \ / _ \| __| |/ __|_ / 4 | // | __| |_| | (_) | | | | | | (_) | |_| | (__ / / 5 | // \___|____/ \___/|_| |_| |_|\___/ \__|_|\___/___| 6 | // www.npmjs.com/package/homebridge-edomoticz 7 | // 8 | // A Platform Plugin for HomeBridge by Marci & TheRamon 9 | // [http://twitter.com/marcisshadow] 10 | // [http://domoticz.com/forum/memberlist.php?mode=viewprofile&u=10884] 11 | // 12 | var Domoticz = require('./lib/domoticz.js').Domoticz; 13 | var Mqtt = require('./lib/mqtt.js').Mqtt; 14 | var eDomoticzAccessory = require('./lib/domoticz_accessory.js'); 15 | var Constants = require('./lib/constants.js'); 16 | var Helper = require('./lib/helper.js').Helper; 17 | var eDomoticzServices = require('./lib/services.js').eDomoticzServices; 18 | const util = require('util'); 19 | 20 | module.exports = function(homebridge) { 21 | Service = homebridge.hap.Service; 22 | Characteristic = homebridge.hap.Characteristic; 23 | Categories = homebridge.hap.Accessory.Categories; 24 | Types = homebridge.hapLegacyTypes; 25 | UUID = homebridge.hap.uuid; 26 | 27 | util.inherits(eDomoticzServices.TotalConsumption, Characteristic); 28 | util.inherits(eDomoticzServices.CurrentConsumption, Characteristic); 29 | util.inherits(eDomoticzServices.GasConsumption, Characteristic); 30 | util.inherits(eDomoticzServices.TempOverride, Characteristic); 31 | util.inherits(eDomoticzServices.MeterDeviceService, Service); 32 | util.inherits(eDomoticzServices.GasDeviceService, Service); 33 | util.inherits(eDomoticzServices.Ampere, Characteristic); 34 | util.inherits(eDomoticzServices.AMPDeviceService, Service); 35 | util.inherits(eDomoticzServices.Volt, Characteristic); 36 | util.inherits(eDomoticzServices.VOLTDeviceService, Service); 37 | util.inherits(eDomoticzServices.CurrentUsage, Characteristic); 38 | util.inherits(eDomoticzServices.UsageDeviceService, Service); 39 | util.inherits(eDomoticzServices.TodayConsumption, Characteristic); 40 | util.inherits(eDomoticzServices.Barometer, Characteristic); 41 | util.inherits(eDomoticzServices.WaterFlow, Characteristic); 42 | util.inherits(eDomoticzServices.TotalWaterFlow, Characteristic); 43 | util.inherits(eDomoticzServices.WaterDeviceService, Service); 44 | util.inherits(eDomoticzServices.WeatherService, Service); 45 | util.inherits(eDomoticzServices.WindSpeed, Characteristic); 46 | util.inherits(eDomoticzServices.WindChill, Characteristic); 47 | util.inherits(eDomoticzServices.WindDirection, Characteristic); 48 | util.inherits(eDomoticzServices.WindDeviceService, Service); 49 | util.inherits(eDomoticzServices.Rainfall, Characteristic); 50 | util.inherits(eDomoticzServices.RainDeviceService, Service); 51 | util.inherits(eDomoticzServices.Visibility, Characteristic); 52 | util.inherits(eDomoticzServices.VisibilityDeviceService, Service); 53 | util.inherits(eDomoticzServices.SolRad, Characteristic); 54 | util.inherits(eDomoticzServices.SolRadDeviceService, Service); 55 | util.inherits(eDomoticzServices.LocationService, Service); 56 | util.inherits(eDomoticzServices.Location, Characteristic); 57 | util.inherits(eDomoticzServices.InfotextDeviceService, Service); 58 | util.inherits(eDomoticzServices.Infotext, Characteristic); 59 | util.inherits(eDomoticzServices.UVDeviceService, Service); 60 | util.inherits(eDomoticzServices.UVIndex, Characteristic); 61 | 62 | //homebridge.registerAccessory("homebridge-edomoticz", "eDomoticz", eDomoticzAccessory); 63 | homebridge.registerPlatform("homebridge-edomoticz", "eDomoticz", eDomoticzPlatform, true); 64 | }; 65 | 66 | function eDomoticzPlatform(log, config, api) { 67 | this.isSynchronizingAccessories = false; 68 | this.accessories = []; 69 | this.forceLog = log; 70 | this.log = function() { 71 | if (typeof process.env.DEBUG !== 'undefined') { 72 | log(util.format.apply(this, arguments)); 73 | } 74 | }; 75 | 76 | this.config = config; 77 | try { 78 | this.server = config.server; 79 | this.authorizationToken = false; 80 | if (this.server.indexOf(":") > -1 && this.server.indexOf("@") > -1) { 81 | var tmparr = this.server.split("@"); 82 | this.authorizationToken = Helper.Base64.encode(tmparr[0]); 83 | this.server = tmparr[1]; 84 | } 85 | 86 | this.ssl = (config.ssl == 1); 87 | this.port = config.port; 88 | this.webroot = config.webroot; 89 | this.room = config.roomid; 90 | this.api = api; 91 | this.apiBaseURL = "http" + (this.ssl ? "s" : "") + "://" + this.server + ":" + this.port + ((this.webroot === undefined) ? "" : "/" + this.webroot ) + "/json.htm?"; 92 | this.mqtt = false; 93 | } catch (e) { 94 | this.forceLog(e); 95 | return; 96 | } 97 | var requestHeaders = {}; 98 | if (this.authorizationToken) { 99 | requestHeaders['Authorization'] = 'Basic ' + this.authorizationToken; 100 | } 101 | Domoticz.initialize(this.ssl, requestHeaders); 102 | 103 | if (this.api) { 104 | this.api.once("didFinishLaunching", function() { 105 | var syncDevices = function() { 106 | this.synchronizeAccessories(); 107 | setTimeout(syncDevices.bind(this), 600000); // Sync devices every 10 minutes 108 | }.bind(this); 109 | syncDevices(); 110 | 111 | if (config.mqtt) { 112 | setupMqttConnection(this); 113 | } 114 | }.bind(this)); 115 | } 116 | } 117 | 118 | eDomoticzPlatform.prototype = { 119 | synchronizeAccessories: function() { 120 | if (this.isSynchronizingAccessories) { 121 | return; 122 | } 123 | 124 | this.isSynchronizingAccessories = true; 125 | this.forceLog('synchronizeAccessories in progress...'); 126 | var excludedDevices = (typeof this.config.excludedDevices !== 'undefined') ? this.config.excludedDevices : []; 127 | 128 | Domoticz.devices(this.apiBaseURL, this.room, function(devices) { 129 | var removedAccessories = [], 130 | externalAccessories = []; 131 | 132 | 133 | for (var i = 0; i < devices.length; i++) { 134 | var device = devices[i], exclude = !1; 135 | if (!(excludedDevices.indexOf(device.idx) <= -1)) { 136 | exclude = !0; 137 | this.log(device.Name + ' (idx:' + device.idx + ') excluded via config array'); 138 | } 139 | 140 | if (device.Image == undefined) { 141 | device.Image = 'Switch'; 142 | } 143 | 144 | var existingAccessory = this.accessories.find(function(existingAccessory) { 145 | return existingAccessory.idx == device.idx; 146 | }); 147 | 148 | if (existingAccessory) { 149 | if ((device.SwitchTypeVal > 0 && device.SwitchTypeVal !== existingAccessory.swTypeVal) || exclude == !0) { 150 | if (exclude == !1) { 151 | this.forceLog("Device " + existingAccessory.name + " has changed it's type. Recreating..."); 152 | } else { 153 | this.forceLog("Device " + existingAccessory.name + " has been excluded. Removing..."); 154 | } 155 | removedAccessories.push(existingAccessory); 156 | try { 157 | this.api.unregisterPlatformAccessories("homebridge-edomoticz", "eDomoticz", [existingAccessory.platformAccessory]); 158 | } catch (e) { 159 | this.forceLog("Could not unregister platform accessory! (" + existingAccessory.name + ")\n" + e); 160 | } 161 | } else { 162 | continue; 163 | } 164 | } 165 | 166 | if (exclude == !1) { 167 | // Generate a new accessory 168 | var uuid = UUID.generate(device.idx + "_" + device.Name); 169 | this.forceLog("Device: " + device.Name + " (" + device.idx + ")"); 170 | var accessory = new eDomoticzAccessory(this, false, false, device.Used, device.idx, device.Name, uuid, device.HaveDimmer, device.MaxDimLevel, device.SubType, device.Type, device.BatteryLevel, device.SwitchType, device.SwitchTypeVal, device.HardwareID, device.HardwareTypeVal, device.Image, this.eve, device.HaveTimeout, device.Description); 171 | this.accessories.push(accessory); 172 | 173 | // Register the accessories 174 | try { 175 | accessory.platformAccessory.context = { 176 | device: device, 177 | uuid: uuid, 178 | eve: this.eve 179 | }; 180 | if ((device.SwitchTypeVal == Constants.DeviceTypeMedia) || (device.SwitchTypeVal == Constants.DeviceTypeSelector && device.Image == "TV")) { 181 | externalAccessories.push(accessory); 182 | } else { 183 | this.api.registerPlatformAccessories("homebridge-edomoticz", "eDomoticz", [accessory.platformAccessory]); 184 | } 185 | 186 | } catch (e) { 187 | this.forceLog("Could not register platform accessory! (" + accessory.name + ")\n" + e); 188 | } 189 | 190 | } 191 | } 192 | // Publish external (ie: TV) accessories now that they're fully assembled 193 | for (var ei = 0; ei < externalAccessories.length; ei++) { 194 | var externalAccessory = externalAccessories[ei]; 195 | if (externalAccessory.subType !== 'Selector Switch') 196 | { 197 | this.api.publishExternalAccessories("homebridge-edomoticz", [externalAccessory.platformAccessory]); 198 | this.forceLog("External Device: " + externalAccessory.platformAccessory.context.device.Name + " (" + externalAccessory.platformAccessory.context.device.idx + ")"); 199 | } 200 | } 201 | 202 | // Remove the old accessories 203 | for (var i = 0; i < this.accessories.length; i++) { 204 | var removedAccessory = this.accessories[i]; 205 | var existingDevice = devices.find(function(existingDevice) { 206 | return existingDevice.idx == removedAccessory.idx; 207 | }); 208 | 209 | if (!existingDevice) { 210 | removedAccessories.push(removedAccessory); 211 | try { 212 | this.api.unregisterPlatformAccessories("homebridge-edomoticz", "eDomoticz", [removedAccessory.platformAccessory]); 213 | } catch (e) { 214 | this.forceLog("Could not unregister platform accessory! (" + removedAccessory.name + ")\n" + e); 215 | } 216 | } 217 | } 218 | 219 | for (var i = 0; i < removedAccessories.length; i++) { 220 | var removedAccessory = removedAccessories[i]; 221 | removedAccessory.removed(); 222 | var index = this.accessories.indexOf(removedAccessory); 223 | this.accessories.splice(index, 1); 224 | } 225 | this.isSynchronizingAccessories = false; 226 | }.bind(this), function(response, err) { 227 | Helper.LogConnectionError(this, response, err); 228 | this.isSynchronizingAccessories = false; 229 | }.bind(this)); 230 | }, 231 | configureAccessory: function(platformAccessory) { 232 | if (!platformAccessory.context || !platformAccessory.context.device) { 233 | // Remove this invalid device from the cache. 234 | try { 235 | this.api.unregisterPlatformAccessories("homebridge-edomoticz", "eDomoticz", [platformAccessory]); 236 | } catch (e) { 237 | this.forceLog("Could not unregister cached platform accessory!\n" + e); 238 | } 239 | return; 240 | } 241 | 242 | var device = platformAccessory.context.device; 243 | var uuid = platformAccessory.context.uuid; 244 | var eve = platformAccessory.context.eve; 245 | 246 | // Generate the already cached accessory again 247 | var accessory = new eDomoticzAccessory(this, platformAccessory, false, device.Used, device.idx, device.Name, uuid, device.HaveDimmer, device.MaxDimLevel, device.SubType, device.Type, device.BatteryLevel, device.SwitchType, device.SwitchTypeVal, device.HardwareID, device.HardwareTypeVal, device.Image, eve, device.HaveTimeout, device.Description); 248 | this.accessories.push(accessory); 249 | } 250 | }; 251 | 252 | function setupMqttConnection(platform) { 253 | var connectionInformation = { 254 | host: (typeof platform.config.mqtt.host !== 'undefined' ? platform.config.mqtt.host : '127.0.0.1'), 255 | port: (typeof platform.config.mqtt.port !== 'undefined' ? platform.config.mqtt.port : 1883), 256 | topic: (typeof platform.config.mqtt.topic !== 'undefined' ? platform.config.mqtt.topic : 'domoticz/out'), 257 | username: (typeof platform.config.mqtt.username !== 'undefined' ? platform.config.mqtt.username : ''), 258 | password: (typeof platform.config.mqtt.password !== 'undefined' ? platform.config.mqtt.password : ''), 259 | }; 260 | 261 | var mqttError = function() { 262 | platform.forceLog("There was an error while getting the MQTT Hardware Device from Domoticz.\nPlease verify that you have added the MQTT Hardware Device and that the hardware device is enabled."); 263 | }; 264 | 265 | Domoticz.hardware(platform.apiBaseURL, function(hardware) { 266 | var mqttHardware = false; 267 | for (var i = 0; i < hardware.length; i++) { 268 | if (hardware[i].Type == Constants.HardwareTypeMQTT) { 269 | mqttHardware = hardware[i]; 270 | break; 271 | } 272 | } 273 | 274 | if (mqttHardware === false || (mqttHardware.Enabled != "true")) { 275 | mqttError(); 276 | return; 277 | } 278 | 279 | if (typeof platform.config.mqtt.host === 'undefined') { 280 | connectionInformation.host = mqttHardware.Address; 281 | } 282 | 283 | if (typeof platform.config.mqtt.port === 'undefined') { 284 | connectionInformation.port = mqttHardware.Port; 285 | } 286 | 287 | if (typeof platform.config.mqtt.username === 'undefined') { 288 | connectionInformation.username = mqttHardware.Username; 289 | } 290 | 291 | if (typeof platform.config.mqtt.password === 'undefined') { 292 | connectionInformation.password = mqttHardware.Password; 293 | } 294 | 295 | platform.mqtt = new Mqtt(platform, connectionInformation.host, connectionInformation.port, connectionInformation.topic, { 296 | username: connectionInformation.username, 297 | password: connectionInformation.password 298 | }); 299 | }, mqttError); 300 | } 301 | -------------------------------------------------------------------------------- /lib/services.js: -------------------------------------------------------------------------------- 1 | var Constants = require('./constants.js'); 2 | 3 | module.exports = { 4 | eDomoticzServices: eDomoticzServices 5 | } 6 | 7 | 8 | function eDomoticzServices() { 9 | 10 | } 11 | 12 | /* Define Custom Services & Characteristics */ 13 | // PowerMeter Characteristics 14 | eDomoticzServices.TotalConsumption = function() { 15 | var charUUID = 'E863F10C-079E-48FF-8F27-9C2605A29F52'; //UUID.generate('eDomoticz:customchar:TotalConsumption'); 16 | Characteristic.call(this, 'Total Consumption', charUUID); 17 | this.setProps({ 18 | format: Characteristic.Formats.FLOAT, 19 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 20 | unit: 'kWh' 21 | }); 22 | this.value = this.getDefaultValue(); 23 | this.UUID = charUUID; 24 | }; 25 | eDomoticzServices.TodayConsumption = function() { 26 | var charUUID = UUID.generate('eDomoticz:customchar:TodayConsumption'); 27 | Characteristic.call(this, 'Today', charUUID); 28 | this.setProps({ 29 | format: Characteristic.Formats.FLOAT, 30 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 31 | unit: 'kWh' 32 | }); 33 | this.value = this.getDefaultValue(); 34 | this.UUID = charUUID; 35 | }; 36 | eDomoticzServices.CurrentConsumption = function() { 37 | var charUUID = 'E863F10D-079E-48FF-8F27-9C2605A29F52'; //UUID.generate('eDomoticz:customchar:CurrentConsumption'); 38 | Characteristic.call(this, 'Consumption', charUUID); 39 | this.setProps({ 40 | format: Characteristic.Formats.FLOAT, 41 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 42 | unit: 'W' 43 | }); 44 | this.value = this.getDefaultValue(); 45 | this.UUID = charUUID; 46 | }; 47 | eDomoticzServices.Ampere = function() { 48 | var charUUID = 'E863F126-079E-48FF-8F27-9C2605A29F52'; //AMPERE 49 | Characteristic.call(this, 'Amps', charUUID); 50 | this.setProps({ 51 | format: Characteristic.Formats.FLOAT, 52 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 53 | unit: 'A' 54 | }); 55 | this.value = this.getDefaultValue(); 56 | this.UUID = charUUID; 57 | }; 58 | eDomoticzServices.Volt = function() { 59 | var charUUID = 'E863F10A-079E-48FF-8F27-9C2605A29F52'; //VOLT 60 | Characteristic.call(this, 'Volts', charUUID); 61 | this.setProps({ 62 | format: Characteristic.Formats.FLOAT, 63 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 64 | unit: 'V' 65 | }); 66 | this.value = this.getDefaultValue(); 67 | this.UUID = charUUID; 68 | }; 69 | eDomoticzServices.GasConsumption = function() { 70 | var charUUID = UUID.generate('eDomoticz:customchar:CurrentConsumption'); 71 | Characteristic.call(this, 'Meter Total', charUUID); 72 | this.setProps({ 73 | format: Characteristic.Formats.FLOAT, 74 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] 75 | }); 76 | this.value = this.getDefaultValue(); 77 | this.UUID = charUUID; 78 | }; 79 | eDomoticzServices.WaterFlow = function() { 80 | var charUUID = UUID.generate('eDomoticz:customchar:WaterFlow'); 81 | Characteristic.call(this, 'Flow Rate', charUUID); 82 | this.setProps({ 83 | format: Characteristic.Formats.FLOAT, 84 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 85 | unit: 'm3' 86 | }); 87 | this.value = this.getDefaultValue(); 88 | this.UUID = charUUID; 89 | }; 90 | eDomoticzServices.TotalWaterFlow = function() { 91 | var charUUID = UUID.generate('eDomoticz:customchar:TotalWaterFlow'); 92 | Characteristic.call(this, 'Flow Total', charUUID); 93 | this.setProps({ 94 | format: Characteristic.Formats.FLOAT, 95 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 96 | unit: 'l' 97 | }); 98 | this.value = this.getDefaultValue(); 99 | this.UUID = charUUID; 100 | }; 101 | // Custom SetPoint Minutes characteristic for TempOverride modes 102 | eDomoticzServices.TempOverride = function() { 103 | var charUUID = UUID.generate('eDomoticz:customchar:OverrideTime'); 104 | Characteristic.call(this, 'Override (Mins, 0 = Auto, 481 = Permanent)', charUUID); 105 | this.setProps({ 106 | format: Characteristic.Formats.FLOAT, 107 | maxValue: 481, 108 | minValue: 0, 109 | minStep: 1, 110 | unit: 'mins', 111 | perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY] 112 | }); 113 | this.value = this.getDefaultValue(); 114 | this.UUID = charUUID; 115 | }; 116 | // Ampere Meter 117 | eDomoticzServices.AMPDeviceService = function(displayName, subtype) { 118 | var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice'); 119 | Service.call(this, displayName, serviceUUID, subtype); 120 | this.addCharacteristic(new eDomoticzServices.Ampere()); 121 | }; 122 | // Voltage Meter 123 | eDomoticzServices.VOLTDeviceService = function(displayName, subtype) { 124 | var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice'); 125 | Service.call(this, displayName, serviceUUID, subtype); 126 | this.addCharacteristic(new eDomoticzServices.Volt()); 127 | }; 128 | 129 | // The PowerMeter itself 130 | eDomoticzServices.MeterDeviceService = function(displayName, subtype) { 131 | 132 | var serviceUUID = UUID.generate('eDomoticz:powermeter:customservice'); 133 | Service.call(this, displayName, serviceUUID, subtype); 134 | this.addCharacteristic(new eDomoticzServices.CurrentConsumption()); 135 | this.addOptionalCharacteristic(new eDomoticzServices.TotalConsumption()); 136 | this.addOptionalCharacteristic(new eDomoticzServices.TodayConsumption()); 137 | }; 138 | // Waterflow Meter 139 | eDomoticzServices.WaterDeviceService = function(displayName, subtype) { 140 | var serviceUUID = UUID.generate('eDomoticz:watermeter:customservice'); 141 | Service.call(this, displayName, serviceUUID, subtype); 142 | this.addCharacteristic(new eDomoticzServices.WaterFlow()); 143 | this.addOptionalCharacteristic(new eDomoticzServices.TotalWaterFlow()); 144 | }; 145 | // P1 Smart Meter -> Gas 146 | eDomoticzServices.GasDeviceService = function(displayName, subtype) { 147 | var serviceUUID = UUID.generate('eDomoticz:gasmeter:customservice'); 148 | Service.call(this, displayName, serviceUUID, subtype); 149 | this.addCharacteristic(new eDomoticzServices.GasConsumption()); 150 | }; 151 | // Usage Meter Characteristics 152 | eDomoticzServices.CurrentUsage = function() { 153 | var charUUID = UUID.generate('eDomoticz:customchar:CurrentUsage'); 154 | Characteristic.call(this, 'Current Usage', charUUID); 155 | this.setProps({ 156 | format: Characteristic.Formats.FLOAT, 157 | unit: Characteristic.Units.PERCENTAGE, 158 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 159 | minValue:0, 160 | maxValue:100, 161 | minStep:0.1 162 | }); 163 | this.value = this.getDefaultValue(); 164 | this.UUID = charUUID; 165 | }; 166 | // The Usage Meter itself 167 | eDomoticzServices.UsageDeviceService = function(displayName, subtype) { 168 | var serviceUUID = UUID.generate('eDomoticz:usagedevice:customservice'); 169 | Service.call(this, displayName, serviceUUID, subtype); 170 | this.addCharacteristic(new eDomoticzServices.CurrentUsage()); 171 | }; 172 | // Location Meter (sensor should have 'Location' in title) 173 | eDomoticzServices.Location = function() { 174 | var charUUID = UUID.generate('eDomoticz:customchar:Location'); 175 | Characteristic.call(this, 'Location', charUUID); 176 | this.setProps({ 177 | format: Characteristic.Formats.STRING, 178 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] 179 | }); 180 | this.value = this.getDefaultValue(); 181 | this.UUID = charUUID; 182 | }; 183 | eDomoticzServices.LocationService = function(displayName, subtype) { 184 | var serviceUUID = UUID.generate('eDomoticz:location:customservice'); 185 | Service.call(this, displayName, serviceUUID, subtype); 186 | this.addCharacteristic(new eDomoticzServices.Location()); 187 | }; 188 | // DarkSkies WindSpeed Characteristic 189 | eDomoticzServices.WindSpeed = function() { 190 | var charUUID = '49C8AE5A-A3A5-41AB-BF1F-12D5654F9F41';//'9331096F-E49E-4D98-B57B-57803498FA36'; //UUID.generate('eDomoticz:customchar:WindSpeed'); 191 | Characteristic.call(this, 'Wind Speed', charUUID); 192 | this.setProps({ 193 | format: Characteristic.Formats.FLOAT, 194 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 195 | unit:'m/s', 196 | minValue:0, 197 | maxValue:360, 198 | minStep:0.1 199 | }); 200 | this.value = this.getDefaultValue(); 201 | this.UUID = charUUID; 202 | }; 203 | // DarkSkies WindChill Characteristic 204 | eDomoticzServices.WindChill = function() { 205 | var charUUID = UUID.generate('eDomoticz:customchar:WindChill'); 206 | Characteristic.call(this, 'Wind Chill', charUUID); 207 | this.setProps({ 208 | format: Characteristic.Formats.FLOAT, 209 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 210 | unit: Characteristic.Units.CELSIUS, 211 | minValue:-50, 212 | maxValue:100, 213 | minStep:0.1 214 | }); 215 | this.value = this.getDefaultValue(); 216 | this.UUID = charUUID; 217 | }; 218 | // DarkSkies WindDirection Characteristic 219 | eDomoticzServices.WindDirection = function() { 220 | var charUUID = '46f1284c-1912-421b-82f5-eb75008b167e';//'6C3F6DFA-7340-4ED4-AFFD-0E0310ECCD9E'; //UUID.generate('eDomoticz:customchar:WindDirection'); 221 | Characteristic.call(this, 'Wind Direction', charUUID); 222 | this.setProps({ 223 | format: Characteristic.Formats.INT, 224 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 225 | unit: Characteristic.Units.ARC_DEGREE, 226 | minValue:0, 227 | maxValue:360, 228 | minStep:1 229 | }); 230 | this.value = this.getDefaultValue(); 231 | this.UUID = charUUID; 232 | }; 233 | // DarkSkies Virtual Wind Sensor 234 | eDomoticzServices.WindDeviceService = function(displayName, subtype) { 235 | var serviceUUID = '2AFB775E-79E5-4399-B3CD-398474CAE86C'; //UUID.generate('eDomoticz:winddevice:customservice'); 236 | Service.call(this, displayName, serviceUUID, subtype); 237 | this.addCharacteristic(new eDomoticzServices.WindSpeed()); 238 | this.addOptionalCharacteristic(new eDomoticzServices.WindChill()); 239 | this.addOptionalCharacteristic(new eDomoticzServices.WindDirection()); 240 | this.addOptionalCharacteristic(new Characteristic.CurrentTemperature()); 241 | }; 242 | // DarkSkies Rain Characteristics 243 | eDomoticzServices.Rainfall = function() { 244 | var charUUID = 'ccc04890-565b-4376-b39a-3113341d9e0f';//'C53F35CE-C615-4AA4-9112-EBF679C5EB14'; //UUID.generate('eDomoticz:customchar:Rainfall'); 245 | Characteristic.call(this, 'Amount today', charUUID); 246 | this.setProps({ 247 | format: Characteristic.Formats.FLOAT, 248 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 249 | unit: 'mm', 250 | minValue:0, 251 | maxValue:360, 252 | minStep:0.1 253 | }); 254 | this.value = this.getDefaultValue(); 255 | this.UUID = charUUID; 256 | }; 257 | // DarkSkies Rain Meter itself 258 | eDomoticzServices.RainDeviceService = function(displayName, subtype) { 259 | var serviceUUID = 'D92D5391-92AF-4824-AF4A-356F25F25EA1'; //UUID.generate('eDomoticz:raindevice:customservice'); 260 | Service.call(this, displayName, serviceUUID, subtype); 261 | this.addCharacteristic(new eDomoticzServices.Rainfall()); 262 | }; 263 | // DarkSkies Visibility Characteristics 264 | eDomoticzServices.Visibility = function() { 265 | var charUUID = 'd24ecc1e-6fad-4fb5-8137-5af88bd5e857';//UUID.generate('eDomoticz:customchar:Visibility'); 266 | Characteristic.call(this, 'Distance', charUUID); 267 | this.setProps({ 268 | format: Characteristic.Formats.FLOAT, 269 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 270 | unit: 'miles', 271 | minValue:0, 272 | maxValue:20, 273 | minStep:0.1 274 | }); 275 | this.value = this.getDefaultValue(); 276 | this.UUID = charUUID; 277 | }; 278 | // DarkSkies Visibility Meter itself 279 | eDomoticzServices.VisibilityDeviceService = function(displayName, subtype) { 280 | var serviceUUID = UUID.generate('eDomoticz:visibilitydevice:customservice'); 281 | Service.call(this, displayName, serviceUUID, subtype); 282 | this.addCharacteristic(new eDomoticzServices.Visibility()); 283 | }; 284 | // DarkSkies UVIndex Characteristics 285 | eDomoticzServices.UVIndex = function() { 286 | var charUUID = '05ba0fe0-b848-4226-906d-5b64272e05ce';//UUID.generate('eDomoticz:customchar:Visibility'); 287 | Characteristic.call(this, 'UVIndex', charUUID); 288 | this.setProps({ 289 | format: Characteristic.Formats.FLOAT, 290 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 291 | unit: 'UVI', 292 | minValue:0, 293 | maxValue:20, 294 | minStep:0.1 295 | }); 296 | this.value = this.getDefaultValue(); 297 | this.UUID = charUUID; 298 | }; 299 | 300 | // DarkSkies UV Index Meter itself 301 | eDomoticzServices.UVDeviceService = function(displayName, subtype) { 302 | var serviceUUID = UUID.generate('eDomoticz:uvdevice:customservice'); 303 | Service.call(this, displayName, serviceUUID, subtype); 304 | this.addCharacteristic(new eDomoticzServices.UVIndex()); 305 | }; 306 | // DarkSkies Solar Radiation Characteristics 307 | eDomoticzServices.SolRad = function() { 308 | var charUUID = UUID.generate('eDomoticz:customchar:SolRad'); 309 | Characteristic.call(this, 'Radiation', charUUID); 310 | this.setProps({ 311 | format: Characteristic.Formats.FLOAT, 312 | unit: 'W/m2', 313 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 314 | minValue:0, 315 | maxValue:10000, 316 | minStep:0.1 317 | }); 318 | this.value = this.getDefaultValue(); 319 | this.UUID = charUUID; 320 | }; 321 | // DarkSkies Solar Radiation Meter itself 322 | eDomoticzServices.SolRadDeviceService = function(displayName, subtype) { 323 | var serviceUUID = UUID.generate('eDomoticz:solraddevice:customservice'); 324 | Service.call(this, displayName, serviceUUID, subtype); 325 | this.addCharacteristic(new eDomoticzServices.SolRad()); 326 | }; 327 | // Barometer Characteristic 328 | eDomoticzServices.Barometer = function() { 329 | var charUUID = 'E863F10F-079E-48FF-8F27-9C2605A29F52'; 330 | Characteristic.call(this, 'Pressure', charUUID); 331 | this.setProps({ 332 | format: Characteristic.Formats.FLOAT, 333 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY], 334 | unit: 'hPA', 335 | minValue: 500, 336 | maxValue: 2000, 337 | minStep: 0.1 338 | }); 339 | this.value = this.getDefaultValue(); 340 | this.UUID = charUUID; 341 | }; 342 | // Weather Service 343 | eDomoticzServices.WeatherService = function(displayName, subtype) { 344 | var serviceUUID = 'debf1b79-312e-47f7-bf82-993d9950f3a2';//'E863F001-079E-48FF-8F27-9C2605A29F52'; 345 | Service.call(this, displayName, serviceUUID, subtype); 346 | this.addCharacteristic(new Characteristic.CurrentTemperature()); 347 | this.addOptionalCharacteristic(new Characteristic.CurrentRelativeHumidity()); 348 | this.addOptionalCharacteristic(new eDomoticzServices.Barometer()); 349 | }; 350 | // DarkSkies Visibility Characteristics 351 | eDomoticzServices.Infotext = function() { 352 | var charUUID = UUID.generate('eDomoticz:customchar:Infotext'); 353 | Characteristic.call(this, 'Infotext', charUUID); 354 | this.setProps({ 355 | format: 'string', 356 | perms: [Characteristic.Perms.READ, Characteristic.Perms.NOTIFY] 357 | }); 358 | this.value = this.getDefaultValue(); 359 | this.UUID = charUUID; 360 | }; 361 | // DarkSkies Visibility Meter itself 362 | eDomoticzServices.InfotextDeviceService = function(displayName, subtype) { 363 | var serviceUUID = UUID.generate('eDomoticz:infotextdevice:customservice'); 364 | Service.call(this, displayName, serviceUUID, subtype); 365 | this.addCharacteristic(new eDomoticzServices.Infotext()); 366 | }; 367 | /* End of Custom Services & Characteristics */ 368 | -------------------------------------------------------------------------------- /lib/domoticz_accessory.js: -------------------------------------------------------------------------------- 1 | var request = require("request"); 2 | var Constants = require('./constants.js'); 3 | var Helper = require('./helper.js').Helper; 4 | var Domoticz = require('./domoticz.js').Domoticz; 5 | var eDomoticzServices = require('./services.js').eDomoticzServices; 6 | const { performance } = require('perf_hooks'); 7 | module.exports = eDomoticzAccessory; 8 | 9 | var tvAccessories = {}; 10 | var tvInputAccessories = {}; 11 | 12 | function eDomoticzAccessory(platform, platformAccessory, IsScene, status, idx, name, uuid, haveDimmer, maxDimLevel, subType, Type, batteryRef, swType, swTypeVal, hwId, hwType, image, eve, hwtimeout, descript) { 13 | 14 | if ((haveDimmer) || (swType == "Dimmer")) { 15 | if ((hwType !== 51) && (swType !== "On/Off")) { 16 | this.haveDimmer = true; 17 | this.maxDimLevel = maxDimLevel; 18 | } else { 19 | this.haveDimmer = false; 20 | } 21 | } else { 22 | this.haveDimmer = false; 23 | } 24 | 25 | this.services = []; 26 | this.published = false; 27 | this.platform = platform; 28 | this.IsScene = IsScene; // Domoticz Scenes ignored for now... 29 | this.status = status; 30 | this.idx = idx; 31 | this.name = name; 32 | this.eve = eve; 33 | this.subType = subType; 34 | this.swType = swType; 35 | this.image = image; 36 | this.swTypeVal = swTypeVal; 37 | this.hwtimeout = hwtimeout; 38 | this.isSwitch = (typeof this.swTypeVal !== 'undefined' && this.swTypeVal >= 0 && this.name.indexOf("Occupied") == -1); 39 | switch (hwType) { 40 | case 67: // Domoticz Security Panel 41 | this.swTypeVal = Constants.DeviceTypeSecuritySystem; 42 | break; 43 | 44 | default: 45 | break; 46 | } 47 | 48 | this.Type = Type; 49 | this.batteryRef = batteryRef; 50 | this.CounterToday = 1; 51 | this.onValue = "On"; 52 | this.offValue = "Off"; 53 | this.cachedValues = {}; 54 | this.hwId = hwId; 55 | this.hwType = hwType; 56 | this.descript = descript; 57 | this.powerOnBySetLevelTime = 0; 58 | 59 | // Initialize default values, e.g. to get the "factor" 60 | var voidCallback = function () {}; 61 | switch (true) { 62 | case this.swTypeVal == Constants.DeviceTypeDimmer: 63 | case this.swTypeVal == Constants.DeviceTypeBlindsPercentage: 64 | case this.swTypeVal == Constants.DeviceTypeBlindsPercentageInverted: 65 | case this.swTypeVal == Constants.DeviceTypeBlindsPlusStop: 66 | { 67 | if (this.swTypeVal == Constants.DeviceTypeBlindsPercentage) { 68 | this.isPercentageBlind = Constants.DeviceTypeBlindsPercentage; 69 | } 70 | if (this.swTypeVal == Constants.DeviceTypeBlindsPlusStop) { 71 | this.isPercentageBlind = Constants.DeviceTypeBlindsPlusStop; 72 | } 73 | if (this.swTypeVal == Constants.DeviceTypeBlindsPercentageInverted) { 74 | this.isInvertedBlind = Constants.DeviceTypeBlindsPercentageInverted; 75 | } 76 | this.getdValue(voidCallback); 77 | break; 78 | } 79 | default: 80 | break; 81 | } 82 | 83 | this.platformAccessory = platformAccessory; 84 | if (!this.platformAccessory) { 85 | this.platformAccessory = new platform.api.platformAccessory(this.name, uuid); 86 | } 87 | this.platformAccessory.reachable = true; 88 | if (this.swTypeVal == Constants.DeviceTypeMedia) { 89 | this.platformAccessory.category = Categories.TELEVISION; 90 | } 91 | this.publishServices(); 92 | } 93 | 94 | eDomoticzAccessory.prototype = { 95 | identify: function (callback) { 96 | callback(); 97 | }, 98 | publishServices: function () { 99 | var services = this.getServices(); 100 | for (var i = 0; i < services.length; i++) { 101 | this.publishService(services[i]); 102 | } 103 | this.published = true; 104 | }, 105 | publishService: function (service) { 106 | var existingService = this.platformAccessory.services.find(function (eService) { 107 | return eService.UUID == service.UUID && eService.subtype == service.subtype; 108 | }); 109 | 110 | if (!existingService) { 111 | this.platformAccessory.addService(service, this.name); 112 | } 113 | }, 114 | getService: function (name, subtype) { 115 | var service = false; 116 | try { 117 | if (subtype) { 118 | service = this.platformAccessory.getServiceByUUIDAndSubType(name, subtype); 119 | } else { 120 | service = this.platformAccessory.getService(name); 121 | } 122 | } catch (e) { 123 | service = false; 124 | } 125 | 126 | if (!service) { 127 | var targetService = new name(); 128 | service = this.platformAccessory.services.find(function (existingService) { 129 | return existingService.UUID == targetService.UUID && existingService.subtype == targetService.subtype; 130 | }); 131 | } 132 | 133 | return service; 134 | }, 135 | getCharacteristic: function (service, name) { 136 | var characteristic = false; 137 | try { 138 | characteristic = service.getCharacteristic(name); 139 | } catch (e) { 140 | //console.log("^ For: " + service.displayName); 141 | characteristic = false; 142 | } 143 | 144 | if (!characteristic) { 145 | var targetCharacteristic = new name(); 146 | characteristic = service.characteristics.find(function (existingCharacteristic) { 147 | return existingCharacteristic.UUID == targetCharacteristic.UUID && existingCharacteristic.subtype == targetCharacteristic.subtype; 148 | }); 149 | } 150 | 151 | return characteristic; 152 | }, 153 | gracefullyAddCharacteristic: function (service, characteristicType) { 154 | var characteristic = this.getCharacteristic(service, characteristicType); 155 | if (characteristic) { 156 | return characteristic; 157 | } 158 | 159 | return service.addCharacteristic(new characteristicType()); 160 | }, 161 | setPowerState: function (powerOn, callback, context) { 162 | if (context && context == "eDomoticz-MQTT" 163 | || (this.cachedValues[Characteristic.On.UUID] == powerOn && powerOn) // Prevents message loop while dimming lights. 164 | || (this.powerOnBySetLevelTime > 0 && (performance.now() - this.powerOnBySetLevelTime) < 500 && powerOn) // Ignore a power ON right after a setlevel to allow turning ON a light using a dimmer. 165 | ) { 166 | this.powerOnBySetLevelTime = 0; 167 | callback(); 168 | return; 169 | } 170 | 171 | this.powerOnBySetLevelTime = 0; 172 | Domoticz.updateDeviceStatus(this, "switchlight", { 173 | "switchcmd": (powerOn ? "On" : "Off") 174 | }, function (success) { 175 | this.cachedValues[Characteristic.On.UUID] = powerOn; 176 | callback(); 177 | }.bind(this)); 178 | }, 179 | getPowerState: function (callback) { 180 | var cachedValue = this.cachedValues[Characteristic.On.UUID]; 181 | if (typeof cachedValue !== 'undefined') { 182 | callback(null, cachedValue); 183 | } 184 | 185 | Domoticz.deviceStatus(this, function (json) { 186 | var value; 187 | var sArray = Helper.sortByKey(json.result, "Name"); 188 | sArray.map(function (s) { 189 | if (this.swTypeVal == Constants.DeviceTypePushOn) { 190 | value = (s.Data == "Off") ? false : true; 191 | } else { 192 | value = (s.Status == "Off") ? false : true; 193 | } 194 | }.bind(this)); 195 | 196 | if (typeof cachedValue === 'undefined') { 197 | callback(null, value); 198 | } 199 | 200 | this.cachedValues[Characteristic.On.UUID] = value; 201 | }.bind(this)); 202 | }, 203 | setActiveState: function (state, callback, context) { 204 | if (context && context == "eDomoticz-MQTT") { 205 | callback(); 206 | return; 207 | } 208 | 209 | Domoticz.updateDeviceStatus(this, "switchlight", { 210 | "switchcmd": (state ? "On" : "Off") 211 | }, function (success) { 212 | this.cachedValues[Characteristic.Active.UUID] = state; 213 | callback(); 214 | }.bind(this)); 215 | }, 216 | getActiveState: function (callback) { 217 | var cachedValue = this.cachedValues[Characteristic.Active.UUID]; 218 | if (typeof cachedValue !== 'undefined') { 219 | callback(null, cachedValue); 220 | } 221 | 222 | Domoticz.deviceStatus(this, function (json) { 223 | var value; 224 | var sArray = Helper.sortByKey(json.result, "Name"); 225 | sArray.map(function (s) { 226 | value = (s.Status == "Off") ? false : true; 227 | }.bind(this)); 228 | 229 | if (typeof cachedValue === 'undefined') { 230 | callback(null, value); 231 | } 232 | 233 | this.cachedValues[Characteristic.Active.UUID] = value; 234 | }.bind(this)); }, 235 | getRainfall: function (callback) { 236 | Domoticz.deviceStatus(this, function (json) { 237 | var value; 238 | var sArray = Helper.sortByKey(json.result, "Name"); 239 | sArray.map(function (s) { 240 | value = Helper.cleanFloat(s.Rain); 241 | }.bind(this)); 242 | this.platform.log("Data Received for " + this.name + ": " + value); 243 | callback(null, value); 244 | }.bind(this)); 245 | }, 246 | setdValue: function (level, callback, context) { 247 | this.cachedValues[Characteristic.Brightness.UUID] = level; 248 | if (context && context == "eDomoticz-MQTT") { 249 | callback(); 250 | return; 251 | } 252 | 253 | if (!(this.factor)) { 254 | Domoticz.deviceStatus(this, function (json) { 255 | var sArray = Helper.sortByKey(json.result, "Name"); 256 | sArray.map(function (s) { 257 | this.factor = 100 / s.MaxDimLevel; 258 | }.bind(this)); 259 | }.bind(this)); 260 | } 261 | 262 | var dim = this.platform.config.dimFix == 1 ? Math.floor(level / this.factor) + 1 : Math.floor(level / this.factor); 263 | this.powerOnBySetLevelTime = !this.cachedValues[Characteristic.On.UUID] ? performance.now() : 0; 264 | Domoticz.updateDeviceStatus(this, "switchlight", { 265 | "switchcmd": "Set Level", 266 | "level": dim 267 | }, function (success) { 268 | callback(); 269 | }.bind(this)); 270 | }, 271 | getdValue: function (callback) { 272 | var cachedValue = (this.isPercentageBlind || this.isInvertedBlind) ? this.cachedValues[Characteristic.CurrentPosition.UUID] : this.cachedValues[Characteristic.Brightness.UUID]; 273 | if (typeof cachedValue !== 'undefined') { 274 | callback(null, cachedValue); 275 | } 276 | 277 | Domoticz.deviceStatus(this, function (json) { 278 | var value; 279 | var sArray = Helper.sortByKey(json.result, "Name"); 280 | sArray.map(function (s) { 281 | this.factor = 100 / s.MaxDimLevel; 282 | value = Math.floor(s.LevelInt * this.factor); 283 | }.bind(this)); 284 | this.platform.log("Data Received for " + this.name + ": " + value); 285 | 286 | if (typeof cachedValue === 'undefined') { 287 | callback(null, value); 288 | } 289 | 290 | if (value > 0) { 291 | this.cachedValues[Characteristic.Brightness.UUID] = value; 292 | } 293 | }.bind(this)); 294 | }, 295 | getColorTempValue: function (service, callback) { 296 | Domoticz.deviceStatus(this, function (json) { 297 | var value; 298 | var sv = this.getService(Service.Lightbulb); 299 | var chr = this.getCharacteristic(sv, Characteristic.ColorTemperature); 300 | var sArray = Helper.sortByKey(json.result, "Name"); 301 | var error = !1; 302 | sArray.map(function (s) { 303 | try { 304 | var tValue = JSON.parse(s.Color).t 305 | value = chr.props.minValue + ( 306 | (chr.props.maxValue - chr.props.minValue) / 255 * tValue 307 | ) 308 | this.platform.log("Data Received for " + this.name + " (WW Light): " + value); 309 | } catch(e) { 310 | this.platform.forceLog(this.name + '(WW Light): This device does not comply to Domoticz lighting standard for a WW light. Ignoring "Color" and setting White.'); 311 | value = 140; 312 | } 313 | }.bind(this)); 314 | 315 | callback(null, value); 316 | }.bind(this)); 317 | }, 318 | setColorTempValue: function (service, value, callback, context) { 319 | if (context && context == "eDomoticz-MQTT") { 320 | callback(); 321 | return; 322 | } 323 | 324 | var sv = this.getService(Service.Lightbulb); 325 | var chr = this.getCharacteristic(sv, Characteristic.ColorTemperature); 326 | Domoticz.updateDeviceStatus(this, "setkelvinlevel", { 327 | "kelvin": (value - chr.props.minValue) / (chr.props.maxValue - chr.props.minValue) * 100 328 | }, function (success) { 329 | this.platform.log("Data Set for " + this.name + " (WW Light): " + value); 330 | callback(); 331 | }.bind(this)); 332 | }, 333 | getHueValue: function (type, callback) { 334 | if (type == 'Hue') { 335 | callback(null, (this.hueValue !== undefined ? this.hueValue : 0)); 336 | } else if (type == 'Saturation') { 337 | callback(null, (this.saturationValue !== undefined ? this.saturationValue : 0)); 338 | } else { 339 | callback(null, 0); 340 | } 341 | }, 342 | setHueValue: function (type, value, callback, context) { 343 | if (context && context == "eDomoticz-MQTT") { 344 | callback(); 345 | return; 346 | } 347 | if (type == 'Hue') { 348 | this.hueValue = value; 349 | this.hueSemaphore = (this.hueSemaphore === undefined ? 0 : this.hueSemaphore + 1); 350 | } else if (type == 'Saturation') { 351 | this.saturationValue = value; 352 | this.hueSemaphore = (this.hueSemaphore === undefined ? 0 : this.hueSemaphore + 1); 353 | } 354 | if (this.hueValue !== undefined && this.saturationValue !== undefined && this.hueSemaphore !== undefined && this.hueSemaphore > 0) { 355 | this.hueSemaphore = undefined; 356 | var c = this.cachedValues[Characteristic.Brightness.UUID], 357 | b = 100; // retain current brightness... 358 | if (typeof c !== 'undefined') { 359 | b = this.platform.config.dimFix == 1 ? Math.floor(c / this.factor) + 1 : Math.floor(c / this.factor); 360 | } 361 | Domoticz.updateDeviceStatus(this, "setcolbrightnessvalue", { 362 | "hex": Helper.HSVtoRGB([this.hueValue, this.saturationValue, b]) 363 | }, function (success) { 364 | callback(); 365 | }.bind(this)); 366 | } else { 367 | callback(); 368 | } 369 | }, 370 | getValue: function (callback) { 371 | Domoticz.deviceStatus(this, function (json) { 372 | var value; 373 | var sArray = Helper.sortByKey(json.result, "Name"); 374 | sArray.map(function (s) { 375 | value = Helper.cleanFloat(s.Data); 376 | value = Helper.oneDP(value); 377 | }.bind(this)); 378 | this.platform.log("Data Received for " + this.name + ": " + value); 379 | callback(null, value); 380 | }.bind(this)); 381 | }, 382 | getQualValue: function (callback) { 383 | Domoticz.deviceStatus(this, function (json) { 384 | var value; 385 | var sArray = Helper.sortByKey(json.result, "Name"); 386 | sArray.map(function (s) { 387 | value = s.Quality; 388 | switch (value) { 389 | case "Unknown": 390 | { 391 | value = Characteristic.AirQuality.UNKNOWN; 392 | break; 393 | } 394 | case "Excellent": 395 | { 396 | value = Characteristic.AirQuality.EXCELLENT; 397 | break; 398 | } 399 | case "Good": 400 | { 401 | value = Characteristic.AirQuality.GOOD; 402 | break; 403 | } 404 | case "Fair": 405 | { 406 | value = Characteristic.AirQuality.FAIR; 407 | break; 408 | } 409 | case "Mediocre": 410 | case "Inferior": 411 | { 412 | value = Characteristic.AirQuality.INFERIOR; 413 | break; 414 | } 415 | case "Bad": 416 | case "Poor": 417 | { 418 | value = Characteristic.AirQuality.POOR; 419 | break; 420 | } 421 | default: 422 | { 423 | value = Characteristic.AirQuality.FAIR; 424 | break; 425 | } 426 | } 427 | }.bind(this)); 428 | this.platform.log("Data Received for " + this.name + ": " + value); 429 | callback(null, value); 430 | }.bind(this)); 431 | }, 432 | getDoorbellSensorValue: function(callback) { 433 | callback(null, false); 434 | }, 435 | getStringValue: function (callback) { 436 | Domoticz.deviceStatus(this, function (json) { 437 | var value; 438 | var sArray = Helper.sortByKey(json.result, "Name"); 439 | sArray.map(function (s) { 440 | if (s.SwitchTypeVal == Constants.DeviceTypeContact || s.SwitchTypeVal == Constants.DeviceTypeDoorContact) { 441 | if (s.Data == "Closed") { 442 | value = Characteristic.ContactSensorState.CONTACT_DETECTED; 443 | } else { 444 | value = Characteristic.ContactSensorState.CONTACT_NOT_DETECTED; 445 | } 446 | } else if (s.SwitchTypeVal == Constants.DeviceTypeSmoke) { 447 | if (s.Data == "Off" || s.Data == "Normal") { 448 | value = Characteristic.SmokeDetected.SMOKE_NOT_DETECTED; 449 | } else { 450 | value = Characteristic.SmokeDetected.SMOKE_DETECTED; 451 | } 452 | } else if (s.SwitchTypeVal == Constants.DeviceTypeMotion) { 453 | if (s.Data == "Off") { 454 | value = false; 455 | } else { 456 | value = true; 457 | } 458 | } else if (this.Type == "Lux") { //Lux 459 | value = parseInt(s.Data, 10); 460 | value = (value == 0) ? 0.0001 : value; 461 | } else if (this.subType == "Waterflow" || (this.name.indexOf("Gas") > -1 && this.Type == "General" && this.subType == "kWh")) { 462 | value = Helper.cleanFloat(s.Data); 463 | } else if (this.subType == "RFXMeter counter" || this.subType == "Percentage" || this.subType == "kWh" || this.subType == "Energy" || this.subType == "Solar Radiation" || this.subType == "UVN800" || this.subType == "UVN128,UV138" || this.subType == "Visibility") { 464 | value = (s.Counter !== undefined) ? Helper.cleanFloat(s.Counter) : Helper.cleanFloat(s.Data); 465 | } else if (this.subType == "Text") { 466 | value = s.Data.toString(); 467 | value = encodeURIComponent(value); 468 | } else { 469 | value = s.Data.toString(); 470 | value = encodeURIComponent(value); 471 | } 472 | }.bind(this)); 473 | callback(null, value); 474 | }.bind(this)); 475 | }, 476 | getYLTodayValue: function (callback) { 477 | Domoticz.deviceStatus(this, function (json) { 478 | var value; 479 | var sArray = Helper.sortByKey(json.result, "Name"); 480 | sArray.map(function (s) { 481 | value = Helper.cleanFloat(s.CounterToday); 482 | }.bind(this)); 483 | this.platform.log("Data Received for " + this.name + ": " + value); 484 | callback(null, value); 485 | }.bind(this)); 486 | }, 487 | getYLTotalValue: function (callback) { 488 | Domoticz.deviceStatus(this, function (json) { 489 | var value; 490 | var sArray = Helper.sortByKey(json.result, "Name"); 491 | sArray.map(function (s) { 492 | value = Helper.cleanFloat(s.Counter); 493 | }.bind(this)); 494 | this.platform.log("Data Received for " + this.name + ": " + value); 495 | callback(null, value); 496 | }.bind(this)); 497 | }, 498 | getWindSpeed: function (callback) { 499 | Domoticz.deviceStatus(this, function (json) { 500 | var value; 501 | var sArray = Helper.sortByKey(json.result, "Name"); 502 | sArray.map(function (s) { 503 | value = Helper.cleanFloat(s.Speed); 504 | value = Helper.oneDP(value); 505 | }.bind(this)); 506 | this.platform.log("Data Received for " + this.name + ": " + value); 507 | callback(null, value); 508 | }.bind(this)); 509 | }, 510 | getWindChill: function (callback) { 511 | Domoticz.deviceStatus(this, function (json) { 512 | var value; 513 | var sArray = Helper.sortByKey(json.result, "Name"); 514 | sArray.map(function (s) { 515 | value = Helper.cleanFloat(s.Chill); 516 | value = Helper.oneDP(value); 517 | }.bind(this)); 518 | this.platform.log("Data Received for " + this.name + ": " + value); 519 | callback(null, value); 520 | }.bind(this)); 521 | }, 522 | getWindDirection: function (callback) { 523 | Domoticz.deviceStatus(this, function (json) { 524 | var value; 525 | var sArray = Helper.sortByKey(json.result, "Name"); 526 | sArray.map(function (s) { 527 | value = s.Direction.toString() + " (" + s.DirectionStr.toString() + ")"; 528 | }.bind(this)); 529 | this.platform.log("Data Received for " + this.name + ": " + value); 530 | callback(null, value); 531 | }.bind(this)); 532 | }, 533 | getCPower: function (callback) { 534 | Domoticz.deviceStatus(this, function (json) { 535 | var value; 536 | var sArray = Helper.sortByKey(json.result, "Name"); 537 | sArray.map(function (s) { 538 | value = (this.Type == "Usage" && this.subType == "Electric") ? Helper.cleanFloat(s.Data) : Helper.cleanFloat(s.Usage); 539 | }.bind(this)); 540 | this.platform.log("Data Received for " + this.name + ": " + value); 541 | callback(null, value); 542 | }.bind(this)); 543 | }, 544 | getState: function (callback) { 545 | value = 1; 546 | this.platform.log("Static Data for " + this.name + ": " + value); 547 | callback(null, value); 548 | }, 549 | getTemperature: function (callback) { 550 | Domoticz.deviceStatus(this, function (json) { 551 | var value; 552 | var sArray = Helper.sortByKey(json.result, "Name"); 553 | sArray.map(function (s) { 554 | var heat = (this.subType == "Zone") ? true : false; 555 | var therm = (this.subType == "SetPoint") ? true : false; 556 | value = ((heat) || (therm)) ? Helper.oneDP(Helper.cleanFloat(s.SetPoint)) : Helper.oneDP(Helper.cleanFloat(s.Temp)); 557 | if (s.HaveTimeout=='true') { 558 | value = null; 559 | } 560 | }.bind(this)); 561 | this.platform.log("Data Received for " + this.name + ": " + value); 562 | callback(null, value); 563 | }.bind(this)); 564 | }, 565 | getTemperatureAlternative: function (callback) { 566 | Domoticz.deviceStatus(this, function (json) { 567 | var value; 568 | var sArray = Helper.sortByKey(json.result, "Name"); 569 | sArray.map(function (s) { 570 | var heat = (this.subType == "Zone") ? true : false; 571 | var therm = (this.subType == "SetPoint") ? true : false; 572 | value = Helper.oneDP(Helper.cleanFloat(s.Temp)); 573 | if (s.HaveTimeout=='true') { 574 | value = null; 575 | } 576 | }.bind(this)); 577 | this.platform.log("Data Received for " + this.name + ": " + value); 578 | callback(null, value); 579 | }.bind(this)); 580 | }, 581 | getTimeout: function (callback) { 582 | Domoticz.deviceStatus(this, function (json) { 583 | var value; 584 | var sArray = Helper.sortByKey(json.result, "Name"); 585 | sArray.map(function (s) { 586 | var reachable = (s.HaveTimeout === true) ? '1' : '0'; 587 | value = reachable; 588 | }.bind(this)); 589 | this.platform.log("Data Received for " + this.name + " Timeout: " + value); 590 | callback(null, value); 591 | }.bind(this)); 592 | }, 593 | setPoint: function (setpoint, callback, context) { 594 | if (context && context == "eDomoticz-MQTT") { 595 | callback(); 596 | return; 597 | } 598 | var url = ""; 599 | if (this.subType == "SetPoint") { 600 | url = this.platform.apiBaseURL + "type=command¶m=udevice&idx=" + this.idx; 601 | url = url + "&nvalue=0&svalue=" + setpoint; 602 | } else if (this.subType == "Zone") { 603 | url = this.platform.apiBaseURL + "type=command¶m=setused&idx=" + this.idx + "&setpoint="; 604 | url = url + setpoint + "&mode=PermanentOverride&used=true"; 605 | } 606 | this.platform.log("Setting thermostat SetPoint to " + setpoint); 607 | Domoticz.updateWithURL(this, url, function (success) { 608 | callback(null, setpoint); 609 | }.bind(this)); 610 | }, 611 | setTempOverride: function (setuntil, callback, context) { 612 | if (context && context == "eDomoticz-MQTT") { 613 | callback(); 614 | return; 615 | } 616 | var url = ""; 617 | var temp; 618 | var now = new Date(); 619 | var newnow, isonow; 620 | var mode; 621 | if (setuntil < 1) { 622 | mode = "Auto"; 623 | } else if (setuntil > 480) { 624 | mode = "PermanentOverride"; 625 | } else { 626 | mode = "TemporaryOverride"; 627 | newnow = new Date(now.getTime() + (setuntil * 60 * 1000)); 628 | isonow = newnow.toISOString(); 629 | } 630 | 631 | Domoticz.deviceStatus(this, function (json) { 632 | var value; 633 | var sArray = Helper.sortByKey(json.result, "Name"); 634 | sArray.map(function (s) { 635 | var heat = (this.Type == "Heating" && this.subType == "Zone") ? true : false; 636 | var therm = ((this.Type == "Thermostat" || this.Type == "Setpoint") && this.subType == "SetPoint") ? true : false; 637 | temp = (heat || therm) ? Helper.oneDP(Helper.cleanFloat(s.SetPoint)) : Helper.oneDP(Helper.cleanFloat(s.Temp)); 638 | url = this.platform.apiBaseURL + "type=command¶m=setused&idx=" + this.idx + "&setpoint="; 639 | url = url + temp + "&mode=" + mode; 640 | url = (mode == "TemporaryOverride") ? url + "&until=" + isonow + "&used=true" : url + "&used=true"; 641 | this.platform.log("Setting thermostat SetPoint to " + temp + ", mode to " + mode); 642 | Domoticz.updateWithURL(this, url, function (success) { 643 | callback(null, setuntil); 644 | }.bind(this)); 645 | }.bind(this)); 646 | }.bind(this), function (error) { 647 | callback(); 648 | }); 649 | }, 650 | getTempOverride: function (callback) { 651 | Domoticz.deviceStatus(this, function (json) { 652 | var value; 653 | var sArray = Helper.sortByKey(json.result, "Name"); 654 | sArray.map(function (s) { 655 | var d1 = new Date(s.Until); 656 | var now = new Date().getTime(); 657 | var diff = d1 - now; 658 | value = (diff / (60 * 1000)); 659 | }.bind(this)); 660 | this.platform.log("Data Received for " + this.name + ": " + value); 661 | callback(null, value); 662 | }.bind(this)); 663 | }, 664 | getHumidity: function (callback) { 665 | Domoticz.deviceStatus(this, function (json) { 666 | var value; 667 | var sArray = Helper.sortByKey(json.result, "Name"); 668 | sArray.map(function (s) { 669 | value = Helper.cleanFloat(s.Humidity); 670 | value = Helper.oneDP(value); 671 | }.bind(this)); 672 | this.platform.log("Data Received for " + this.name + ": " + value); 673 | callback(null, value); 674 | }.bind(this)); 675 | }, 676 | getPressure: function (callback) { 677 | Domoticz.deviceStatus(this, function (json) { 678 | var value; 679 | var sArray = Helper.sortByKey(json.result, "Name"); 680 | sArray.map(function (s) { 681 | var val = Helper.cleanFloat(s.Barometer); 682 | val = Math.ceil(val); 683 | value = val; 684 | }.bind(this)); 685 | this.platform.log("Data Received for " + this.name + ": " + value); 686 | callback(null, value); 687 | }.bind(this)); 688 | }, 689 | getLowBatteryStatus: function (callback) { 690 | Domoticz.deviceStatus(this, function (json) { 691 | var value; 692 | var sArray = Helper.sortByKey(json.result, "Name"); 693 | sArray.map(function (s) { 694 | value = Helper.cleanFloat(s.BatteryLevel); 695 | }.bind(this)); 696 | if (value > 20) { 697 | callback(null, 0); 698 | } else { 699 | callback(null, 1); 700 | } 701 | }.bind(this)); 702 | }, 703 | getBlindStatus: function (callback) { 704 | if (this.isPercentageBlind) { 705 | this.getdValue(callback); 706 | return; 707 | } 708 | 709 | Domoticz.deviceStatus(this, function (json) { 710 | var value; 711 | var sArray = Helper.sortByKey(json.result, "Name"); 712 | sArray.map(function (s) { 713 | value = s.Data.toString(); 714 | }.bind(this)); 715 | if (value == "Open") { 716 | callback(null, 100); 717 | } else { 718 | callback(null, 0); 719 | } 720 | }.bind(this)); 721 | }, 722 | setBlindStatus: function (blindService, pos, callback, context) { 723 | var shouldOpen = (pos <= 50); 724 | if (this.isInvertedBlind) { 725 | shouldOpen = !shouldOpen; 726 | } 727 | 728 | var finish = function (position) { 729 | callback(); 730 | 731 | if (!this.isPercentageBlind) { 732 | this.getCharacteristic(blindService, Characteristic.CurrentPosition).setValue(position, false, this); 733 | } 734 | }.bind(this); 735 | 736 | if (context && context == "eDomoticz-MQTT") { 737 | finish(pos); 738 | return; 739 | } 740 | 741 | if (this.isPercentageBlind && pos > 0 && pos < 100) { 742 | this.setdValue(pos, function () { 743 | finish(pos); 744 | }); 745 | return; 746 | } 747 | 748 | if (this.platform.config.legacyBlinds == 1) { 749 | var command = (shouldOpen ? "On" : "Off"); 750 | } else { 751 | var command = (shouldOpen ? "Close" : "Open"); 752 | } 753 | 754 | Domoticz.updateDeviceStatus(this, "switchlight", { 755 | "switchcmd": command 756 | }, function (success) { 757 | finish(pos); 758 | }.bind(this)); 759 | }, 760 | getBlindPStatus: function (callback) { 761 | callback(null, Characteristic.PositionState.STOPPED); 762 | }, 763 | getLockStatus: function (callback) { 764 | Domoticz.deviceStatus(this, function (json) { 765 | var value; 766 | var sArray = Helper.sortByKey(json.result, "Name"); 767 | sArray.map(function (s) { 768 | value = (s.Data == "Open" || s.Data == "Unlocked") ? Characteristic.LockCurrentState.UNSECURED : Characteristic.LockCurrentState.SECURED; 769 | }.bind(this)); 770 | this.platform.log("Data Received for " + this.name + ": " + value); 771 | callback(null, value); 772 | }.bind(this)); 773 | }, 774 | setLockStatus: function (doorstate, callback, context) { 775 | if (context && context == "eDomoticz-MQTT") { 776 | callback(); 777 | return; 778 | } 779 | 780 | var command = (doorstate == Characteristic.LockTargetState.UNSECURED); 781 | if (this.swTypeVal == Constants.DeviceTypeDoorLock) { 782 | command = !command; 783 | } 784 | 785 | Domoticz.updateDeviceStatus(this, "switchlight", { 786 | "switchcmd": (command ? "On" : "Off") 787 | }, function (success) { 788 | callback(); 789 | }.bind(this)); 790 | }, 791 | setLockInvertedStatus: function (doorstate, callback, context) { 792 | if (context && context == "eDomoticz-MQTT") { 793 | callback(); 794 | return; 795 | } 796 | 797 | var command = (doorstate == Characteristic.LockTargetState.SECURED); 798 | if (this.swTypeVal == Constants.DeviceTypeDoorLockInverted) { 799 | command = !command; 800 | } 801 | 802 | Domoticz.updateDeviceStatus(this, "switchlight", { 803 | "switchcmd": (command ? "On" : "Off") 804 | }, function (success) { 805 | callback(); 806 | }.bind(this)); 807 | }, 808 | getDoorStatus: function (callback) { 809 | Domoticz.deviceStatus(this, function (json) { 810 | var value; 811 | var sArray = Helper.sortByKey(json.result, "Name"); 812 | sArray.map(function (s) { 813 | value = (s.Data == "Open" || s.Data == "Unlocked") ? Characteristic.CurrentDoorState.OPEN : Characteristic.CurrentDoorState.CLOSED; 814 | }.bind(this)); 815 | this.platform.log("Data Received for " + this.name + ": " + value); 816 | callback(null, value); 817 | }.bind(this)); 818 | }, 819 | setDoorStatus: function (doorstate, callback, context) { 820 | if (context && context == "eDomoticz-MQTT") { 821 | callback(); 822 | return; 823 | } 824 | 825 | var command = (doorstate == Characteristic.TargetDoorState.OPEN); 826 | if (this.swTypeVal == Constants.DeviceTypeDoorLock) { 827 | command = !command; 828 | } 829 | 830 | Domoticz.updateDeviceStatus(this, "switchlight", { 831 | "switchcmd": (command ? "On" : "Off") 832 | }, function (success) { 833 | callback(); 834 | }.bind(this)); 835 | }, 836 | getSecuritySystemStatus: function (callback) { 837 | var cachedValue = this.cachedValues[Characteristic.SecuritySystemCurrentState.UUID]; 838 | if (typeof cachedValue !== 'undefined') { 839 | callback(null, cachedValue); 840 | } 841 | 842 | Domoticz.deviceStatus(this, function (json) { 843 | var value; 844 | var sArray = Helper.sortByKey(json.result, "Name"); 845 | sArray.map(function (s) { 846 | switch (s.Data) { 847 | case "Arm Home": 848 | value = Characteristic.SecuritySystemCurrentState.STAY_ARM; 849 | break; 850 | 851 | case "Arm Away": 852 | value = Characteristic.SecuritySystemCurrentState.AWAY_ARM; 853 | break; 854 | 855 | case "Normal": 856 | default: 857 | value = Characteristic.SecuritySystemCurrentState.DISARMED; 858 | break; 859 | } 860 | }.bind(this)); 861 | 862 | if (typeof cachedValue === 'undefined') { 863 | callback(null, value); 864 | } 865 | 866 | this.cachedValues[Characteristic.SecuritySystemCurrentState.UUID] = value; 867 | }.bind(this)); 868 | }, 869 | setSecuritySystemStatus: function (securityService, alarmState, callback, context) { 870 | if (context && (context == "eDomoticz-MQTT" || context == "callback-self")) { 871 | if (callback) { 872 | callback(); 873 | } 874 | return; 875 | } 876 | 877 | Domoticz.settings(this, function (settings) { 878 | var secStatus = "0"; 879 | var targetState = alarmState; 880 | switch (alarmState) { 881 | case Characteristic.SecuritySystemCurrentState.STAY_ARM: 882 | case Characteristic.SecuritySystemCurrentState.NIGHT_ARM: 883 | secStatus = "1"; 884 | 885 | if (Characteristic.SecuritySystemCurrentState.NIGHT_ARM) { 886 | targetState = Characteristic.SecuritySystemCurrentState.STAY_ARM; 887 | } 888 | break; 889 | 890 | case Characteristic.SecuritySystemCurrentState.AWAY_ARM: 891 | secStatus = "2"; 892 | break; 893 | 894 | case Characteristic.SecuritySystemCurrentState.DISARMED: 895 | default: 896 | secStatus = "0"; 897 | targetState = Characteristic.SecuritySystemCurrentState.DISARMED; 898 | break; 899 | } 900 | 901 | var url = this.platform.apiBaseURL + "type=command¶m=setsecstatus&secstatus=" + secStatus + "&seccode=" + settings.SecPassword; 902 | Domoticz.updateWithURL(this, url, function (success) { 903 | this.cachedValues[Characteristic.SecuritySystemCurrentState.UUID] = targetState; 904 | callback(); 905 | this.getCharacteristic(securityService, Characteristic.SecuritySystemCurrentState).setValue(targetState, false, "callback-self"); 906 | 907 | setTimeout(function () { 908 | this.getCharacteristic(securityService, Characteristic.SecuritySystemTargetState).setValue(targetState, false, "callback-self"); 909 | }.bind(this), 200); 910 | }.bind(this)); 911 | }.bind(this)); 912 | }, 913 | getSelectorValue: function (callback) { 914 | Domoticz.deviceStatus(this, function (json) { 915 | var value; 916 | var sArray = Helper.sortByKey(json.result, "Name"); 917 | sArray.map(function (s) { 918 | switch (s.Level){ 919 | case "10": 920 | value = Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS; 921 | break; 922 | case "20": 923 | value = Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS; 924 | break; 925 | case "30": 926 | value = Characteristic.ProgrammableSwitchEvent.LONG_PRESS; 927 | break; 928 | } 929 | }.bind(this)); 930 | this.platform.log("Data Received for " + this.name + ": " + value); 931 | callback(null, value); 932 | }.bind(this)); 933 | }, 934 | sendTelevisionRemoteKey: function (key, callback) { 935 | if(this.mediaCommandMapping && key in this.mediaCommandMapping) { 936 | Domoticz.updateDeviceStatus(this, "kodimediacommand", { 937 | "action": this.mediaCommandMapping[key], 938 | }, function (success) { 939 | callback(); 940 | }.bind(this)); 941 | } else { 942 | callback(new Error("Unsupported remote key!")); 943 | } 944 | }, 945 | setTelevisionVolume: function (action, callback) { 946 | var domoticzAction; 947 | if (action == Characteristic.VolumeSelector.INCREMENT) { 948 | domoticzAction = "VolumeUp"; 949 | } else if (action == Characteristic.VolumeSelector.DECREMENT) { 950 | domoticzAction = "VolumeDown"; 951 | } else { 952 | callback(new Error("Unsupported volume action!")); 953 | return; 954 | } 955 | 956 | Domoticz.updateDeviceStatus(this, "kodimediacommand", { 957 | "action": domoticzAction 958 | }, function (success) { 959 | callback(); 960 | }.bind(this)); 961 | }, 962 | setTelevisionMuteState: function (state, callback, context) { 963 | if (context && context == "eDomoticz-MQTT") { 964 | callback(); 965 | return; 966 | } 967 | 968 | Domoticz.updateDeviceStatus(this, "kodimediacommand", { 969 | "action": "Mute", 970 | }, function (success) { 971 | this.cachedValues[Characteristic.Mute.UUID] = state; 972 | callback(); 973 | }.bind(this)); 974 | }, 975 | getTelevisionMuteState: function (callback) { 976 | var cachedValue = this.cachedValues[Characteristic.Mute.UUID]; 977 | if (typeof cachedValue !== 'undefined') { 978 | callback(null, cachedValue); 979 | } 980 | 981 | Domoticz.deviceStatus(this, function (json) { 982 | var value; 983 | var sArray = Helper.sortByKey(json.result, "Name"); 984 | sArray.map(function (s) { 985 | value = (s.Data.indexOf("(muted)") > -1); 986 | }.bind(this)); 987 | 988 | if (typeof cachedValue === 'undefined') { 989 | callback(null, value); 990 | } 991 | 992 | this.cachedValues[Characteristic.Mute.UUID] = value; 993 | }.bind(this)); 994 | }, 995 | setActiveIdentifier: function (identifier, callback, context) { 996 | if (context && context == "eDomoticz-MQTT") { 997 | callback(); 998 | return; 999 | } 1000 | 1001 | if (this.descript in tvInputAccessories) { 1002 | Domoticz.updateDeviceStatus(tvInputAccessories[this.descript], "switchlight", { 1003 | "switchcmd": "Set Level", 1004 | "level": identifier * 10 1005 | }, function (success) { 1006 | this.cachedValues[Characteristic.ActiveIdentifier.UUID] = identifier; 1007 | callback(); 1008 | }.bind(this)); 1009 | } 1010 | }, 1011 | getActiveIdentifier: function (callback) { 1012 | var cachedValue = this.cachedValues[Characteristic.ActiveIdentifier.UUID]; 1013 | if (typeof cachedValue !== 'undefined') { 1014 | callback(null, cachedValue); 1015 | } 1016 | 1017 | if (this.descript in tvInputAccessories) { 1018 | Domoticz.deviceStatus(tvInputAccessories[this.descript], function (json) { 1019 | var value = 0; 1020 | var sArray = Helper.sortByKey(json.result, "Name"); 1021 | sArray.map(function (s) { 1022 | value = s.Level / 10; 1023 | }.bind(this)); 1024 | 1025 | if (typeof cachedValue === 'undefined') { 1026 | callback(null, value); 1027 | } 1028 | 1029 | this.cachedValues[Characteristic.ActiveIdentifier.UUID] = value; 1030 | }.bind(this)); 1031 | } else if (typeof cachedValue === 'undefined') { 1032 | this.cachedValues[Characteristic.ActiveIdentifier.UUID] = 0; 1033 | callback(null, 0); 1034 | } 1035 | }, 1036 | handleMQTTMessage: function (message, callback) { 1037 | this.platform.log("MQTT Message received for %s.\nName:\t\t%s\nDevice:\t\t%s,%s\nIs Switch:\t%s\nSwitchTypeVal:\t%s\nMQTT Message:\n%s", this.name, this.name, this.Type, this.subType, this.isSwitch, this.swTypeVal, JSON.stringify(message, null, 4)); 1038 | 1039 | if ((this.Type == "P1 Smart Meter" && this.swTypeVal == 0 && this.subType == "Energy") || (this.Type == "P1 Smart Meter" && this.swTypeVal == 1 && this.subType == "Gas") || (this.Type == "General" && this.swTypeVal == 2 && this.subType == "Counter Incremental") || (this.name.indexOf("Occupied") > -1) || (this.Type == "General" && this.swTypeVal == 1 && this.subType == "Visibility") || (this.Type == "General" && this.swTypeVal === 0 && this.subType == "kWh") || (this.Type == "General" && this.subType == "Solar Radiation" && this.swTypeVal === 0) || (this.Type == "YouLess Meter" && this.swTypeVal === 0) || (this.name.indexOf("Location") > -1) || (this.Type == "RFXMeter")) { 1040 | this.swTypeVal = false; 1041 | this.isSwitch = false; 1042 | //cludgey fix for a P1 SmartMeter Virtual Sensor being ID'd as a doorbell in Domoticz, and Incremental Counters being id'd as contact switches 1043 | //and other such Domoticz-generated oddities 1044 | } 1045 | if (this.isSwitch) { 1046 | switch (true) { 1047 | case this.swTypeVal == Constants.DeviceTypeSwitch || this.swTypeVal == Constants.DeviceTypePushOn: 1048 | { 1049 | var service = false; 1050 | if (this.image !== undefined && this.swTypeVal !== Constants.DeviceTypePushOn) { 1051 | if (this.image.indexOf("Fan") > -1) { 1052 | service = this.getService(Service.Fan); 1053 | 1054 | } else if (this.image.indexOf("Light") > -1) { 1055 | service = this.getService(Service.Lightbulb); 1056 | 1057 | } else if (this.image.indexOf("WallSocket") > -1) { 1058 | service = this.getService(Service.Outlet); 1059 | 1060 | } else { 1061 | service = this.getService(Service.Switch); 1062 | 1063 | } 1064 | } else { 1065 | service = this.getService(Service.Switch); 1066 | } 1067 | 1068 | if (!service) { 1069 | break; 1070 | } 1071 | 1072 | var powerOn = (message.nvalue > 0); 1073 | this.cachedValues[Characteristic.On.UUID] = powerOn; 1074 | var characteristic = this.getCharacteristic(service, Characteristic.On); 1075 | callback(characteristic, powerOn); 1076 | break; 1077 | } 1078 | case this.swTypeVal == Constants.DeviceTypeContact: 1079 | case this.swTypeVal == Constants.DeviceTypeDoorContact: 1080 | { 1081 | var service = this.getService(Service.ContactSensor); 1082 | var characteristic = this.getCharacteristic(service, Characteristic.ContactSensorState); 1083 | callback(characteristic, message.nvalue); 1084 | break; 1085 | } 1086 | case this.swTypeVal == Constants.DeviceTypeSmoke: 1087 | { 1088 | var service = this.getService(Service.SmokeSensor); 1089 | var characteristic = this.getCharacteristic(service, Characteristic.SmokeDetected); 1090 | callback(characteristic, message.nvalue); 1091 | break; 1092 | } 1093 | case this.swTypeVal == Constants.DeviceTypeDimmer: 1094 | { 1095 | var isFan = this.image && this.image.indexOf("Fan") > -1 1096 | var service = this.getService(isFan ? Service.Fan : Service.Lightbulb); 1097 | var powerCharacteristic = this.getCharacteristic(service, Characteristic.On); 1098 | var dimCharacteristic = this.getCharacteristic(service, isFan ? Characteristic.RotationSpeed : Characteristic.Brightness); 1099 | var isOn = (message.nvalue > 0); 1100 | var wasOn = this.cachedValues[Characteristic.On.UUID]; 1101 | var dimCallbackDelay = 1; 1102 | if (message.svalue1 == 0 || isOn != wasOn) { 1103 | callback(powerCharacteristic, isOn); 1104 | this.cachedValues[Characteristic.On.UUID] = isOn; 1105 | 1106 | if (isOn) { 1107 | dimCallbackDelay = 200; 1108 | } 1109 | } 1110 | 1111 | if (isOn && this.factor) { 1112 | var handleDimLevelChange = function (level) { 1113 | level = Math.floor(level); 1114 | if (level > 0) { 1115 | setTimeout(function () { 1116 | this.cachedValues[Characteristic.Brightness.UUID] = level; 1117 | callback(dimCharacteristic, level); 1118 | }.bind(this), dimCallbackDelay); 1119 | } 1120 | }.bind(this); 1121 | 1122 | // Switch is a dimmer but MQTT didn't return level 1123 | if (typeof message.svalue1 == 'undefined') { 1124 | this.cachedValues[Characteristic.Brightness.UUID] = 0; 1125 | 1126 | dimCharacteristic.getValue(function (sender, level) { 1127 | handleDimLevelChange(level); 1128 | }.bind(this)); 1129 | return; 1130 | } 1131 | 1132 | var level = message.svalue1 * this.factor; 1133 | handleDimLevelChange(level); 1134 | } 1135 | break; 1136 | } 1137 | case this.swTypeVal == Constants.DeviceTypeMedia: 1138 | { 1139 | // TV power state. 1140 | var tvService = this.getService(Service.Television); 1141 | 1142 | var activeCharacteristic = this.getCharacteristic(tvService, Characteristic.Active); 1143 | var state = (message.nvalue > 0) ? Characteristic.Active.ACTIVE : Characteristic.Active.INACTIVE; 1144 | var oldState = this.cachedValues[Characteristic.Active.UUID]; 1145 | if (state != oldState) { 1146 | this.cachedValues[Characteristic.Active.UUID] = state; 1147 | callback(activeCharacteristic, state); 1148 | } 1149 | 1150 | // TV mute state. 1151 | var tvSpeakerService = this.getService(Service.TelevisionSpeaker); 1152 | 1153 | var mutedCharacteristic = this.getCharacteristic(tvSpeakerService, Characteristic.Mute); 1154 | var isMuted = value = (message.svalue1.indexOf("(muted)") > -1); 1155 | var oldIsMuted = this.cachedValues[Characteristic.Mute.UUID]; 1156 | if (isMuted != oldIsMuted) { 1157 | this.cachedValues[Characteristic.Mute.UUID] = isMuted; 1158 | callback(mutedCharacteristic, isMuted); 1159 | } 1160 | 1161 | break; 1162 | } 1163 | case this.swTypeVal == Constants.DeviceTypeMotion: 1164 | { 1165 | var service = this.getService(Service.MotionSensor); 1166 | var characteristic = this.getCharacteristic(service, Characteristic.MotionDetected); 1167 | callback(characteristic, message.nvalue); 1168 | break; 1169 | } 1170 | case this.swTypeVal == Constants.DeviceTypeDoorbell: 1171 | { 1172 | var service = this.getService(Service.StatelessProgrammableSwitch); 1173 | var characteristic = this.getCharacteristic(service, Characteristic.ProgrammableSwitchEvent); 1174 | callback(characteristic, Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS); 1175 | 1176 | var service = this.getService(Service.Doorbell); 1177 | var characteristic = this.getCharacteristic(service, Characteristic.ProgrammableSwitchEvent); 1178 | callback(characteristic, Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS); 1179 | break; 1180 | } 1181 | case this.swTypeVal == Constants.DeviceTypeSelector && this.image !== "TV": 1182 | { 1183 | var service = this.getService(Service.StatelessProgrammableSwitch); 1184 | var characteristic = this.getCharacteristic(service, Characteristic.ProgrammableSwitchEvent); 1185 | var value; 1186 | switch (message.svalue1) { 1187 | case "10": 1188 | value = Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS; 1189 | break; 1190 | case "20": 1191 | value = Characteristic.ProgrammableSwitchEvent.DOUBLE_PRESS; 1192 | break; 1193 | case "30": 1194 | value = Characteristic.ProgrammableSwitchEvent.LONG_PRESS; 1195 | break; 1196 | } 1197 | callback(characteristic, value); 1198 | break; 1199 | } 1200 | case this.swTypeVal == Constants.DeviceTypeSelector && this.image == "TV": 1201 | { 1202 | var tvAccessory = tvAccessories[this.descript]; 1203 | if (typeof tvAccessory !== undefined) { 1204 | var tvService = tvAccessory.getService(Service.Television); 1205 | var characteristic = tvAccessory.getCharacteristic(tvService, Characteristic.ActiveIdentifier); 1206 | var identifier = parseInt(message.svalue1) / 10; 1207 | var oldIdentifier = tvAccessory.cachedValues[Characteristic.ActiveIdentifier.UUID]; 1208 | 1209 | if (identifier != oldIdentifier) { 1210 | tvAccessory.cachedValues[Characteristic.ActiveIdentifier.UUID] = identifier; 1211 | callback(characteristic, identifier); 1212 | } 1213 | } else { 1214 | callback(); 1215 | } 1216 | 1217 | } 1218 | break; 1219 | case this.swTypeVal == Constants.DeviceTypeDoorLock: 1220 | { 1221 | if (this.name.indexOf("garage") > -1) { 1222 | var command = (parseInt(message.nvalue) == 1); 1223 | 1224 | if (this.swTypeVal == Constants.DeviceTypeDoorLock) { 1225 | command = command; 1226 | } 1227 | 1228 | var garageState = (command ? Characteristic.TargetDoorState.UNSECURED : Characteristic.TargetDoorState.SECURED); 1229 | 1230 | var service = this.getService(Service.GarageDoorOpener); 1231 | var targetCharacteristic = this.getCharacteristic(service, Characteristic.TargetDoorState); 1232 | callback(targetCharacteristic, garageState); 1233 | 1234 | var currentCharacteristic = this.getCharacteristic(service, Characteristic.CurrentDoorState); 1235 | callback(currentCharacteristic, garageState); 1236 | break; 1237 | 1238 | 1239 | } else { 1240 | var command = (parseInt(message.nvalue) == 1); 1241 | 1242 | if (this.swTypeVal == Constants.DeviceTypeDoorLock) { 1243 | command = !command; 1244 | } 1245 | 1246 | var doorState = (command ? Characteristic.LockTargetState.UNSECURED : Characteristic.LockTargetState.SECURED); 1247 | 1248 | var service = this.getService(Service.LockMechanism); 1249 | var targetCharacteristic = this.getCharacteristic(service, Characteristic.LockTargetState); 1250 | callback(targetCharacteristic, doorState); 1251 | 1252 | var currentCharacteristic = this.getCharacteristic(service, Characteristic.LockCurrentState); 1253 | callback(currentCharacteristic, doorState); 1254 | break; 1255 | } 1256 | } 1257 | case this.swTypeVal == Constants.DeviceTypeDoorLockInverted: 1258 | { 1259 | if (this.name.indexOf("garage") > -1) { 1260 | var command = (parseInt(message.nvalue) == 1); 1261 | 1262 | if (this.swTypeVal == Constants.DeviceTypeDoorLockInverted) { 1263 | command = command; 1264 | } 1265 | 1266 | var garageState = (command ? Characteristic.TargetDoorState.UNSECURED : Characteristic.TargetDoorState.SECURED); 1267 | 1268 | var service = this.getService(Service.GarageDoorOpener); 1269 | var targetCharacteristic = this.getCharacteristic(service, Characteristic.TargetDoorState); 1270 | callback(targetCharacteristic, garageState); 1271 | 1272 | var currentCharacteristic = this.getCharacteristic(service, Characteristic.CurrentDoorState); 1273 | callback(currentCharacteristic, garageState); 1274 | break; 1275 | 1276 | 1277 | } else { 1278 | var command = (parseInt(message.nvalue) == 1); 1279 | 1280 | if (this.swTypeVal == Constants.DeviceTypeDoorLockInverted) { 1281 | command = !command; 1282 | } 1283 | 1284 | var doorState = (command ? Characteristic.LockTargetState.SECURED : Characteristic.LockTargetState.UNSECURED); 1285 | 1286 | var service = this.getService(Service.LockMechanism); 1287 | var targetCharacteristic = this.getCharacteristic(service, Characteristic.LockTargetState); 1288 | callback(targetCharacteristic, doorState); 1289 | 1290 | var currentCharacteristic = this.getCharacteristic(service, Characteristic.LockCurrentState); 1291 | callback(currentCharacteristic, doorState); 1292 | break; 1293 | } 1294 | } 1295 | case this.swTypeVal == Constants.DeviceTypeBlinds: 1296 | case this.swTypeVal == Constants.DeviceTypeBlindsInverted: 1297 | case this.swTypeVal == Constants.DeviceTypeBlindsVenetianUS: 1298 | case this.swTypeVal == Constants.DeviceTypeBlindsVenetianEU: 1299 | case this.swTypeVal == Constants.DeviceTypeBlindsPercentage: 1300 | case this.swTypeVal == Constants.DeviceTypeBlindsPercentageInverted: 1301 | case this.swTypeVal == Constants.DeviceTypeBlindsPlusStop: 1302 | { 1303 | if (this.platform.config.legacyBlinds == 1) { 1304 | var position = 0; 1305 | if (this.isPercentageBlind && message.nvalue > 1) { 1306 | position = message.svalue1 * this.factor; 1307 | } else if ((this.swTypeVal == Constants.DeviceTypeBlindsVenetianUS || this.swTypeVal == Constants.DeviceTypeBlindsVenetianEU) && message.nvalue > 1) { 1308 | position = (message.nvalue == 15 ? 100 : 0); 1309 | } else { 1310 | position = (message.nvalue == 1 ? 0 : 100); 1311 | if (message.stype == 'RFY') { 1312 | position = 100 - position; 1313 | } 1314 | 1315 | if (this.isInvertedBlind) { 1316 | position = 100 - position; 1317 | } 1318 | } 1319 | } else { 1320 | var position = 0; 1321 | if (this.isPercentageBlind && message.nvalue > 1) { 1322 | if (message.ReversePosition == 'true') { 1323 | position = (100 - message.svalue1) * this.factor; 1324 | } else { 1325 | position = message.svalue1 * this.factor; 1326 | } 1327 | } else if ((this.swTypeVal == Constants.DeviceTypeBlindsVenetianUS || this.swTypeVal == Constants.DeviceTypeBlindsVenetianEU) && message.nvalue > 1) { 1328 | //position = (message.nvalue == 15 ? 100 : 0); 1329 | if (message.ReverseState == 'true') { 1330 | position = ((message.nvalue == 16 || message.nvalue == 18) ? 100 : 0); 1331 | } else { 1332 | position = ((message.nvalue == 15 || message.nvalue == 17) ? 100 : 0); 1333 | } 1334 | } else { 1335 | if (message.ReverseState == 'true') { 1336 | position = (message.nvalue == 1 ? 0 : 100); 1337 | } else { 1338 | position = (message.nvalue == 1 ? 100 : 0); 1339 | } 1340 | } 1341 | } 1342 | 1343 | var lastActivity = false; 1344 | if (this.cachedValues["lastActivity"]) { 1345 | lastActivity = this.cachedValues["lastActivity"]; 1346 | } 1347 | 1348 | this.cachedValues["lastActivity"] = new Date(); 1349 | 1350 | if (this.isPercentageBlind) { 1351 | this.cachedValues[Characteristic.Brightness.UUID] = position; 1352 | } 1353 | 1354 | var service = this.getService(Service.WindowCovering); 1355 | var currentPositionCharacteristic = this.getCharacteristic(service, Characteristic.CurrentPosition); 1356 | var targetPositionCharacteristic = this.getCharacteristic(service, Characteristic.TargetPosition); 1357 | 1358 | if (this.isPercentageBlind) 1359 | { 1360 | if (!lastActivity || (new Date()) - lastActivity > 500) 1361 | { 1362 | callback(currentPositionCharacteristic, position); 1363 | callback(targetPositionCharacteristic, position); 1364 | } 1365 | else { 1366 | callback(currentPositionCharacteristic, position); 1367 | } 1368 | } 1369 | else 1370 | { 1371 | callback(currentPositionCharacteristic, position); 1372 | callback(targetPositionCharacteristic, position); 1373 | } 1374 | break; 1375 | } 1376 | case this.swTypeVal == Constants.DeviceTypeSecuritySystem: 1377 | { 1378 | var systemState = Characteristic.SecuritySystemCurrentState.STAY_ARM; 1379 | var targetState = Characteristic.SecuritySystemTargetState.STAY_ARM; 1380 | switch (message.nvalue) { 1381 | case 0: //Disarm 1382 | case 1: //Normal Delay 1383 | case 13: //Disarm 1384 | systemState = Characteristic.SecuritySystemCurrentState.DISARMED; 1385 | targetState = Characteristic.SecuritySystemTargetState.DISARM; 1386 | break; 1387 | case 9: //Arm Away 1388 | case 10: //Arm Away Delayed 1389 | systemState = Characteristic.SecuritySystemCurrentState.AWAY_ARM; 1390 | targetState = Characteristic.SecuritySystemTargetState.AWAY_ARM; 1391 | break; 1392 | case 11: //Arm Home 1393 | case 12: //Arm Home Delayed 1394 | systemState = Characteristic.SecuritySystemCurrentState.STAY_ARM; 1395 | targetState = Characteristic.SecuritySystemTargetState.STAY_ARM; 1396 | break; 1397 | case 6: 1398 | systemState = Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED; 1399 | targetState = Characteristic.SecuritySystemTargetState.STAY_ARM; 1400 | break; 1401 | default: 1402 | case 2: 1403 | systemState = Characteristic.SecuritySystemCurrentState.ALARM_TRIGGERED; 1404 | targetState = Characteristic.SecuritySystemTargetState.STAY_ARM; 1405 | break; 1406 | case 3: //Alarm Delayed 1407 | case 4: //Motion 1408 | case 5: //No Motion 1409 | case 7: //Panic End 1410 | case 8: 1411 | } 1412 | 1413 | this.cachedValues[Characteristic.SecuritySystemCurrentState.UUID] = systemState; 1414 | var service = this.getService(Service.SecuritySystem); 1415 | var currentStateCharacteristic = this.getCharacteristic(service, Characteristic.SecuritySystemCurrentState); 1416 | var targetStateCharacteristic = this.getCharacteristic(service, Characteristic.SecuritySystemTargetState); 1417 | callback(currentStateCharacteristic, systemState); 1418 | callback(targetStateCharacteristic, targetState); 1419 | break; 1420 | } 1421 | 1422 | default: 1423 | break; 1424 | } 1425 | } else { // Accessory is a sensor 1426 | switch (true) { 1427 | case this.Type == "General" || this.Type == "YouLess Meter" || this.Type == "Current" || this.Type == "UV" || this.Type == "Usage" || this.Type == "Lux": 1428 | { 1429 | if ('undefined' !== typeof message.svalue1) { 1430 | if (this.subType == "kWh" || this.subType == "YouLess counter" || this.subType == "Electric") { 1431 | if (this.subType == "kWh") { 1432 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1433 | var CurrentConsumptionCharacteristic = this.getCharacteristic(service, eDomoticzServices.CurrentConsumption); 1434 | var ccc = Helper.cleanFloat(message.svalue1); 1435 | callback(CurrentConsumptionCharacteristic, ccc); 1436 | if ('undefined' !== typeof message.svalue2) { 1437 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1438 | var TotalConsumptionCharacteristic = this.getCharacteristic(service, eDomoticzServices.TotalConsumption); 1439 | var val1 = Helper.cleanFloat(message.svalue2); 1440 | val1 = (this.name.indexOf('Gas') > -1) ? val1 / 1000 : val1; 1441 | callback(TotalConsumptionCharacteristic, val1); 1442 | } 1443 | } else if (this.subType == "YouLess counter") { 1444 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1445 | if ('undefined' !== typeof message.svalue2) { 1446 | var CurrentConsumptionCharacteristic2 = this.getCharacteristic(service, eDomoticzServices.CurrentConsumption); 1447 | var newval2 = Helper.cleanFloat(message.svalue2); 1448 | callback(CurrentConsumptionCharacteristic2, newval2); 1449 | } 1450 | var TotalConsumptionCharacteristic2 = this.getCharacteristic(service, eDomoticzServices.TotalConsumption); 1451 | var newval = Helper.oneDP(Helper.cleanFloat(message.svalue1) / 1000); 1452 | callback(TotalConsumptionCharacteristic2, newval); 1453 | } 1454 | if (this.name.indexOf('Gas') < 1 && this.subType !== "Electric" && this.subType !== "Youless counter" && this.subType !== "Energy") { 1455 | if ('undefined' !== typeof message.svalue2) { 1456 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1457 | var TodayConsumptionCharacteristic3 = this.getCharacteristic(service, eDomoticzServices.TodayConsumption); 1458 | var val3 = Helper.cleanFloat(message.svalue2); 1459 | callback(TodayConsumptionCharacteristic3, val3); 1460 | } 1461 | } 1462 | break; 1463 | } else if (this.subType == "Barometer") { 1464 | var service = this.getService(eDomoticzServices.WeatherService); 1465 | var UsageDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.Barometer); 1466 | var val4 = Helper.cleanFloat(message.svalue1); 1467 | callback(UsageDeviceCharacteristic, val4); 1468 | break; 1469 | } else if (this.subType == "Percentage") { 1470 | var service = this.getService(eDomoticzServices.UsageDeviceService); 1471 | var UsageDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.CurrentUsage); 1472 | var val4 = Helper.cleanFloat(message.svalue1); 1473 | callback(UsageDeviceCharacteristic, val4); 1474 | break; 1475 | } else if (this.subType == "Visibility") { 1476 | var service = this.getService(eDomoticzServices.VisibilityDeviceService); 1477 | var VisibilityDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.Visibility); 1478 | var val5 = Helper.cleanFloat(message.svalue1); 1479 | callback(VisibilityDeviceCharacteristic, val5); 1480 | break; 1481 | } else if (this.subType == "Solar Radiation" || this.subType == "UVN800") { 1482 | var service = this.getService(eDomoticzServices.SolRadDeviceService); 1483 | var SolRadDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.SolRad); 1484 | var val6 = Helper.cleanFloat(message.svalue1); 1485 | callback(SolRadDeviceCharacteristic, val6); 1486 | break; 1487 | } else if ((this.subType) == "Text" && (this.name.indexOf('Location') > -1)) { 1488 | var service = this.getService(eDomoticzServices.LocationService); 1489 | var LocationDeviceCharacteristic = this.getCharacteristic(service, Characteristic.Version); 1490 | var text = message.svalue1.toString(); 1491 | callback(LocationDeviceCharacteristic, text); 1492 | break; 1493 | } else if (this.subType == "Counter Incremental") { 1494 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1495 | var wMeterDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.CurrentConsumption); 1496 | var val8 = Helper.cleanFloat(message.svalue1); 1497 | callback(wMeterDeviceCharacteristic, val8); 1498 | break; 1499 | } else if (this.subType == "Lux") { 1500 | var service = this.getService(Service.LightSensor); 1501 | var lightSensorCharacteristic = this.getCharacteristic(service, Characteristic.CurrentAmbientLightLevel); 1502 | var val9 = Helper.cleanFloat(message.svalue1); 1503 | val9 = (val9 == 0) ? 0.0001 : val9; 1504 | callback(lightSensorCharacteristic, val9); 1505 | break; 1506 | } else if (this.subType == "Waterflow") { 1507 | var service = this.getService(eDomoticzServices.WaterDeviceService); 1508 | var WaterMeterDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.WaterFlow); 1509 | var newval8 = Helper.cleanFloat(message.svalue1); 1510 | callback(WaterMeterDeviceCharacteristic, newval8); 1511 | } else if (this.subType == "UVN128,UV138") { 1512 | var service = this.getService(eDomoticzServices.UVDeviceService); 1513 | var UVDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.UVIndex); 1514 | var newval8 = Helper.cleanFloat(message.svalue1); 1515 | callback(UVDeviceCharacteristic, newval8); 1516 | } else if (this.subType == "Current") { 1517 | var service = this.getService(eDomoticzServices.AMPDeviceService); 1518 | var AMPDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.Ampere); 1519 | var val11 = Helper.cleanFloat(message.svalue1); 1520 | callback(AMPDeviceCharacteristic, val11); 1521 | break; 1522 | } else if (this.subType == "Voltage") { 1523 | var service = this.getService(eDomoticzServices.VOLTDeviceService); 1524 | var VOLTDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.Volt); 1525 | var val12 = Helper.cleanFloat(message.svalue1); 1526 | callback(VOLTDeviceCharacteristic, val12); 1527 | break; 1528 | } else { 1529 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1530 | var dMeterDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.CurrentConsumption); 1531 | var val10 = Helper.cleanFloat(message.svalue1); 1532 | callback(dMeterDeviceCharacteristic, val10); 1533 | break; 1534 | } 1535 | } 1536 | break; 1537 | } 1538 | case this.Type == "Air Quality": 1539 | { 1540 | if ('undefined' !== typeof message.nvalue) { 1541 | var service = this.getService(Service.AirQualitySensor); 1542 | var airQualityServiceCharacteristic = this.getCharacteristic(service, Characteristic.AirParticulateDensity); 1543 | var airQual = Helper.cleanFloat(message.nvalue); 1544 | callback(airQualityServiceCharacteristic, airQual); 1545 | } 1546 | break; 1547 | } 1548 | case this.Type == "Wind": 1549 | { 1550 | if ('undefined' !== typeof message.svalue5) { 1551 | var service = this.getService(Service.TemperatureSensor); 1552 | var temperatureSensorServiceCurrentCharacteristic = this.getCharacteristic(service, Characteristic.CurrentTemperature); 1553 | var tempCurr = Helper.cleanFloat(message.svalue5); 1554 | callback(temperatureSensorServiceCurrentCharacteristic, tempCurr); 1555 | } 1556 | if ('undefined' !== typeof message.svalue3) { 1557 | var service = this.getService(eDomoticzServices.WindDeviceService); 1558 | var windServiceWindSpeedCharacteristic = this.getCharacteristic(service, eDomoticzServices.WindSpeed); 1559 | var wspeed = Helper.cleanFloat(message.svalue3); 1560 | var newval1 = wspeed / 10; 1561 | callback(windServiceWindSpeedCharacteristic, newval1); 1562 | } 1563 | if ('undefined' !== typeof message.svalue6) { 1564 | var service = this.getService(eDomoticzServices.WindDeviceService); 1565 | var windServiceWindChillCharacteristic = this.getCharacteristic(service, eDomoticzServices.WindChill); 1566 | var windChill = Helper.cleanFloat(message.svalue6); 1567 | callback(windServiceWindChillCharacteristic, windChill); 1568 | } 1569 | if ('undefined' !== typeof message.svalue1) { 1570 | var service = this.getService(eDomoticzServices.WindDeviceService); 1571 | var windServiceWindDirectionCharacteristic = this.getCharacteristic(service, eDomoticzServices.WindDirection); 1572 | var windeg = Helper.cleanFloat(message.svalue1); 1573 | var winDeg = Math.round(windeg); 1574 | callback(windServiceWindDirectionCharacteristic, winDeg); 1575 | } 1576 | break; 1577 | } 1578 | case this.Type == "Rain": 1579 | { 1580 | if ('undefined' !== typeof message.svalue1) { 1581 | var service = this.getService(eDomoticzServices.RainDeviceService); 1582 | var rainServiceCharacteristic = this.getCharacteristic(service, eDomoticzServices.Rainfall); 1583 | var rainfall = Helper.cleanFloat(message.svalue1); 1584 | callback(rainServiceCharacteristic, rainfall); 1585 | } 1586 | break; 1587 | } 1588 | case this.Type == "Humidity": 1589 | { 1590 | if (typeof message.nvalue !== 'undefined') { 1591 | var service = this.getService(Service.HumiditySensor); 1592 | var characteristic = this.getCharacteristic(service, Characteristic.CurrentRelativeHumidity); 1593 | var humidity = Helper.oneDP(Helper.cleanFloat(message.nvalue)); 1594 | callback(characteristic, humidity); 1595 | } 1596 | break; 1597 | } 1598 | case this.Type == "Temp" || this.Type == "Temp + Humidity": 1599 | { 1600 | if ('undefined' !== typeof message.svalue1) { 1601 | var service = this.getService(Service.TemperatureSensor); 1602 | var temperatureSensorCharacteristic = this.getCharacteristic(service, Characteristic.CurrentTemperature); 1603 | var temperature = Helper.oneDP(Helper.cleanFloat(message.svalue1)); 1604 | callback(temperatureSensorCharacteristic, temperature); 1605 | if (this.Type == "Temp + Humidity") { 1606 | var HumidityCharacteristic = this.getCharacteristic(service, Characteristic.CurrentRelativeHumidity); 1607 | var humidity = Helper.oneDP(Helper.cleanFloat(message.svalue2)); 1608 | callback(HumidityCharacteristic, humidity); 1609 | } 1610 | } 1611 | break; 1612 | } 1613 | case this.Type == "Temp + Humidity + Baro": 1614 | { 1615 | if ('undefined' !== typeof message.svalue1) { 1616 | var service = this.getService(eDomoticzServices.WeatherService); 1617 | var temperatureSensorCharacteristic = this.getCharacteristic(service, Characteristic.CurrentTemperature); 1618 | var temperature = Helper.cleanFloat(message.svalue1); 1619 | temperature = Helper.oneDP(temperature); 1620 | callback(temperatureSensorCharacteristic, temperature); 1621 | 1622 | var service2 = this.getService(Service.TemperatureSensor); 1623 | var temperatureSensorCharacteristic2 = this.getCharacteristic(service2, Characteristic.CurrentTemperature); 1624 | callback(temperatureSensorCharacteristic2, temperature); 1625 | } 1626 | if ('undefined' !== typeof message.svalue2) { 1627 | var service = this.getService(eDomoticzServices.WeatherService); 1628 | var HumidityCharacteristic = this.getCharacteristic(service, Characteristic.CurrentRelativeHumidity); 1629 | var humidity = Helper.cleanFloat(message.svalue2); 1630 | humidity = Helper.oneDP(humidity); 1631 | callback(HumidityCharacteristic, humidity); 1632 | 1633 | if (!service2) { 1634 | service2 = this.getService(Service.TemperatureSensor); 1635 | } 1636 | var HumidityCharacteristic2 = this.getCharacteristic(service2, Characteristic.CurrentRelativeHumidity); 1637 | callback(HumidityCharacteristic2, humidity); 1638 | } 1639 | if ('undefined' !== typeof message.svalue4) { 1640 | var service = this.getService(eDomoticzServices.WeatherService); 1641 | var BarometerCharacteristic = this.getCharacteristic(service, eDomoticzServices.Barometer); 1642 | var pressure = Helper.cleanFloat(message.svalue4); 1643 | pressure = Math.ceil(pressure); 1644 | callback(BarometerCharacteristic, pressure); 1645 | } 1646 | break; 1647 | } 1648 | case this.Type == "P1 Smart Meter" || this.Type == "RFXMeter": 1649 | { 1650 | if ('undefined' !== typeof message.svalue1) { 1651 | if (this.subType == "Gas") { 1652 | var service = this.getService(eDomoticzServices.GasDeviceService); 1653 | var P1GasMeterDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.GasConsumption); 1654 | var newval6 = Helper.cleanFloat(message.svalue1); 1655 | newval6 = Helper.oneDP(newval6 / 1000); 1656 | callback(P1GasMeterDeviceCharacteristic, newval6); 1657 | } else if (this.subType == "kWh" || this.subType == "Energy") { 1658 | var service = this.getService(eDomoticzServices.MeterDeviceService); 1659 | var P1ElecMeterDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.CurrentConsumption); 1660 | var newval7 = Helper.cleanFloat(message.svalue1); 1661 | callback(P1ElecMeterDeviceCharacteristic, newval7); 1662 | } else if (this.subType == "RFXMeter counter") { 1663 | var service = this.getService(eDomoticzServices.WaterDeviceService); 1664 | var RFXMeterDeviceCharacteristic = this.getCharacteristic(service, eDomoticzServices.WaterFlow); 1665 | var newval8 = Helper.cleanFloat(message.svalue1); 1666 | newval8 = Helper.oneDP(newval8 / 1000); 1667 | callback(RFXMeterDeviceCharacteristic, newval8); 1668 | } 1669 | } 1670 | break; 1671 | } 1672 | default: 1673 | { 1674 | if (this.name.indexOf("Occupied") > -1) { 1675 | if ('undefined' !== typeof message.nvalue) { 1676 | var service = this.getService(Service.OccupancySensor); 1677 | var occServiceCharacteristic = this.getCharacteristic(service, Characteristic.OccupancyDetected); 1678 | callback(occServiceCharacteristic, message.nvalue); 1679 | } 1680 | break; 1681 | } else { 1682 | if ('undefined' !== typeof message.nvalue) { 1683 | var infoTextService = this.getService(eDomoticzServices.InfotextDeviceService); 1684 | if (infoTextService) { 1685 | var infoTextCharacteristic = this.getCharacteristic(infoTextService, eDomoticzServices.Infotext); 1686 | if (infoTextCharacteristic) { 1687 | callback(infoTextCharacteristic, message.svalue1.toString()); 1688 | } 1689 | } 1690 | } 1691 | break; 1692 | } 1693 | } 1694 | } 1695 | } 1696 | }, 1697 | getServices: function () { 1698 | this.services = []; 1699 | var informationService = this.getService(Service.AccessoryInformation); 1700 | if (!informationService) { 1701 | informationService = new Service.AccessoryInformation(); 1702 | } 1703 | informationService.setCharacteristic(Characteristic.Manufacturer, "eDomoticz").setCharacteristic(Characteristic.Model, this.Type).setCharacteristic(Characteristic.SerialNumber, "Domoticz IDX " + this.idx); 1704 | this.services.push(informationService); 1705 | 1706 | if ((this.Type == "P1 Smart Meter" && this.swTypeVal == 0 && this.subType == "Energy") || (this.Type == "P1 Smart Meter" && this.swTypeVal == 1 && this.subType == "Gas") || (this.Type == "General" && this.swTypeVal == 2 && this.subType == "Counter Incremental") || (this.name.indexOf("Occupied") > -1) || (this.Type == "General" && this.swTypeVal == 1 && this.subType == "Visibility") || (this.Type == "General" && this.swTypeVal === 0 && this.subType == "kWh") || (this.Type == "General" && this.subType == "Solar Radiation" && this.swTypeVal === 0) || (this.Type == "YouLess Meter" && this.swTypeVal === 0) || (this.name.indexOf("Location") > -1) || (this.Type == "RFXMeter")) { 1707 | this.swTypeVal = false; 1708 | this.isSwitch = false; 1709 | //cludgey fix for a P1 SmartMeter Virtual Sensor being ID'd as a doorbell in Domoticz, and Incremental Counters being id'd as contact switches 1710 | //and other Domoticz-generated oddities... 1711 | } 1712 | if (this.isSwitch) { 1713 | switch (true) { 1714 | case this.swTypeVal == Constants.DeviceTypeSwitch || this.swTypeVal == Constants.DeviceTypePushOn: 1715 | { 1716 | 1717 | var service = false; 1718 | if (this.image !== undefined && this.swTypeVal !== Constants.DeviceTypePushOn) { 1719 | if (this.image.indexOf("Fan") > -1) { 1720 | service = this.getService(Service.Fan); 1721 | if (!service) { 1722 | service = new Service.Fan(this.name); 1723 | } 1724 | } else if (this.image.indexOf("Light") > -1) { 1725 | service = this.getService(Service.Lightbulb); 1726 | if (!service) { 1727 | service = new Service.Lightbulb(this.name); 1728 | } 1729 | } else if (this.image.indexOf("WallSocket") > -1) { 1730 | service = this.getService(Service.Outlet); 1731 | if (!service) { 1732 | service = new Service.Outlet(this.name); 1733 | } 1734 | } else { 1735 | service = this.getService(Service.Switch); 1736 | if (!service) { 1737 | service = new Service.Switch(this.name); 1738 | } 1739 | } 1740 | } else { 1741 | service = this.getService(Service.Switch); 1742 | if (!service) { 1743 | service = new Service.Switch(this.name); 1744 | } 1745 | } 1746 | this.getCharacteristic(service, Characteristic.On).on('set', this.setPowerState.bind(this)).on('get', this.getPowerState.bind(this)); 1747 | this.services.push(service); 1748 | break; 1749 | } 1750 | case this.swTypeVal == Constants.DeviceTypeContact: 1751 | case this.swTypeVal == Constants.DeviceTypeDoorContact: 1752 | { 1753 | var contactService = this.getService(Service.ContactSensor); 1754 | if (!contactService) { 1755 | contactService = new Service.ContactSensor(this.name); 1756 | } 1757 | this.getCharacteristic(contactService, Characteristic.ContactSensorState).on('get', this.getStringValue.bind(this)); 1758 | this.services.push(contactService); 1759 | break; 1760 | } 1761 | case this.swTypeVal == Constants.DeviceTypeSmoke: 1762 | { 1763 | var smokeService = this.getService(Service.SmokeSensor); 1764 | if (!smokeService) { 1765 | smokeService = new Service.SmokeSensor(this.name); 1766 | } 1767 | this.getCharacteristic(smokeService, Characteristic.SmokeDetected).on('get', this.getStringValue.bind(this)); 1768 | if (this.batteryRef && this.batteryRef !== 255) { // if batteryRef == 255 we're running on mains 1769 | this.gracefullyAddCharacteristic(smokeService, Characteristic.StatusLowBattery).on('get', this.getLowBatteryStatus.bind(this)); 1770 | } 1771 | this.services.push(smokeService); 1772 | break; 1773 | } 1774 | case this.swTypeVal == Constants.DeviceTypeDimmer: 1775 | { 1776 | var isFan = this.image && this.image.indexOf("Fan") > -1 1777 | var service = this.getService(isFan ? Service.Fan : Service.Lightbulb); 1778 | if (!service) { 1779 | service = isFan ? new Service.Fan(this.name) : new Service.Lightbulb(this.name); 1780 | } 1781 | this.getCharacteristic(service, Characteristic.On).on('set', this.setPowerState.bind(this)).on('get', this.getPowerState.bind(this)); 1782 | if (isFan) { 1783 | service.getCharacteristic(Characteristic.RotationSpeed).setProps({ 1784 | minValue: 0, 1785 | maxValue: 100 1786 | }).on('set', this.setdValue.bind(this)).on('get', this.getdValue.bind(this)); 1787 | } else { 1788 | this.gracefullyAddCharacteristic(service, Characteristic.Brightness).on('set', this.setdValue.bind(this)).on('get', this.getdValue.bind(this)); 1789 | if (this.subType == "RGBW" || this.subType == "RGBWW" || this.subType == "RGBWWZ" || this.subType == "RGBWZ" || this.subType == "RGB" ) { 1790 | this.gracefullyAddCharacteristic(service, Characteristic.Hue).on('set', this.setHueValue.bind(this, 'Hue')).on('get', this.getHueValue.bind(this, 'Hue')); 1791 | this.gracefullyAddCharacteristic(service, Characteristic.Saturation).on('set', this.setHueValue.bind(this, 'Saturation')).on('get', this.getHueValue.bind(this, 'Saturation')); 1792 | } else if (this.subType == 'WW') { 1793 | this.gracefullyAddCharacteristic(service, Characteristic.ColorTemperature).on('set', this.setColorTempValue.bind(this, 'ColorTemperature')).on('get', this.getColorTempValue.bind(this, 'ColorTemperature')); 1794 | } 1795 | } 1796 | this.services.push(service); 1797 | break; 1798 | } 1799 | case this.swTypeVal == Constants.DeviceTypeMedia: 1800 | { 1801 | // TV control. 1802 | if(!this.mediaCommandMapping) { 1803 | this.mediaCommandMapping = {}; 1804 | this.mediaCommandMapping[Characteristic.RemoteKey.REWIND] = 'Rewind'; 1805 | this.mediaCommandMapping[Characteristic.RemoteKey.FAST_FORWARD] = 'FastForward'; 1806 | this.mediaCommandMapping[Characteristic.RemoteKey.NEXT_TRACK] = 'BigStepForward'; 1807 | this.mediaCommandMapping[Characteristic.RemoteKey.PREVIOUS_TRACK] = 'BigStepBack'; 1808 | this.mediaCommandMapping[Characteristic.RemoteKey.ARROW_UP] = 'Up'; 1809 | this.mediaCommandMapping[Characteristic.RemoteKey.ARROW_DOWN] = 'Down'; 1810 | this.mediaCommandMapping[Characteristic.RemoteKey.ARROW_LEFT] = 'Left'; 1811 | this.mediaCommandMapping[Characteristic.RemoteKey.ARROW_RIGHT] = 'Right'; 1812 | this.mediaCommandMapping[Characteristic.RemoteKey.SELECT] = 'Select'; 1813 | this.mediaCommandMapping[Characteristic.RemoteKey.BACK] = 'Back'; 1814 | this.mediaCommandMapping[Characteristic.RemoteKey.EXIT] = 'Back'; 1815 | this.mediaCommandMapping[Characteristic.RemoteKey.PLAY_PAUSE] = 'PlayPause'; 1816 | this.mediaCommandMapping[Characteristic.RemoteKey.INFORMATION] = 'Info'; 1817 | } 1818 | 1819 | var tvService = this.getService(Service.Television); 1820 | if (!tvService) { 1821 | tvService = new Service.Television(this.name); 1822 | } 1823 | tvService 1824 | .setCharacteristic(Characteristic.ConfiguredName, this.name) 1825 | .setCharacteristic(Characteristic.SleepDiscoveryMode, Characteristic.SleepDiscoveryMode.ALWAYS_DISCOVERABLE); 1826 | this.getCharacteristic(tvService, Characteristic.Active) 1827 | .on('set', this.setActiveState.bind(this)) 1828 | .on('get', this.getActiveState.bind(this)); 1829 | this.getCharacteristic(tvService, Characteristic.ActiveIdentifier) 1830 | .on('set', this.setActiveIdentifier.bind(this)) 1831 | .on('get', this.getActiveIdentifier.bind(this)); 1832 | this.getCharacteristic(tvService, Characteristic.RemoteKey) 1833 | .on('set', this.sendTelevisionRemoteKey.bind(this)); 1834 | this.services.push(tvService); 1835 | tvAccessories[this.descript] = this; 1836 | 1837 | // TV volume. 1838 | var tvSpeakerService = this.getService(Service.TelevisionSpeaker); 1839 | if (!tvSpeakerService) { 1840 | tvSpeakerService = new Service.TelevisionSpeaker(this.name + ' volume', 'tvSpeakerService'); 1841 | } 1842 | tvSpeakerService 1843 | .setCharacteristic(Characteristic.VolumeControlType, Characteristic.VolumeControlType.RELATIVE); 1844 | this.getCharacteristic(tvSpeakerService, Characteristic.VolumeSelector) 1845 | .on('set', this.setTelevisionVolume.bind(this)); 1846 | this.getCharacteristic(tvSpeakerService, Characteristic.Mute) 1847 | .on('set', this.setTelevisionMuteState.bind(this)) 1848 | .on('get', this.getTelevisionMuteState.bind(this)); 1849 | tvService.addLinkedService(tvSpeakerService); 1850 | this.services.push(tvSpeakerService); 1851 | 1852 | if (this.descript in tvInputAccessories) { 1853 | this.createTvInputService(tvInputAccessories[this.descript]); 1854 | } 1855 | 1856 | break; 1857 | } 1858 | case this.swTypeVal == Constants.DeviceTypeSelector && this.image == "TV": 1859 | { 1860 | tvInputAccessories[this.descript] = this; 1861 | 1862 | if (this.descript in tvAccessories) { 1863 | tvAccessories[this.descript].createTvInputService(this); 1864 | } 1865 | 1866 | break; 1867 | } 1868 | case this.swTypeVal == Constants.DeviceTypeSelector && this.image != "TV": 1869 | { 1870 | var selectorService = this.getService(Service.StatelessProgrammableSwitch); 1871 | if (!selectorService) { 1872 | selectorService = new Service.StatelessProgrammableSwitch(this.name); 1873 | } 1874 | this.getCharacteristic(selectorService, Characteristic.ProgrammableSwitchEvent).on('get', this.getSelectorValue.bind(this)); 1875 | if (this.batteryRef && this.batteryRef !== 255) { // if batteryRef == 255 we're running on mains 1876 | this.gracefullyAddCharacteristic(selectorService, Characteristic.StatusLowBattery).on('get', this.getLowBatteryStatus.bind(this)); 1877 | } 1878 | this.services.push(selectorService); 1879 | break; 1880 | } 1881 | 1882 | case this.swTypeVal == Constants.DeviceTypeMotion: 1883 | { 1884 | var motionService = this.getService(Service.MotionSensor); 1885 | if (!motionService) { 1886 | motionService = new Service.MotionSensor(this.name); 1887 | } 1888 | this.getCharacteristic(motionService, Characteristic.MotionDetected).on('get', this.getStringValue.bind(this)); 1889 | if (this.batteryRef && this.batteryRef !== 255) { // if batteryRef == 255 we're running on mains 1890 | this.gracefullyAddCharacteristic(motionService, Characteristic.StatusLowBattery).on('get', this.getLowBatteryStatus.bind(this)); 1891 | } 1892 | this.services.push(motionService); 1893 | break; 1894 | } 1895 | 1896 | case this.swTypeVal == Constants.DeviceTypeDoorbell: 1897 | { 1898 | var doorbellButtonService = this.getService(Service.StatelessProgrammableSwitch); 1899 | if (!doorbellButtonService) { 1900 | doorbellButtonService = new Service.StatelessProgrammableSwitch(this.name); 1901 | } 1902 | this.getCharacteristic(doorbellButtonService, Characteristic.ProgrammableSwitchEvent).on('get', this.getSelectorValue.bind(this)); 1903 | this.services.push(doorbellButtonService); 1904 | 1905 | var doorbellSensorService = this.getService(Service.Doorbell); 1906 | if (!doorbellSensorService) { 1907 | doorbellSensorService = new Service.Doorbell(this.name); 1908 | } 1909 | this.getCharacteristic(doorbellSensorService, Characteristic.ProgrammableSwitchEvent).on('get', this.getDoorbellSensorValue.bind(this)); 1910 | if (this.batteryRef && this.batteryRef !== 255) { // if batteryRef == 255 we're running on mains 1911 | this.gracefullyAddCharacteristic(doorbellSensorService, Characteristic.StatusLowBattery).on('get', this.getLowBatteryStatus.bind(this)); 1912 | } 1913 | this.services.push(doorbellSensorService); 1914 | break; 1915 | } 1916 | case this.swTypeVal == Constants.DeviceTypeDoorLock: 1917 | { 1918 | if (this.name.indexOf("garage") > -1) { 1919 | var garageService = this.getService(Service.GarageDoorOpener); 1920 | if (!garageService) { 1921 | garageService = new Service.GarageDoorOpener(this.name); 1922 | } 1923 | this.getCharacteristic(garageService, Characteristic.CurrentDoorState).on('get', this.getDoorStatus.bind(this)); 1924 | this.getCharacteristic(garageService, Characteristic.TargetDoorState).on('get', this.getDoorStatus.bind(this)).on('set', this.setDoorStatus.bind(this)); 1925 | //this.getCharacteristic(garageService, Characteristic.ObstructionDetected).on('get', this.getDoorStatus.bind(this)); 1926 | 1927 | this.services.push(garageService); 1928 | break; 1929 | } else { 1930 | 1931 | var lockService = this.getService(Service.LockMechanism); 1932 | if (!lockService) { 1933 | lockService = new Service.LockMechanism(this.name); 1934 | } 1935 | this.getCharacteristic(lockService, Characteristic.LockCurrentState).on('get', this.getLockStatus.bind(this)); 1936 | this.getCharacteristic(lockService, Characteristic.LockTargetState).on('get', this.getLockStatus.bind(this)).on('set', this.setLockStatus.bind(this)); 1937 | this.services.push(lockService); 1938 | break; 1939 | } 1940 | } 1941 | case this.swTypeVal == Constants.DeviceTypeDoorLockInverted: 1942 | { 1943 | if (this.name.indexOf("garage") > -1) { 1944 | var garageService = this.getService(Service.GarageDoorOpener); 1945 | if (!garageService) { 1946 | garageService = new Service.GarageDoorOpener(this.name); 1947 | } 1948 | this.getCharacteristic(garageService, Characteristic.CurrentDoorState).on('get', this.getDoorStatus.bind(this)); 1949 | this.getCharacteristic(garageService, Characteristic.TargetDoorState).on('get', this.getDoorStatus.bind(this)).on('set', this.setDoorStatus.bind(this)); 1950 | //this.getCharacteristic(garageService, Characteristic.ObstructionDetected).on('get', this.getDoorStatus.bind(this)); 1951 | 1952 | this.services.push(garageService); 1953 | break; 1954 | } else { 1955 | 1956 | var lockService = this.getService(Service.LockMechanism); 1957 | if (!lockService) { 1958 | lockService = new Service.LockMechanism(this.name); 1959 | } 1960 | this.getCharacteristic(lockService, Characteristic.LockCurrentState).on('get', this.getLockStatus.bind(this)); 1961 | this.getCharacteristic(lockService, Characteristic.LockTargetState).on('get', this.getLockStatus.bind(this)).on('set', this.setLockInvertedStatus.bind(this)); 1962 | this.services.push(lockService); 1963 | break; 1964 | } 1965 | } 1966 | case this.swTypeVal == Constants.DeviceTypeBlinds: 1967 | case this.swTypeVal == Constants.DeviceTypeBlindsInverted: 1968 | case this.swTypeVal == Constants.DeviceTypeBlindsVenetianUS: 1969 | case this.swTypeVal == Constants.DeviceTypeBlindsVenetianEU: 1970 | case this.swTypeVal == Constants.DeviceTypeBlindsPercentage: 1971 | case this.swTypeVal == Constants.DeviceTypeBlindsPercentageInverted: 1972 | case this.swTypeVal == Constants.DeviceTypeBlindsPlusStop: 1973 | { 1974 | this.isInvertedBlind = (this.swTypeVal == Constants.DeviceTypeBlindsInverted || this.swTypeVal == Constants.DeviceTypeBlindsPercentageInverted); 1975 | this.isPercentageBlind = (this.swTypeVal == Constants.DeviceTypeBlindsPercentage || this.swTypeVal == Constants.DeviceTypeBlindsPercentageInverted || this.swTypeVal == Constants.DeviceTypeBlindsPlusStop); 1976 | 1977 | var blindService = this.getService(Service.WindowCovering); 1978 | if (!blindService) { 1979 | blindService = new Service.WindowCovering(this.name); 1980 | } 1981 | this.getCharacteristic(blindService, Characteristic.CurrentPosition).on('get', this.getBlindStatus.bind(this)); 1982 | this.getCharacteristic(blindService, Characteristic.TargetPosition).on('get', this.getBlindStatus.bind(this)).on('set', this.setBlindStatus.bind(this, blindService)); 1983 | this.getCharacteristic(blindService, Characteristic.PositionState).on('get', this.getBlindPStatus.bind(this)); 1984 | if (this.batteryRef && this.batteryRef !== 255) { // if batteryRef == 255 we're running on mains 1985 | this.gracefullyAddCharacteristic(blindService, Characteristic.StatusLowBattery).on('get', this.getLowBatteryStatus.bind(this)); 1986 | } 1987 | this.services.push(blindService); 1988 | break; 1989 | } 1990 | case this.swTypeVal == Constants.DeviceTypeSecuritySystem: 1991 | { 1992 | var securityService = this.getService(Service.SecuritySystem); 1993 | if (!securityService) { 1994 | securityService = new Service.SecuritySystem(this.name); 1995 | } 1996 | this.getCharacteristic(securityService, Characteristic.SecuritySystemCurrentState).on('get', this.getSecuritySystemStatus.bind(this)); 1997 | this.getCharacteristic(securityService, Characteristic.SecuritySystemTargetState).on('get', this.getSecuritySystemStatus.bind(this)).on('set', this.setSecuritySystemStatus.bind(this, securityService)); 1998 | this.services.push(securityService); 1999 | break; 2000 | } 2001 | 2002 | default: 2003 | break; 2004 | } 2005 | } else // Accessory is a sensor 2006 | { 2007 | switch (true) { 2008 | case this.Type == "General" || this.Type == "RFXMeter" || this.Type == "YouLess Meter" || this.Type == "Current" || this.Type == "UV" || this.Type == "Usage" || this.Type == "Lux": 2009 | { 2010 | if (this.subType == "kWh" || this.subType == "YouLess counter" || this.subType == "Electric") { 2011 | var MeterDeviceService = this.getService(eDomoticzServices.MeterDeviceService) 2012 | if (!MeterDeviceService) { 2013 | MeterDeviceService = new eDomoticzServices.MeterDeviceService(this.name); 2014 | } 2015 | 2016 | this.getCharacteristic(MeterDeviceService, eDomoticzServices.CurrentConsumption).on('get', this.getCPower.bind(this)); 2017 | if (this.subType == "kWh") { 2018 | this.getCharacteristic(MeterDeviceService, eDomoticzServices.TotalConsumption).on('get', this.getStringValue.bind(this)); 2019 | } else if (this.subType == "YouLess counter") { 2020 | this.getCharacteristic(MeterDeviceService, eDomoticzServices.TotalConsumption).on('get', this.getYLTotalValue.bind(this)); 2021 | } 2022 | if (this.subType !== "Electric") { 2023 | this.getCharacteristic(MeterDeviceService, eDomoticzServices.TodayConsumption).on('get', this.getYLTodayValue.bind(this)); 2024 | } 2025 | this.services.push(MeterDeviceService); 2026 | break; 2027 | } else if (this.subType == "Percentage") { 2028 | var UsageDeviceService = this.getService(eDomoticzServices.UsageDeviceService); 2029 | if (!UsageDeviceService) { 2030 | UsageDeviceService = new eDomoticzServices.UsageDeviceService(this.name); 2031 | } 2032 | this.getCharacteristic(UsageDeviceService, eDomoticzServices.CurrentUsage).on('get', this.getStringValue.bind(this)); 2033 | this.services.push(UsageDeviceService); 2034 | break; 2035 | } else if (this.subType == "Barometer") { 2036 | var Baroservice = this.getService(eDomoticzServices.WeatherService); 2037 | if (!Baroservice) { 2038 | Baroservice = new eDomoticzServices.WeatherService(this.name); 2039 | } 2040 | this.getCharacteristic(Baroservice, eDomoticzServices.Barometer).on('get', this.getPressure.bind(this)); 2041 | this.services.push(Baroservice); 2042 | break; 2043 | } else if (this.subType == "Visibility") { 2044 | var VisibilityDeviceService = this.getService(eDomoticzServices.VisibilityDeviceService); 2045 | if (!VisibilityDeviceService) { 2046 | VisibilityDeviceService = new eDomoticzServices.VisibilityDeviceService(this.name); 2047 | } 2048 | this.getCharacteristic(VisibilityDeviceService, eDomoticzServices.Visibility).on('get', this.getStringValue.bind(this)); 2049 | this.services.push(VisibilityDeviceService); 2050 | break; 2051 | } else if (this.subType == "Solar Radiation" || this.subType == "UVN800") { 2052 | var SolRadDeviceService = this.getService(eDomoticzServices.SolRadDeviceService); 2053 | if (!SolRadDeviceService) { 2054 | SolRadDeviceService = new eDomoticzServices.SolRadDeviceService(this.name); 2055 | } 2056 | this.getCharacteristic(SolRadDeviceService, eDomoticzServices.SolRad).on('get', this.getStringValue.bind(this)); 2057 | this.services.push(SolRadDeviceService); 2058 | break; 2059 | } else if ((this.subType) == "Text" && (this.name.indexOf("Location") > -1)) { 2060 | var LocationDeviceService = this.getService(eDomoticzServices.LocationService); 2061 | if (!LocationDeviceService) { 2062 | LocationDeviceService = new eDomoticzServices.LocationService(this.name); 2063 | } 2064 | this.getCharacteristic(LocationDeviceService, eDomoticzServices.Location).on('get', this.getStringValue.bind(this)); 2065 | this.services.push(LocationDeviceService); 2066 | break; 2067 | } else if (this.subType == "Counter Incremental") { 2068 | var wMeterDeviceService = this.getService(eDomoticzServices.MeterDeviceService); 2069 | if (!wMeterDeviceService) { 2070 | wMeterDeviceService = new eDomoticzServices.MeterDeviceService(this.name); 2071 | } 2072 | this.getCharacteristic(wMeterDeviceService, eDomoticzServices.CurrentConsumption).on('get', this.getStringValue.bind(this)); 2073 | this.services.push(wMeterDeviceService); 2074 | break; 2075 | } else if (this.subType == "Lux") { 2076 | var lightSensorService = this.getService(Service.LightSensor); 2077 | if (!lightSensorService) { 2078 | lightSensorService = new Service.LightSensor(this.name); 2079 | } 2080 | this.getCharacteristic(lightSensorService, Characteristic.CurrentAmbientLightLevel).on('get', this.getStringValue.bind(this)); 2081 | this.services.push(lightSensorService); 2082 | break; 2083 | } else if (this.subType == "RFXMeter counter" || this.subType == "Waterflow") { 2084 | var WaterMeterService = this.getService(eDomoticzServices.WaterDeviceService); 2085 | if (!WaterMeterService) { 2086 | WaterMeterService = new eDomoticzServices.WaterDeviceService(this.name); 2087 | } 2088 | this.getCharacteristic(WaterMeterService, eDomoticzServices.WaterFlow).on('get', this.getStringValue.bind(this)); 2089 | if (this.subType == "RFXMeter counter") { 2090 | this.getCharacteristic(WaterMeterService, eDomoticzServices.TotalWaterFlow).on('get', this.getYLTodayValue.bind(this)); 2091 | } 2092 | this.services.push(WaterMeterService); 2093 | break; 2094 | } else if (this.subType == "UVN128,UV138") { 2095 | var UVservice = this.getService(eDomoticzServices.UVDeviceService); 2096 | if (!UVservice) { 2097 | UVservice = new eDomoticzServices.UVDeviceService(this.name); 2098 | } 2099 | this.getCharacteristic(UVservice, eDomoticzServices.UVIndex).on('get', this.getStringValue.bind(this)); 2100 | this.services.push(UVservice); 2101 | break; 2102 | } else if (this.subType == "Current") { 2103 | var AMPDeviceService = this.getService(eDomoticzServices.AMPDeviceService); 2104 | if (!AMPDeviceService) { 2105 | AMPDeviceService = new eDomoticzServices.AMPDeviceService(this.name); 2106 | } 2107 | this.getCharacteristic(AMPDeviceService, eDomoticzServices.Ampere).on('get', this.getStringValue.bind(this)); 2108 | this.services.push(AMPDeviceService); 2109 | break; 2110 | } else if (this.subType == "Voltage") { 2111 | var VOLTDeviceService = this.getService(eDomoticzServices.VOLTDeviceService); 2112 | if (!VOLTDeviceService) { 2113 | VOLTDeviceService = new eDomoticzServices.VOLTDeviceService(this.name); 2114 | } 2115 | this.getCharacteristic(VOLTDeviceService, eDomoticzServices.Volt).on('get', this.getStringValue.bind(this)); 2116 | this.services.push(VOLTDeviceService); 2117 | break; 2118 | } else { 2119 | var dMeterDeviceService = this.getService(eDomoticzServices.MeterDeviceService); 2120 | if (!dMeterDeviceService) { 2121 | dMeterDeviceService = new eDomoticzServices.MeterDeviceService(this.name); 2122 | } 2123 | this.getCharacteristic(dMeterDeviceService, eDomoticzServices.CurrentConsumption).on('get', this.getStringValue.bind(this)); 2124 | this.services.push(dMeterDeviceService); 2125 | break; 2126 | } 2127 | break; 2128 | } 2129 | case this.Type == "Humidity": 2130 | { 2131 | var service = this.getService(Service.HumiditySensor) 2132 | if (!service) { 2133 | service = new Service.HumiditySensor(this.name); 2134 | } 2135 | this.getCharacteristic(service, Characteristic.CurrentRelativeHumidity).on('get', this.getHumidity.bind(this)); 2136 | this.services.push(service); 2137 | break; 2138 | } 2139 | case this.Type == "Temp" || this.Type == "Temp + Humidity" || this.Type == "Temp + Humidity + Baro": 2140 | { 2141 | var temperatureSensorService = ((this.Type == "Temp + Humidity + Baro") ? this.getService(eDomoticzServices.WeatherService) : this.getService(Service.TemperatureSensor)); 2142 | 2143 | if (!temperatureSensorService) { 2144 | temperatureSensorService = ((this.Type == "Temp + Humidity + Baro") ? new eDomoticzServices.WeatherService(this.name) : new Service.TemperatureSensor(this.name)); 2145 | } 2146 | this.getCharacteristic(temperatureSensorService, Characteristic.CurrentTemperature).on('get', this.getTemperature.bind(this)); 2147 | this.getCharacteristic(temperatureSensorService, Characteristic.CurrentTemperature).setProps({ 2148 | minValue: -50 2149 | }); 2150 | if (this.Type == "Temp + Humidity" || this.Type == "Temp + Humidity + Baro") { 2151 | this.gracefullyAddCharacteristic(temperatureSensorService, Characteristic.CurrentRelativeHumidity).on('get', this.getHumidity.bind(this)); 2152 | if (this.Type == "Temp + Humidity + Baro") { 2153 | this.gracefullyAddCharacteristic(temperatureSensorService, eDomoticzServices.Barometer).on('get', this.getPressure.bind(this)); 2154 | } 2155 | } 2156 | if (this.batteryRef && this.batteryRef !== 255) { 2157 | this.gracefullyAddCharacteristic(temperatureSensorService, Characteristic.StatusLowBattery).on('get', this.getLowBatteryStatus.bind(this)); 2158 | } 2159 | this.gracefullyAddCharacteristic(temperatureSensorService, Characteristic.StatusFault).on('get', this.getTimeout.bind(this)); 2160 | this.services.push(temperatureSensorService); 2161 | 2162 | if (this.Type == "Temp + Humidity + Baro") { 2163 | var additionalSensorService = this.getService(Service.TemperatureSensor); 2164 | if (!additionalSensorService) { 2165 | additionalSensorService = new Service.TemperatureSensor(this.name); 2166 | } 2167 | this.getCharacteristic(additionalSensorService, Characteristic.CurrentTemperature).on('get', this.getTemperature.bind(this)); 2168 | this.getCharacteristic(additionalSensorService, Characteristic.CurrentTemperature).setProps({ 2169 | minValue: -50 2170 | }); 2171 | this.gracefullyAddCharacteristic(additionalSensorService, Characteristic.CurrentRelativeHumidity).on('get', this.getHumidity.bind(this)); 2172 | this.gracefullyAddCharacteristic(additionalSensorService, Characteristic.StatusFault).on('get', this.getTimeout.bind(this)); 2173 | this.services.push(additionalSensorService); 2174 | } 2175 | break; 2176 | } 2177 | case this.Type == "Air Quality": 2178 | { 2179 | var airQualityService = this.getService(Service.AirQualitySensor); 2180 | if (!airQualityService) { 2181 | airQualityService = new Service.AirQualitySensor(this.name); 2182 | } 2183 | this.getCharacteristic(airQualityService, Characteristic.AirQuality).on('get', this.getQualValue.bind(this)); 2184 | var airParticulateDensityCharacteristic = this.getCharacteristic(airQualityService, Characteristic.AirParticulateDensity); 2185 | if (!airParticulateDensityCharacteristic) { 2186 | airQualityService.addOptionalCharacteristic(Characteristic.AirParticulateDensity); 2187 | airParticulateDensityCharacteristic = this.getCharacteristic(airQualityService, Characteristic.AirParticulateDensity); 2188 | } 2189 | airParticulateDensityCharacteristic.on('get', this.getValue.bind(this)); 2190 | this.services.push(airQualityService); 2191 | break; 2192 | } 2193 | case this.Type == "Wind": 2194 | { 2195 | var windService = this.getService(eDomoticzServices.WindDeviceService); 2196 | if (!windService) { 2197 | windService = new eDomoticzServices.WindDeviceService(this.name); 2198 | } 2199 | this.getCharacteristic(windService, eDomoticzServices.WindSpeed).on('get', this.getWindSpeed.bind(this)); 2200 | this.getCharacteristic(windService, eDomoticzServices.WindChill).on('get', this.getWindChill.bind(this)); 2201 | this.getCharacteristic(windService, eDomoticzServices.WindDirection).on('get', this.getWindDirection.bind(this)); 2202 | this.services.push(windService); 2203 | 2204 | var temperatureSensorService = this.getService(Service.TemperatureSensor); 2205 | if (!temperatureSensorService) { 2206 | temperatureSensorService = new Service.TemperatureSensor(this.name); 2207 | } 2208 | 2209 | this.getCharacteristic(temperatureSensorService, Characteristic.CurrentTemperature).on('get', this.getTemperature.bind(this)); 2210 | this.getCharacteristic(temperatureSensorService, Characteristic.CurrentTemperature).setProps({ 2211 | minValue: -50 2212 | }); 2213 | this.services.push(temperatureSensorService); 2214 | break; 2215 | } 2216 | case this.Type == "Rain": 2217 | { 2218 | var rainService = this.getService(eDomoticzServices.RainDeviceService); 2219 | if (!rainService) { 2220 | rainService = new eDomoticzServices.RainDeviceService(this.name); 2221 | } 2222 | this.getCharacteristic(rainService, eDomoticzServices.Rainfall).on('get', this.getRainfall.bind(this)); 2223 | this.services.push(rainService); 2224 | break; 2225 | } 2226 | case this.Type == "Heating" || this.Type == "Thermostat" || this.Type == "Setpoint": 2227 | { 2228 | var HeatingDeviceService = this.getService(Service.Thermostat); 2229 | if (!HeatingDeviceService) { 2230 | HeatingDeviceService = new Service.Thermostat(this.name); 2231 | } 2232 | this.getCharacteristic(HeatingDeviceService, Characteristic.CurrentHeatingCoolingState).on('get', this.getState.bind(this)); 2233 | this.getCharacteristic(HeatingDeviceService, Characteristic.TargetHeatingCoolingState).on('get', this.getState.bind(this)); 2234 | // If this is an HGI80, get the current temperature slightly differently 2235 | if (this.hwType == Constants.DeviceTypeHoneywellHGI80) { 2236 | this.getCharacteristic(HeatingDeviceService, Characteristic.CurrentTemperature).on('get', this.getTemperatureAlternative.bind(this)); 2237 | } else { 2238 | this.getCharacteristic(HeatingDeviceService, Characteristic.CurrentTemperature).on('get', this.getTemperature.bind(this)); 2239 | } 2240 | this.getCharacteristic(HeatingDeviceService, Characteristic.TargetTemperature).on('get', this.getTemperature.bind(this)).on('set', this.setPoint.bind(this)); 2241 | this.getCharacteristic(HeatingDeviceService, Characteristic.TargetTemperature).setProps({ 2242 | minValue: 4 2243 | }); 2244 | if (this.subType == "Zone") { 2245 | this.gracefullyAddCharacteristic(HeatingDeviceService, eDomoticzServices.TempOverride).on('set', this.setTempOverride.bind(this)).on('get', this.getTempOverride.bind(this)); 2246 | } 2247 | this.services.push(HeatingDeviceService); 2248 | break; 2249 | } 2250 | case this.Type == "P1 Smart Meter": 2251 | { 2252 | if (this.subType == "Gas") { 2253 | var P1GasMeterDeviceService = this.getService(eDomoticzServices.GasDeviceService); 2254 | if (!P1GasMeterDeviceService) { 2255 | P1GasMeterDeviceService = new eDomoticzServices.GasDeviceService(this.name); 2256 | } 2257 | this.getCharacteristic(P1GasMeterDeviceService, eDomoticzServices.GasConsumption).on('get', this.getStringValue.bind(this)); 2258 | this.services.push(P1GasMeterDeviceService); 2259 | } else if (this.subType == "kWh" || this.subType == "Energy") { 2260 | var P1ElecMeterDeviceService = this.getService(eDomoticzServices.MeterDeviceService); 2261 | if (!P1ElecMeterDeviceService) { 2262 | P1ElecMeterDeviceService = new eDomoticzServices.MeterDeviceService(this.name); 2263 | } 2264 | this.getCharacteristic(P1ElecMeterDeviceService, eDomoticzServices.CurrentConsumption).on('get', this.getCPower.bind(this)); 2265 | this.getCharacteristic(P1ElecMeterDeviceService, eDomoticzServices.TotalConsumption).on('get', this.getStringValue.bind(this)); 2266 | this.getCharacteristic(P1ElecMeterDeviceService, eDomoticzServices.TodayConsumption).on('get', this.getYLTodayValue.bind(this)); 2267 | this.services.push(P1ElecMeterDeviceService); 2268 | } 2269 | break; 2270 | } 2271 | default: 2272 | { 2273 | if (this.name.indexOf("Occupied") > -1) { 2274 | var occServiceB = this.getService(Service.OccupancySensor); 2275 | if (!occServiceB) { 2276 | occServiceB = new Service.OccupancySensor(this.name); 2277 | } 2278 | this.getCharacteristic(occServiceB, Characteristic.OccupancyDetected).on('get', this.getPowerState.bind(this)); 2279 | this.services.push(occServiceB); 2280 | break; 2281 | } else { 2282 | var infotextService = this.getService(eDomoticzServices.InfotextDeviceService); 2283 | if (!infotextService) { 2284 | infotextService = new eDomoticzServices.InfotextDeviceService(this.name); 2285 | } 2286 | this.getCharacteristic(infotextService, eDomoticzServices.Infotext).on('get', this.getStringValue.bind(this)); 2287 | this.services.push(infotextService); 2288 | break; 2289 | } 2290 | } 2291 | } 2292 | } 2293 | return this.services; 2294 | }, 2295 | createTvInputService: function (domoticzInputSourceAccessory) { 2296 | var tvService = this.services[1]; 2297 | if (typeof tvService !== undefined) { 2298 | Domoticz.deviceStatus(domoticzInputSourceAccessory, function (json) { 2299 | var sArray = Helper.sortByKey(json.result, "Name"); 2300 | sArray.map(function (s) { 2301 | var inputs = new Buffer(s.LevelNames, 'base64').toString("utf8").split("|"); 2302 | if (inputs.length > 0 && inputs[0] == "Off") { 2303 | inputs.shift(); 2304 | } 2305 | 2306 | inputs.forEach((input, index) => { 2307 | var inputType; 2308 | switch (true) { 2309 | case input.match(/^TV|Live$/i): 2310 | inputType = Characteristic.InputSourceType.TUNER; 2311 | break; 2312 | case input.match(/hdmi/i): 2313 | inputType = Characteristic.InputSourceType.HDMI; 2314 | break; 2315 | case input.match(/ypbpr/i): 2316 | inputType = Characteristic.InputSourceType.COMPONENT_VIDEO; 2317 | break; 2318 | default: 2319 | inputType = Characteristic.InputSourceType.APPLICATION; 2320 | break; 2321 | } 2322 | 2323 | var inputService = this.getService(Service.InputSource, input); 2324 | if (!inputService) { 2325 | inputService = new Service.InputSource(input.replace(/\s/g, '').toLowerCase(), input); 2326 | } 2327 | inputService 2328 | .setCharacteristic(Characteristic.Identifier, index + 1) 2329 | .setCharacteristic(Characteristic.ConfiguredName, input) 2330 | .setCharacteristic(Characteristic.IsConfigured, Characteristic.IsConfigured.CONFIGURED) 2331 | .setCharacteristic(Characteristic.InputSourceType, inputType) 2332 | .setCharacteristic(Characteristic.CurrentVisibilityState, Characteristic.CurrentVisibilityState.SHOWN); 2333 | tvService.addLinkedService(inputService); 2334 | this.services.push(inputService); 2335 | 2336 | if(this.published) { 2337 | this.publishService(inputService); 2338 | } 2339 | }); 2340 | }.bind(this)); 2341 | }.bind(this)); 2342 | } 2343 | }, 2344 | removed: function() { // This accessory has been removed. 2345 | if (this.descript in tvAccessories) { 2346 | delete tvAccessories[this.descript]; 2347 | } 2348 | if (this.descript in tvInputAccessories) { 2349 | delete tvInputAccessories[this.descript]; 2350 | } 2351 | } 2352 | }; 2353 | --------------------------------------------------------------------------------