@homebridge-plugins/homebridge-govee 10.12.1

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 (78) hide show
  1. package/CHANGELOG.md +1937 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/config.schema.json +1727 -0
  5. package/eslint.config.js +49 -0
  6. package/lib/connection/aws.js +174 -0
  7. package/lib/connection/ble.js +208 -0
  8. package/lib/connection/cert/AmazonRootCA1.pem +20 -0
  9. package/lib/connection/http.js +240 -0
  10. package/lib/connection/lan.js +284 -0
  11. package/lib/device/cooler-single.js +300 -0
  12. package/lib/device/dehumidifier-H7150.js +182 -0
  13. package/lib/device/dehumidifier-H7151.js +157 -0
  14. package/lib/device/diffuser-H7161.js +117 -0
  15. package/lib/device/diffuser-H7162.js +117 -0
  16. package/lib/device/fan-H7100.js +274 -0
  17. package/lib/device/fan-H7101.js +330 -0
  18. package/lib/device/fan-H7102.js +274 -0
  19. package/lib/device/fan-H7105.js +503 -0
  20. package/lib/device/fan-H7106.js +274 -0
  21. package/lib/device/fan-H7111.js +335 -0
  22. package/lib/device/heater-single.js +300 -0
  23. package/lib/device/heater1a.js +353 -0
  24. package/lib/device/heater1b.js +616 -0
  25. package/lib/device/heater2.js +838 -0
  26. package/lib/device/humidifier-H7140.js +224 -0
  27. package/lib/device/humidifier-H7141.js +257 -0
  28. package/lib/device/humidifier-H7142.js +522 -0
  29. package/lib/device/humidifier-H7143.js +157 -0
  30. package/lib/device/humidifier-H7148.js +157 -0
  31. package/lib/device/humidifier-H7160.js +446 -0
  32. package/lib/device/ice-maker-H7162.js +46 -0
  33. package/lib/device/index.js +105 -0
  34. package/lib/device/kettle.js +269 -0
  35. package/lib/device/light-switch.js +86 -0
  36. package/lib/device/light.js +617 -0
  37. package/lib/device/outlet-double.js +121 -0
  38. package/lib/device/outlet-single.js +172 -0
  39. package/lib/device/outlet-triple.js +160 -0
  40. package/lib/device/purifier-H7120.js +336 -0
  41. package/lib/device/purifier-H7121.js +336 -0
  42. package/lib/device/purifier-H7122.js +449 -0
  43. package/lib/device/purifier-H7123.js +411 -0
  44. package/lib/device/purifier-H7124.js +411 -0
  45. package/lib/device/purifier-H7126.js +296 -0
  46. package/lib/device/purifier-H7127.js +296 -0
  47. package/lib/device/purifier-H712C.js +296 -0
  48. package/lib/device/purifier-single.js +119 -0
  49. package/lib/device/sensor-button.js +22 -0
  50. package/lib/device/sensor-contact.js +22 -0
  51. package/lib/device/sensor-leak.js +87 -0
  52. package/lib/device/sensor-monitor.js +190 -0
  53. package/lib/device/sensor-presence.js +53 -0
  54. package/lib/device/sensor-thermo.js +144 -0
  55. package/lib/device/sensor-thermo4.js +55 -0
  56. package/lib/device/switch-double.js +121 -0
  57. package/lib/device/switch-single.js +95 -0
  58. package/lib/device/switch-triple.js +160 -0
  59. package/lib/device/tap-single.js +108 -0
  60. package/lib/device/template.js +43 -0
  61. package/lib/device/tv-single.js +84 -0
  62. package/lib/device/valve-single.js +155 -0
  63. package/lib/fakegato/LICENSE +21 -0
  64. package/lib/fakegato/fakegato-history.js +814 -0
  65. package/lib/fakegato/fakegato-storage.js +108 -0
  66. package/lib/fakegato/fakegato-timer.js +125 -0
  67. package/lib/fakegato/uuid.js +27 -0
  68. package/lib/homebridge-ui/public/index.html +433 -0
  69. package/lib/homebridge-ui/server.js +10 -0
  70. package/lib/index.js +8 -0
  71. package/lib/platform.js +1967 -0
  72. package/lib/utils/colour.js +564 -0
  73. package/lib/utils/constants.js +579 -0
  74. package/lib/utils/custom-chars.js +225 -0
  75. package/lib/utils/eve-chars.js +68 -0
  76. package/lib/utils/functions.js +117 -0
  77. package/lib/utils/lang-en.js +131 -0
  78. package/package.json +75 -0
