diff --git a/api/rest-client.ts b/api/rest-client.ts index 85342a89..20fd412c 100644 --- a/api/rest-client.ts +++ b/api/rest-client.ts @@ -1,5 +1,5 @@ import axios, { AxiosRequestConfig, ResponseType } from 'axios' -import { delay, generateRandomId, logError, logInfo } from './util' +import { delay, generateRandomId, logError, logInfo, stringify } from './util' import * as querystring from 'querystring' import { AuthTokenResponse, SessionResponse } from './ring-types' @@ -184,7 +184,7 @@ export class RingRestClient { waitSeconds = isNaN(retryAfter) ? 200 : Number.parseInt(retryAfter) logError( - `Session response rate limited. Waiting to retry for ${waitSeconds} seconds` + `Session response rate limited. Waiting to retry after ${waitSeconds} seconds` ) await delay((waitSeconds + 1) * 1000) @@ -265,11 +265,16 @@ export class RingRestClient { } if (response.status === 404 && url.startsWith(clientApiBaseUrl)) { - logError( - 'Session hardware_id not found. Creating a new session and trying again.' - ) - this.refreshSession() - return this.request(options) + logError('404 from endpoint ' + url) + if (response.data === '') { + logError( + 'Session hardware_id not found. Creating a new session and trying again.' + ) + this.refreshSession() + return this.request(options) + } + + throw new Error('Not found with response: ' + stringify(response.data)) } logError(`Request to ${url} failed`) diff --git a/api/ring-camera.ts b/api/ring-camera.ts index 6692ee50..905788dc 100644 --- a/api/ring-camera.ts +++ b/api/ring-camera.ts @@ -102,6 +102,14 @@ export class RingCamera { return getBatteryLevel(this.data) } + get hasLowBattery() { + return this.data.alerts.battery === 'low' + } + + get isOffline() { + return this.data.alerts.connection === 'offline' + } + doorbotUrl(path: string) { return clientApi(`doorbots/${this.id}/${path}`) } diff --git a/api/util.ts b/api/util.ts index d524c36a..f9d4fd91 100644 --- a/api/util.ts +++ b/api/util.ts @@ -65,3 +65,15 @@ export async function requestInput(question: string) { return answer.trim() } + +export function stringify(data: any) { + if (typeof data === 'string') { + return data + } + + if (typeof data === 'object' && Buffer.isBuffer(data)) { + return data.toString() + } + + return JSON.stringify(data) + '' +} diff --git a/homebridge/camera-source.ts b/homebridge/camera-source.ts index 42bf5467..3bdee875 100644 --- a/homebridge/camera-source.ts +++ b/homebridge/camera-source.ts @@ -73,9 +73,18 @@ export class CameraSource { request: { width: number; height: number }, callback: (err?: Error, snapshot?: Buffer) => void ) { + const start = Date.now() try { - const start = Date.now() this.logger.info(`Snapshot Requested for ${this.ringCamera.name}`) + + if (this.ringCamera.isOffline) { + this.logger.error( + `Cannot retrieve snapshot because ${this.ringCamera.name} is offline. Make sure it has power and a good wifi connection.` + ) + callback(new Error('Offline')) + return + } + const snapshot = await this.ringCamera.getSnapshot(true), duration = (Date.now() - start) / 1000 this.logger.info( @@ -87,6 +96,16 @@ export class CameraSource { // HomeKit does a good job of resizing and doesn't seem to care if it's not right callback(undefined, snapshot) } catch (e) { + this.logger.error( + `Failed to retrieve snapshot for ${ + this.ringCamera.name + } (${getDurationSeconds( + start + )}s). Make sure the camera has power and a good wifi connection. The camera currently reports that is it ${ + this.ringCamera.isOffline ? 'offline' : 'online' + }` + ) + this.logger.error(e) callback(e) } } diff --git a/homebridge/camera.ts b/homebridge/camera.ts index 3ade0138..f2e90670 100644 --- a/homebridge/camera.ts +++ b/homebridge/camera.ts @@ -107,8 +107,8 @@ export class Camera extends BaseAccessory { this.registerCharacteristic( Characteristic.StatusLowBattery, Service.BatteryService, - data => { - return data.alerts.battery === 'low' + () => { + return device.hasLowBattery ? StatusLowBattery.BATTERY_LEVEL_LOW : StatusLowBattery.BATTERY_LEVEL_NORMAL }