├── .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 | 
2 | 
3 | [](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 | 
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 |
--------------------------------------------------------------------------------