@switchbot/homebridge-switchbot 4.0.1-beta.5 → 4.1.1-beta.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.
- package/CHANGELOG.md +9 -0
- package/dist/device/bot.js +1 -1
- package/dist/device/bot.js.map +1 -1
- package/dist/device/device.d.ts.map +1 -1
- package/dist/device/device.js +12 -4
- package/dist/device/device.js.map +1 -1
- package/dist/device/meterpro.d.ts +42 -0
- package/dist/device/meterpro.d.ts.map +1 -0
- package/dist/device/meterpro.js +369 -0
- package/dist/device/meterpro.js.map +1 -0
- package/dist/platform.d.ts +1 -0
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +63 -0
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +3 -3
- package/dist/settings.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/device/bot.ts +1 -1
- package/src/device/device.ts +12 -3
- package/src/device/meterpro.ts +417 -0
- package/src/platform.ts +65 -0
- package/src/settings.ts +3 -3
package/dist/settings.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IClientOptions } from 'async-mqtt';
|
|
2
2
|
import type { PlatformConfig } from 'homebridge';
|
|
3
|
-
import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from 'node-switchbot';
|
|
3
|
+
import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName, SwitchBotModel } from 'node-switchbot';
|
|
4
4
|
/**
|
|
5
5
|
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json
|
|
6
6
|
*/
|
|
@@ -49,7 +49,7 @@ export interface options {
|
|
|
49
49
|
export type devicesConfig = botConfig | meterConfig | indoorOutdoorSensorConfig | humidifierConfig | curtainConfig | blindTiltConfig | contactConfig | motionConfig | waterDetectorConfig | plugConfig | colorBulbConfig | stripLightConfig | ceilingLightConfig | lockConfig | hubConfig;
|
|
50
50
|
export interface BaseDeviceConfig extends device {
|
|
51
51
|
bleMac?: string;
|
|
52
|
-
model:
|
|
52
|
+
model: SwitchBotModel;
|
|
53
53
|
bleModel: SwitchBotBLEModel;
|
|
54
54
|
bleModelName: SwitchBotBLEModelName;
|
|
55
55
|
bleModelFriednlyName: SwitchBotBLEModelFriendlyName;
|
|
@@ -87,7 +87,7 @@ export interface botConfig extends BaseDeviceConfig {
|
|
|
87
87
|
multiPress?: boolean;
|
|
88
88
|
}
|
|
89
89
|
export interface meterConfig extends BaseDeviceConfig {
|
|
90
|
-
configDeviceType: 'Meter' | 'MeterPlus';
|
|
90
|
+
configDeviceType: 'Meter' | 'MeterPlus' | 'Meter Pro' | 'Meter Pro CO2';
|
|
91
91
|
hide_temperature?: boolean;
|
|
92
92
|
convertUnitTo?: string;
|
|
93
93
|
hide_humidity?: boolean;
|
package/dist/settings.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAKhD,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAC/
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@switchbot/homebridge-switchbot",
|
|
3
3
|
"displayName": "SwitchBot",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.1.1-beta.0",
|
|
6
6
|
"description": "The SwitchBot plugin allows you to access your SwitchBot device(s) from HomeKit.",
|
|
7
7
|
"author": "SwitchBot <support@wondertechlabs.com> (https://github.com/SwitchBot)",
|
|
8
8
|
"contributors": [
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"async-mqtt": "^2.6.3",
|
|
82
82
|
"fakegato-history": "^0.6.5",
|
|
83
83
|
"homebridge-lib": "^7.0.9",
|
|
84
|
-
"node-switchbot": "^3.
|
|
84
|
+
"node-switchbot": "^3.2.2-beta.0",
|
|
85
85
|
"rxjs": "^7.8.1"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"@types/debug": "^4.1.12",
|
|
91
91
|
"@types/fs-extra": "^11.0.4",
|
|
92
92
|
"@types/mdast": "^4.0.4",
|
|
93
|
-
"@types/node": "^22.7.
|
|
93
|
+
"@types/node": "^22.7.8",
|
|
94
94
|
"@types/semver": "^7.5.8",
|
|
95
95
|
"@types/source-map-support": "^0.5.10",
|
|
96
96
|
"@vitest/coverage-v8": "^2.1.3",
|
package/src/device/bot.ts
CHANGED
|
@@ -498,7 +498,7 @@ export class Bot extends deviceBase {
|
|
|
498
498
|
await this.debugLog(`Bot Mode: ${this.botMode}`)
|
|
499
499
|
if (this.botMode === 'press') {
|
|
500
500
|
switchBotBLE
|
|
501
|
-
.discover({ model:
|
|
501
|
+
.discover({ model: this.device.bleModel, quick: true, id: this.device.bleMac })
|
|
502
502
|
.then(async (device_list: SwitchbotDevice[]) => {
|
|
503
503
|
const deviceList = device_list as unknown as WoHand[]
|
|
504
504
|
await this.infoLog(`On: ${this.On}`)
|
package/src/device/device.ts
CHANGED
|
@@ -343,9 +343,6 @@ export abstract class deviceBase {
|
|
|
343
343
|
this.debugLog(`address: ${ad.address}, model: ${ad.serviceData.model}`)
|
|
344
344
|
this.debugLog(`serviceData: ${JSON.stringify(ad.serviceData)}`)
|
|
345
345
|
serviceData = ad.serviceData
|
|
346
|
-
} else {
|
|
347
|
-
serviceData = { model: '', modelName: '', modelFriendlyName: '' } as unknown as ad['serviceData']
|
|
348
|
-
this.debugLog(`serviceData: ${JSON.stringify(ad.serviceData)}`)
|
|
349
346
|
}
|
|
350
347
|
}
|
|
351
348
|
// Wait
|
|
@@ -481,6 +478,18 @@ export abstract class deviceBase {
|
|
|
481
478
|
bleModelName: SwitchBotBLEModelName.MeterPlus,
|
|
482
479
|
bleModelFriendlyName: SwitchBotBLEModelFriendlyName.MeterPlus,
|
|
483
480
|
},
|
|
481
|
+
'Meter Pro': {
|
|
482
|
+
model: SwitchBotModel.MeterPro,
|
|
483
|
+
bleModel: SwitchBotBLEModel.MeterPro,
|
|
484
|
+
bleModelName: SwitchBotBLEModelName.MeterPro,
|
|
485
|
+
bleModelFriendlyName: SwitchBotBLEModelFriendlyName.MeterPro,
|
|
486
|
+
},
|
|
487
|
+
'Meter Pro CO2': {
|
|
488
|
+
model: SwitchBotModel.MeterProCO2,
|
|
489
|
+
bleModel: SwitchBotBLEModel.MeterPro,
|
|
490
|
+
bleModelName: SwitchBotBLEModelName.MeterPro,
|
|
491
|
+
bleModelFriendlyName: SwitchBotBLEModelFriendlyName.MeterPro,
|
|
492
|
+
},
|
|
484
493
|
'WoIOSensor': {
|
|
485
494
|
model: SwitchBotModel.OutdoorMeter,
|
|
486
495
|
bleModel: SwitchBotBLEModel.OutdoorMeter,
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/* Copyright(C) 2021-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* MeterPro.ts: @switchbot/homebridge-switchbot.
|
|
4
|
+
*/
|
|
5
|
+
import type { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'
|
|
6
|
+
import type { device, meterProServiceData, meterProStatus, meterProWebhookContext } from 'node-switchbot'
|
|
7
|
+
|
|
8
|
+
import type { SwitchBotPlatform } from '../platform.js'
|
|
9
|
+
import type { devicesConfig, meterConfig } from '../settings.js'
|
|
10
|
+
|
|
11
|
+
import { Units } from 'homebridge'
|
|
12
|
+
/*
|
|
13
|
+
* For Testing Locally:
|
|
14
|
+
* import { SwitchBotBLEModel, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
|
|
15
|
+
*/
|
|
16
|
+
import { SwitchBotBLEModel, SwitchBotBLEModelName } from 'node-switchbot'
|
|
17
|
+
import { interval, skipWhile, Subject } from 'rxjs'
|
|
18
|
+
|
|
19
|
+
import { convertUnits, formatDeviceIdAsMac, validHumidity } from '../utils.js'
|
|
20
|
+
import { deviceBase } from './device.js'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Platform Accessory
|
|
24
|
+
* An instance of this class is created for each accessory your platform registers
|
|
25
|
+
* Each accessory may expose multiple services of different service types.
|
|
26
|
+
*/
|
|
27
|
+
export class MeterPro extends deviceBase {
|
|
28
|
+
// Services
|
|
29
|
+
private Battery: {
|
|
30
|
+
Name: CharacteristicValue
|
|
31
|
+
Service: Service
|
|
32
|
+
BatteryLevel: CharacteristicValue
|
|
33
|
+
StatusLowBattery: CharacteristicValue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private HumiditySensor?: {
|
|
37
|
+
Name: CharacteristicValue
|
|
38
|
+
Service: Service
|
|
39
|
+
CurrentRelativeHumidity: CharacteristicValue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private TemperatureSensor?: {
|
|
43
|
+
Name: CharacteristicValue
|
|
44
|
+
Service: Service
|
|
45
|
+
CurrentTemperature: CharacteristicValue
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// OpenAPI
|
|
49
|
+
deviceStatus!: meterProStatus
|
|
50
|
+
|
|
51
|
+
// Webhook
|
|
52
|
+
webhookContext!: meterProWebhookContext
|
|
53
|
+
|
|
54
|
+
// BLE
|
|
55
|
+
serviceData!: meterProServiceData
|
|
56
|
+
|
|
57
|
+
// Updates
|
|
58
|
+
meterUpdateInProgress!: boolean
|
|
59
|
+
doMeterUpdate: Subject<void>
|
|
60
|
+
|
|
61
|
+
constructor(
|
|
62
|
+
readonly platform: SwitchBotPlatform,
|
|
63
|
+
accessory: PlatformAccessory,
|
|
64
|
+
device: device & devicesConfig,
|
|
65
|
+
) {
|
|
66
|
+
super(platform, accessory, device)
|
|
67
|
+
// Set category
|
|
68
|
+
accessory.category = this.hap.Categories.SENSOR
|
|
69
|
+
|
|
70
|
+
// this is subject we use to track when we need to POST changes to the SwitchBot API
|
|
71
|
+
this.doMeterUpdate = new Subject()
|
|
72
|
+
this.meterUpdateInProgress = false
|
|
73
|
+
|
|
74
|
+
// Initialize Battery Service
|
|
75
|
+
accessory.context.Battery = accessory.context.Battery ?? {}
|
|
76
|
+
this.Battery = {
|
|
77
|
+
Name: `${accessory.displayName} Battery`,
|
|
78
|
+
Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
|
|
79
|
+
BatteryLevel: accessory.context.BatteryLevel ?? 100,
|
|
80
|
+
StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
|
|
81
|
+
}
|
|
82
|
+
accessory.context.Battery = this.Battery as object
|
|
83
|
+
|
|
84
|
+
// Initialize Battery Characteristics
|
|
85
|
+
this.Battery.Service.setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name).setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE).getCharacteristic(this.hap.Characteristic.BatteryLevel).onGet(() => {
|
|
86
|
+
return this.Battery.BatteryLevel
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
this.Battery.Service.getCharacteristic(this.hap.Characteristic.StatusLowBattery).onGet(() => {
|
|
90
|
+
return this.Battery.StatusLowBattery
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Initialize Temperature Sensor Service
|
|
94
|
+
if ((device as meterConfig).hide_temperature) {
|
|
95
|
+
if (this.TemperatureSensor) {
|
|
96
|
+
this.debugLog('Removing Temperature Sensor Service')
|
|
97
|
+
this.TemperatureSensor.Service = this.accessory.getService(this.hap.Service.TemperatureSensor) as Service
|
|
98
|
+
accessory.removeService(this.TemperatureSensor.Service)
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {}
|
|
102
|
+
this.TemperatureSensor = {
|
|
103
|
+
Name: `${accessory.displayName} Temperature Sensor`,
|
|
104
|
+
Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? this.accessory.addService(this.hap.Service.TemperatureSensor) as Service,
|
|
105
|
+
CurrentTemperature: accessory.context.CurrentTemperature ?? 30,
|
|
106
|
+
}
|
|
107
|
+
accessory.context.TemperatureSensor = this.TemperatureSensor as object
|
|
108
|
+
|
|
109
|
+
// Initialize Temperature Sensor Characteristics
|
|
110
|
+
this.TemperatureSensor.Service.setCharacteristic(this.hap.Characteristic.Name, this.TemperatureSensor.Name).getCharacteristic(this.hap.Characteristic.CurrentTemperature).setProps({
|
|
111
|
+
unit: Units.CELSIUS,
|
|
112
|
+
validValueRanges: [-273.15, 100],
|
|
113
|
+
minValue: -273.15,
|
|
114
|
+
maxValue: 100,
|
|
115
|
+
minStep: 0.1,
|
|
116
|
+
}).onGet(() => {
|
|
117
|
+
return this.TemperatureSensor!.CurrentTemperature!
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
// Initialize Humidity Sensor Service
|
|
121
|
+
if ((device as meterConfig).hide_humidity) {
|
|
122
|
+
if (this.HumiditySensor) {
|
|
123
|
+
this.debugLog('Removing Humidity Sensor Service')
|
|
124
|
+
this.HumiditySensor.Service = this.accessory.getService(this.hap.Service.HumiditySensor) as Service
|
|
125
|
+
accessory.removeService(this.HumiditySensor.Service)
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {}
|
|
129
|
+
this.HumiditySensor = {
|
|
130
|
+
Name: `${accessory.displayName} Humidity Sensor`,
|
|
131
|
+
Service: accessory.getService(this.hap.Service.HumiditySensor) ?? this.accessory.addService(this.hap.Service.HumiditySensor) as Service,
|
|
132
|
+
CurrentRelativeHumidity: accessory.context.CurrentRelativeHumidity ?? 50,
|
|
133
|
+
}
|
|
134
|
+
accessory.context.HumiditySensor = this.HumiditySensor as object
|
|
135
|
+
|
|
136
|
+
// Initialize Humidity Sensor Characteristics
|
|
137
|
+
this.HumiditySensor.Service.setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name).getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity).setProps({
|
|
138
|
+
minStep: 0.1,
|
|
139
|
+
}).onGet(() => {
|
|
140
|
+
return this.HumiditySensor!.CurrentRelativeHumidity!
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Retrieve initial values and updateHomekit
|
|
145
|
+
try {
|
|
146
|
+
this.debugLog('Retrieve initial values and update Homekit')
|
|
147
|
+
this.refreshStatus()
|
|
148
|
+
} catch (e: any) {
|
|
149
|
+
this.errorLog(`failed to retrieve initial values and update Homekit, Error: ${e.message ?? e}`)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// regisiter webhook event handler if enabled
|
|
153
|
+
try {
|
|
154
|
+
this.debugLog('Registering Webhook Event Handler')
|
|
155
|
+
this.registerWebhook()
|
|
156
|
+
} catch (e: any) {
|
|
157
|
+
this.errorLog(`failed to registerWebhook, Error: ${e.message ?? e}`)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// regisiter platform BLE event handler if enabled
|
|
161
|
+
try {
|
|
162
|
+
this.debugLog('Registering Platform BLE Event Handler')
|
|
163
|
+
this.registerPlatformBLE()
|
|
164
|
+
} catch (e: any) {
|
|
165
|
+
this.errorLog(`failed to registerPlatformBLE, Error: ${e.message ?? e}`)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Start an update interval
|
|
169
|
+
interval(this.deviceRefreshRate * 1000)
|
|
170
|
+
.pipe(skipWhile(() => this.meterUpdateInProgress))
|
|
171
|
+
.subscribe(async () => {
|
|
172
|
+
await this.refreshStatus()
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async BLEparseStatus(): Promise<void> {
|
|
177
|
+
await this.debugLog('BLEparseStatus')
|
|
178
|
+
await this.debugLog(`(temperature, humidity) = BLE:(${this.serviceData.celsius}, ${this.serviceData.humidity}), current:(${this.TemperatureSensor?.CurrentTemperature}, ${this.HumiditySensor?.CurrentRelativeHumidity})`)
|
|
179
|
+
|
|
180
|
+
// CurrentRelativeHumidity
|
|
181
|
+
if (!(this.device as meterConfig).hide_humidity && this.HumiditySensor?.Service) {
|
|
182
|
+
this.HumiditySensor.CurrentRelativeHumidity = validHumidity(this.serviceData.humidity, 0, 100)
|
|
183
|
+
await this.debugLog(`CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}%`)
|
|
184
|
+
}
|
|
185
|
+
// Current Temperature
|
|
186
|
+
if (!(this.device as meterConfig).hide_temperature && this.TemperatureSensor?.Service) {
|
|
187
|
+
const CELSIUS = this.serviceData.celsius < 0 ? 0 : this.serviceData.celsius > 100 ? 100 : this.serviceData.celsius
|
|
188
|
+
this.TemperatureSensor.CurrentTemperature = CELSIUS
|
|
189
|
+
await this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}°c`)
|
|
190
|
+
}
|
|
191
|
+
// BatteryLevel
|
|
192
|
+
this.Battery.BatteryLevel = this.serviceData.battery
|
|
193
|
+
await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`)
|
|
194
|
+
// StatusLowBattery
|
|
195
|
+
this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
|
|
196
|
+
? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
|
|
197
|
+
: this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
|
|
198
|
+
await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async openAPIparseStatus(): Promise<void> {
|
|
202
|
+
await this.debugLog('openAPIparseStatus')
|
|
203
|
+
await this.debugLog(`(temperature, humidity) = OpenAPI:(${this.deviceStatus.temperature}, ${this.deviceStatus.humidity}), current:(${this.TemperatureSensor?.CurrentTemperature}, ${this.HumiditySensor?.CurrentRelativeHumidity})`)
|
|
204
|
+
|
|
205
|
+
// CurrentRelativeHumidity
|
|
206
|
+
if (!(this.device as meterConfig).hide_humidity && this.HumiditySensor?.Service) {
|
|
207
|
+
this.HumiditySensor.CurrentRelativeHumidity = this.deviceStatus.humidity
|
|
208
|
+
await this.debugLog(`CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}%`)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// CurrentTemperature
|
|
212
|
+
if (!(this.device as meterConfig).hide_temperature && this.TemperatureSensor?.Service) {
|
|
213
|
+
this.TemperatureSensor.CurrentTemperature = this.deviceStatus.temperature
|
|
214
|
+
await this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}°c`)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// BatteryLevel
|
|
218
|
+
this.Battery.BatteryLevel = this.deviceStatus.battery
|
|
219
|
+
await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`)
|
|
220
|
+
|
|
221
|
+
// StatusLowBattery
|
|
222
|
+
this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
|
|
223
|
+
? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW
|
|
224
|
+
: this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
|
|
225
|
+
await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`)
|
|
226
|
+
|
|
227
|
+
// FirmwareVersion
|
|
228
|
+
if (this.deviceStatus.version) {
|
|
229
|
+
const version = this.deviceStatus.version.toString()
|
|
230
|
+
this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`)
|
|
231
|
+
const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0'
|
|
232
|
+
this.accessory
|
|
233
|
+
.getService(this.hap.Service.AccessoryInformation)!
|
|
234
|
+
.setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
|
|
235
|
+
.setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
|
|
236
|
+
.getCharacteristic(this.hap.Characteristic.FirmwareRevision)
|
|
237
|
+
.updateValue(deviceVersion)
|
|
238
|
+
this.accessory.context.version = deviceVersion
|
|
239
|
+
this.debugSuccessLog(`v: ${this.accessory.context.version}`)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async parseStatusWebhook(): Promise<void> {
|
|
244
|
+
await this.debugLog('parseStatusWebhook')
|
|
245
|
+
await this.debugLog(`(scale, temperature, humidity) = Webhook:(${this.webhookContext.scale}, ${convertUnits(this.webhookContext.temperature, this.webhookContext.scale, (this.device as meterConfig).convertUnitTo)}, ${this.webhookContext.humidity}) current:(${this.TemperatureSensor?.CurrentTemperature}, ${this.HumiditySensor?.CurrentRelativeHumidity})`)
|
|
246
|
+
// Check if the scale is not CELSIUS
|
|
247
|
+
if (this.webhookContext.scale !== 'CELSIUS' && (this.device as meterConfig).convertUnitTo === undefined) {
|
|
248
|
+
await this.warnLog(`received a non-CELSIUS Webhook scale: ${this.webhookContext.scale}, Use the *convertUnitsTo* config under Hub settings, if displaying incorrectly in HomeKit.`)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// CurrentRelativeHumidity
|
|
252
|
+
if (!(this.device as meterConfig).hide_humidity && this.HumiditySensor?.Service) {
|
|
253
|
+
this.HumiditySensor.CurrentRelativeHumidity = this.webhookContext.humidity
|
|
254
|
+
await this.debugLog(`CurrentRelativeHumidity: ${this.HumiditySensor.CurrentRelativeHumidity}`)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// CurrentTemperature
|
|
258
|
+
if (!(this.device as meterConfig).hide_temperature && this.TemperatureSensor?.Service) {
|
|
259
|
+
this.TemperatureSensor.CurrentTemperature = convertUnits(this.webhookContext.temperature, this.webhookContext.scale, (this.device as meterConfig).convertUnitTo)
|
|
260
|
+
await this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}`)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Asks the SwitchBot API for the latest device information
|
|
266
|
+
*/
|
|
267
|
+
async refreshStatus(): Promise<void> {
|
|
268
|
+
if (!this.device.enableCloudService && this.OpenAPI) {
|
|
269
|
+
await this.errorLog(`refreshStatus enableCloudService: ${this.device.enableCloudService}`)
|
|
270
|
+
} else if (this.BLE) {
|
|
271
|
+
await this.BLERefreshStatus()
|
|
272
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
273
|
+
await this.openAPIRefreshStatus()
|
|
274
|
+
} else {
|
|
275
|
+
await this.offlineOff()
|
|
276
|
+
await this.debugWarnLog(`Connection Type: ${this.device.connectionType}, refreshStatus will not happen.`)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
async BLERefreshStatus(): Promise<void> {
|
|
281
|
+
await this.debugLog('BLERefreshStatus')
|
|
282
|
+
const switchBotBLE = await this.switchbotBLE()
|
|
283
|
+
if (switchBotBLE === undefined) {
|
|
284
|
+
await this.BLERefreshConnection(switchBotBLE)
|
|
285
|
+
} else {
|
|
286
|
+
// Start to monitor advertisement packets
|
|
287
|
+
(async () => {
|
|
288
|
+
// Start to monitor advertisement packets
|
|
289
|
+
const serviceData = await this.monitorAdvertisementPackets(switchBotBLE) as meterProServiceData
|
|
290
|
+
// Update HomeKit
|
|
291
|
+
if (serviceData.model === SwitchBotBLEModel.MeterPro && serviceData.modelName === SwitchBotBLEModelName.MeterPro) {
|
|
292
|
+
this.serviceData = serviceData
|
|
293
|
+
await this.BLEparseStatus()
|
|
294
|
+
await this.updateHomeKitCharacteristics()
|
|
295
|
+
} else {
|
|
296
|
+
await this.errorLog(`failed to get serviceData, serviceData: ${JSON.stringify(serviceData)}`)
|
|
297
|
+
await this.BLERefreshConnection(switchBotBLE)
|
|
298
|
+
}
|
|
299
|
+
})()
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async registerPlatformBLE(): Promise<void> {
|
|
304
|
+
await this.debugLog('registerPlatformBLE')
|
|
305
|
+
if (this.config.options?.BLE) {
|
|
306
|
+
await this.debugLog('is listening to Platform BLE.')
|
|
307
|
+
try {
|
|
308
|
+
const formattedDeviceId = formatDeviceIdAsMac(this.device.deviceId)
|
|
309
|
+
this.device.bleMac = formattedDeviceId
|
|
310
|
+
await this.debugLog(`bleMac: ${this.device.bleMac}`)
|
|
311
|
+
this.platform.bleEventHandler[this.device.bleMac] = async (context: meterProServiceData) => {
|
|
312
|
+
try {
|
|
313
|
+
await this.debugLog(`received BLE: ${JSON.stringify(context)}`)
|
|
314
|
+
this.serviceData = context
|
|
315
|
+
await this.BLEparseStatus()
|
|
316
|
+
await this.updateHomeKitCharacteristics()
|
|
317
|
+
} catch (e: any) {
|
|
318
|
+
await this.errorLog(`failed to handle BLE. Received: ${JSON.stringify(context)} Error: ${e.message ?? e}`)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
} catch (error) {
|
|
322
|
+
await this.errorLog(`failed to format device ID as MAC, Error: ${error}`)
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
await this.debugLog('is not listening to Platform BLE')
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async openAPIRefreshStatus(): Promise<void> {
|
|
330
|
+
await this.debugLog('openAPIRefreshStatus')
|
|
331
|
+
try {
|
|
332
|
+
const { body } = await this.deviceRefreshStatus()
|
|
333
|
+
const deviceStatus: any = await body
|
|
334
|
+
await this.debugLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
|
|
335
|
+
if (await this.successfulStatusCodes(deviceStatus)) {
|
|
336
|
+
await this.debugSuccessLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
|
|
337
|
+
this.deviceStatus = deviceStatus.body
|
|
338
|
+
await this.openAPIparseStatus()
|
|
339
|
+
await this.updateHomeKitCharacteristics()
|
|
340
|
+
} else {
|
|
341
|
+
await this.debugWarnLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
|
|
342
|
+
await this.debugWarnLog(deviceStatus)
|
|
343
|
+
}
|
|
344
|
+
} catch (e: any) {
|
|
345
|
+
await this.apiError(e)
|
|
346
|
+
await this.errorLog(`failed openAPIRefreshStatus with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async registerWebhook() {
|
|
351
|
+
if (this.device.webhook) {
|
|
352
|
+
await this.debugLog('is listening webhook.')
|
|
353
|
+
this.platform.webhookEventHandler[this.device.deviceId] = async (context: meterProWebhookContext) => {
|
|
354
|
+
try {
|
|
355
|
+
await this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
|
|
356
|
+
this.webhookContext = context
|
|
357
|
+
await this.parseStatusWebhook()
|
|
358
|
+
await this.updateHomeKitCharacteristics()
|
|
359
|
+
} catch (e: any) {
|
|
360
|
+
await this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e.message ?? e}`)
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
await this.debugLog('is not listening webhook.')
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Updates the status for each of the HomeKit Characteristics
|
|
370
|
+
*/
|
|
371
|
+
async updateHomeKitCharacteristics(): Promise<void> {
|
|
372
|
+
// CurrentRelativeHumidity
|
|
373
|
+
if (!(this.device as meterConfig).hide_humidity && this.HumiditySensor?.Service) {
|
|
374
|
+
await this.updateCharacteristic(this.HumiditySensor.Service, this.hap.Characteristic.CurrentRelativeHumidity, this.HumiditySensor.CurrentRelativeHumidity, 'CurrentRelativeHumidity')
|
|
375
|
+
}
|
|
376
|
+
// CurrentTemperature
|
|
377
|
+
if (!(this.device as meterConfig).hide_temperature && this.TemperatureSensor?.Service) {
|
|
378
|
+
await this.updateCharacteristic(this.TemperatureSensor.Service, this.hap.Characteristic.CurrentTemperature, this.TemperatureSensor.CurrentTemperature, 'CurrentTemperature')
|
|
379
|
+
}
|
|
380
|
+
// BatteryLevel
|
|
381
|
+
await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel, 'BatteryLevel')
|
|
382
|
+
// StatusLowBattery
|
|
383
|
+
await this.updateCharacteristic(this.Battery.Service, this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery, 'StatusLowBattery')
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async BLERefreshConnection(switchbot: any): Promise<void> {
|
|
387
|
+
await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`)
|
|
388
|
+
if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
|
|
389
|
+
await this.warnLog('Using OpenAPI Connection to Refresh Status')
|
|
390
|
+
await this.openAPIRefreshStatus()
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async offlineOff(): Promise<void> {
|
|
395
|
+
if (this.device.offline) {
|
|
396
|
+
if (!(this.device as meterConfig).hide_humidity && this.HumiditySensor?.Service) {
|
|
397
|
+
this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, 50)
|
|
398
|
+
}
|
|
399
|
+
if (!(this.device as meterConfig).hide_temperature && this.TemperatureSensor?.Service) {
|
|
400
|
+
this.TemperatureSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, 30)
|
|
401
|
+
}
|
|
402
|
+
this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, 100)
|
|
403
|
+
this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL)
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async apiError(e: any): Promise<void> {
|
|
408
|
+
if (!(this.device as meterConfig).hide_humidity && this.HumiditySensor?.Service) {
|
|
409
|
+
this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e)
|
|
410
|
+
}
|
|
411
|
+
if (!(this.device as meterConfig).hide_temperature && this.TemperatureSensor?.Service) {
|
|
412
|
+
this.TemperatureSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e)
|
|
413
|
+
}
|
|
414
|
+
this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e)
|
|
415
|
+
this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e)
|
|
416
|
+
}
|
|
417
|
+
}
|
package/src/platform.ts
CHANGED
|
@@ -39,6 +39,7 @@ import { StripLight } from './device/lightstrip.js'
|
|
|
39
39
|
import { Lock } from './device/lock.js'
|
|
40
40
|
import { Meter } from './device/meter.js'
|
|
41
41
|
import { MeterPlus } from './device/meterplus.js'
|
|
42
|
+
import { MeterPro } from './device/meterpro.js'
|
|
42
43
|
import { Motion } from './device/motion.js'
|
|
43
44
|
import { Plug } from './device/plug.js'
|
|
44
45
|
import { RobotVacuumCleaner } from './device/robotvacuumcleaner.js'
|
|
@@ -630,6 +631,7 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
630
631
|
'Meter': this.createMeter.bind(this),
|
|
631
632
|
'MeterPlus': this.createMeterPlus.bind(this),
|
|
632
633
|
'Meter Plus (JP)': this.createMeterPlus.bind(this),
|
|
634
|
+
'Meter Pro': this.createMeterPro.bind(this),
|
|
633
635
|
'WoIOSensor': this.createIOSensor.bind(this),
|
|
634
636
|
'Water Detector': this.createWaterDetector.bind(this),
|
|
635
637
|
'Motion Sensor': this.createMotion.bind(this),
|
|
@@ -960,6 +962,69 @@ export class SwitchBotPlatform implements DynamicPlatformPlugin {
|
|
|
960
962
|
}
|
|
961
963
|
}
|
|
962
964
|
|
|
965
|
+
private async createMeterPro(device: device & devicesConfig) {
|
|
966
|
+
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`)
|
|
967
|
+
|
|
968
|
+
// see if an accessory with the same uuid has already been registered and restored from
|
|
969
|
+
// the cached devices we stored in the `configureAccessory` method above
|
|
970
|
+
const existingAccessory = this.accessories.find(accessory => accessory.UUID === uuid)
|
|
971
|
+
|
|
972
|
+
if (existingAccessory) {
|
|
973
|
+
// the accessory already exists
|
|
974
|
+
if (await this.registerDevice(device)) {
|
|
975
|
+
// console.log("existingAccessory", existingAccessory);
|
|
976
|
+
// if you need to update the accessory.context then you should run `api.updatePlatformAccessories`. eg.:
|
|
977
|
+
existingAccessory.context.device = device
|
|
978
|
+
existingAccessory.context.model = SwitchBotModel.MeterPro ?? SwitchBotModel.MeterProCO2
|
|
979
|
+
existingAccessory.context.deviceId = device.deviceId
|
|
980
|
+
existingAccessory.context.deviceType = device.deviceType
|
|
981
|
+
existingAccessory.displayName = device.configDeviceName
|
|
982
|
+
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
983
|
+
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
984
|
+
existingAccessory.context.connectionType = await this.connectionType(device)
|
|
985
|
+
existingAccessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0'
|
|
986
|
+
this.infoLog(`Restoring existing accessory from cache: ${existingAccessory.displayName} deviceId: ${device.deviceId}`)
|
|
987
|
+
this.api.updatePlatformAccessories([existingAccessory])
|
|
988
|
+
// create the accessory handler for the restored accessory
|
|
989
|
+
// this is imported from `platformAccessory.ts`
|
|
990
|
+
new MeterPro(this, existingAccessory, device)
|
|
991
|
+
await this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${existingAccessory.UUID})`)
|
|
992
|
+
} else {
|
|
993
|
+
this.unregisterPlatformAccessories(existingAccessory)
|
|
994
|
+
}
|
|
995
|
+
} else if (await this.registerDevice(device)) {
|
|
996
|
+
// create a new accessory
|
|
997
|
+
const accessory = new this.api.platformAccessory(device.configDeviceName
|
|
998
|
+
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
999
|
+
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName), uuid)
|
|
1000
|
+
|
|
1001
|
+
// store a copy of the device object in the `accessory.context`
|
|
1002
|
+
// the `context` property can be used to store any data about the accessory you may need
|
|
1003
|
+
accessory.context.device = device
|
|
1004
|
+
accessory.context.model = SwitchBotModel.MeterPro ?? SwitchBotModel.MeterProCO2
|
|
1005
|
+
accessory.context.deviceId = device.deviceId
|
|
1006
|
+
accessory.context.deviceType = device.deviceType
|
|
1007
|
+
accessory.displayName = device.configDeviceName
|
|
1008
|
+
? await this.validateAndCleanDisplayName(device.configDeviceName, 'configDeviceName', device.configDeviceName)
|
|
1009
|
+
: await this.validateAndCleanDisplayName(device.deviceName, 'deviceName', device.deviceName)
|
|
1010
|
+
accessory.context.connectionType = await this.connectionType(device)
|
|
1011
|
+
accessory.context.connectionType = await this.connectionType(device)
|
|
1012
|
+
accessory.context.version = device.firmware ?? device.version ?? this.version ?? '0.0.0'
|
|
1013
|
+
const newOrExternal = !device.external ? 'Adding new' : 'Loading external'
|
|
1014
|
+
await this.infoLog(`${newOrExternal} accessory: ${accessory.displayName} deviceId: ${device.deviceId}`)
|
|
1015
|
+
// create the accessory handler for the newly create accessory
|
|
1016
|
+
// this is imported from `platformAccessory.ts`
|
|
1017
|
+
new MeterPro(this, accessory, device)
|
|
1018
|
+
await this.debugLog(`${device.deviceType} uuid: ${device.deviceId}-${device.deviceType}, (${accessory.UUID})`)
|
|
1019
|
+
|
|
1020
|
+
// publish device externally or link the accessory to your platform
|
|
1021
|
+
this.externalOrPlatform(device, accessory)
|
|
1022
|
+
this.accessories.push(accessory)
|
|
1023
|
+
} else {
|
|
1024
|
+
await this.debugLog(`Device not registered: ${device.deviceName} ${device.deviceType} deviceId: ${device.deviceId}`)
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
963
1028
|
private async createHub2(device: device & devicesConfig) {
|
|
964
1029
|
const uuid = this.api.hap.uuid.generate(`${device.deviceId}-${device.deviceType}`)
|
|
965
1030
|
|
package/src/settings.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type { PlatformConfig } from 'homebridge'
|
|
|
8
8
|
* For Testing Locally:
|
|
9
9
|
* import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
|
|
10
10
|
*/
|
|
11
|
-
import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from 'node-switchbot'
|
|
11
|
+
import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName, SwitchBotModel } from 'node-switchbot'
|
|
12
12
|
/**
|
|
13
13
|
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json
|
|
14
14
|
*/
|
|
@@ -57,7 +57,7 @@ export type devicesConfig = botConfig | meterConfig | indoorOutdoorSensorConfig
|
|
|
57
57
|
|
|
58
58
|
export interface BaseDeviceConfig extends device {
|
|
59
59
|
bleMac?: string
|
|
60
|
-
model:
|
|
60
|
+
model: SwitchBotModel
|
|
61
61
|
bleModel: SwitchBotBLEModel
|
|
62
62
|
bleModelName: SwitchBotBLEModelName
|
|
63
63
|
bleModelFriednlyName: SwitchBotBLEModelFriendlyName
|
|
@@ -97,7 +97,7 @@ export interface botConfig extends BaseDeviceConfig {
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
export interface meterConfig extends BaseDeviceConfig {
|
|
100
|
-
configDeviceType: 'Meter' | 'MeterPlus'
|
|
100
|
+
configDeviceType: 'Meter' | 'MeterPlus' | 'Meter Pro' | 'Meter Pro CO2'
|
|
101
101
|
hide_temperature?: boolean
|
|
102
102
|
convertUnitTo?: string
|
|
103
103
|
hide_humidity?: boolean
|