@homebridge-plugins/homebridge-firstalert 0.0.1-beta.6 → 0.0.1-beta.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/platform.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AACvG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAOtD,qBAAa,eAAgB,YAAW,qBAAqB;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,SAAgB,MAAM,EAAG,aAAa,CAAA;IACtC,OAAO,CAAC,SAAS,CAAC,CAAK;IACvB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,eAAe,CAAiC;gBAE5C,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG;IAanD,eAAe;IA+CrB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE;IAQ1B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE;IAoBrC,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;CAIhD"}
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEvG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAOtD,qBAAa,eAAgB,YAAW,qBAAqB;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,SAAgB,MAAM,EAAG,aAAa,CAAA;IACtC,OAAO,CAAC,SAAS,CAAC,CAAK;IACvB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,eAAe,CAAiC;gBAE5C,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG;IAanD,eAAe;IA+CrB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE;IAQ1B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE;IAoBrC,kBAAkB,CAAC,SAAS,EAAE,iBAAiB;CAIhD"}
@@ -1,8 +1,8 @@
1
1
  import { ResideoClient } from './api/resideoClient.js';
2
- import { Thermostats } from './devices/thermostats.js';
3
2
  import { LeakSensor } from './devices/leaksensors.js';
4
- import { Valve } from './devices/valve.js';
5
3
  import { SmokeSensor } from './devices/smoke.js';
