homebridge-ring 10.0.0 → 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.LocationModeSwitch = void 0;
13
4
  const operators_1 = require("rxjs/operators");
@@ -38,7 +29,7 @@ class LocationModeSwitch extends base_accessory_1.BaseAccessory {
38
29
  this.device = this.location; // for use in BaseAccessory
39
30
  const { Characteristic, Service: { SecuritySystem, AccessoryInformation }, } = hap_1.hap, accessoryName = location.name + ' Mode', service = this.getService(SecuritySystem, accessoryName), currentState = service.getCharacteristic(Characteristic.SecuritySystemCurrentState), targetState = service.getCharacteristic(Characteristic.SecuritySystemTargetState), getCurrentMode = () => {
40
31
  return (0, rxjs_1.firstValueFrom)(location.onLocationMode);
41
- }, getCurrentState = () => __awaiter(this, void 0, void 0, function* () { return getStateFromMode(yield getCurrentMode()); });
32
+ }, getCurrentState = async () => getStateFromMode(await getCurrentMode());
42
33
  location.onLocationMode.pipe((0, operators_1.distinctUntilChanged)()).subscribe((mode) => {
43
34
  const state = getStateFromMode(mode);
44
35
  if (state === this.targetState) {
@@ -49,23 +40,23 @@ class LocationModeSwitch extends base_accessory_1.BaseAccessory {
49
40
  }
50
41
  currentState.updateValue(state);
51
42
  });
52
- currentState.on("get" /* GET */, (callback) => __awaiter(this, void 0, void 0, function* () {
43
+ currentState.on("get" /* GET */, async (callback) => {
53
44
  location.getLocationMode().catch((e) => {
54
45
  (0, util_1.logError)('Failed to retrieve location mode for ' + location.name);
55
46
  (0, util_1.logError)(e);
56
47
  });
57
- const state = yield getCurrentState();
48
+ const state = await getCurrentState();
58
49
  if (state === this.targetState) {
59
50
  this.targetState = undefined;
60
51
  }
61
52
  callback(null, state);
62
- }));
63
- targetState.on("get" /* GET */, (callback) => __awaiter(this, void 0, void 0, function* () {
53
+ });
54
+ targetState.on("get" /* GET */, async (callback) => {
64
55
  callback(null, this.targetState !== undefined
65
56
  ? this.targetState
66
- : yield getCurrentState());
67
- }));
68
- targetState.on("set" /* SET */, (state, callback) => __awaiter(this, void 0, void 0, function* () {
57
+ : await getCurrentState());
58
+ });
59
+ targetState.on("set" /* SET */, async (state, callback) => {
69
60
  const { Characteristic: { SecuritySystemTargetState: State }, } = hap_1.hap;
70
61
  callback();
71
62
  if (state === State.NIGHT_ARM) {
@@ -73,7 +64,7 @@ class LocationModeSwitch extends base_accessory_1.BaseAccessory {
73
64
  // Ring doesn't have night mode, so switch over to stay mode
74
65
  setTimeout(() => targetState.updateValue(state), 100);
75
66
  }
76
- if (state === (yield getCurrentState())) {
67
+ if (state === (await getCurrentState())) {
77
68
  this.targetState = undefined;
78
69
  return;
79
70
  }
@@ -88,7 +79,7 @@ class LocationModeSwitch extends base_accessory_1.BaseAccessory {
88
79
  }
89
80
  this.logger.info(`Setting ${this.location.name} Mode to home`);
90
81
  return this.location.setLocationMode('home');
91
- }));
82
+ });
92
83
  targetState.setProps({
93
84
  validValues: [
94
85
  Characteristic.SecuritySystemTargetState.AWAY_ARM,
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.RingPlatform = exports.pluginName = exports.platformName = void 0;
13
4
  const api_1 = require("../api");
@@ -122,7 +113,6 @@ function getAccessoryClass(device) {
122
113
  }
123
114
  class RingPlatform {
124
115
  constructor(log, config, api) {
125
- var _a, _b;
126
116
  this.log = log;
127
117
  this.config = config;
128
118
  this.api = api;
@@ -139,8 +129,8 @@ class RingPlatform {
139
129
  this.log.info('No configuration found for platform Ring');
140
130
  return;
141
131
  }
142
- config.cameraStatusPollingSeconds = (_a = config.cameraStatusPollingSeconds) !== null && _a !== void 0 ? _a : 20;
143
- config.locationModePollingSeconds = (_b = config.locationModePollingSeconds) !== null && _b !== void 0 ? _b : 20;
132
+ config.cameraStatusPollingSeconds = config.cameraStatusPollingSeconds ?? 20;
133
+ config.locationModePollingSeconds = config.locationModePollingSeconds ?? 20;
144
134
  this.api.on('didFinishLaunching', () => {
145
135
  this.log.debug('didFinishLaunching');
146
136
  if (config.refreshToken) {
@@ -160,106 +150,107 @@ class RingPlatform {
160
150
  this.log.debug('%j', accessory);
161
151
  this.homebridgeAccessories[accessory.UUID] = accessory;
162
152
  }
163
- connectToApi() {
164
- return __awaiter(this, void 0, void 0, function* () {
165
- const { api, config } = this, systemId = (0, config_1.getSystemId)(api), ringApi = new api_1.RingApi(Object.assign(Object.assign({ controlCenterDisplayName: 'homebridge-ring' }, config), { systemId })), locations = yield ringApi.getLocations(), cachedAccessoryIds = Object.keys(this.homebridgeAccessories), platformAccessories = [], activeAccessoryIds = [];
166
- this.log.info('Found the following locations:');
167
- locations.forEach((location) => {
168
- this.log.info(` locationId: ${location.id} - ${location.name}`);
169
- });
170
- yield Promise.all(locations.map((location) => __awaiter(this, void 0, void 0, function* () {
171
- var _a;
172
- const devices = yield location.getDevices(), cameras = location.cameras, chimes = location.chimes, allDevices = [...devices, ...cameras, ...chimes], securityPanel = devices.find((x) => x.deviceType === api_1.RingDeviceType.SecurityPanel), debugPrefix = debug ? 'TEST ' : '', hapDevices = allDevices.map((device) => {
173
- const isCamera = device instanceof api_1.RingCamera, cameraIdDifferentiator = isCamera ? 'camera' : '', // this forces bridged cameras from old version of the plugin to be seen as "stale"
174
- AccessoryClass = (device instanceof api_1.RingCamera
175
- ? camera_1.Camera
176
- : device instanceof api_1.RingChime
177
- ? chime_1.Chime
178
- : getAccessoryClass(device));
179
- return {
180
- deviceType: device.deviceType,
181
- device: device,
182
- isCamera,
183
- id: device.id.toString() + cameraIdDifferentiator,
184
- name: device.name,
185
- AccessoryClass,
186
- };
187
- }), hideDeviceIds = config.hideDeviceIds || [], onlyDeviceTypes = ((_a = config.onlyDeviceTypes) === null || _a === void 0 ? void 0 : _a.length)
188
- ? config.onlyDeviceTypes
189
- : undefined;
190
- if (config.showPanicButtons && securityPanel) {
191
- hapDevices.push({
192
- deviceType: securityPanel.deviceType,
193
- device: securityPanel,
194
- isCamera: false,
195
- id: securityPanel.id.toString() + 'panic',
196
- name: 'Panic Buttons',
197
- AccessoryClass: panic_buttons_1.PanicButtons,
198
- });
199
- }
200
- if (config.locationModePollingSeconds &&
201
- (yield location.supportsLocationModeSwitching())) {
202
- hapDevices.push({
203
- deviceType: 'location.mode',
204
- device: location,
205
- isCamera: false,
206
- id: location.id + 'mode',
207
- name: location.name + ' Mode',
208
- AccessoryClass: location_mode_switch_1.LocationModeSwitch,
209
- });
210
- }
211
- this.log.info(`Configuring ${cameras.length} cameras and ${hapDevices.length} devices for location "${location.name}" - locationId: ${location.id}`);
212
- hapDevices.forEach(({ deviceType, device, isCamera, id, name, AccessoryClass }) => {
213
- const uuid = hap_1.hap.uuid.generate(debugPrefix + id), displayName = debugPrefix + name;
214
- if (!AccessoryClass ||
215
- (config.hideLightGroups &&
216
- deviceType === api_1.RingDeviceType.BeamsLightGroupSwitch) ||
217
- (config.hideUnsupportedServices &&
218
- unsupportedDeviceTypes.includes(deviceType)) ||
219
- hideDeviceIds.includes(uuid) ||
220
- (onlyDeviceTypes && !onlyDeviceTypes.includes(deviceType))) {
221
- if (!ignoreHiddenDeviceTypes.includes(deviceType)) {
222
- this.log.info(`Hidden accessory ${uuid} ${deviceType} ${displayName}`);
223
- }
224
- return;
225
- }
226
- const createHomebridgeAccessory = () => {
227
- const accessory = new api.platformAccessory(displayName, uuid, isCamera
228
- ? 17 /* CAMERA */
229
- : 11 /* SECURITY_SYSTEM */);
230
- this.log.info(`Adding new accessory ${uuid} ${deviceType} ${displayName}`);
231
- platformAccessories.push(accessory);
232
- if (isCamera &&
233
- typeof hap_1.hap.Accessory.cleanupAccessoryData === 'function') {
234
- // This is a one-time cleanup that will remove persist files for old external accessories from before camera bridging in version 8
235
- hap_1.hap.Accessory.cleanupAccessoryData((0, util_2.generateMacAddress)(accessory.UUID));
236
- }
237
- return accessory;
238
- }, homebridgeAccessory = this.homebridgeAccessories[uuid] || createHomebridgeAccessory(), accessory = new AccessoryClass(device, homebridgeAccessory, this.log, config);
239
- accessory.initBase();
240
- this.homebridgeAccessories[uuid] = homebridgeAccessory;
241
- activeAccessoryIds.push(uuid);
153
+ async connectToApi() {
154
+ const { api, config } = this, systemId = (0, config_1.getSystemId)(api), ringApi = new api_1.RingApi({
155
+ controlCenterDisplayName: 'homebridge-ring',
156
+ ...config,
157
+ systemId,
158
+ }), locations = await ringApi.getLocations(), cachedAccessoryIds = Object.keys(this.homebridgeAccessories), platformAccessories = [], activeAccessoryIds = [];
159
+ this.log.info('Found the following locations:');
160
+ locations.forEach((location) => {
161
+ this.log.info(` locationId: ${location.id} - ${location.name}`);
162
+ });
163
+ await Promise.all(locations.map(async (location) => {
164
+ const devices = await location.getDevices(), cameras = location.cameras, chimes = location.chimes, allDevices = [...devices, ...cameras, ...chimes], securityPanel = devices.find((x) => x.deviceType === api_1.RingDeviceType.SecurityPanel), debugPrefix = debug ? 'TEST ' : '', hapDevices = allDevices.map((device) => {
165
+ const isCamera = device instanceof api_1.RingCamera, cameraIdDifferentiator = isCamera ? 'camera' : '', // this forces bridged cameras from old version of the plugin to be seen as "stale"
166
+ AccessoryClass = (device instanceof api_1.RingCamera
167
+ ? camera_1.Camera
168
+ : device instanceof api_1.RingChime
169
+ ? chime_1.Chime
170
+ : getAccessoryClass(device));
171
+ return {
172
+ deviceType: device.deviceType,
173
+ device: device,
174
+ isCamera,
175
+ id: device.id.toString() + cameraIdDifferentiator,
176
+ name: device.name,
177
+ AccessoryClass,
178
+ };
179
+ }), hideDeviceIds = config.hideDeviceIds || [], onlyDeviceTypes = config.onlyDeviceTypes?.length
180
+ ? config.onlyDeviceTypes
181
+ : undefined;
182
+ if (config.showPanicButtons && securityPanel) {
183
+ hapDevices.push({
184
+ deviceType: securityPanel.deviceType,
185
+ device: securityPanel,
186
+ isCamera: false,
187
+ id: securityPanel.id.toString() + 'panic',
188
+ name: 'Panic Buttons',
189
+ AccessoryClass: panic_buttons_1.PanicButtons,
242
190
  });
243
- })));
244
- if (platformAccessories.length) {
245
- api.registerPlatformAccessories(exports.pluginName, exports.platformName, platformAccessories);
246
191
  }
247
- const staleAccessories = cachedAccessoryIds
248
- .filter((cachedId) => !activeAccessoryIds.includes(cachedId))
249
- .map((id) => this.homebridgeAccessories[id]);
250
- staleAccessories.forEach((staleAccessory) => {
251
- this.log.info(`Removing stale cached accessory ${staleAccessory.UUID} ${staleAccessory.displayName}`);
252
- });
253
- if (staleAccessories.length) {
254
- this.api.unregisterPlatformAccessories(exports.pluginName, exports.platformName, staleAccessories);
192
+ if (config.locationModePollingSeconds &&
193
+ (await location.supportsLocationModeSwitching())) {
194
+ hapDevices.push({
195
+ deviceType: 'location.mode',
196
+ device: location,
197
+ isCamera: false,
198
+ id: location.id + 'mode',
199
+ name: location.name + ' Mode',
200
+ AccessoryClass: location_mode_switch_1.LocationModeSwitch,
201
+ });
255
202
  }
256
- ringApi.onRefreshTokenUpdated.subscribe(({ oldRefreshToken, newRefreshToken }) => {
257
- if (!oldRefreshToken) {
203
+ this.log.info(`Configuring ${cameras.length} cameras and ${hapDevices.length} devices for location "${location.name}" - locationId: ${location.id}`);
204
+ hapDevices.forEach(({ deviceType, device, isCamera, id, name, AccessoryClass }) => {
205
+ const uuid = hap_1.hap.uuid.generate(debugPrefix + id), displayName = debugPrefix + name;
206
+ if (!AccessoryClass ||
207
+ (config.hideLightGroups &&
208
+ deviceType === api_1.RingDeviceType.BeamsLightGroupSwitch) ||
209
+ (config.hideUnsupportedServices &&
210
+ unsupportedDeviceTypes.includes(deviceType)) ||
211
+ hideDeviceIds.includes(uuid) ||
212
+ (onlyDeviceTypes && !onlyDeviceTypes.includes(deviceType))) {
213
+ if (!ignoreHiddenDeviceTypes.includes(deviceType)) {
214
+ this.log.info(`Hidden accessory ${uuid} ${deviceType} ${displayName}`);
215
+ }
258
216
  return;
259
217
  }
260
- (0, config_1.updateHomebridgeConfig)(this.api, (configContents) => {
261
- return configContents.replace(oldRefreshToken, newRefreshToken);
262
- });
218
+ const createHomebridgeAccessory = () => {
219
+ const accessory = new api.platformAccessory(displayName, uuid, isCamera
220
+ ? 17 /* CAMERA */
221
+ : 11 /* SECURITY_SYSTEM */);
222
+ this.log.info(`Adding new accessory ${uuid} ${deviceType} ${displayName}`);
223
+ platformAccessories.push(accessory);
224
+ if (isCamera &&
225
+ typeof hap_1.hap.Accessory.cleanupAccessoryData === 'function') {
226
+ // This is a one-time cleanup that will remove persist files for old external accessories from before camera bridging in version 8
227
+ hap_1.hap.Accessory.cleanupAccessoryData((0, util_2.generateMacAddress)(accessory.UUID));
228
+ }
229
+ return accessory;
230
+ }, homebridgeAccessory = this.homebridgeAccessories[uuid] || createHomebridgeAccessory(), accessory = new AccessoryClass(device, homebridgeAccessory, this.log, config);
231
+ accessory.initBase();
232
+ this.homebridgeAccessories[uuid] = homebridgeAccessory;
233
+ activeAccessoryIds.push(uuid);
234
+ });
235
+ }));
236
+ if (platformAccessories.length) {
237
+ api.registerPlatformAccessories(exports.pluginName, exports.platformName, platformAccessories);
238
+ }
239
+ const staleAccessories = cachedAccessoryIds
240
+ .filter((cachedId) => !activeAccessoryIds.includes(cachedId))
241
+ .map((id) => this.homebridgeAccessories[id]);
242
+ staleAccessories.forEach((staleAccessory) => {
243
+ this.log.info(`Removing stale cached accessory ${staleAccessory.UUID} ${staleAccessory.displayName}`);
244
+ });
245
+ if (staleAccessories.length) {
246
+ this.api.unregisterPlatformAccessories(exports.pluginName, exports.platformName, staleAccessories);
247
+ }
248
+ ringApi.onRefreshTokenUpdated.subscribe(({ oldRefreshToken, newRefreshToken }) => {
249
+ if (!oldRefreshToken) {
250
+ return;
251
+ }
252
+ (0, config_1.updateHomebridgeConfig)(this.api, (configContents) => {
253
+ return configContents.replace(oldRefreshToken, newRefreshToken);
263
254
  });
264
255
  });
265
256
  }
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.SecurityPanel = void 0;
13
4
  const base_device_accessory_1 = require("./base-device-accessory");
@@ -95,51 +86,49 @@ class SecurityPanel extends base_device_accessory_1.BaseDeviceAccessory {
95
86
  }
96
87
  return this.getTargetState(data);
97
88
  }
98
- setTargetState(state) {
99
- return __awaiter(this, void 0, void 0, function* () {
100
- const { Characteristic: { SecuritySystemTargetState: State }, } = hap_1.hap, { location } = this.device, { nightModeBypassFor } = this.config;
101
- let bypass = false;
102
- this.targetingNightMode = state === State.NIGHT_ARM;
103
- if (state === State.NIGHT_ARM) {
104
- if (nightModeBypassFor &&
105
- (nightModeBypassFor === 'all' || nightModeBypassFor === 'some')) {
106
- state = nightModeBypassFor === 'all' ? State.AWAY_ARM : State.STAY_ARM;
107
- bypass = true;
108
- }
109
- else {
110
- // Switch to Home since we don't know which mode the user wanted
111
- state = State.STAY_ARM;
112
- }
89
+ async setTargetState(state) {
90
+ const { Characteristic: { SecuritySystemTargetState: State }, } = hap_1.hap, { location } = this.device, { nightModeBypassFor } = this.config;
91
+ let bypass = false;
92
+ this.targetingNightMode = state === State.NIGHT_ARM;
93
+ if (state === State.NIGHT_ARM) {
94
+ if (nightModeBypassFor &&
95
+ (nightModeBypassFor === 'all' || nightModeBypassFor === 'some')) {
96
+ state = nightModeBypassFor === 'all' ? State.AWAY_ARM : State.STAY_ARM;
97
+ bypass = true;
113
98
  }
114
- const bypassContactSensors = bypass
115
- ? (yield location.getDevices()).filter((device) => {
116
- return (device.deviceType === api_1.RingDeviceType.ContactSensor &&
117
- device.data.faulted);
118
- })
119
- : [], bypassSensorZids = bypassContactSensors.map((sensor) => sensor.id), bypassSensorNames = bypassContactSensors.map((sensor) => sensor.name), bypassLog = bypassSensorNames.length
120
- ? ' - Bypassing Sensors: ' + bypassSensorNames.join(', ')
121
- : '';
122
- try {
123
- if (state === State.AWAY_ARM) {
124
- this.logger.info(`Arming (Away) ${this.device.name}${bypassLog}`);
125
- yield location.armAway(bypassSensorZids);
126
- }
127
- else if (state === State.DISARM) {
128
- this.logger.info(`Disarming ${this.device.name}`);
129
- yield location.disarm();
130
- }
131
- else {
132
- this.logger.info(`Arming (Home) ${this.device.name}${bypassLog}`);
133
- yield location.armHome(bypassSensorZids);
134
- }
99
+ else {
100
+ // Switch to Home since we don't know which mode the user wanted
101
+ state = State.STAY_ARM;
135
102
  }
136
- catch (e) {
137
- this.logger.error(e);
138
- this.getService(hap_1.hap.Service.SecuritySystem)
139
- .getCharacteristic(hap_1.hap.Characteristic.SecuritySystemTargetState)
140
- .updateValue(this.getTargetState(this.device.data));
103
+ }
104
+ const bypassContactSensors = bypass
105
+ ? (await location.getDevices()).filter((device) => {
106
+ return (device.deviceType === api_1.RingDeviceType.ContactSensor &&
107
+ device.data.faulted);
108
+ })
109
+ : [], bypassSensorZids = bypassContactSensors.map((sensor) => sensor.id), bypassSensorNames = bypassContactSensors.map((sensor) => sensor.name), bypassLog = bypassSensorNames.length
110
+ ? ' - Bypassing Sensors: ' + bypassSensorNames.join(', ')
111
+ : '';
112
+ try {
113
+ if (state === State.AWAY_ARM) {
114
+ this.logger.info(`Arming (Away) ${this.device.name}${bypassLog}`);
115
+ await location.armAway(bypassSensorZids);
141
116
  }
142
- });
117
+ else if (state === State.DISARM) {
118
+ this.logger.info(`Disarming ${this.device.name}`);
119
+ await location.disarm();
120
+ }
121
+ else {
122
+ this.logger.info(`Arming (Home) ${this.device.name}${bypassLog}`);
123
+ await location.armHome(bypassSensorZids);
124
+ }
125
+ }
126
+ catch (e) {
127
+ this.logger.error(e);
128
+ this.getService(hap_1.hap.Service.SecuritySystem)
129
+ .getCharacteristic(hap_1.hap.Characteristic.SecuritySystemTargetState)
130
+ .updateValue(this.getTargetState(this.device.data));
131
+ }
143
132
  }
144
133
  }
145
134
  exports.SecurityPanel = SecurityPanel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homebridge-ring",
3
- "version": "10.0.0",
3
+ "version": "11.0.0",
4
4
  "description": "Homebridge plugin for Ring doorbells, cameras, security alarm system and smart lighting",
5
5
  "main": "lib/homebridge/index.js",
6
6
  "bin": {