Skip to content

Commit

Permalink
feat: rest 2nd gen support
Browse files Browse the repository at this point in the history
  • Loading branch information
dgreif committed May 8, 2022
1 parent 54e1f72 commit ea30705
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"no-catch-shadow": 2,
"no-delete-var": 2,
"no-label-var": 2,
"no-shadow": 2,
"no-shadow": 0,
"no-shadow-restricted-names": 2,
"no-undef": 2,
"no-undef-init": 2,
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [3.3.0-beta.1](https://github.com/dgreif/homebridge-hatch-baby-rest/compare/v3.3.0-beta.0...v3.3.0-beta.1) (2021-12-27)

## [3.3.0-beta.0](https://github.com/dgreif/homebridge-hatch-baby-rest/compare/v3.2.5...v3.3.0-beta.0) (2021-12-26)


### Features

* rest 2nd gen support ([efdf49d](https://github.com/dgreif/homebridge-hatch-baby-rest/commit/efdf49d0e75a386eb1908d94079bc2bb7ea0daba))

### [3.2.5](https://github.com/dgreif/homebridge-hatch-baby-rest/compare/v3.2.4...v3.2.5) (2021-11-27)


Expand Down
18 changes: 18 additions & 0 deletions examples/riot-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'dotenv/config'
import { HatchBabyApi } from '../src/api'

const { env } = process

async function example() {
const api = new HatchBabyApi({
email: env.HBR_EMAIL!,
password: env.HBR_PASSWORD!,
}),
devices = await api.getDevices(),
riot = devices.restIots[0]

await riot.turnOnRoutine()
setTimeout(() => riot.turnOff(), 4000)
}

example()
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "homebridge-hatch-baby-rest",
"version": "3.2.5",
"version": "3.3.0-beta.1",
"description": "Homebridge plugin for Hatch Baby Rest bluetooth night light",
"main": "lib/index.js",
"scripts": {
Expand Down
8 changes: 5 additions & 3 deletions src/accessories/restore-accessory.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { hap } from '../hap'
import { PlatformAccessory } from 'homebridge'
import { BaseAccessory } from './base-accessory'
import { RestIot } from '../rest-iot'
import { Restore } from '../restore'
import { logInfo } from '../util'

export class RestoreAccessory extends BaseAccessory {
constructor(restore: Restore, accessory: PlatformAccessory) {
constructor(restore: Restore | RestIot, accessory: PlatformAccessory) {
super(restore, accessory)

const { Service, Characteristic } = hap,
onOffService = this.getService(Service.Switch)
onOffService = this.getService(Service.Switch),
stepName = restore instanceof RestIot ? 'favorite' : 'bedtime step'

this.registerCharacteristic(
onOffService.getCharacteristic(Characteristic.On),
restore.onSomeContentPlaying,
(on) => {
logInfo(
`Turning ${on ? 'on first bedtime step for' : 'off'} ${restore.name}`
`Turning ${on ? `on first ${stepName} for` : 'off'} ${restore.name}`
)
if (on) {
restore.turnOnRoutine()
Expand Down
31 changes: 23 additions & 8 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { thingShadow as AwsIotDevice } from 'aws-iot-device-sdk'
import { logDebug, logError, logInfo } from './util'
import { RestPlus } from './rest-plus'
import { RestIot } from './rest-iot'
import { RestMini } from './rest-mini'
import { Restore } from './restore'
import { BehaviorSubject } from 'rxjs'
Expand All @@ -17,7 +18,13 @@ import { debounceTime } from 'rxjs/operators'

export interface ApiConfig extends EmailAuth {}

const knownProducts = [Product.restPlus, Product.restMini, Product.restore],
const knownProducts = [
Product.restPlus,
Product.riot,
Product.restMini,
Product.restore,
Product.restoreIot,
],
productFetchQueryString = knownProducts
.map((product) => 'iotProducts=' + product)
.join('&'),
Expand Down Expand Up @@ -148,13 +155,17 @@ export class HatchBabyApi {
this.getOnIotClient(),
this.getMember(),
]),
createDevice = <T extends IotDevice<any>>(
product: string,
Device: new (info: IotDeviceInfo, onClient: typeof onIotClient) => T
createDevices = <T extends IotDevice<any>>(
product: Product,
Device: new (
info: IotDeviceInfo,
onClient: typeof onIotClient,
restClient: RestClient
) => T
): T[] => {
return devices
.filter((device) => device.product === product)
.map((info) => new Device(info, onIotClient))
.map((info) => new Device(info, onIotClient, this.restClient))
}

for (const product of member.products) {
Expand All @@ -164,9 +175,13 @@ export class HatchBabyApi {
}

return {
restPluses: createDevice(Product.restPlus, RestPlus),
restMinis: createDevice(Product.restMini, RestMini),
restores: createDevice(Product.restore, Restore),
restPluses: createDevices(Product.restPlus, RestPlus),
restIots: createDevices(Product.riot, RestIot),
restMinis: createDevices(Product.restMini, RestMini),
restores: [
...createDevices(Product.restore, Restore),
...createDevices(Product.restoreIot, Restore),
],
}
}
}
102 changes: 91 additions & 11 deletions src/hatch-sleep-types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { ApiConfig } from './api'

// eslint-disable-line no-shadow
export const enum Product {
rest = 'rest',
riot = 'riot',
restPlus = 'restPlus',
restMini = 'restMini',
restore = 'restore',
restoreIot = 'restoreIot',
}

export interface Baby {
Expand Down Expand Up @@ -148,6 +151,15 @@ interface Audio {
v: number // volume, max 65535
}

export interface IotSound {
id: number
mute: boolean
url: string
until: 'indefinite' | 'duration' | string
duration: number
v: number
}

export interface RestPlusState {
owned: boolean
a: Audio
Expand Down Expand Up @@ -227,6 +239,83 @@ export interface RestPlusState {
debug: number
}

export interface RestIotState {
env: 'prod' | string
alarmsDisabled: boolean
nightlightOn: boolean
nightlightIntensity: number
toddlerLockOn: boolean
snoozeDuration: 540
current: {
srId: number
playing: 'none' | 'remote' | 'routine' | string
step: number
color: {
i: number
id: number
r: number
g: number
b: number
w: number
duration: number
until: 'indefinite'
}
sound: IotSound
}
dataVersion: string
sleepScene: {
srId: number
enabled: boolean
}
timer: { s: string; d: number }
timezone: string
rF: {
v: string
i: boolean
u: string
}
deviceInfo: { f: string; fR: number; hwVersion: string }
clock: {
i: number
turnOffAt: string
turnOnAt: string
flags: number
turnOffMode: 'never' | string
}
toddlerLock: {
turnOffAt: string
turnOnAt: string
turnOnMode: 'never' | string
}
lucky: number
LDR: 'OK' | string
LWTP: boolean
debug: number
logging: number
owned: boolean
lastReset: 'PowerOn' | string
REX: { lock: number; key: number; command: 'none' | string }
connected: boolean
rssi: number
streaming: { status: 'none' | string }
}

export interface RestIotFavorite {
id: number
macAddress: string
name: string
type: 'favorite'
active: boolean
enabled: boolean
displayOrder: number
sleepScene: boolean
followBySleepScene: boolean
startTime: null
endTime: null
daysOfWeek: null
steps: any[]
}

export interface RestoreState {
alarmsDisabled: boolean
snoozeDuration: number
Expand Down Expand Up @@ -370,25 +459,16 @@ export const restMiniAudioTracks = [
RestMiniAudioTrack.Heartbeat,
]

export interface RestMiniSound {
id: number
mute: boolean
url: string
until: 'indefinite' | 'duration' | string
duration: number
v: number
}

export interface RestMiniState {
env: 'prod' | string
current: {
playing: 'none' | 'remote' | string
step: number
sound: RestMiniSound
sound: IotSound
}
playNext: {
enabled: boolean
sound: RestMiniSound & {
sound: IotSound & {
ignoreVolume: boolean
}
}
Expand Down
18 changes: 12 additions & 6 deletions src/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { HatchBabyPlatformOptions } from './hatch-sleep-types'
import { Rest } from './rest'
import { RestoreAccessory } from './accessories/restore-accessory'
import { RestIot } from './rest-iot'
import { Restore } from './restore'

export class HatchBabyRestPlatform implements DynamicPlatformPlugin {
Expand Down Expand Up @@ -67,19 +68,24 @@ export class HatchBabyRestPlatform implements DynamicPlatformPlugin {
this.config.restLights?.map(
(lightConfig) => new Rest(lightConfig.name, lightConfig.macAddress)
) || [],
{ restPluses, restMinis, restores } = hatchBabyApi
{ restPluses, restMinis, restores, restIots } = hatchBabyApi
? await hatchBabyApi.getDevices()
: { restPluses: [], restMinis: [], restores: [] },
lights = [...restLights, ...restPluses],
: { restPluses: [], restMinis: [], restores: [], restIots: [] },
{ api } = this,
cachedAccessoryIds = Object.keys(this.homebridgeAccessories),
platformAccessories: PlatformAccessory[] = [],
activeAccessoryIds: string[] = [],
debugPrefix = isTestHomebridge ? 'TEST ' : '',
devices = [...lights, ...restMinis, ...restores]
devices = [
...restLights,
...restPluses,
...restMinis,
...restIots,
...restores,
]

this.log.info(
`Configuring ${restLights.length} Rest, ${restPluses.length} Rest+, ${restMinis.length} Rest Mini, and ${restores.length} Restore Devices`
`Configuring ${restLights.length} Rest, ${restPluses.length} Rest+, ${restMinis.length} Rest Mini, ${restIots.length} Rest 2nd Gens, and ${restores.length} Restore Devices`
)

devices.forEach((device) => {
Expand All @@ -102,7 +108,7 @@ export class HatchBabyRestPlatform implements DynamicPlatformPlugin {
homebridgeAccessory =
this.homebridgeAccessories[uuid] || createHomebridgeAccessory()

if (device instanceof Restore) {
if (device instanceof Restore || device instanceof RestIot) {
new RestoreAccessory(device, homebridgeAccessory)
} else if ('onBrightness' in device) {
new LightAndSoundMachineAccessory(device, homebridgeAccessory)
Expand Down

0 comments on commit ea30705

Please sign in to comment.