4
+ import { Thermostats } from './devices/thermostats.js';
5
+ import { Valve } from './devices/valve.js';
6
6
  export class ResideoPlatform {
7
7
  log;
8
8
  config;
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/platform.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/platform.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@homebridge-plugins/homebridge-firstalert",
3
3
  "displayName": "FirstAlert",
4
4
  "type": "module",
5
- "version": "0.0.1-beta.6",
5
+ "version": "0.0.1-beta.7",
6
6
  "description": "The FirstAlert plugin allows you to access your FirstAlert device(s) from HomeKit.",
7
7
  "author": {
8
8
  "name": "donavanbecker",
@@ -53,8 +53,11 @@
53
53
  ],
54
54
  "main": "dist/index.js",
55
55
  "files": [
56
+ "README.md",
56
57
  "branding",
57
- "dist"
58
+ "dist",
59
+ "package.json",
60
+ "src"
58
61
  ],
59
62
  "engines": {
60
63
  "homebridge": "^1.11.3 || ^2.0.0-beta.77",
@@ -0,0 +1,106 @@
1
+ // FirstAlert API client for OAuth and device polling
2
+ // Implements token refresh, account/device fetch, and strong typing
3
+
4
+ import { request } from 'undici'
5
+
6
+ export interface ResideoDevice {
7
+ id: string
8
+ name: string
9
+ deviceId: string
10
+ globalDeviceType: string
11
+ }
12
+
13
+ export interface ResideoAccount {
14
+ id: string
15
+ firstName: string
16
+ lastName: string
17
+ contactEmail: string
18
+ countryCode: string
19
+ locale: string
20
+ devices: ResideoDevice[]
21
+ }
22
+
23
+ export interface ResideoDeviceState {
24
+ name: string
25
+ deviceType: string
26
+ isOnline: boolean
27
+ deviceState: any
28
+ }
29
+
30
+ export class ResideoClient {
31
+ private clientId = 'SRmiA7CaYi1JgivDZdzzoZu4X5VBogGt'
32
+ private refreshToken: string
33
+ private accessToken: string | null = null
34
+
35
+ constructor(refreshToken: string) {
36
+ this.refreshToken = refreshToken
37
+ }
38
+
39
+ async refreshAccessToken(): Promise<string> {
40
+ const body = JSON.stringify({
41
+ grant_type: 'refresh_token',
42
+ refresh_token: this.refreshToken,
43
+ client_id: this.clientId,
44
+ })
45
+ const { body: resBody } = await request('https://login.firstalert.com/oauth/token', {
46
+ method: 'POST',
47
+ headers: { 'Content-Type': 'application/json' },
48
+ body,
49
+ })
50
+ const data = await resBody.json() as { access_token?: string }
51
+ this.accessToken = data.access_token ?? ''
52
+ if (!this.accessToken) {
53
+ throw new Error('Failed to obtain access token from FirstAlert API')
54
+ }
55
+ return this.accessToken
56
+ }
57
+
58
+ async getAccessToken(): Promise<string> {
59
+ if (!this.accessToken) {
60
+ await this.refreshAccessToken()
61
+ }
62
+ return this.accessToken!
63
+ }
64
+
65
+ async getAccount(): Promise<ResideoAccount> {
66
+ const token = await this.getAccessToken()
67
+ const { body: resBody } = await request('https://api.firstalert.com/ris-public-api/api/v1/accounts', {
68
+ method: 'GET',
69
+ headers: { Authorization: `Bearer ${token}` },
70
+ })
71
+ const resp = await resBody.json() as { data: any }
72
+ // Parse and flatten devices
73
+ const data = resp.data
74
+ const devices: ResideoDevice[] = []
75
+ for (const user of data.consumerUsers) {
76
+ for (const loc of user.consumerAccount.locations) {
77
+ for (const dev of loc.consumerDevices) {
78
+ devices.push({
79
+ id: dev.id,
80
+ name: dev.name,
81
+ deviceId: dev.device.deviceId,
82
+ globalDeviceType: dev.device.globalDeviceType,
83
+ })
84
+ }
85
+ }
86
+ }
87
+ return {
88
+ id: data.id,
89
+ firstName: data.firstName,
90
+ lastName: data.lastName,
91
+ contactEmail: data.contactEmail,
92
+ countryCode: data.countryCode,
93
+ locale: data.locale,
94
+ devices,
95
+ }
96
+ }
97
+
98
+ async getDeviceState(deviceId: string): Promise<ResideoDeviceState> {
99
+ const token = await this.getAccessToken()
100
+ const { body: resBody } = await request(`https://api.firstalert.com/ris-public-api/api/v2/devices/smokeDetectors/${deviceId}/state`, {
101
+ method: 'GET',
102
+ headers: { Authorization: `Bearer ${token}` },
103
+ })
104
+ return await resBody.json() as ResideoDeviceState
105
+ }
106
+ }
@@ -0,0 +1,226 @@
1
+ // Static regexes for version parsing (for lint rule e18e/prefer-static-regex)
2
+ /* Copyright(C) 2022-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
3
+ *
4
+ * device.ts: homebridge-firstalert.
5
+ */
6
+ import type { API, HAP, Logging, PlatformAccessory } from 'homebridge'
7
+
8
+ import type { ResideoDevice } from '../api/resideoClient.js'
9
+ import type { ResideoPlatform } from '../platform.js'
10
+ import type { ResideoPlatformConfig } from '../settings.js'
11
+
12
+ export abstract class deviceBase {
13
+ public readonly api: API
14
+ public readonly log: Logging
15
+ public readonly config!: ResideoPlatformConfig
16
+ protected readonly hap: HAP
17
+
18
+ // Config
19
+ protected deviceLogging!: string
20
+ protected deviceRefreshRate!: number
21
+ protected deviceUpdateRate!: number
22
+ protected devicePushRate!: number
23
+ protected deviceFirmwareVersion!: string
24
+ protected deviceMaxRetries!: number
25
+ protected deviceDelayBetweenRetries!: number
26
+
27
+ constructor(
28
+ protected readonly platform: ResideoPlatform,
29
+ protected accessory: PlatformAccessory,
30
+ protected device: ResideoDevice,
31
+ ) {
32
+ this.api = (platform as any).api
33
+ this.log = (platform as any).log
34
+ this.config = (platform as any).config as ResideoPlatformConfig
35
+ this.hap = (platform as any).api.hap
36
+
37
+ this.getDeviceLogSettings()
38
+ this.getDeviceRateSettings()
39
+ this.getDeviceConfigSettings(device)
40
+ this.getDeviceContext(accessory, device)
41
+
42
+ // Set accessory information
43
+ accessory
44
+ .getService(this.hap.Service.AccessoryInformation)!
45
+ .setCharacteristic(this.hap.Characteristic.Manufacturer, 'FirstAlert')
46
+ .setCharacteristic(this.hap.Characteristic.Name, accessory.displayName)
47
+ .setCharacteristic(this.hap.Characteristic.ConfiguredName, accessory.displayName)
48
+ .setCharacteristic(this.hap.Characteristic.Model, accessory.context.model)
49
+ .setCharacteristic(this.hap.Characteristic.SerialNumber, accessory.context.deviceID)
50
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, this.deviceFirmwareVersion)
51
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
52
+ .updateValue(this.deviceFirmwareVersion)
53
+ }
54
+
55
+ async getDeviceLogSettings(): Promise<void> {
56
+ this.deviceLogging = 'standard'
57
+ await this.debugLog(`Using Device Logging: ${this.deviceLogging}`)
58
+ }
59
+
60
+ async getDeviceRateSettings(): Promise<void> {
61
+ // Use default values; ResideoDevice does not have these properties
62
+ this.deviceRefreshRate = 120
63
+ this.deviceUpdateRate = 5
64
+ this.devicePushRate = 0.1
65
+ await this.debugLog(`Using refreshRate: ${this.deviceRefreshRate}, updateRate: ${this.deviceUpdateRate}, pushRate: ${this.devicePushRate}`)
66
+ this.deviceMaxRetries = 5
67
+ await this.debugLog(`Using maxRetries: ${this.deviceMaxRetries}`)
68
+ this.deviceDelayBetweenRetries = 3 * 1000
69
+ await this.debugLog(`Using delayBetweenRetries: ${this.deviceDelayBetweenRetries}`)
70
+ }
71
+
72
+ async getDeviceConfigSettings(device: ResideoDevice): Promise<void> {
73
+ // No config merging; ResideoDevice does not have these properties
74
+ this.debugSuccessLog(`Config: ${JSON.stringify(device)}`)
75
+ }
76
+
77
+ async getDeviceContext(accessory: PlatformAccessory, device: ResideoDevice): Promise<void> {
78
+ // Context Information
79
+ accessory.context.model = device.globalDeviceType
80
+ accessory.context.deviceID = device.deviceId
81
+ accessory.context.deviceType = device.globalDeviceType
82
+ // FirmwareRevision
83
+ const version = '0.0.0'
84
+ this.deviceFirmwareVersion = version
85
+ accessory
86
+ .getService(this.hap.Service.AccessoryInformation)!
87
+ .setCharacteristic(this.hap.Characteristic.HardwareRevision, this.deviceFirmwareVersion)
88
+ .setCharacteristic(this.hap.Characteristic.SoftwareRevision, this.deviceFirmwareVersion)
89
+ .setCharacteristic(this.hap.Characteristic.FirmwareRevision, this.deviceFirmwareVersion)
90
+ .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
91
+ .updateValue(this.deviceFirmwareVersion)
92
+ this.debugSuccessLog(`deviceFirmwareVersion: ${this.deviceFirmwareVersion}`)
93
+ }
94
+
95
+ async statusCode(statusCode: number, action: string): Promise<void> {
96
+ switch (statusCode) {
97
+ case 200:
98
+ this.debugLog(`${this.device.name}: ${this.accessory.displayName} Standard Response, statusCode: ${statusCode}, Action: ${action}`)
99
+ break
100
+ case 400:
101
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} Bad Request, statusCode: ${statusCode}, Action: ${action}`)
102
+ break
103
+ case 401:
104
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} Unauthorized, statusCode: ${statusCode}, Action: ${action}`)
105
+ break
106
+ case 403:
107
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} Forbidden, The request has been authenticated but does not have appropriate permissions, or a requested resource is not found, statusCode: ${statusCode}`)
108
+ break
109
+ case 404:
110
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} Not Found, statusCode: ${statusCode}, Action: ${action}`)
111
+ break
112
+ case 429:
113
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} Too Many Requests, statusCode: ${statusCode}, Action: ${action}`)
114
+ break
115
+ case 500:
116
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} Internal Server Error (Meater Server), statusCode: ${statusCode}, Action: ${action}`)
117
+ break
118
+ default:
119
+ this.infoLog(`${this.device.name}: ${this.accessory.displayName} Unknown statusCode: ${statusCode}, Action: ${action}, Report Bugs Here: https://bit.ly/homebridge-firstalert-bug-report`)
120
+ }
121
+ }
122
+
123
+ async resideoAPIError(e: any, action: string): Promise<void> {
124
+ if (e.message.includes('400')) {
125
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Bad Request`)
126
+ this.debugLog('The client has issued an invalid request. This is commonly used to specify validation errors in a request payload.')
127
+ } else if (e.message.includes('401')) {
128
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Unauthorized Request`)
129
+ this.debugLog('Authorization for the API is required, but the request has not been authenticated.')
130
+ } else if (e.message.includes('403')) {
131
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Forbidden Request`)
132
+ this.debugLog('The request has been authenticated but does not have appropriate permissions, or a requested resource is not found.')
133
+ } else if (e.message.includes('404')) {
134
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Requst Not Found`)
135
+ this.debugLog('Specifies the requested path does not exist.')
136
+ } else if (e.message.includes('406')) {
137
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Request Not Acceptable`)
138
+ this.debugLog('The client has requested a MIME type via the Accept header for a value not supported by the server.')
139
+ } else if (e.message.includes('415')) {
140
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Unsupported Requst Header`)
141
+ this.debugLog('The client has defined a contentType header that is not supported by the server.')
142
+ } else if (e.message.includes('422')) {
143
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Unprocessable Entity`)
144
+ this.debugLog(
145
+ 'The client has made a valid request, but the server cannot process it.'
146
+ + ' This is often used for APIs for which certain limits have been exceeded.',
147
+ )
148
+ } else if (e.message.includes('429')) {
149
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Too Many Requests`)
150
+ this.debugLog('The client has exceeded the number of requests allowed for a given time window.')
151
+ } else if (e.message.includes('500')) {
152
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action}, Internal Server Error`)
153
+ this.debugLog('An unexpected error on the SmartThings servers has occurred. These errors should be rare.')
154
+ } else {
155
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to ${action},`)
156
+ }
157
+ if (this.deviceLogging.includes('debug')) {
158
+ this.errorLog(`${this.device.name}: ${this.accessory.displayName} failed to pushChanges, Error Message: ${JSON.stringify(e.message)}`)
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Logging for Device
164
+ */
165
+ async infoLog(...log: any[]): Promise<void> {
166
+ if (await this.enablingDeviceLogging()) {
167
+ this.log.info(`${this.device.name}: ${this.accessory.displayName}`, String(...log))
168
+ }
169
+ }
170
+
171
+ async successLog(...log: any[]): Promise<void> {
172
+ if (await this.enablingDeviceLogging()) {
173
+ this.log.success(`${this.device.name}: ${this.accessory.displayName}`, String(...log))
174
+ }
175
+ }
176
+
177
+ async debugSuccessLog(...log: any[]): Promise<void> {
178
+ if (await this.enablingDeviceLogging()) {
179
+ if (this.deviceLogging?.includes('debug')) {
180
+ this.log.success(`[DEBUG] ${this.device.name}: ${this.accessory.displayName}`, String(...log))
181
+ }
182
+ }
183
+ }
184
+
185
+ async warnLog(...log: any[]): Promise<void> {
186
+ if (await this.enablingDeviceLogging()) {
187
+ this.log.warn(`${this.device.name}: ${this.accessory.displayName}`, String(...log))
188
+ }
189
+ }
190
+
191
+ async debugWarnLog(...log: any[]): Promise<void> {
192
+ if (await this.enablingDeviceLogging()) {
193
+ if (this.deviceLogging?.includes('debug')) {
194
+ this.log.warn(`[DEBUG] ${this.device.name}: ${this.accessory.displayName}`, String(...log))
195
+ }
196
+ }
197
+ }
198
+
199
+ async errorLog(...log: any[]): Promise<void> {
200
+ if (await this.enablingDeviceLogging()) {
201
+ this.log.error(`${this.device.name}: ${this.accessory.displayName}`, String(...log))
202
+ }
203
+ }
204
+
205
+ async debugErrorLog(...log: any[]): Promise<void> {
206
+ if (await this.enablingDeviceLogging()) {
207
+ if (this.deviceLogging?.includes('debug')) {
208
+ this.log.error(`[DEBUG] ${this.device.name}: ${this.accessory.displayName}`, String(...log))
209
+ }
210
+ }
211
+ }
212
+
213
+ async debugLog(...log: any[]): Promise<void> {
214
+ if (await this.enablingDeviceLogging()) {
215
+ if (this.deviceLogging === 'debug') {
216
+ this.log.info(`[DEBUG] ${this.device.name}: ${this.accessory.displayName}`, String(...log))
217
+ } else {
218
+ this.log.debug(`${this.device.name}: ${this.accessory.displayName}`, String(...log))
219
+ }
220
+ }
221
+ }
222
+
223
+ async enablingDeviceLogging(): Promise<boolean> {
224
+ return this.deviceLogging.includes('debug') ?? this.deviceLogging === 'standard'
225
+ }
226
+ }
@@ -0,0 +1,206 @@
1
+ /* Copyright(C) 2022-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
2
+ *
3
+ * leaksensors.ts: homebridge-firstalert.
4
+ */
5
+ import type { CharacteristicValue, PlatformAccessory, Service } from 'homebridge'
6
+ import { interval, Subject } from 'rxjs'
7
+ import { skipWhile } from 'rxjs/operators'
8
+
9
+ import type { ResideoDevice } from '../api/resideoClient.js'
10
+ import type { ResideoPlatform } from '../platform.js'
11
+ import { deviceBase } from './device.js'
12
+
13
+ /**
14
+ * Platform Accessory
15
+ * An instance of this class is created for each accessory your platform registers
16
+ * Each accessory may expose multiple services of different service types.
17
+ */
18
+ export class LeakSensor extends deviceBase {
19
+ // Services
20
+ private Battery: {
21
+ Name: CharacteristicValue
22
+ Service: Service
23
+ BatteryLevel: CharacteristicValue
24
+ ChargingState: CharacteristicValue
25
+ StatusLowBattery: CharacteristicValue
26
+ }
27
+
28
+ private LeakSensor?: {
29
+ Name: CharacteristicValue
30
+ Service: Service
31
+ StatusActive: CharacteristicValue
32
+ LeakDetected: CharacteristicValue
33
+ }
34
+
35
+ private HumiditySensor?: {
36
+ Name: CharacteristicValue
37
+ Service: Service
38
+ CurrentRelativeHumidity: CharacteristicValue
39
+ }
40
+
41
+ private TemperatureSensor?: {
42
+ Name: CharacteristicValue
43
+ Service: Service
44
+ CurrentTemperature: CharacteristicValue
45
+ }
46
+
47
+ // Sensor Update
48
+ SensorUpdateInProgress!: boolean
49
+ doSensorUpdate!: Subject<void>
50
+
51
+ constructor(
52
+ readonly platform: ResideoPlatform,
53
+ accessory: PlatformAccessory,
54
+ device: ResideoDevice,
55
+ ) {
56
+ super(platform, accessory, device)
57
+
58
+ this.doSensorUpdate = new Subject()
59
+ this.SensorUpdateInProgress = false
60
+
61
+ // Initialize Battery Service
62
+ accessory.context.Battery = accessory.context.Battery ?? {}
63
+ this.Battery = {
64
+ Name: accessory.context.Battery.Name ?? `${accessory.displayName} Battery`,
65
+ Service: accessory.getService(this.hap.Service.Battery) ?? accessory.addService(this.hap.Service.Battery) as Service,
66
+ BatteryLevel: accessory.context.BatteryLevel ?? 100,
67
+ ChargingState: accessory.context.ChargingState ?? this.hap.Characteristic.ChargingState.NOT_CHARGEABLE,
68
+ StatusLowBattery: accessory.context.StatusLowBattery ?? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL,
69
+ }
70
+ accessory.context.Battery = this.Battery as object
71
+ this.Battery.Service
72
+ .setCharacteristic(this.hap.Characteristic.Name, this.Battery.Name)
73
+ .setCharacteristic(this.hap.Characteristic.ChargingState, this.hap.Characteristic.ChargingState.NOT_CHARGEABLE)
74
+ .getCharacteristic(this.hap.Characteristic.BatteryLevel)
75
+ .onGet(() => this.Battery.BatteryLevel)
76
+
77
+ // Leak Sensor Service
78
+ accessory.context.LeakSensor = accessory.context.LeakSensor ?? {}
79
+ this.LeakSensor = {
80
+ Name: accessory.context.LeakSensor.Name ?? `${accessory.displayName} Leak Sensor`,
81
+ Service: accessory.getService(this.hap.Service.LeakSensor) ?? accessory.addService(this.hap.Service.LeakSensor) as Service,
82
+ StatusActive: accessory.context.StatusActive ?? false,
83
+ LeakDetected: accessory.context.LeakDetected ?? this.hap.Characteristic.LeakDetected.LEAK_NOT_DETECTED,
84
+ }
85
+ accessory.context.LeakSensor = this.LeakSensor as object
86
+ this.LeakSensor.Service
87
+ .setCharacteristic(this.hap.Characteristic.Name, this.LeakSensor.Name)
88
+ .getCharacteristic(this.hap.Characteristic.StatusActive)
89
+ .onGet(() => this.LeakSensor!.StatusActive)
90
+ this.LeakSensor.Service
91
+ .getCharacteristic(this.hap.Characteristic.LeakDetected)
92
+ .onGet(() => this.LeakSensor!.LeakDetected)
93
+
94
+ // Temperature Sensor Service
95
+ accessory.context.TemperatureSensor = accessory.context.TemperatureSensor ?? {}
96
+ this.TemperatureSensor = {
97
+ Name: accessory.context.TemperatureSensor.Name ?? `${accessory.displayName} Temperature Sensor`,
98
+ Service: accessory.getService(this.hap.Service.TemperatureSensor) ?? accessory.addService(this.hap.Service.TemperatureSensor) as Service,
99
+ CurrentTemperature: accessory.context.CurrentTemperature ?? 20,
100
+ }
101
+ accessory.context.TemperatureSensor = this.TemperatureSensor as object
102
+ this.TemperatureSensor.Service
103
+ .setCharacteristic(this.hap.Characteristic.Name, this.TemperatureSensor.Name)
104
+ .getCharacteristic(this.hap.Characteristic.CurrentTemperature)
105
+ .setProps({
106
+ minValue: -273.15,
107
+ maxValue: 100,
108
+ minStep: 0.1,
109
+ })
110
+ .onGet(() => this.TemperatureSensor!.CurrentTemperature)
111
+
112
+ // Humidity Sensor Service
113
+ accessory.context.HumiditySensor = accessory.context.HumiditySensor ?? {}
114
+ this.HumiditySensor = {
115
+ Name: accessory.context.HumiditySensor.Name ?? `${accessory.displayName} Humidity Sensor`,
116
+ Service: accessory.getService(this.hap.Service.HumiditySensor) ?? accessory.addService(this.hap.Service.HumiditySensor) as Service,
117
+ CurrentRelativeHumidity: accessory.context.CurrentRelativeHumidity ?? 50,
118
+ }
119
+ accessory.context.HumiditySensor = this.HumiditySensor as object
120
+ this.HumiditySensor.Service
121
+ .setCharacteristic(this.hap.Characteristic.Name, this.HumiditySensor.Name)
122
+ this.HumiditySensor.Service
123
+ .getCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity)
124
+ .setProps({ minStep: 0.1 })
125
+ .onGet(() => this.HumiditySensor!.CurrentRelativeHumidity)
126
+
127
+ // Initial refresh
128
+ this.refreshStatus()
129
+ this.updateHomeKitCharacteristics()
130
+ interval(120 * 1000)
131
+ .pipe(skipWhile(() => this.SensorUpdateInProgress))
132
+ .subscribe(async () => {
133
+ await this.refreshStatus()
134
+ })
135
+ }
136
+
137
+ /**
138
+ * Parse the device status from the FirstAlert api
139
+ */
140
+ async parseStatus(): Promise<void> {
141
+ // Example: parse state from API response (simulate for now)
142
+ // In a real implementation, fetch and parse state from the API
143
+ // For now, just set some dummy values
144
+ this.Battery.BatteryLevel = 100
145
+ this.Battery.StatusLowBattery = this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL
146
+ if (this.LeakSensor) {
147
+ this.LeakSensor.StatusActive = true
148
+ this.LeakSensor.LeakDetected = this.hap.Characteristic.LeakDetected.LEAK_NOT_DETECTED
149
+ }
150
+ if (this.TemperatureSensor) {
151
+ this.TemperatureSensor.CurrentTemperature = 20
152
+ }
153
+ if (this.HumiditySensor) {
154
+ this.HumiditySensor.CurrentRelativeHumidity = 50
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Asks the FirstAlert Home API for the latest device information
160
+ */
161
+ async refreshStatus(): Promise<void> {
162
+ try {
163
+ const deviceId = String(this.device.deviceId)
164
+ await this.platform.client.getDeviceState(deviceId)
165
+ // In a real implementation, parse deviceState and update class state
166
+ await this.parseStatus()
167
+ await this.updateHomeKitCharacteristics()
168
+ } catch (e: any) {
169
+ const action = 'refreshStatus'
170
+ this.resideoAPIError(e, action)
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Updates the status for each of the HomeKit Characteristics
176
+ */
177
+ async updateHomeKitCharacteristics(): Promise<void> {
178
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, this.Battery.BatteryLevel)
179
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, this.Battery.StatusLowBattery)
180
+ if (this.LeakSensor) {
181
+ this.LeakSensor.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, this.LeakSensor.LeakDetected)
182
+ this.LeakSensor.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, this.LeakSensor.StatusActive)
183
+ }
184
+ if (this.TemperatureSensor) {
185
+ this.TemperatureSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, this.TemperatureSensor.CurrentTemperature)
186
+ }
187
+ if (this.HumiditySensor) {
188
+ this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, this.HumiditySensor.CurrentRelativeHumidity)
189
+ }
190
+ }
191
+
192
+ async apiError(e: any): Promise<void> {
193
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.BatteryLevel, e)
194
+ this.Battery.Service.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, e)
195
+ if (this.LeakSensor) {
196
+ this.LeakSensor.Service.updateCharacteristic(this.hap.Characteristic.LeakDetected, e)
197
+ this.LeakSensor.Service.updateCharacteristic(this.hap.Characteristic.StatusActive, e)
198
+ }
199
+ if (this.TemperatureSensor) {
200
+ this.TemperatureSensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentTemperature, e)
201
+ }
202
+ if (this.HumiditySensor) {
203
+ this.HumiditySensor.Service.updateCharacteristic(this.hap.Characteristic.CurrentRelativeHumidity, e)
204
+ }
205
+ }
206
+ }