@homebridge-plugins/homebridge-wemo 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +809 -0
  2. package/LICENSE +21 -0
  3. package/README.md +66 -0
  4. package/config.schema.json +814 -0
  5. package/eslint.config.js +50 -0
  6. package/lib/connection/http.js +174 -0
  7. package/lib/connection/upnp.js +155 -0
  8. package/lib/device/coffee.js +167 -0
  9. package/lib/device/crockpot.js +380 -0
  10. package/lib/device/dimmer.js +280 -0
  11. package/lib/device/heater.js +416 -0
  12. package/lib/device/humidifier.js +379 -0
  13. package/lib/device/index.js +39 -0
  14. package/lib/device/insight.js +353 -0
  15. package/lib/device/lightswitch.js +154 -0
  16. package/lib/device/link-bulb.js +467 -0
  17. package/lib/device/link-hub.js +63 -0
  18. package/lib/device/maker-garage.js +426 -0
  19. package/lib/device/maker-switch.js +202 -0
  20. package/lib/device/motion.js +148 -0
  21. package/lib/device/outlet.js +148 -0
  22. package/lib/device/purifier.js +468 -0
  23. package/lib/device/simulation/purifier-insight.js +357 -0
  24. package/lib/device/simulation/purifier.js +159 -0
  25. package/lib/device/simulation/switch-insight.js +315 -0
  26. package/lib/device/simulation/switch.js +154 -0
  27. package/lib/fakegato/LICENSE +21 -0
  28. package/lib/fakegato/fakegato-history.js +814 -0
  29. package/lib/fakegato/fakegato-storage.js +108 -0
  30. package/lib/fakegato/fakegato-timer.js +125 -0
  31. package/lib/fakegato/uuid.js +27 -0
  32. package/lib/homebridge-ui/public/index.html +315 -0
  33. package/lib/homebridge-ui/server.js +10 -0
  34. package/lib/index.js +8 -0
  35. package/lib/platform.js +1423 -0
  36. package/lib/utils/colour.js +135 -0
  37. package/lib/utils/constants.js +129 -0
  38. package/lib/utils/eve-chars.js +130 -0
  39. package/lib/utils/functions.js +52 -0
  40. package/lib/utils/lang-en.js +125 -0
  41. package/package.json +70 -0