@@ -0,0 +1,55 @@
1
+ import { base64ToHex, getTwoItemPosition, hexToTwoItems } 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
+ // remove temperature sensor, humidity sensor, battery service
16
+ if (this.accessory.getService(this.hapServ.TemperatureSensor)) {
17
+ this.accessory.removeService(this.accessory.getService(this.hapServ.TemperatureSensor))
18
+ }
19
+ if (this.accessory.getService(this.hapServ.HumiditySensor)) {
20
+ this.accessory.removeService(this.accessory.getService(this.hapServ.HumiditySensor))
21
+ }
22
+ if (this.accessory.getService(this.hapServ.Battery)) {
23
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Battery))
24
+ }
25
+
26
+ // Output the customised options to the log
27
+ const opts = JSON.stringify({})
28
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
29
+ }
30
+
31
+ externalUpdate(params) {
32
+ this.accessory.logWarn(JSON.stringify(params, null, 2));
33
+
34
+ // Check for some other scene/mode change
35
+ (params.commands || []).forEach((command) => {
36
+ const hexString = base64ToHex(command)
37
+ const hexParts = hexToTwoItems(hexString)
38
+
39
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
40
+
41
+ // Return now if not a device query update code
42
+ if (getTwoItemPosition(hexParts, 1) !== 'aa') {
43
+ return
44
+ }
45
+
46
+ const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`
47
+
48
+ switch (deviceFunction) {
49
+ default:
50
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
51
+ break
52
+ }
53
+ })
54
+ }
55
+ }
@@ -0,0 +1,121 @@
1
+ import { 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
+ // Remove outlet services if they exist
16
+ if (this.accessory.getService('Outlet 1')) {
17
+ this.accessory.removeService(this.accessory.getService('Outlet 1'))
18
+ }
19
+ if (this.accessory.getService('Outlet 2')) {
20
+ this.accessory.removeService(this.accessory.getService('Outlet 2'))
21
+ }
22
+
23
+ // Add the switch services if they don't already exist
24
+ this.service1 = this.accessory.getService('Switch 1')
25
+ || this.accessory.addService(this.hapServ.Switch, 'Switch 1', 'switch1')
26
+ this.service2 = this.accessory.getService('Switch 2')
27
+ || this.accessory.addService(this.hapServ.Switch, 'Switch 2', 'switch2')
28
+
29
+ if (!this.service1.testCharacteristic(this.hapChar.ConfiguredName)) {
30
+ this.service1.addCharacteristic(this.hapChar.ConfiguredName)
31
+ this.service1.updateCharacteristic(this.hapChar.ConfiguredName, 'Switch 1')
32
+ }
33
+ if (!this.service1.testCharacteristic(this.hapChar.ServiceLabelIndex)) {
34
+ this.service1.addCharacteristic(this.hapChar.ServiceLabelIndex)
35
+ this.service1.updateCharacteristic(this.hapChar.ServiceLabelIndex, 1)
36
+ }
37
+ if (!this.service2.testCharacteristic(this.hapChar.ConfiguredName)) {
38
+ this.service2.addCharacteristic(this.hapChar.ConfiguredName)
39
+ this.service2.updateCharacteristic(this.hapChar.ConfiguredName, 'Switch 2')
40
+ }
41
+ if (!this.service2.testCharacteristic(this.hapChar.ServiceLabelIndex)) {
42
+ this.service2.addCharacteristic(this.hapChar.ServiceLabelIndex)
43
+ this.service2.updateCharacteristic(this.hapChar.ServiceLabelIndex, 2)
44
+ }
45
+
46
+ // Add the set handler to the switch on/off characteristic
47
+ this.service1.getCharacteristic(this.hapChar.On).onSet(async (value) => {
48
+ await this.internalStateUpdate(this.service1, value ? 34 : 32)
49
+ })
50
+ this.service1.cacheState = this.service1.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
51
+ this.service2.getCharacteristic(this.hapChar.On).onSet(async (value) => {
52
+ await this.internalStateUpdate(this.service2, value ? 17 : 16)
53
+ })
54
+ this.service2.cacheState = this.service2.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
55
+
56
+ // Output the customised options to the log
57
+ const opts = JSON.stringify({
58
+ showAs: 'switch',
59
+ })
60
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
61
+
62
+ // 51 turns BOTH ON
63
+ // 48 turns BOTH OFF
64
+ // 34 turns outlet 1 ON
65
+ // 32 turns outlet 1 OFF
66
+ // 17 turns outlet 2 ON
67
+ // 16 turns outlet 2 OFF
68
+ }
69
+
70
+ async internalStateUpdate(service, value) {
71
+ try {
72
+ const newValue = value % 16 === 0 ? 'off' : 'on'
73
+
74
+ // Don't continue if the new value is the same as before
75
+ if (service.cacheState === newValue) {
76
+ return
77
+ }
78
+
79
+ // Send the request to the platform sender function
80
+ await this.platform.sendDeviceUpdate(this.accessory, {
81
+ cmd: 'stateDual',
82
+ value,
83
+ })
84
+
85
+ // Cache the new state and log if appropriate
86
+ if (service.cacheState !== newValue) {
87
+ service.cacheState = newValue
88
+ this.accessory.log(`[${service.getCharacteristic(this.hapChar.ConfiguredName).value}] ${platformLang.curState} [${newValue}]`)
89
+ }
90
+ } catch (err) {
91
+ // Catch any errors during the process
92
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
93
+
94
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
95
+ setTimeout(() => {
96
+ service.updateCharacteristic(this.hapChar.On, service.cacheState === 'on')
97
+ }, 2000)
98
+ throw new this.hapErr(-70402)
99
+ }
100
+ }
101
+
102
+ externalUpdate(params) {
103
+ if (!Array.isArray(params.state)) {
104
+ return
105
+ }
106
+
107
+ if (params.state[0] !== this.service1.cacheState) {
108
+ this.service1.cacheState = params.state[0]
109
+ this.service1.updateCharacteristic(this.hapChar.On, this.service1.cacheState === 'on')
110
+
111
+ this.accessory.log(`[${this.service1.getCharacteristic(this.hapChar.ConfiguredName).value}] ${platformLang.curState} [${this.service1.cacheState}]`)
112
+ }
113
+
114
+ if (params.state[1] !== this.service2.cacheState) {
115
+ this.service2.cacheState = params.state[1]
116
+ this.service2.updateCharacteristic(this.hapChar.On, this.service2.cacheState === 'on')
117
+
118
+ this.accessory.log(`[${this.service2.getCharacteristic(this.hapChar.ConfiguredName).value}] ${platformLang.curState} [${this.service2.cacheState}]`)
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,95 @@
1
+ import { 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
+ // Remove any old services from simulations
16
+ ['AirPurifier', 'HeaterCooler', 'Lightbulb', 'Outlet', 'Valve'].forEach((service) => {
17
+ if (this.accessory.getService(this.hapServ[service])) {
18
+ this.accessory.removeService(this.accessory.getService(this.hapServ[service]))
19
+ }
20
+ })
21
+
22
+ // Add the switch service if it doesn't already exist
23
+ this.service = this.accessory.getService(this.hapServ.Switch)
24
+ || this.accessory.addService(this.hapServ.Switch)
25
+
26
+ // Add the set handler to the switch on/off characteristic
27
+ this.service.getCharacteristic(this.hapChar.On).onSet(async (value) => {
28
+ await this.internalStateUpdate(value)
29
+ })
30
+ this.cacheState = this.service.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
31
+
32
+ // Pass the accessory to Fakegato to set up with Eve
33
+ this.accessory.eveService = new platform.eveService('switch', this.accessory, {
34
+ log: () => {},
35
+ })
36
+
37
+ // Output the customised options to the log
38
+ const opts = JSON.stringify({
39
+ showAs: 'switch',
40
+ })
41
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
42
+ }
43
+
44
+ async internalStateUpdate(value) {
45
+ try {
46
+ const newValue = value ? 'on' : 'off'
47
+
48
+ // Don't continue if the new value is the same as before
49
+ if (newValue === this.cacheState) {
50
+ return
51
+ }
52
+
53
+ // Send the request to the platform sender function
54
+ await this.platform.sendDeviceUpdate(this.accessory, {
55
+ cmd: 'stateOutlet',
56
+ value: newValue,
57
+ })
58
+
59
+ // Cache the new state and log if appropriate
60
+ if (this.cacheState !== newValue) {
61
+ this.cacheState = newValue
62
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
63
+ }
64
+
65
+ // Add the entry to the Eve history service
66
+ this.accessory.eveService.addEntry({ status: value ? 1 : 0 })
67
+ } catch (err) {
68
+ // Catch any errors during the process
69
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
70
+
71
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
72
+ setTimeout(() => {
73
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
74
+ }, 2000)
75
+ throw new this.hapErr(-70402)
76
+ }
77
+ }
78
+
79
+ externalUpdate(params) {
80
+ // Check to see if the provided state is different from the cached state
81
+ if (params.state && params.state !== this.cacheState) {
82
+ // State is different so update Homebridge with new values
83
+ this.cacheState = params.state
84
+ this.service.updateCharacteristic(this.hapChar.On, this.cacheState === 'on')
85
+
86
+ // Log the change
87
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
88
+
89
+ // Add the entry to the Eve history service
90
+ this.accessory.eveService.addEntry({
91
+ status: this.cacheState === 'on' ? 1 : 0,
92
+ })
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,160 @@
1
+ import { 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
+ // Remove outlet services if they exist
16
+ if (this.accessory.getService('Outlet 1')) {
17
+ this.accessory.removeService(this.accessory.getService('Outlet 1'))
18
+ }
19
+ if (this.accessory.getService('Outlet 2')) {
20
+ this.accessory.removeService(this.accessory.getService('Outlet 2'))
21
+ }
22
+ if (this.accessory.getService('Outlet 3')) {
23
+ this.accessory.removeService(this.accessory.getService('Outlet 3'))
24
+ }
25
+
26
+ // Add the switch services if they don't already exist
27
+ this.service1 = this.accessory.getService('Switch 1')
28
+ || this.accessory.addService(this.hapServ.Switch, 'Switch 1', 'switch1')
29
+ this.service2 = this.accessory.getService('Switch 2')
30
+ || this.accessory.addService(this.hapServ.Switch, 'Switch 2', 'switch2')
31
+ this.service3 = this.accessory.getService('Switch 3')
32
+ || this.accessory.addService(this.hapServ.Switch, 'Switch 3', 'switch3')
33
+
34
+ // Add the set handler to the switch on/off characteristic
35
+ this.service1.getCharacteristic(this.hapChar.On).onSet(async (value) => {
36
+ await this.internalStateUpdate(this.service1, value ? 17 : 16)
37
+ })
38
+ this.service1.cacheState = this.service1.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
39
+ this.service2.getCharacteristic(this.hapChar.On).onSet(async (value) => {
40
+ await this.internalStateUpdate(this.service2, value ? 34 : 32)
41
+ })
42
+ this.service2.cacheState = this.service2.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
43
+ this.service3.getCharacteristic(this.hapChar.On).onSet(async (value) => {
44
+ await this.internalStateUpdate(this.service3, value ? 68 : 64)
45
+ })
46
+ this.service3.cacheState = this.service3.getCharacteristic(this.hapChar.On).value ? 'on' : 'off'
47
+
48
+ // Output the customised options to the log
49
+ const opts = JSON.stringify({
50
+ showAs: 'switch',
51
+ })
52
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
53
+
54
+ // 119 turns BOTH ON
55
+ // 112 turns BOTH OFF
56
+
57
+ // 68 turns outlet 3 ON
58
+ // 64 turns outlet 3 OFF
59
+
60
+ // 34 turns outlet 2 ON
61
+ // 32 turns outlet 2 OFF
62
+
63
+ // 17 turns outlet 1 ON
64
+ // 16 turns outlet 1 OFF
65
+ }
66
+
67
+ async internalStateUpdate(service, value) {
68
+ try {
69
+ const newValue = value % 16 === 0 ? 'off' : 'on'
70
+
71
+ // Don't continue if the new value is the same as before
72
+ if (service.cacheState === newValue) {
73
+ return
74
+ }
75
+
76
+ // Send the request to the platform sender function
77
+ await this.platform.sendDeviceUpdate(this.accessory, {
78
+ cmd: 'stateDual',
79
+ value,
80
+ })
81
+
82
+ // Cache the new state and log if appropriate
83
+ service.cacheState = newValue
84
+ this.accessory.log(`[${service.displayName}] ${platformLang.curState} [${newValue}]`)
85
+ } catch (err) {
86
+ // Catch any errors during the process
87
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
88
+
89
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
90
+ setTimeout(() => {
91
+ service.updateCharacteristic(this.hapChar.On, service.cacheState === 'on')
92
+ }, 2000)
93
+ throw new this.hapErr(-70402)
94
+ }
95
+ }
96
+
97
+ externalUpdate(params) {
98
+ // Check to see if the provided state is different from the cached state
99
+ if (!params.stateDual) {
100
+ return
101
+ }
102
+
103
+ if ([112, 119].includes(params.stateDual)) {
104
+ // 112 -> both off
105
+ // 119 -> both on
106
+ const newState = params.stateDual === 119 ? 'on' : 'off'
107
+ if (newState !== this.service1.cacheState) {
108
+ this.service1.cacheState = newState
109
+ this.service1.updateCharacteristic(this.hapChar.On, this.service1.cacheState === 'on')
110
+
111
+ // Log the change
112
+ this.accessory.log(`[${this.service1.displayName}] ${platformLang.curState} [${this.service1.cacheState}]`)
113
+ }
114
+ if (newState !== this.service2.cacheState) {
115
+ this.service2.cacheState = newState
116
+ this.service2.updateCharacteristic(this.hapChar.On, this.service2.cacheState === 'on')
117
+
118
+ // Log the change
119
+ this.accessory.log(`[${this.service2.displayName}] ${platformLang.curState} [${this.service2.cacheState}]`)
120
+ }
121
+ if (newState !== this.service3.cacheState) {
122
+ this.service3.cacheState = newState
123
+ this.service3.updateCharacteristic(this.hapChar.On, this.service3.cacheState === 'on')
124
+
125
+ // Log the change
126
+ this.accessory.log(`[${this.service3.displayName}] ${platformLang.curState} [${this.service3.cacheState}]`)
127
+ }
128
+ }
129
+ if ([16, 17].includes(params.stateDual)) {
130
+ const newState = params.stateDual === 17 ? 'on' : 'off'
131
+ if (newState !== this.service1.cacheState) {
132
+ this.service1.cacheState = newState
133
+ this.service1.updateCharacteristic(this.hapChar.On, this.service1.cacheState === 'on')
134
+
135
+ // Log the change
136
+ this.accessory.log(`[${this.service1.displayName}] ${platformLang.curState} [${this.service1.cacheState}]`)
137
+ }
138
+ }
139
+ if ([32, 34].includes(params.stateDual)) {
140
+ const newState = params.stateDual === 34 ? 'on' : 'off'
141
+ if (newState !== this.service2.cacheState) {
142
+ this.service2.cacheState = newState
143
+ this.service2.updateCharacteristic(this.hapChar.On, this.service2.cacheState === 'on')
144
+
145
+ // Log the change
146
+ this.accessory.log(`[${this.service2.displayName}] ${platformLang.curState} [${this.service2.cacheState}]`)
147
+ }
148
+ }
149
+ if ([64, 68].includes(params.stateDual)) {
150
+ const newState = params.stateDual === 68 ? 'on' : 'off'
151
+ if (newState !== this.service3.cacheState) {
152
+ this.service3.cacheState = newState
153
+ this.service3.updateCharacteristic(this.hapChar.On, this.service3.cacheState === 'on')
154
+
155
+ // Log the change
156
+ this.accessory.log(`[${this.service3.displayName}] ${platformLang.curState} [${this.service3.cacheState}]`)
157
+ }
158
+ }
159
+ }
160
+ }
@@ -0,0 +1,108 @@
1
+ import { generateRandomString, 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
+ // Remove any old services from simulations
16
+ ['AirPurifier', 'HeaterCooler', 'Lightbulb', 'Outlet', 'Switch'].forEach((service) => {
17
+ if (this.accessory.getService(this.hapServ[service])) {
18
+ this.accessory.removeService(this.accessory.getService(this.hapServ[service]))
19
+ }
20
+ })
21
+
22
+ // Make sure this wasn't setup as a valve
23
+ if (
24
+ this.accessory.getService(this.hapServ.Valve)
25
+ && this.accessory.context.valveType !== 'tap'
26
+ ) {
27
+ this.accessory.removeService(this.accessory.getService(this.hapServ.Valve))
28
+ }
29
+
30
+ // Add the tap service if it doesn't already exist
31
+ this.service = this.accessory.getService(this.hapServ.Valve)
32
+ if (!this.service) {
33
+ this.service = this.accessory.addService(this.hapServ.Valve)
34
+ this.service.updateCharacteristic(this.hapChar.Active, 0)
35
+ this.service.updateCharacteristic(this.hapChar.InUse, 0)
36
+ this.service.updateCharacteristic(this.hapChar.ValveType, 3)
37
+ this.accessory.context.valveType = 'tap'
38
+ }
39
+
40
+ // Add the set handler to the switch on/off characteristic
41
+ this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => {
42
+ await this.internalStateUpdate(value)
43
+ })
44
+
45
+ // Output the customised options to the log
46
+ const opts = JSON.stringify({
47
+ showAs: 'tap',
48
+ })
49
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
50
+ }
51
+
52
+ async internalStateUpdate(value) {
53
+ try {
54
+ const newValue = value === 1 ? 'on' : 'off'
55
+
56
+ // Don't continue if the new value is the same as before
57
+ if (newValue === this.cacheState) {
58
+ return
59
+ }
60
+
61
+ // Set up a one-minute timeout for the plugin to ignore incoming updates
62
+ const timerKey = generateRandomString(5)
63
+ this.updateTimeout = timerKey
64
+ setTimeout(() => {
65
+ if (this.updateTimeout === timerKey) {
66
+ this.updateTimeout = false
67
+ }
68
+ }, 60000)
69
+
70
+ // Send the request to the platform sender function
71
+ await this.platform.sendDeviceUpdate(this.accessory, {
72
+ cmd: 'stateOutlet',
73
+ value: newValue,
74
+ })
75
+
76
+ // Cache the new state and log if appropriate
77
+ if (this.cacheState !== newValue) {
78
+ this.cacheState = newValue
79
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
80
+ }
81
+
82
+ // Update the InUse characteristic
83
+ this.service.updateCharacteristic(this.hapChar.InUse, value)
84
+ } catch (err) {
85
+ // Catch any errors during the process
86
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
87
+
88
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
89
+ setTimeout(() => {
90
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
91
+ }, 2000)
92
+ throw new this.hapErr(-70402)
93
+ }
94
+ }
95
+
96
+ externalUpdate(params) {
97
+ // Check to see if the provided state is different from the cached state
98
+ if (params.state && params.state !== this.cacheState) {
99
+ // State is different so update Homebridge with new values
100
+ this.cacheState = params.state
101
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
102
+ this.service.updateCharacteristic(this.hapChar.InUse, this.cacheState === 'on' ? 1 : 0)
103
+
104
+ // Log the change
105
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,43 @@
1
+ import { base64ToHex, getTwoItemPosition, hexToTwoItems } 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
+ // Output the customised options to the log
16
+ const opts = JSON.stringify({})
17
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
18
+ this.accessory.logWarn('note that support for this device is under construction, but may not be possible if this is a bluetooth-only device')
19
+ }
20
+
21
+ externalUpdate(params) {
22
+ this.accessory.logWarn(JSON.stringify(params))
23
+
24
+ // Check for some other scene/mode change
25
+ ;(params.commands || []).forEach((command) => {
26
+ const hexString = base64ToHex(command)
27
+ const hexParts = hexToTwoItems(hexString)
28
+
29
+ // Return now if not a device query update code
30
+ if (getTwoItemPosition(hexParts, 1) !== 'aa') {
31
+ return
32
+ }
33
+
34
+ const deviceFunction = `${getTwoItemPosition(hexParts, 1)}${getTwoItemPosition(hexParts, 2)}`
35
+
36
+ switch (deviceFunction) {
37
+ default:
38
+ this.accessory.logDebugWarn(`${platformLang.newScene}: [${command}] [${hexString}]`)
39
+ break
40
+ }
41
+ })
42
+ }
43
+ }
@@ -0,0 +1,84 @@
1
+ import { generateRandomString, 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
+ // Add the tv service if it doesn't already exist
16
+ this.service = this.accessory.getService(this.hapServ.Television)
17
+ || this.accessory.addService(this.hapServ.Television)
18
+
19
+ // Add the set handler to the tv active characteristic
20
+ this.service.getCharacteristic(this.hapChar.Active).onSet(async (value) => {
21
+ await this.internalUpdate(value)
22
+ })
23
+ this.cacheState = this.service.getCharacteristic(this.hapChar.Active).value === 1 ? 'on' : 'off'
24
+
25
+ // Output the customised options to the log
26
+ const opts = JSON.stringify({
27
+ showAs: 'audio/box/stick',
28
+ })
29
+ platform.log('[%s] %s %s.', accessory.displayName, platformLang.devInitOpts, opts)
30
+ }
31
+
32
+ async internalStateUpdate(value) {
33
+ try {
34
+ const newValue = value === 1 ? 'on' : 'off'
35
+
36
+ // Don't continue if the new value is the same as before
37
+ if (newValue === this.cacheState) {
38
+ return
39
+ }
40
+
41
+ // Set up a one-minute timeout for the plugin to ignore incoming updates
42
+ const timerKey = generateRandomString(5)
43
+ this.updateTimeout = timerKey
44
+ setTimeout(() => {
45
+ if (this.updateTimeout === timerKey) {
46
+ this.updateTimeout = false
47
+ }
48
+ }, 60000)
49
+
50
+ // Send the request to the platform sender function
51
+ await this.platform.sendDeviceUpdate(this.accessory, {
52
+ cmd: 'stateOutlet',
53
+ value: newValue,
54
+ })
55
+
56
+ // Cache the new state and log if appropriate
57
+ if (this.cacheState !== newValue) {
58
+ this.cacheState = newValue
59
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
60
+ }
61
+ } catch (err) {
62
+ // Catch any errors during the process
63
+ this.accessory.logWarn(`${platformLang.devNotUpdated} ${parseError(err)}`)
64
+
65
+ // Throw a 'no response' error and set a timeout to revert this after 2 seconds
66
+ setTimeout(() => {
67
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
68
+ }, 2000)
69
+ throw new this.hapErr(-70402)
70
+ }
71
+ }
72
+
73
+ externalUpdate(params) {
74
+ // Check to see if the provided state is different from the cached state
75
+ if (params.state && params.state !== this.cacheState) {
76
+ // State is different so update Homebridge with new values
77
+ this.cacheState = params.state
78
+ this.service.updateCharacteristic(this.hapChar.Active, this.cacheState === 'on' ? 1 : 0)
79
+
80
+ // Log the change
81
+ this.accessory.log(`${platformLang.curState} [${this.cacheState}]`)
82
+ }
83
+ }
84
+ }