@homebridge-plugins/homebridge-ewelink 12.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1363 -0
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/config.schema.json +1757 -0
- package/eslint.config.js +15 -0
- package/lib/connection/api.js +508 -0
- package/lib/connection/http.js +304 -0
- package/lib/connection/lan.js +318 -0
- package/lib/connection/ws.js +414 -0
- package/lib/device/curtain.js +324 -0
- package/lib/device/diffuser.js +473 -0
- package/lib/device/fan.js +349 -0
- package/lib/device/group.js +106 -0
- package/lib/device/humidifier.js +199 -0
- package/lib/device/index.js +61 -0
- package/lib/device/light-cct.js +333 -0
- package/lib/device/light-dimmer.js +257 -0
- package/lib/device/light-rgb-cct.js +809 -0
- package/lib/device/light-rgb.js +272 -0
- package/lib/device/motor.js +363 -0
- package/lib/device/outlet-multi.js +417 -0
- package/lib/device/outlet-single-inched.js +409 -0
- package/lib/device/outlet-single.js +384 -0
- package/lib/device/panel.js +382 -0
- package/lib/device/rf-bridge.js +321 -0
- package/lib/device/rf-button.js +125 -0
- package/lib/device/rf-sensor.js +173 -0
- package/lib/device/sensor-ambient.js +311 -0
- package/lib/device/sensor-contact.js +140 -0
- package/lib/device/sensor-temp-humi.js +182 -0
- package/lib/device/simulation/blind.js +253 -0
- package/lib/device/simulation/cooler.js +312 -0
- package/lib/device/simulation/door.js +253 -0
- package/lib/device/simulation/doorbell.js +190 -0
- package/lib/device/simulation/garage-eachen.js +235 -0
- package/lib/device/simulation/garage-four.js +176 -0
- package/lib/device/simulation/garage-od-switch.js +36 -0
- package/lib/device/simulation/garage-one.js +395 -0
- package/lib/device/simulation/garage-two.js +394 -0
- package/lib/device/simulation/gate-one.js +327 -0
- package/lib/device/simulation/heater.js +389 -0
- package/lib/device/simulation/index.js +75 -0
- package/lib/device/simulation/light-fan.js +258 -0
- package/lib/device/simulation/lock-eachen.js +163 -0
- package/lib/device/simulation/lock-one.js +366 -0
- package/lib/device/simulation/p-button.js +223 -0
- package/lib/device/simulation/purifier.js +289 -0
- package/lib/device/simulation/rf-blind.js +192 -0
- package/lib/device/simulation/rf-door.js +180 -0
- package/lib/device/simulation/rf-window.js +180 -0
- package/lib/device/simulation/sensor-hidden.js +105 -0
- package/lib/device/simulation/sensor-leak.js +123 -0
- package/lib/device/simulation/sensor-visible.js +231 -0
- package/lib/device/simulation/sensor.js +300 -0
- package/lib/device/simulation/switch-valve.js +351 -0
- package/lib/device/simulation/tap-one.js +283 -0
- package/lib/device/simulation/tap-two.js +266 -0
- package/lib/device/simulation/th-cooler.js +443 -0
- package/lib/device/simulation/th-dehumidifier.js +424 -0
- package/lib/device/simulation/th-heater.js +449 -0
- package/lib/device/simulation/th-humidifier.js +424 -0
- package/lib/device/simulation/th-thermostat.js +611 -0
- package/lib/device/simulation/tv.js +252 -0
- package/lib/device/simulation/valve-four.js +232 -0
- package/lib/device/simulation/valve-one.js +345 -0
- package/lib/device/simulation/valve-two.js +340 -0
- package/lib/device/simulation/window.js +253 -0
- package/lib/device/switch-man.js +106 -0
- package/lib/device/switch-mate.js +82 -0
- package/lib/device/switch-multi.js +411 -0
- package/lib/device/switch-single-inched.js +332 -0
- package/lib/device/switch-single.js +307 -0
- package/lib/device/template.js +43 -0
- package/lib/device/thermostat.js +286 -0
- package/lib/device/zigbee/index.js +27 -0
- package/lib/device/zigbee/light-cct.js +263 -0
- package/lib/device/zigbee/light-dimmer.js +148 -0
- package/lib/device/zigbee/light-rgb-cct.js +400 -0
- package/lib/device/zigbee/motor.js +301 -0
- package/lib/device/zigbee/sensor-ambient.js +177 -0
- package/lib/device/zigbee/sensor-contact.js +137 -0
- package/lib/device/zigbee/sensor-leak.js +119 -0
- package/lib/device/zigbee/sensor-motion.js +119 -0
- package/lib/device/zigbee/sensor-occupancy.js +119 -0
- package/lib/device/zigbee/sensor-smoke.js +96 -0
- package/lib/device/zigbee/switch-stateless.js +104 -0
- package/lib/device/zigbee/thermostat.js +323 -0
- package/lib/fakegato/LICENSE +21 -0
- package/lib/fakegato/fakegato-history.js +813 -0
- package/lib/fakegato/fakegato-storage.js +108 -0
- package/lib/fakegato/fakegato-timer.js +125 -0
- package/lib/fakegato/uuid.js +27 -0
- package/lib/homebridge-ui/public/index.html +365 -0
- package/lib/homebridge-ui/server.js +46 -0
- package/lib/index.js +7 -0
- package/lib/node-dns-sd/LICENSE +21 -0
- package/lib/node-dns-sd/README.md +613 -0
- package/lib/node-dns-sd/lib/dns-sd-classes.json +6 -0
- package/lib/node-dns-sd/lib/dns-sd-composer.js +83 -0
- package/lib/node-dns-sd/lib/dns-sd-parser.js +344 -0
- package/lib/node-dns-sd/lib/dns-sd-types.json +52 -0
- package/lib/node-dns-sd/lib/dns-sd.js +580 -0
- package/lib/platform.js +2156 -0
- package/lib/utils/colour.js +552 -0
- package/lib/utils/constants.js +589 -0
- package/lib/utils/custom-chars.js +33 -0
- package/lib/utils/eve-chars.js +130 -0
- package/lib/utils/functions.js +42 -0
- package/lib/utils/lang-en.js +160 -0
- package/lib/utils/lang-fr.js +163 -0
- package/lib/utils/lang-th.js +160 -0
- package/lib/utils/lang.js +5 -0
- package/package.json +75 -0
package/eslint.config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { antfu } from '@antfu/eslint-config'
|
|
2
|
+
|
|
3
|
+
/** @type {typeof antfu} */
|
|
4
|
+
export default antfu(
|
|
5
|
+
{
|
|
6
|
+
ignores: [],
|
|
7
|
+
jsx: false,
|
|
8
|
+
rules: {
|
|
9
|
+
'new-cap': 'off',
|
|
10
|
+
'style/brace-style': ['error', '1tbs', { allowSingleLine: true }],
|
|
11
|
+
'unused-imports/no-unused-vars': ['error', { caughtErrors: 'none' }],
|
|
12
|
+
},
|
|
13
|
+
typescript: false,
|
|
14
|
+
},
|
|
15
|
+
)
|
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer'
|
|
2
|
+
|
|
3
|
+
export default class {
|
|
4
|
+
constructor(platform, devicesInHB) {
|
|
5
|
+
// Set up variables from the platform
|
|
6
|
+
this.config = platform.config
|
|
7
|
+
this.debug = platform.config.debug
|
|
8
|
+
this.devicesInHB = devicesInHB
|
|
9
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
10
|
+
this.hapServ = platform.api.hap.Service
|
|
11
|
+
this.hapUUIDGen = platform.api.hap.uuid.generate
|
|
12
|
+
this.log = platform.log
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
showHome() {
|
|
16
|
+
// Return the home page for the API
|
|
17
|
+
return `<!doctype html>
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<head>
|
|
20
|
+
<meta charset="utf-8">
|
|
21
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
22
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
|
23
|
+
<title>homebridge-ewelink API Docs</title>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<div class="container-fluid my-3">
|
|
27
|
+
<div class="row content">
|
|
28
|
+
<div class="col-lg-2"></div>
|
|
29
|
+
<div class="col-lg-8">
|
|
30
|
+
<p class="text-center">
|
|
31
|
+
<img src="https://user-images.githubusercontent.com/43026681/101325266-63126600-3863-11eb-9382-4a2924f0e540.png" alt="homebridge-ewelink logo" style="width: 60%;">
|
|
32
|
+
<h4 class="text-center">homebridge-ewelink</h3>
|
|
33
|
+
</p>
|
|
34
|
+
<hr class="mb-0">
|
|
35
|
+
<h5 class="mt-4 mb-2">Intro</h5>
|
|
36
|
+
<ul class="small">
|
|
37
|
+
<li>The internal API allows you to query and control your homebridge-ewelink accessories using HTTP requests</li>
|
|
38
|
+
</ul>
|
|
39
|
+
<h5 class="mt-4 mb-2">Documentation</h5>
|
|
40
|
+
<ul class="small">
|
|
41
|
+
<li>All requests are of type <code>HTTP GET</code></li>
|
|
42
|
+
<li>All requests must include an HTTP authentication header in the form:
|
|
43
|
+
<ul>
|
|
44
|
+
<li><code>Authorization: "Basic %%%"</code></li>
|
|
45
|
+
<li>Where <code>%%%</code> is a base64-encoded string of your eWeLink credentials in the form <code>username:password</code></li>
|
|
46
|
+
</ul>
|
|
47
|
+
</li>
|
|
48
|
+
<li>All requests will return a <code>HTTP 200 OK</code> success code with a JSON response</li>
|
|
49
|
+
<li>Success or failure of any request can be determined by the <code>success</code> response property which will be <code>true</code> or <code>false</code></li>
|
|
50
|
+
<li>Error messages will be returned in the <code>error</code> parameter as a <code>string</code></li>
|
|
51
|
+
<li>Replace <code>{hbDeviceId}</code> with the Homebridge ID of the device, e.g. <code>10000abcdeSWX</code></li>
|
|
52
|
+
<li>A note about offline devices:
|
|
53
|
+
<ul>
|
|
54
|
+
<li>Querying any characteristic will return the HomeKit cache value</li>
|
|
55
|
+
<li>Updating a characteristic which matches the HomeKit cache value will return a <code>success:true</code> response</li>
|
|
56
|
+
<li>Updating a characteristic which does not match the HomeKit cache value will return a <code>success:false</code> with an <code>error:"HAP Status Error: -70402"</code> response</li>
|
|
57
|
+
</ul>
|
|
58
|
+
</li>
|
|
59
|
+
</ul>
|
|
60
|
+
<div class="alert alert-secondary small text-center" role="alert" style="display: none;" id="baseUrlBanner"></div>
|
|
61
|
+
<h5 class="mt-4 mb-2">Accessory Query Commands</h5>
|
|
62
|
+
<div class="table-responsive">
|
|
63
|
+
<table class="table table-sm table-hover">
|
|
64
|
+
<thead>
|
|
65
|
+
<tr>
|
|
66
|
+
<th scope="col" class="small" style="width: 50%;">Function</th>
|
|
67
|
+
<th scope="col" class="small" style="width: 50%;">Path</th>
|
|
68
|
+
</tr>
|
|
69
|
+
</thead>
|
|
70
|
+
<tbody>
|
|
71
|
+
<tr>
|
|
72
|
+
<td class="small">
|
|
73
|
+
<strong>Obtain a device list.</strong><br>
|
|
74
|
+
<code>response</code> property is an <code>array</code>, for example:<br>
|
|
75
|
+
<code><pre>{
|
|
76
|
+
"success": true,
|
|
77
|
+
"response":[
|
|
78
|
+
{
|
|
79
|
+
"name": "Bedroom Switch",
|
|
80
|
+
"hbdeviceid": "1000aa1a1aSW1",
|
|
81
|
+
"status": {
|
|
82
|
+
"wan": true,
|
|
83
|
+
"lan": true,
|
|
84
|
+
"ip": "192.168.1.20"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}</pre>
|
|
89
|
+
</code>
|
|
90
|
+
</td>
|
|
91
|
+
<td class="align-middle small"><code>/get/devicelist</code></td>
|
|
92
|
+
</tr>
|
|
93
|
+
<tr>
|
|
94
|
+
<td class="small">
|
|
95
|
+
<strong>Obtain a device's current state.</strong><br>
|
|
96
|
+
<code>response</code> property is an <code>object</code>, for example:<br>
|
|
97
|
+
<code><pre>{
|
|
98
|
+
"success": true,
|
|
99
|
+
"response": {
|
|
100
|
+
"status": {
|
|
101
|
+
"wan": true,
|
|
102
|
+
"lan": true,
|
|
103
|
+
"ip": "192.168.1.20"
|
|
104
|
+
},
|
|
105
|
+
"services": ["switch"],
|
|
106
|
+
"switch": {
|
|
107
|
+
"state": "off"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}</pre>
|
|
111
|
+
</code>
|
|
112
|
+
</td>
|
|
113
|
+
<td class="align-middle small"><code>/get/{hbDeviceId}</code></td>
|
|
114
|
+
</tr>
|
|
115
|
+
</tbody>
|
|
116
|
+
</table>
|
|
117
|
+
</div>
|
|
118
|
+
<ul class="small">
|
|
119
|
+
<li><code>services</code> is an array of services that the device has</li>
|
|
120
|
+
<li>Possible services include <code>switch</code>, <code>outlet</code>, <code>light</code>, <code>fan</code>, <code>temperature</code> and <code>humidity</code>
|
|
121
|
+
<li>Each service will have a corresponding property of characteristic(s)
|
|
122
|
+
<ul>
|
|
123
|
+
<li>In the above example the service is <code>switch</code> and the only characteristic is <code>state</code></li>
|
|
124
|
+
</ul>
|
|
125
|
+
</li>
|
|
126
|
+
<li>Use the service and characteristic when using the below commands to control an accessory</li>
|
|
127
|
+
</ul>
|
|
128
|
+
<h5 class="mt-4 mb-2">Accessory Control Commands</h5>
|
|
129
|
+
<div class="table-responsive">
|
|
130
|
+
<table class="table table-sm table-hover">
|
|
131
|
+
<thead>
|
|
132
|
+
<tr>
|
|
133
|
+
<th scope="col" class="small" style="width: 50%;">Function</th>
|
|
134
|
+
<th scope="col" class="small" style="width: 50%;">Path</th>
|
|
135
|
+
</tr>
|
|
136
|
+
</thead>
|
|
137
|
+
<tbody>
|
|
138
|
+
<tr>
|
|
139
|
+
<td class="small">Template</td>
|
|
140
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/{service}/{characteristic}/{value}</code></td>
|
|
141
|
+
</tr>
|
|
142
|
+
<tr>
|
|
143
|
+
<td class="small">
|
|
144
|
+
Service: <code>switch</code>.<br>
|
|
145
|
+
Characteristic: <code>state</code>.<br>
|
|
146
|
+
Value: must be <code>on</code>, <code>off</code> or <code>toggle</code>.
|
|
147
|
+
</td>
|
|
148
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/switch/state/on</code></td>
|
|
149
|
+
</tr>
|
|
150
|
+
<tr>
|
|
151
|
+
<td class="small">
|
|
152
|
+
Service: <code>outlet</code>.<br>
|
|
153
|
+
Characteristic: <code>state</code>.<br>
|
|
154
|
+
Value: must be <code>on</code>, <code>off</code> or <code>toggle</code>.
|
|
155
|
+
</td>
|
|
156
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/outlet/state/off</code></td>
|
|
157
|
+
</tr>
|
|
158
|
+
<tr>
|
|
159
|
+
<td class="small">
|
|
160
|
+
Service: <code>light</code>.<br>
|
|
161
|
+
Characteristic: <code>state</code>.<br>
|
|
162
|
+
Value: must be <code>on</code>, <code>off</code> or <code>toggle</code>.
|
|
163
|
+
</td>
|
|
164
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/light/state/on</code></td>
|
|
165
|
+
</tr>
|
|
166
|
+
<tr>
|
|
167
|
+
<td class="small">
|
|
168
|
+
Service: <code>light</code>.<br>
|
|
169
|
+
Characteristic: <code>brightness</code>.<br>
|
|
170
|
+
Value: must be between <code>0</code> and <code>100</code>.
|
|
171
|
+
</td>
|
|
172
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/light/brightness/54</code></td>
|
|
173
|
+
</tr>
|
|
174
|
+
<tr>
|
|
175
|
+
<td class="small">
|
|
176
|
+
Service: <code>light</code>.<br>
|
|
177
|
+
Characteristic: <code>hue</code>.<br>
|
|
178
|
+
Value: must be between <code>0</code> and <code>360</code>.
|
|
179
|
+
</td>
|
|
180
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/light/hue/157</code></td>
|
|
181
|
+
</tr>
|
|
182
|
+
<tr>
|
|
183
|
+
<td class="small">
|
|
184
|
+
Service: <code>light</code>.<br>
|
|
185
|
+
Characteristic: <code>colourtemperature</code>.<br>
|
|
186
|
+
Value: must be between <code>140</code> and <code>500</code>.
|
|
187
|
+
</td>
|
|
188
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/light/colourtemperature/300</code></td>
|
|
189
|
+
</tr>
|
|
190
|
+
<tr>
|
|
191
|
+
<td class="small">
|
|
192
|
+
Service: <code>fan</code>.<br>
|
|
193
|
+
Characteristic: <code>speed</code>.<br>
|
|
194
|
+
Value: must be <code>low</code>, <code>medium</code> or <code>high</code>.
|
|
195
|
+
</td>
|
|
196
|
+
<td class="align-middle small"><code>/set/{hbDeviceId}/fan/speed/medium</code></td>
|
|
197
|
+
</tr>
|
|
198
|
+
</tbody>
|
|
199
|
+
</table>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
<div class="col-lg-2"></div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.min.js" integrity="sha384-lpyLfhYuitXl2zRZ5Bn2fqnhNAKOAaM/0Kr9laMspuaMiZfGmfwRNFh8HlMy49eQ" crossorigin="anonymous"></script>
|
|
206
|
+
<script>
|
|
207
|
+
const base = window.location.href.slice(0, -1)
|
|
208
|
+
const banner = document.getElementById('baseUrlBanner')
|
|
209
|
+
banner.innerHTML = 'All paths are relative to <strong><code>' + base + '</code></strong>'
|
|
210
|
+
banner.style.display = 'block'
|
|
211
|
+
</script>
|
|
212
|
+
</body>
|
|
213
|
+
</html>`
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async action(req) {
|
|
217
|
+
// Log the request if appropriate
|
|
218
|
+
if (this.debug) {
|
|
219
|
+
this.log('API request [%s].', req.url)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Authenticate the request
|
|
223
|
+
if (
|
|
224
|
+
!req.headers
|
|
225
|
+
|| !req.headers.authorization
|
|
226
|
+
|| !req.headers.authorization.includes('Basic ')
|
|
227
|
+
) {
|
|
228
|
+
throw new Error('Invalid authentication')
|
|
229
|
+
}
|
|
230
|
+
const encodedCreds = req.headers.authorization.split(' ')[1]
|
|
231
|
+
const buff = Buffer.from(encodedCreds, 'base64')
|
|
232
|
+
const decodedCreds = buff
|
|
233
|
+
.toString('utf8')
|
|
234
|
+
.replace(/\r\n|\n|\r/g, '')
|
|
235
|
+
.trim()
|
|
236
|
+
const [user, pass] = decodedCreds.split(':')
|
|
237
|
+
if (user !== this.config.username || pass !== this.config.password) {
|
|
238
|
+
throw new Error('Invalid authentication')
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Obtain the parts of the request url
|
|
242
|
+
const pathParts = req.url.split('/')
|
|
243
|
+
const action = pathParts[1]
|
|
244
|
+
const device = pathParts[2]
|
|
245
|
+
const servToUpdate = pathParts[3]
|
|
246
|
+
const charToUpdate = pathParts[4]
|
|
247
|
+
const newValue = pathParts[5]
|
|
248
|
+
|
|
249
|
+
// Check an action was specified
|
|
250
|
+
if (!action) {
|
|
251
|
+
throw new Error('No action specified')
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Check the action is either get or set
|
|
255
|
+
if (!['get', 'set'].includes(action)) {
|
|
256
|
+
throw new Error('Action must be \'get\' or \'set\'')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Check a device was specified
|
|
260
|
+
if (!device) {
|
|
261
|
+
throw new Error('No accessory specified')
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Special case for the device list
|
|
265
|
+
if (device === 'devicelist') {
|
|
266
|
+
const deviceList = []
|
|
267
|
+
this.devicesInHB.forEach((accessory) => {
|
|
268
|
+
if (accessory.context.hidden) {
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
deviceList.push({
|
|
272
|
+
name: accessory.displayName,
|
|
273
|
+
hbdeviceid: accessory.context.hbDeviceId,
|
|
274
|
+
status: {
|
|
275
|
+
wan: !!accessory.context.reachableWAN,
|
|
276
|
+
lan: !!accessory.context.reachableLAN,
|
|
277
|
+
ip: accessory.context.ip || false,
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
return deviceList
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Try and find the device in Homebridge
|
|
285
|
+
const uuid = this.hapUUIDGen(device)
|
|
286
|
+
if (!this.devicesInHB.has(uuid)) {
|
|
287
|
+
throw new Error('Accessory not found in Homebridge')
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Obtain the corresponding accessory
|
|
291
|
+
const accessory = this.devicesInHB.get(uuid)
|
|
292
|
+
|
|
293
|
+
// Check the accessory isn't hidden from Homebridge
|
|
294
|
+
if (accessory.context.hidden) {
|
|
295
|
+
throw new Error('Accessory not found in Homebridge')
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Check the device is controllable
|
|
299
|
+
if (!accessory.control) {
|
|
300
|
+
throw new Error('Accessory has not been initialised yet')
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// If the action is 'get' then return the properties
|
|
304
|
+
if (action === 'get') {
|
|
305
|
+
if (!accessory.control.currentState()) {
|
|
306
|
+
throw new Error('Accessory does not yet support querying')
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
status: {
|
|
310
|
+
wan: !!accessory.context.reachableWAN,
|
|
311
|
+
lan: !!accessory.context.reachableLAN,
|
|
312
|
+
ip: accessory.context.ip || false,
|
|
313
|
+
},
|
|
314
|
+
...(await accessory.control.currentState()),
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// From now on the action must be 'set'
|
|
319
|
+
|
|
320
|
+
// Check a servToUpdate to update was specified
|
|
321
|
+
if (!servToUpdate) {
|
|
322
|
+
throw new Error('No service specified')
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
let service
|
|
326
|
+
switch (servToUpdate) {
|
|
327
|
+
case 'fan':
|
|
328
|
+
service = this.hapServ.Fan
|
|
329
|
+
break
|
|
330
|
+
case 'light':
|
|
331
|
+
service = this.hapServ.Lightbulb
|
|
332
|
+
break
|
|
333
|
+
case 'outlet':
|
|
334
|
+
service = this.hapServ.Outlet
|
|
335
|
+
break
|
|
336
|
+
case 'switch':
|
|
337
|
+
service = this.hapServ.Switch
|
|
338
|
+
break
|
|
339
|
+
default:
|
|
340
|
+
throw new Error('Invalid service specified')
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (!accessory.getService(service)) {
|
|
344
|
+
throw new Error(`Accessory does not have service:${servToUpdate}`)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Check an charToUpdate for a servToUpdate was specified
|
|
348
|
+
if (!charToUpdate) {
|
|
349
|
+
throw new Error(`No characteristic specified for service:${servToUpdate}`)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const accServ = accessory.getService(service)
|
|
353
|
+
|
|
354
|
+
// These variables depend on the charToUpdate that was supplied
|
|
355
|
+
let charName
|
|
356
|
+
|
|
357
|
+
switch (charToUpdate) {
|
|
358
|
+
case 'adaptivelighting':
|
|
359
|
+
case 'colourtemperature':
|
|
360
|
+
charName = accServ.testCharacteristic(this.hapChar.ColorTemperature)
|
|
361
|
+
? this.hapChar.ColorTemperature
|
|
362
|
+
: false
|
|
363
|
+
break
|
|
364
|
+
case 'brightness':
|
|
365
|
+
charName = accServ.testCharacteristic(this.hapChar.Brightness)
|
|
366
|
+
? this.hapChar.Brightness
|
|
367
|
+
: false
|
|
368
|
+
break
|
|
369
|
+
case 'hue':
|
|
370
|
+
charName = accServ.testCharacteristic(this.hapChar.Hue) ? this.hapChar.Hue : false
|
|
371
|
+
break
|
|
372
|
+
case 'speed':
|
|
373
|
+
charName = accServ.testCharacteristic(this.hapChar.RotationSpeed)
|
|
374
|
+
? this.hapChar.RotationSpeed
|
|
375
|
+
: false
|
|
376
|
+
break
|
|
377
|
+
case 'state':
|
|
378
|
+
charName = accServ.testCharacteristic(this.hapChar.On) ? this.hapChar.On : false
|
|
379
|
+
break
|
|
380
|
+
default:
|
|
381
|
+
throw new Error(`Invalid characteristic specified for service:${servToUpdate}`)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Check that the accessory has the corresponding characteristic for the charToUpdate
|
|
385
|
+
if (!charName) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
`Accessory service:${servToUpdate} does not support characteristic:${charToUpdate}`,
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Check a new status was supplied if the action is set
|
|
392
|
+
if (!newValue) {
|
|
393
|
+
throw new Error(`No value specified for characteristic:${charToUpdate}`)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
let newHKStatus
|
|
397
|
+
switch (charToUpdate) {
|
|
398
|
+
case 'brightness': {
|
|
399
|
+
// The new status for brightness must be an integer between 0 and 100
|
|
400
|
+
newHKStatus = Number.parseInt(newValue, 10)
|
|
401
|
+
if (Number.isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 100) {
|
|
402
|
+
throw new Error('Value must be integer 0-100 for characteristic:brightness')
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Check the accessory has a correct set handler for on/off
|
|
406
|
+
if (!accessory.control.internalBrightnessUpdate) {
|
|
407
|
+
throw new Error('Function to control accessory not found')
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Call the set handler to send the request to eWeLink
|
|
411
|
+
await accessory.control.internalBrightnessUpdate(newHKStatus)
|
|
412
|
+
break
|
|
413
|
+
}
|
|
414
|
+
case 'colourtemperature': {
|
|
415
|
+
// The new status for colour temperature must be an integer between 140 and 500
|
|
416
|
+
newHKStatus = Number.parseInt(newValue, 10)
|
|
417
|
+
if (Number.isNaN(newHKStatus) || newHKStatus < 140 || newHKStatus > 500) {
|
|
418
|
+
throw new Error('Value must be integer 140-500 for characteristic:colourtemperature')
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Check the accessory has a correct set handler for on/off
|
|
422
|
+
if (!accessory.control.internalCTUpdate) {
|
|
423
|
+
throw new Error(`Accessory does not support controlling characteristic:${charToUpdate}`)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Call the set handler to send the request to eWeLink
|
|
427
|
+
if (accessory?.alController?.isAdaptiveLightingActive()) {
|
|
428
|
+
accessory.alController.disableAdaptiveLighting()
|
|
429
|
+
}
|
|
430
|
+
await accessory.control.internalCTUpdate(newHKStatus)
|
|
431
|
+
break
|
|
432
|
+
}
|
|
433
|
+
case 'hue': {
|
|
434
|
+
// The new status for hue must be an integer between 0 and 360
|
|
435
|
+
newHKStatus = Number.parseInt(newValue, 10)
|
|
436
|
+
if (Number.isNaN(newHKStatus) || newHKStatus < 0 || newHKStatus > 360) {
|
|
437
|
+
throw new Error('Value must be integer 0-360 for characteristic:hue')
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Check the accessory has a correct set handler for on/off
|
|
441
|
+
if (!accessory.control.internalColourUpdate) {
|
|
442
|
+
throw new Error('Function to control accessory not found')
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Call the set handler to send the request to eWeLink
|
|
446
|
+
if (accessory?.alController?.isAdaptiveLightingActive()) {
|
|
447
|
+
accessory.alController.disableAdaptiveLighting()
|
|
448
|
+
}
|
|
449
|
+
await accessory.control.internalColourUpdate(newHKStatus)
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
case 'speed':
|
|
453
|
+
// The new status for speed must be low, medium or high
|
|
454
|
+
switch (newValue) {
|
|
455
|
+
case 'low':
|
|
456
|
+
newHKStatus = 33
|
|
457
|
+
break
|
|
458
|
+
case 'medium':
|
|
459
|
+
newHKStatus = 66
|
|
460
|
+
break
|
|
461
|
+
case 'high':
|
|
462
|
+
newHKStatus = 99
|
|
463
|
+
break
|
|
464
|
+
default:
|
|
465
|
+
throw new Error('Value must be \'low\', \'medium\' or \'high\' for characteristic:speed')
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Check the accessory has a correct set handler for speed
|
|
469
|
+
if (!accessory.control.internalSpeedUpdate) {
|
|
470
|
+
throw new Error('Function to control accessory not found')
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Call the set handler to send the request to eWeLink
|
|
474
|
+
await accessory.control.internalSpeedUpdate(newHKStatus)
|
|
475
|
+
break
|
|
476
|
+
case 'state':
|
|
477
|
+
// The new status for state must be on, off or toggle
|
|
478
|
+
switch (newValue) {
|
|
479
|
+
case 'on':
|
|
480
|
+
newHKStatus = true
|
|
481
|
+
break
|
|
482
|
+
case 'off':
|
|
483
|
+
newHKStatus = false
|
|
484
|
+
break
|
|
485
|
+
case 'toggle':
|
|
486
|
+
newHKStatus = !accServ.getCharacteristic(this.hapChar.On).value
|
|
487
|
+
break
|
|
488
|
+
default:
|
|
489
|
+
throw new Error('Value must be \'on\', \'off\' or \'toggle\' for characteristic:state')
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Check the accessory has a correct set handler for on/off
|
|
493
|
+
if (!accessory.control.internalStateUpdate) {
|
|
494
|
+
throw new Error('Function to control accessory not found')
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Call the set handler to send the request to eWeLink
|
|
498
|
+
await accessory.control.internalStateUpdate(newHKStatus)
|
|
499
|
+
break
|
|
500
|
+
default:
|
|
501
|
+
throw new Error(`Invalid value for characteristic:${charToUpdate}`)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// The eWeLink request was successful so update the characteristic in HomeKit
|
|
505
|
+
accServ.updateCharacteristic(charName, newHKStatus)
|
|
506
|
+
return true
|
|
507
|
+
}
|
|
508
|
+
}
|