@@ -0,0 +1,148 @@
1
+ import platformConsts from '../utils/constants.js'
2
+ import { hasProperty, parseError } from '../utils/functions.js'
3
+ import platformLang from '../utils/lang-en.js'
4
+
5
+ export default class {
6
+ constructor(platform, accessory) {
7
+ // Set up variables from the platform
8
+ this.eveChar = platform.eveChar
9
+ this.hapChar = platform.api.hap.Characteristic
10
+ this.hapServ = platform.api.hap.Service
11
+ this.platform = platform
12
+
13
+ // Set up variables from the accessory
14
+ this.accessory = accessory
15
+
16
+ // Set up custom variables for this device type
17
+ const deviceConf = platform.deviceConf[accessory.context.serialNumber] || {}
18
+ this.noMotionTimer = deviceConf.noMotionTimer || platformConsts.defaultValues.noMotionTimer
19
+
20
+ // Add the motion sensor service if it doesn't already exist
21
+ this.service = this.accessory.getService(this.hapServ.MotionSensor)
22
+ || this.accessory.addService(this.hapServ.MotionSensor)
23
+
24
+ // Pass the accessory to fakegato to set up the Eve info service
25
+ this.accessory.historyService = new platform.eveService('motion', this.accessory, {
26
+ log: () => {},
27
+ })
28
+
29
+ // Output the customised options to the log
30
+ const opts = JSON.stringify({
31
+ noMotionTimer: this.noMotionTimer,
32
+ })
33
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
34
+
35
+ // Request a device update immediately
36
+ this.requestDeviceUpdate()
37
+
38
+ // Start a polling interval if the user has disabled upnp
39
+ if (this.accessory.context.connection === 'http') {
40
+ this.pollingInterval = setInterval(
41
+ () => this.requestDeviceUpdate(),
42
+ platform.config.pollingInterval * 1000,
43
+ )
44
+ }
45
+ }
46
+
47
+ receiveDeviceUpdate(attribute) {
48
+ // Log the receiving update if debug is enabled
49
+ this.accessory.logDebug(`${platformLang.recUpd} [${attribute.name}: ${JSON.stringify(attribute.value)}]`)
50
+
51
+ // Send a HomeKit needed true/false argument
52
+ // attribute.value is 1 if and only if motion is detected
53
+ this.externalUpdate(attribute.value === 1)
54
+ }
55
+
56
+ async requestDeviceUpdate() {
57
+ try {
58
+ // Request the update
59
+ const data = await this.platform.httpClient.sendDeviceUpdate(
60
+ this.accessory,
61
+ 'urn:Belkin:service:basicevent:1',
62
+ 'GetBinaryState',
63
+ )
64
+
65
+ // Check for existence since BinaryState can be int 0
66
+ if (hasProperty(data, 'BinaryState')) {
67
+ // Send the data to the receiver function
68
+ this.receiveDeviceUpdate({
69
+ name: 'BinaryState',
70
+ value: Number.parseInt(data.BinaryState, 10),
71
+ })
72
+ }
73
+ } catch (err) {
74
+ const eText = parseError(err, [
75
+ platformLang.timeout,
76
+ platformLang.timeoutUnreach,
77
+ platformLang.noService,
78
+ ])
79
+ this.accessory.logDebugWarn(`${platformLang.rduErr} ${eText}`)
80
+ }
81
+ }
82
+
83
+ externalUpdate(value) {
84
+ try {
85
+ // Obtain the previous state of the motion sensor
86
+ const prevState = this.service.getCharacteristic(this.hapChar.MotionDetected).value
87
+
88
+ // Don't continue in the following cases:
89
+ // (1) the previous state is the same as before and the motion timer isn't running
90
+ // (2) the new value is 'no motion detected' but the motion timer is still running
91
+ if ((value === prevState && !this.motionTimer) || (!value && this.motionTimer)) {
92
+ return
93
+ }
94
+
95
+ // Next logic depends on two cases
96
+ if (value || this.noMotionTimer === 0) {
97
+ // CASE: new motion detected or the user motion timer is set to 0 seconds
98
+ // If a motion timer is already present then stop it
99
+ if (this.motionTimer) {
100
+ this.accessory.log(platformLang.timerStopped)
101
+ clearTimeout(this.motionTimer)
102
+ this.motionTimer = false
103
+ }
104
+
105
+ // Update the HomeKit characteristics
106
+ this.service.updateCharacteristic(this.hapChar.MotionDetected, value)
107
+
108
+ // Add the entry to Eve
109
+ this.accessory.historyService.addEntry({ status: value ? 1 : 0 })
110
+
111
+ // If motion detected then update the LastActivation Eve characteristic
112
+ if (value) {
113
+ this.service.updateCharacteristic(
114
+ this.eveChar.LastActivation,
115
+ Math.round(new Date().valueOf() / 1000) - this.accessory.historyService.getInitialTime(),
116
+ )
117
+ }
118
+
119
+ // Log the change if appropriate
120
+ this.accessory.log(`${platformLang.motionSensor} [${value ? platformLang.motionYes : platformLang.motionNo}]`)
121
+ } else {
122
+ // CASE: motion not detected and the user motion timer is more than 0 seconds
123
+ this.accessory.log(`${platformLang.timerStarted} [${this.noMotionTimer}s]`)
124
+
125
+ // Clear any existing timers
126
+ clearTimeout(this.motionTimer)
127
+
128
+ // Create a new 'no motion timer'
129
+ this.motionTimer = setTimeout(() => {
130
+ // Update the HomeKit characteristic to false
131
+ this.service.updateCharacteristic(this.hapChar.MotionDetected, false)
132
+
133
+ // Add a no motion detected value to Eve
134
+ this.accessory.historyService.addEntry({ status: 0 })
135
+
136
+ // Log the change if appropriate
137
+ this.accessory.log(`${platformLang.motionSensor} [${platformLang.motionNo}] [${platformLang.timerComplete}]`)
138
+
139
+ // Set the motion timer in use to false
140
+ this.motionTimer = false
141
+ }, this.noMotionTimer * 1000)
142
+ }
143
+ } catch (err) {
144
+ // Catch any errors
145
+ this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
146
+ }
147
+ }
148
+ }
@@ -0,0 +1,148 @@
1
+ import { hasProperty, parseError } from '../utils/functions.js'
2
+ import platformLang from '../utils/lang-en.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.platform = platform
11
+
12
+ // Set up variables from the accessory
13
+ this.accessory = accessory
14
+
15
+ // If the accessory has a switch service then remove it
16
+ if (this.accessory.getService(this.hapServ.Switch)) {
17
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Switch))
18
+ }
19
+
20
+ // If the accessory has an air purifier service then remove it
21
+ if (this.accessory.getService(this.hapServ.AirPurifier)) {
22
+ this.accessory.removeService(this.accessory.getService(this.hapServ.AirPurifier))
23
+ }
24
+
25
+ // Add the outlet service if it doesn't already exist
26
+ this.service = this.accessory.getService(this.hapServ.Outlet)
27
+ || this.accessory.addService(this.hapServ.Outlet)
28
+
29
+ // Add the set handler to the outlet on/off characteristic
30
+ this.service
31
+ .getCharacteristic(this.hapChar.On)
32
+ .removeOnSet()
33
+ .onSet(async value => this.internalStateUpdate(value))
34
+
35
+ // Remove the outlet-in-use characteristic as it only matches the state in this case
36
+ if (this.service.testCharacteristic(this.hapChar.OutletInUse)) {
37
+ this.service.removeCharacteristic(this.service.getCharacteristic(this.hapChar.OutletInUse))
38
+ }
39
+
40
+ // Output the customised options to the log
41
+ const opts = JSON.stringify({
42
+ showAs: 'outlet',
43
+ })
44
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
45
+
46
+ // Request a device update immediately
47
+ this.requestDeviceUpdate()
48
+
49
+ // Start a polling interval if the user has disabled upnp
50
+ if (this.accessory.context.connection === 'http') {
51
+ this.pollingInterval = setInterval(
52
+ () => this.requestDeviceUpdate(),
53
+ platform.config.pollingInterval * 1000,
54
+ )
55
+ }
56
+ }
57
+
58
+ receiveDeviceUpdate(attribute) {
59
+ // Log the receiving update if debug is enabled
60
+ this.accessory.logDebug(`${platformLang.recUpd} [${attribute.name}: ${JSON.stringify(attribute.value)}]`)
61
+
62
+ // Send a HomeKit needed true/false argument
63
+ // attribute.value is 0 if and only if the outlet is off
64
+ this.externalStateUpdate(attribute.value !== 0)
65
+ }
66
+
67
+ async sendDeviceUpdate(value) {
68
+ // Log the sending update if debug is enabled
69
+ this.accessory.logDebug(`${platformLang.senUpd} ${JSON.stringify(value)}`)
70
+
71
+ // Send the update
72
+ await this.platform.httpClient.sendDeviceUpdate(
73
+ this.accessory,
74
+ 'urn:Belkin:service:basicevent:1',
75
+ 'SetBinaryState',
76
+ value,
77
+ )
78
+ }
79
+
80
+ async requestDeviceUpdate() {
81
+ try {
82
+ // Request the update
83
+ const data = await this.platform.httpClient.sendDeviceUpdate(
84
+ this.accessory,
85
+ 'urn:Belkin:service:basicevent:1',
86
+ 'GetBinaryState',
87
+ )
88
+
89
+ // Check for existence since BinaryState can be int 0
90
+ if (hasProperty(data, 'BinaryState')) {
91
+ // Send the data to the receiver function
92
+ this.receiveDeviceUpdate({
93
+ name: 'BinaryState',
94
+ value: Number.parseInt(data.BinaryState, 10),
95
+ })
96
+ }
97
+ } catch (err) {
98
+ const eText = parseError(err, [
99
+ platformLang.timeout,
100
+ platformLang.timeoutUnreach,
101
+ platformLang.noService,
102
+ ])
103
+ this.accessory.logDebugWarn(`${platformLang.rduErr} ${eText}`)
104
+ }
105
+ }
106
+
107
+ async internalStateUpdate(value) {
108
+ try {
109
+ // Send the update
110
+ await this.sendDeviceUpdate({
111
+ BinaryState: value ? 1 : 0,
112
+ })
113
+
114
+ // Update the cache value and log the change if appropriate
115
+ this.cacheState = value
116
+ this.accessory.log(`${platformLang.curState} [${value ? 'on' : 'off'}]`)
117
+ } catch (err) {
118
+ // Catch any errors
119
+ const eText = parseError(err, [platformLang.timeout, platformLang.timeoutUnreach])
120
+ this.accessory.logWarn(`${platformLang.cantCtl} ${eText}`)
121
+
122
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
123
+ setTimeout(() => {
124
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState)
125
+ }, 2000)
126
+ throw new this.hapErr(-70402)
127
+ }
128
+ }
129
+
130
+ externalStateUpdate(value) {
131
+ try {
132
+ // Check to see if the cache value is different
133
+ if (value === this.cacheState) {
134
+ return
135
+ }
136
+
137
+ // Update the HomeKit characteristics
138
+ this.service.updateCharacteristic(this.hapChar.On, value)
139
+
140
+ // Update the cache value and log the change if appropriate
141
+ this.cacheState = value
142
+ this.accessory.log(`${platformLang.curState} [${value ? 'on' : 'off'}]`)
143
+ } catch (err) {
144
+ // Catch any errors
145
+ this.accessory.logWarn(`${platformLang.cantUpd} ${parseError(err)}`)
146
+ }
147
+ }
148
+ }