Skip to content

Commit 15cca9a

Browse files
smockledgreif
authored andcommitted
feat(homebridge): add support for fans (#94)
1 parent 53748d0 commit 15cca9a

File tree

5 files changed

+79
-8
lines changed

5 files changed

+79
-8
lines changed

api/location.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class RingDevice {
4343
zid = this.initialData.zid
4444
id = this.zid
4545
deviceType = this.initialData.deviceType
46+
categoryId = this.initialData.categoryId
4647

4748
constructor(
4849
private initialData: RingDeviceData,

api/ring-types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export enum RingDeviceType {
1414
CoAlarm = 'alarm.co',
1515
SmokeCoListener = 'listener.smoke-co',
1616
MultiLevelSwitch = 'switch.multilevel',
17+
Fan = 'switch.multilevel',
1718
MultiLevelBulb = 'switch.multilevel.bulb',
1819
Switch = 'switch',
1920
BeamsMotionSensor = 'motion-sensor.beams',
@@ -22,6 +23,11 @@ export enum RingDeviceType {
2223
BeamsTransformerSwitch = 'switch.transformer.beams'
2324
}
2425

26+
export enum RingDeviceCategory {
27+
Fan = 17,
28+
MultiLevelSwitch = 2
29+
}
30+
2531
export enum RingCameraKind {
2632
doorbot = 'doorbot',
2733
doorbell = 'doorbell',
@@ -123,6 +129,7 @@ export interface RingDeviceData {
123129
zid: string
124130
name: string
125131
deviceType: RingDeviceType
132+
categoryId: number
126133
batteryLevel?: number
127134
batteryStatus: 'full' | 'charged' | 'ok' | 'low' | 'none' | 'charging'
128135
batteryBackup?: 'charged' | 'charging' | 'inUse'

homebridge/README.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
# homebridge-ring
2-
2+
33
[![CircleCI](https://circleci.com/gh/dgreif/ring.svg?style=svg)](https://circleci.com/gh/dgreif/ring)
44
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=HD9ZPB34FY428&currency_code=USD&source=url)
5-
5+
66
This [Homebridge](https://github.com/nfarina/homebridge) plugin provides a platform for
77
[Ring Doorbells](https://shop.ring.com/pages/doorbell-cameras),
88
[Ring Cameras](https://shop.ring.com/pages/security-cameras),
99
the [Ring Alarm System](https://shop.ring.com/pages/security-system),
1010
[Ring Smart Lighting](https://shop.ring.com/pages/smart-lighting),
1111
and third party devices that connect to the Ring Alarm System.
12+
1213

1314
## Installation
1415

@@ -82,8 +83,8 @@ Option | Default | Explanation
8283
`hideCameraSirenSwitch` | `false` | If `true`, hides the siren switch for Ring cameras in HomeKit.
8384
`hideAlarmSirenSwitch` | `false` | If you have a Ring Alarm, you will see both the alarm and a "Siren" switch in HomeKit. The siren switch can sometimes get triggered by Siri commands by accident, which is loud and annoying. Set this option to `true` to hide the siren switch.
8485
`cameraStatusPollingSeconds` | `20` | How frequently to poll for updates to your cameras. Information like light/siren status do not update in real time and need to be requested periodically.
85-
`cameraDingsPollingSeconds` | `2` | How frequently to poll for new events from your cameras. These include motion and doorbell presses.
86-
`locationIds` | All Locations | Use this option if you only want a subset of your locations to appear in HomeKit. If this option is not included, all of your locations will be added to HomeKit (which is what most users will want to do).
86+
`cameraDingsPollingSeconds` | `2` | How frequently to poll for new events from your cameras. These include motion and doorbell presses.
87+
`locationIds` | All Locations | Use this option if you only want a subset of your locations to appear in HomeKit. If this option is not included, all of your locations will be added to HomeKit (which is what most users will want to do).
8788

8889
### Camera Setup
8990

@@ -92,7 +93,7 @@ Don't worry, it's really easy. Due to homebridge/HAP limitations, the cameras ca
9293
Configure the homebridge plugin like normal, then click on the "+" in the upper right in
9394
the Home app, then "Don't have a Code or Can't Scan?", then you should see the cameras listed as individual devices which
9495
which you can add. The code that you need for each is the same code you used when setting up homebridge. It should be in
95-
the output when you start homebridge, or in your homebridge `config.json` file.
96+
the output when you start homebridge, or in your homebridge `config.json` file.
9697
Walk through the setup pages and when you are done, you should see several devices related to the camera:
9798

9899
* Camera Feed
@@ -115,7 +116,7 @@ If you turn on notifications for the motion sensors, or for any doorbell camera,
115116
HomeKit with a snapshot from the camera
116117

117118
If you are having issues with your cameras in the Home app, please see the [Camera Troubleshooting Wiki](https://github.com/dgreif/ring/wiki/Camera-Troubleshooting)
118-
119+
119120
### Supported Devices via Ring Alarm and Ring Smart Lighting Hubs
120121
* Security Panel
121122
* This is a software device that represents the alarm for a Ring location
@@ -145,6 +146,9 @@ If you are having issues with your cameras in the Home app, please see the [Came
145146
* Carbon Monoxide Alarm
146147
* Smoke/Carbon Monoxide Listener
147148
* Smart Locks
149+
* Fans
150+
* On/Off
151+
* Speed
148152
* Lights/Switches
149153
* On/Off
150154
* Brightness Level (if applicable)
@@ -165,7 +169,7 @@ Entry delays and bypassed sensors (ex. for Home mode) are all controlled in the
165169
These settings will automatically be used by HomeKit.
166170

167171
**Note**: Using `Night` mode in HomeKit will activate `Home` mode on the Ring alarm.
168-
HomeKit should immediately switch to `Home` to match.
172+
HomeKit should immediately switch to `Home` to match.
169173

170174
### Siri Commands for Alarm
171175

homebridge/fan.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { BaseDeviceAccessory } from './base-device-accessory'
2+
import { RingDevice } from '../api'
3+
import { HAP, hap } from './hap'
4+
import { RingPlatformConfig } from './config'
5+
6+
export class Fan extends BaseDeviceAccessory {
7+
constructor(
8+
public readonly device: RingDevice,
9+
public readonly accessory: HAP.Accessory,
10+
public readonly logger: HAP.Log,
11+
public readonly config: RingPlatformConfig
12+
) {
13+
super()
14+
15+
const { Characteristic, Service } = hap
16+
const { data: initialData } = this.device
17+
18+
this.registerCharacteristic(
19+
Characteristic.On,
20+
Service.Fan,
21+
data => Boolean(data.on),
22+
value => this.setOnState(value)
23+
)
24+
25+
if (initialData.level !== undefined) {
26+
this.registerLevelCharacteristic(
27+
Characteristic.RotationSpeed,
28+
Service.Fan,
29+
data => (data.level && !isNaN(data.level) ? 100 * data.level : 0),
30+
value => this.setLevelState(value)
31+
)
32+
}
33+
}
34+
35+
setOnState(on: boolean) {
36+
this.logger.info(`Turning ${this.device.name} ${on ? 'On' : 'Off'}`)
37+
38+
return this.device.setInfo({ device: { v1: { on } } })
39+
}
40+
41+
setLevelState(level: number) {
42+
this.logger.info(`Setting speed of ${this.device.name} to ${level}%`)
43+
44+
return this.device.setInfo({
45+
device: { v1: { level: level / 100 } }
46+
})
47+
}
48+
}

homebridge/ring-platform.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { RingApi, RingCamera, RingDevice, RingDeviceType } from '../api'
1+
import {
2+
RingApi,
3+
RingCamera,
4+
RingDevice,
5+
RingDeviceType,
6+
RingDeviceCategory
7+
} from '../api'
28
import { HAP, hap } from './hap'
39
import { SecurityPanel } from './security-panel'
410
import { BaseStation } from './base-station'
@@ -12,6 +18,7 @@ import { SmokeCoListener } from './smoke-co-listener'
1218
import { RingPlatformConfig } from './config'
1319
import { Beam } from './beam'
1420
import { MultiLevelSwitch } from './multi-level-switch'
21+
import { Fan } from './fan'
1522
import { Switch } from './switch'
1623
import { Camera } from './camera'
1724
import { RingAuth } from '../api/rest-client'
@@ -48,6 +55,10 @@ function getAccessoryClass(device: RingDevice | RingCamera) {
4855
case RingDeviceType.BeamsLightGroupSwitch:
4956
return Beam
5057
case RingDeviceType.MultiLevelSwitch:
58+
return device instanceof RingDevice &&
59+
device.categoryId === RingDeviceCategory.Fan
60+
? Fan
61+
: MultiLevelSwitch
5162
case RingDeviceType.MultiLevelBulb:
5263
return MultiLevelSwitch
5364
case RingDeviceType.Switch:

0 commit comments

Comments
 (0)