@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
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
import platformConsts from '../../utils/constants.js'
|
|
2
|
+
import { hasProperty, parseError } from '../../utils/functions.js'
|
|
3
|
+
|
|
4
|
+
export default class {
|
|
5
|
+
constructor(platform, accessory) {
|
|
6
|
+
// Set up variables from the platform
|
|
7
|
+
this.hapChar = platform.api.hap.Characteristic
|
|
8
|
+
this.hapErr = platform.api.hap.HapStatusError
|
|
9
|
+
this.hapServ = platform.api.hap.Service
|
|
10
|
+
this.lang = platform.lang
|
|
11
|
+
this.log = platform.log
|
|
12
|
+
this.platform = platform
|
|
13
|
+
|
|
14
|
+
// Set up variables from the accessory
|
|
15
|
+
this.name = accessory.displayName
|
|
16
|
+
this.accessory = accessory
|
|
17
|
+
|
|
18
|
+
// Initially set the online flag as true (to be then updated as false if necessary)
|
|
19
|
+
this.isOnline = true
|
|
20
|
+
|
|
21
|
+
// Set up custom variables for this device type
|
|
22
|
+
const deviceConf = platform.deviceConf[accessory.context.eweDeviceId] || {}
|
|
23
|
+
this.tempOffset = deviceConf.offset || platformConsts.defaultValues.offset
|
|
24
|
+
this.tempOffsetFactor = deviceConf.offsetFactor
|
|
25
|
+
this.humiOffset = deviceConf.humidityOffset
|
|
26
|
+
? Number.parseInt(deviceConf.humidityOffset, 10)
|
|
27
|
+
: platformConsts.defaultValues.humidityOffset
|
|
28
|
+
this.humiOffsetFactor = deviceConf.humidityOffsetFactor
|
|
29
|
+
this.minTarget = deviceConf.minTarget || platformConsts.defaultValues.minTarget
|
|
30
|
+
this.maxTarget = deviceConf.maxTarget
|
|
31
|
+
? Math.max(deviceConf.maxTarget, this.minTarget + 1)
|
|
32
|
+
: platformConsts.defaultValues.maxTarget
|
|
33
|
+
this.showHeatCool = deviceConf.showHeatCool
|
|
34
|
+
|
|
35
|
+
// Set the correct logging variables for this accessory
|
|
36
|
+
switch (deviceConf.overrideLogging) {
|
|
37
|
+
case 'standard':
|
|
38
|
+
this.enableLogging = true
|
|
39
|
+
this.enableDebugLogging = false
|
|
40
|
+
break
|
|
41
|
+
case 'debug':
|
|
42
|
+
this.enableLogging = true
|
|
43
|
+
this.enableDebugLogging = true
|
|
44
|
+
break
|
|
45
|
+
case 'disable':
|
|
46
|
+
this.enableLogging = false
|
|
47
|
+
this.enableDebugLogging = false
|
|
48
|
+
break
|
|
49
|
+
default:
|
|
50
|
+
this.enableLogging = !platform.config.disableDeviceLogging
|
|
51
|
+
this.enableDebugLogging = platform.config.debug
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// If the accessory has a switch service then remove it
|
|
56
|
+
if (this.accessory.getService(this.hapServ.Switch)) {
|
|
57
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// If the accessory has a temperature sensor service then remove it
|
|
61
|
+
if (this.accessory.getService(this.hapServ.TemperatureSensor)) {
|
|
62
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.TemperatureSensor))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Set up the accessory with default target temp when added the first time
|
|
66
|
+
if (!hasProperty(this.accessory.context, 'cacheTarget')) {
|
|
67
|
+
this.accessory.context.cacheTarget = 20
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// If the accessory has a heater service then remove it
|
|
71
|
+
if (this.accessory.getService(this.hapServ.HeaterCooler)) {
|
|
72
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.HeaterCooler))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// If the accessory has a humidifier service then remove it
|
|
76
|
+
if (this.accessory.getService(this.hapServ.HumidifierDehumidifier)) {
|
|
77
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.HumidifierDehumidifier))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// If the accessory has a humidity sensor service then remove it
|
|
81
|
+
if (this.accessory.getService(this.hapServ.HumiditySensor)) {
|
|
82
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.HumiditySensor))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Add a context property to save the desired state of the showHeatCool option
|
|
86
|
+
if (!hasProperty(accessory.context, 'showHeatCool')) {
|
|
87
|
+
accessory.context.showHeatCool = false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Reset the thermostat service if showHeatCool has been switched on from off
|
|
91
|
+
if (this.showHeatCool && !accessory.context.showHeatCool) {
|
|
92
|
+
accessory.context.showHeatCool = true
|
|
93
|
+
if (this.accessory.getService(this.hapServ.Thermostat)) {
|
|
94
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Thermostat))
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Reset the thermostat service if showHeatCool has been switched off from on
|
|
99
|
+
if (!this.showHeatCool && accessory.context.showHeatCool) {
|
|
100
|
+
accessory.context.showHeatCool = false
|
|
101
|
+
if (this.accessory.getService(this.hapServ.Thermostat)) {
|
|
102
|
+
this.accessory.removeService(this.accessory.getService(this.hapServ.Thermostat))
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Add the thermostat service if it doesn't already exist
|
|
107
|
+
this.service = this.accessory.getService(this.hapServ.Thermostat)
|
|
108
|
+
|| this.accessory.addService(this.hapServ.Thermostat)
|
|
109
|
+
|
|
110
|
+
// The DS18B20 sensor does not provide humidity readings
|
|
111
|
+
if (this.accessory.context.sensorType === 'DS18B20') {
|
|
112
|
+
if (this.service.testCharacteristic(this.hapChar.CurrentRelativeHumidity)) {
|
|
113
|
+
this.service.removeCharacteristic(
|
|
114
|
+
this.service.getCharacteristic(this.hapChar.CurrentRelativeHumidity),
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
if (!this.service.testCharacteristic(this.hapChar.CurrentRelativeHumidity)) {
|
|
119
|
+
this.service.addCharacteristic(this.hapChar.CurrentRelativeHumidity)
|
|
120
|
+
}
|
|
121
|
+
this.humiService = true
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Set custom properties of the current temperature characteristic
|
|
125
|
+
this.service.getCharacteristic(this.hapChar.CurrentTemperature).setProps({
|
|
126
|
+
minStep: 0.1,
|
|
127
|
+
})
|
|
128
|
+
this.cacheTemp = this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
|
|
129
|
+
this.updateCache()
|
|
130
|
+
|
|
131
|
+
// Add options to the target state characteristic
|
|
132
|
+
this.service
|
|
133
|
+
.getCharacteristic(this.hapChar.TargetHeatingCoolingState)
|
|
134
|
+
.setProps({
|
|
135
|
+
validValues: this.showHeatCool ? [0, 1, 2] : [0, 3],
|
|
136
|
+
})
|
|
137
|
+
.onSet(async value => this.internalStateUpdate(value))
|
|
138
|
+
|
|
139
|
+
// Add the set handler to the target temperature characteristic
|
|
140
|
+
this.service
|
|
141
|
+
.getCharacteristic(this.hapChar.TargetTemperature)
|
|
142
|
+
.updateValue(this.accessory.context.cacheTarget)
|
|
143
|
+
.setProps({
|
|
144
|
+
minValue: this.minTarget,
|
|
145
|
+
maxValue: this.maxTarget,
|
|
146
|
+
minStep: 0.5,
|
|
147
|
+
})
|
|
148
|
+
.onSet(async value => this.internalTargetTempUpdate(value))
|
|
149
|
+
|
|
150
|
+
// Add the get handlers only if the user hasn't disabled the disableNoResponse setting
|
|
151
|
+
if (!platform.config.disableNoResponse) {
|
|
152
|
+
this.service.getCharacteristic(this.hapChar.CurrentTemperature).onGet(() => {
|
|
153
|
+
if (!this.isOnline) {
|
|
154
|
+
throw new this.hapErr(-70402)
|
|
155
|
+
}
|
|
156
|
+
return this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
|
|
157
|
+
})
|
|
158
|
+
this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).onGet(() => {
|
|
159
|
+
if (!this.isOnline) {
|
|
160
|
+
throw new this.hapErr(-70402)
|
|
161
|
+
}
|
|
162
|
+
return this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).value
|
|
163
|
+
})
|
|
164
|
+
this.service.getCharacteristic(this.hapChar.CurrentHeatingCoolingState).onGet(() => {
|
|
165
|
+
if (!this.isOnline) {
|
|
166
|
+
throw new this.hapErr(-70402)
|
|
167
|
+
}
|
|
168
|
+
return this.service.getCharacteristic(this.hapChar.CurrentHeatingCoolingState).value
|
|
169
|
+
})
|
|
170
|
+
this.service.getCharacteristic(this.hapChar.TargetTemperature).onGet(() => {
|
|
171
|
+
if (!this.isOnline) {
|
|
172
|
+
throw new this.hapErr(-70402)
|
|
173
|
+
}
|
|
174
|
+
return this.service.getCharacteristic(this.hapChar.TargetTemperature).value
|
|
175
|
+
})
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Initialise these caches now since they aren't determined by the initial externalUpdate()
|
|
179
|
+
const curState = this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).value
|
|
180
|
+
this.cacheState = curState > 0 ? 'on' : 'off'
|
|
181
|
+
const heatTest = this.service.getCharacteristic(this.hapChar.TargetTemperature).value
|
|
182
|
+
> this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
|
|
183
|
+
? 'on'
|
|
184
|
+
: 'off'
|
|
185
|
+
this.cacheHeat = this.cacheState === 'on' && [1, 3].includes(curState)
|
|
186
|
+
? heatTest
|
|
187
|
+
: undefined
|
|
188
|
+
const coolTest = this.service.getCharacteristic(this.hapChar.TargetTemperature).value
|
|
189
|
+
< this.service.getCharacteristic(this.hapChar.CurrentTemperature).value
|
|
190
|
+
? 'on'
|
|
191
|
+
: 'off'
|
|
192
|
+
this.cacheCool = this.cacheState === 'on' && curState === 2
|
|
193
|
+
? coolTest
|
|
194
|
+
: undefined
|
|
195
|
+
|
|
196
|
+
// Pass the accessory to Fakegato to set up with Eve
|
|
197
|
+
this.accessory.eveService = new platform.eveService('custom', this.accessory, {
|
|
198
|
+
log: () => {},
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Set up an interval to get eWeLink to send regular temperature/humidity updates
|
|
202
|
+
if (platform.config.mode !== 'lan') {
|
|
203
|
+
setTimeout(() => {
|
|
204
|
+
this.internalUIUpdate()
|
|
205
|
+
this.intervalPoll = setInterval(() => this.internalUIUpdate(), 120000)
|
|
206
|
+
}, 5000)
|
|
207
|
+
|
|
208
|
+
// Stop the intervals on Homebridge shutdown
|
|
209
|
+
platform.api.on('shutdown', () => clearInterval(this.intervalPoll))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Output the customised options to the log
|
|
213
|
+
const normalLogging = this.enableLogging ? 'standard' : 'disable'
|
|
214
|
+
const opts = JSON.stringify({
|
|
215
|
+
humidityOffset: this.humiOffset,
|
|
216
|
+
humidityOffsetFactor: this.humiOffsetFactor,
|
|
217
|
+
logging: this.enableDebugLogging ? 'debug' : normalLogging,
|
|
218
|
+
maxTarget: this.maxTarget,
|
|
219
|
+
minTarget: this.minTarget,
|
|
220
|
+
offset: this.tempOffset,
|
|
221
|
+
offsetFactor: this.tempOffsetFactor,
|
|
222
|
+
showAs: 'heater',
|
|
223
|
+
})
|
|
224
|
+
this.log('[%s] %s %s.', this.name, this.lang.devInitOpts, opts)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async internalStateUpdate(value) {
|
|
228
|
+
try {
|
|
229
|
+
const params = { deviceType: 'normal' }
|
|
230
|
+
|
|
231
|
+
// this.showHeatCool true, values can be 0, 1, 2 otherwise 0, 3
|
|
232
|
+
let newState
|
|
233
|
+
let newHeat
|
|
234
|
+
let newCool
|
|
235
|
+
switch (value) {
|
|
236
|
+
case 0:
|
|
237
|
+
// Turning off
|
|
238
|
+
params.mainSwitch = 'off'
|
|
239
|
+
params.switch = 'off'
|
|
240
|
+
newState = 'off'
|
|
241
|
+
newHeat = 'off'
|
|
242
|
+
newCool = 'off'
|
|
243
|
+
break
|
|
244
|
+
case 1:
|
|
245
|
+
// Turning to heat
|
|
246
|
+
if (!this.showHeatCool) {
|
|
247
|
+
return
|
|
248
|
+
}
|
|
249
|
+
if (this.cacheTemp < this.accessory.context.cacheTarget) {
|
|
250
|
+
params.mainSwitch = 'on'
|
|
251
|
+
params.switch = 'on'
|
|
252
|
+
newState = 'on'
|
|
253
|
+
newHeat = 'on'
|
|
254
|
+
newCool = 'off'
|
|
255
|
+
} else {
|
|
256
|
+
params.mainSwitch = 'off'
|
|
257
|
+
params.switch = 'off'
|
|
258
|
+
newState = 'on'
|
|
259
|
+
newHeat = 'off'
|
|
260
|
+
newCool = 'off'
|
|
261
|
+
}
|
|
262
|
+
break
|
|
263
|
+
case 2:
|
|
264
|
+
// Turning to cool
|
|
265
|
+
if (!this.showHeatCool) {
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
if (this.cacheTemp > this.accessory.context.cacheTarget) {
|
|
269
|
+
params.mainSwitch = 'on'
|
|
270
|
+
params.switch = 'on'
|
|
271
|
+
newState = 'on'
|
|
272
|
+
newHeat = 'off'
|
|
273
|
+
newCool = 'on'
|
|
274
|
+
} else {
|
|
275
|
+
params.mainSwitch = 'off'
|
|
276
|
+
params.switch = 'off'
|
|
277
|
+
newState = 'on'
|
|
278
|
+
newHeat = 'off'
|
|
279
|
+
newCool = 'off'
|
|
280
|
+
}
|
|
281
|
+
break
|
|
282
|
+
case 3:
|
|
283
|
+
// Turning to auto
|
|
284
|
+
if (this.showHeatCool) {
|
|
285
|
+
return
|
|
286
|
+
}
|
|
287
|
+
if (this.cacheTemp < this.accessory.context.cacheTarget) {
|
|
288
|
+
params.mainSwitch = 'on'
|
|
289
|
+
params.switch = 'on'
|
|
290
|
+
newState = 'on'
|
|
291
|
+
newHeat = 'on'
|
|
292
|
+
newCool = 'off'
|
|
293
|
+
} else {
|
|
294
|
+
params.mainSwitch = 'off'
|
|
295
|
+
params.switch = 'off'
|
|
296
|
+
newState = 'on'
|
|
297
|
+
newHeat = 'off'
|
|
298
|
+
newCool = 'off'
|
|
299
|
+
}
|
|
300
|
+
break
|
|
301
|
+
default:
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Only send the update if either:
|
|
306
|
+
// * The new value (state) is OFF and (the cacheHeat was ON or cacheCool was ON)
|
|
307
|
+
// * The new value (state) is ON and (newHeat is 'on' or newCool is 'on')
|
|
308
|
+
// * (cacheHeat was ON and newCool is ON) or (cacheCool was ON and newHeat is ON)
|
|
309
|
+
if (
|
|
310
|
+
(value === 0 && (this.cacheHeat === 'on' || this.cacheCool === 'on'))
|
|
311
|
+
|| ([1, 3].includes(value) && newHeat !== this.cacheHeat)
|
|
312
|
+
|| (value === 2 && newCool !== this.cacheCool)
|
|
313
|
+
) {
|
|
314
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
315
|
+
}
|
|
316
|
+
if (newState !== this.cacheState) {
|
|
317
|
+
this.cacheState = newState
|
|
318
|
+
this.cacheHeat = undefined
|
|
319
|
+
this.cacheCool = undefined
|
|
320
|
+
if (this.enableLogging) {
|
|
321
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curState, this.cacheState)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if ([1, 3].includes(value) && newHeat !== this.cacheHeat) {
|
|
325
|
+
this.cacheHeat = newHeat
|
|
326
|
+
this.cacheCool = undefined
|
|
327
|
+
if (this.enableLogging) {
|
|
328
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curHeat, this.cacheHeat)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (value === 2 && newCool !== this.cacheCool) {
|
|
332
|
+
this.cacheCool = newCool
|
|
333
|
+
this.cacheHeat = undefined
|
|
334
|
+
if (this.enableLogging) {
|
|
335
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curCool, this.cacheCool)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const hapState = this.cacheHeat === 'on' ? 1 : 0
|
|
339
|
+
this.service.updateCharacteristic(
|
|
340
|
+
this.hapChar.CurrentHeatingCoolingState,
|
|
341
|
+
this.cacheCool === 'on' ? 2 : hapState,
|
|
342
|
+
)
|
|
343
|
+
} catch (err) {
|
|
344
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
345
|
+
setTimeout(() => {
|
|
346
|
+
const hapState = this.cacheHeat === 'on' ? 1 : 0
|
|
347
|
+
this.service.updateCharacteristic(
|
|
348
|
+
this.hapChar.TargetHeatingCoolingState,
|
|
349
|
+
this.cacheCool === 'on' ? 2 : hapState,
|
|
350
|
+
)
|
|
351
|
+
}, 2000)
|
|
352
|
+
throw new this.hapErr(-70402)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async internalTargetTempUpdate(value) {
|
|
357
|
+
try {
|
|
358
|
+
if (value === this.accessory.context.cacheTarget) {
|
|
359
|
+
return
|
|
360
|
+
}
|
|
361
|
+
this.accessory.context.cacheTarget = value
|
|
362
|
+
if (this.enableLogging) {
|
|
363
|
+
this.log('[%s] %s [%s°C].', this.name, this.lang.curTarg, value)
|
|
364
|
+
}
|
|
365
|
+
if (this.cacheState === 'off') {
|
|
366
|
+
return
|
|
367
|
+
}
|
|
368
|
+
const params = { deviceType: 'normal' }
|
|
369
|
+
let newHeat
|
|
370
|
+
let newCool
|
|
371
|
+
|
|
372
|
+
const curMode = this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).value
|
|
373
|
+
switch (curMode) {
|
|
374
|
+
case 1:
|
|
375
|
+
case 3:
|
|
376
|
+
// Currently in heating or auto mode
|
|
377
|
+
if (this.cacheTemp < this.accessory.context.cacheTarget) {
|
|
378
|
+
params.mainSwitch = 'on'
|
|
379
|
+
params.switch = 'on'
|
|
380
|
+
newHeat = 'on'
|
|
381
|
+
newCool = 'off'
|
|
382
|
+
} else {
|
|
383
|
+
params.mainSwitch = 'off'
|
|
384
|
+
params.switch = 'off'
|
|
385
|
+
newHeat = 'off'
|
|
386
|
+
newCool = 'off'
|
|
387
|
+
}
|
|
388
|
+
break
|
|
389
|
+
case 2:
|
|
390
|
+
// Currently in cooling mode
|
|
391
|
+
if (this.cacheTemp > this.accessory.context.cacheTarget) {
|
|
392
|
+
params.mainSwitch = 'on'
|
|
393
|
+
params.switch = 'on'
|
|
394
|
+
newHeat = 'off'
|
|
395
|
+
newCool = 'on'
|
|
396
|
+
} else {
|
|
397
|
+
params.mainSwitch = 'off'
|
|
398
|
+
params.switch = 'off'
|
|
399
|
+
newHeat = 'off'
|
|
400
|
+
newCool = 'off'
|
|
401
|
+
}
|
|
402
|
+
break
|
|
403
|
+
default:
|
|
404
|
+
return
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Only send the update if either:
|
|
408
|
+
// * The new value (state) is ON and (newHeat is 'on' or newCool is 'on')
|
|
409
|
+
// * (cacheHeat was ON and newCool is ON) or (cacheCool was ON and newHeat is ON)
|
|
410
|
+
if (
|
|
411
|
+
([1, 3].includes(curMode) && newHeat !== this.cacheHeat)
|
|
412
|
+
|| (curMode === 2 && newCool !== this.cacheCool)
|
|
413
|
+
) {
|
|
414
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
415
|
+
}
|
|
416
|
+
if ([1, 3].includes(curMode) && newHeat !== this.cacheHeat) {
|
|
417
|
+
this.cacheHeat = newHeat
|
|
418
|
+
this.cacheCool = undefined
|
|
419
|
+
if (this.enableLogging) {
|
|
420
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curHeat, this.cacheHeat)
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (curMode === 2 && newCool !== this.cacheCool) {
|
|
424
|
+
this.cacheCool = newCool
|
|
425
|
+
this.cacheHeat = undefined
|
|
426
|
+
if (this.enableLogging) {
|
|
427
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curCool, this.cacheCool)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const hapState = this.cacheHeat === 'on' ? 1 : 0
|
|
431
|
+
this.service.updateCharacteristic(
|
|
432
|
+
this.hapChar.CurrentHeatingCoolingState,
|
|
433
|
+
this.cacheCool === 'on' ? 2 : hapState,
|
|
434
|
+
)
|
|
435
|
+
} catch (err) {
|
|
436
|
+
this.platform.deviceUpdateError(this.accessory, err, true)
|
|
437
|
+
setTimeout(() => {
|
|
438
|
+
this.service.updateCharacteristic(
|
|
439
|
+
this.hapChar.TargetTemperature,
|
|
440
|
+
this.accessory.context.cacheTarget,
|
|
441
|
+
)
|
|
442
|
+
}, 2000)
|
|
443
|
+
throw new this.hapErr(-70402)
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async internalCurrentTempUpdate() {
|
|
448
|
+
try {
|
|
449
|
+
if (this.cacheState === 'off') {
|
|
450
|
+
return
|
|
451
|
+
}
|
|
452
|
+
const params = { deviceType: 'normal' }
|
|
453
|
+
let newHeat
|
|
454
|
+
let newCool
|
|
455
|
+
|
|
456
|
+
const curMode = this.service.getCharacteristic(this.hapChar.TargetHeatingCoolingState).value
|
|
457
|
+
switch (curMode) {
|
|
458
|
+
case 1:
|
|
459
|
+
case 3:
|
|
460
|
+
// Currently in heating or auto mode
|
|
461
|
+
if (this.cacheTemp < this.accessory.context.cacheTarget) {
|
|
462
|
+
params.mainSwitch = 'on'
|
|
463
|
+
params.switch = 'on'
|
|
464
|
+
newHeat = 'on'
|
|
465
|
+
newCool = 'off'
|
|
466
|
+
} else {
|
|
467
|
+
params.mainSwitch = 'off'
|
|
468
|
+
params.switch = 'off'
|
|
469
|
+
newHeat = 'off'
|
|
470
|
+
newCool = 'off'
|
|
471
|
+
}
|
|
472
|
+
break
|
|
473
|
+
case 2:
|
|
474
|
+
// Currently in cooling mode
|
|
475
|
+
if (this.cacheTemp > this.accessory.context.cacheTarget) {
|
|
476
|
+
params.mainSwitch = 'on'
|
|
477
|
+
params.switch = 'on'
|
|
478
|
+
newHeat = 'off'
|
|
479
|
+
newCool = 'on'
|
|
480
|
+
} else {
|
|
481
|
+
params.mainSwitch = 'off'
|
|
482
|
+
params.switch = 'off'
|
|
483
|
+
newHeat = 'off'
|
|
484
|
+
newCool = 'off'
|
|
485
|
+
}
|
|
486
|
+
break
|
|
487
|
+
default:
|
|
488
|
+
return
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Only send the update if either:
|
|
492
|
+
// * The new value (state) is ON and (newHeat is 'on' or newCool is 'on')
|
|
493
|
+
// * (cacheHeat was ON and newCool is ON) or (cacheCool was ON and newHeat is ON)
|
|
494
|
+
if (
|
|
495
|
+
([1, 3].includes(curMode) && newHeat !== this.cacheHeat)
|
|
496
|
+
|| (curMode === 2 && newCool !== this.cacheCool)
|
|
497
|
+
) {
|
|
498
|
+
await this.platform.sendDeviceUpdate(this.accessory, params)
|
|
499
|
+
}
|
|
500
|
+
if ([1, 3].includes(curMode) && newHeat !== this.cacheHeat) {
|
|
501
|
+
this.cacheHeat = newHeat
|
|
502
|
+
this.cacheCool = undefined
|
|
503
|
+
if (this.enableLogging) {
|
|
504
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curHeat, this.cacheHeat)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (curMode === 2 && newCool !== this.cacheCool) {
|
|
508
|
+
this.cacheCool = newCool
|
|
509
|
+
this.cacheHeat = undefined
|
|
510
|
+
if (this.enableLogging) {
|
|
511
|
+
this.log('[%s] %s [%s].', this.name, this.lang.curCool, this.cacheCool)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const hapState = this.cacheHeat === 'on' ? 1 : 0
|
|
515
|
+
this.service.updateCharacteristic(
|
|
516
|
+
this.hapChar.CurrentHeatingCoolingState,
|
|
517
|
+
this.cacheCool === 'on' ? 2 : hapState,
|
|
518
|
+
)
|
|
519
|
+
} catch (err) {
|
|
520
|
+
// Suppress errors here
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
async internalUIUpdate() {
|
|
525
|
+
try {
|
|
526
|
+
// Skip polling if device isn't online
|
|
527
|
+
if (!this.isOnline) {
|
|
528
|
+
return
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Send the params to request the updates
|
|
532
|
+
await this.platform.sendDeviceUpdate(this.accessory, { uiActive: 120 })
|
|
533
|
+
} catch (err) {
|
|
534
|
+
// Suppress errors here
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async externalUpdate(params) {
|
|
539
|
+
try {
|
|
540
|
+
if (
|
|
541
|
+
hasProperty(params, 'currentTemperature')
|
|
542
|
+
&& params.currentTemperature !== 'unavailable'
|
|
543
|
+
) {
|
|
544
|
+
let newTemp = Number(params.currentTemperature)
|
|
545
|
+
if (this.tempOffsetFactor) {
|
|
546
|
+
newTemp *= this.tempOffset
|
|
547
|
+
} else {
|
|
548
|
+
newTemp += this.tempOffset
|
|
549
|
+
}
|
|
550
|
+
if (newTemp !== this.cacheTemp) {
|
|
551
|
+
this.cacheTemp = newTemp
|
|
552
|
+
this.service.updateCharacteristic(this.hapChar.CurrentTemperature, this.cacheTemp)
|
|
553
|
+
this.accessory.eveService.addEntry({ temp: this.cacheTemp })
|
|
554
|
+
if (params.updateSource && this.enableLogging) {
|
|
555
|
+
this.log('[%s] %s [%s°C].', this.name, this.lang.curTemp, this.cacheTemp)
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Update the cache file with the new temperature
|
|
559
|
+
this.updateCache()
|
|
560
|
+
this.internalCurrentTempUpdate()
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (
|
|
564
|
+
hasProperty(params, 'currentHumidity')
|
|
565
|
+
&& params.currentHumidity !== 'unavailable'
|
|
566
|
+
&& this.humiService
|
|
567
|
+
) {
|
|
568
|
+
let newHumi = Number.parseInt(params.currentHumidity, 10)
|
|
569
|
+
if (this.humiOffsetFactor) {
|
|
570
|
+
newHumi *= this.humiOffset
|
|
571
|
+
} else {
|
|
572
|
+
newHumi += this.humiOffset
|
|
573
|
+
}
|
|
574
|
+
newHumi = Math.max(Math.min(Number.parseInt(newHumi, 10), 100), 0)
|
|
575
|
+
if (newHumi !== this.cacheHumi) {
|
|
576
|
+
this.cacheHumi = newHumi
|
|
577
|
+
this.service.updateCharacteristic(this.hapChar.CurrentRelativeHumidity, this.cacheHumi)
|
|
578
|
+
this.accessory.eveService.addEntry({ humidity: this.cacheHumi })
|
|
579
|
+
if (params.updateSource && this.enableLogging) {
|
|
580
|
+
this.log('[%s] %s [%s%].', this.name, this.lang.curHumi, this.cacheHumi)
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
} catch (err) {
|
|
585
|
+
this.platform.deviceUpdateError(this.accessory, err, false)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
async updateCache() {
|
|
590
|
+
// Don't continue if the storage client hasn't initialised properly
|
|
591
|
+
if (!this.platform.storageClientData) {
|
|
592
|
+
return
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Attempt to save the new temperature to the cache
|
|
596
|
+
try {
|
|
597
|
+
await this.platform.storageData.setItem(
|
|
598
|
+
`${this.accessory.context.eweDeviceId}_temp`,
|
|
599
|
+
this.cacheTemp,
|
|
600
|
+
)
|
|
601
|
+
} catch (err) {
|
|
602
|
+
if (this.enableLogging) {
|
|
603
|
+
this.log.warn('[%s] %s %s.', this.name, this.lang.storageWriteErr, parseError(err))
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
markStatus(isOnline) {
|
|
609
|
+
this.isOnline = isOnline
|
|
610
|
+
}
|
|
611
|
+
}
|