2018-09-19 07:07:32 +00:00
package arlo
2018-09-17 04:44:41 +00:00
import (
2020-05-27 08:49:40 +00:00
"context"
2018-09-17 04:44:41 +00:00
"fmt"
2018-09-20 22:38:01 +00:00
"time"
2018-09-17 04:44:41 +00:00
)
2020-05-27 08:49:40 +00:00
const eventStreamTimeout = 30 * time . Second
2018-09-22 14:15:22 +00:00
const pingTime = 30 * time . Second
2018-09-17 04:44:41 +00:00
// A Basestation is a Device that's not type "camera" (basestation, arloq, arloqs, etc.).
// This type is here just for semantics. Some methods explicitly require a device of a certain type.
type Basestation struct {
2020-06-13 10:21:29 +00:00
arlo * Arlo
2018-09-17 04:44:41 +00:00
Device
2020-05-27 08:49:40 +00:00
}
type GetModesResponse struct {
Active string ` json:"active" `
Modes [ ] * Mode ` json:"modes" `
}
type Mode struct {
Name string ` json:"name" `
Type string ` json:"type,omitempty" `
RulesIds [ ] string ` json:"rules" `
ID string ` json:"id" `
}
type GetRulesResponse struct {
Rules [ ] Rule ` json:"rules" `
}
type Rule struct {
Name string ` json:"name" `
Protected bool ` json:"protected" `
Triggers [ ] struct {
Type string ` json:"type" `
DeviceID string ` json:"deviceId" `
Sensitivity int ` json:"sensitivity" `
} ` json:"triggers" `
Actions [ ] struct {
Type string ` json:"type" `
Recipients [ ] string ` json:"recipients,omitempty" `
DeviceID string ` json:"deviceId,omitempty" `
StopCondition struct {
Type string ` json:"type" `
DeviceID string ` json:"deviceId" `
} ` json:"stopCondition,omitempty" `
} ` json:"actions" `
ID string ` json:"id" `
}
2020-05-27 11:35:02 +00:00
type CalendarMode struct {
Active bool ` json:"active" `
Schedule [ ] struct {
ModeID string ` json:"modeId" `
StartTime int ` json:"startTime" `
} ` json:"schedule" `
}
2020-06-13 10:21:29 +00:00
func NewBaseStation ( arlo * Arlo , device Device ) * Basestation {
return & Basestation {
arlo : arlo ,
Device : device ,
2018-09-22 14:15:22 +00:00
}
}
// makeEventStreamRequest is a helper function sets up a response channel, sends a message to the event stream, and blocks waiting for the response.
2020-05-27 11:35:02 +00:00
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) GetState ( ctx context . Context ) ( * BaseStationState , error ) {
2020-05-27 08:49:40 +00:00
var state BaseStationState
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "get" , "basestation" , false , nil , & state )
2020-05-27 08:49:40 +00:00
if err != nil {
return nil , fmt . Errorf ( "getting basestation %s state: %v" , b . DeviceName , err )
2018-09-19 07:07:32 +00:00
}
2020-05-27 08:49:40 +00:00
return & state , nil
2018-09-19 21:35:05 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) GetAllCameraState ( ctx context . Context ) ( [ ] CameraState , error ) {
2020-05-27 08:49:40 +00:00
var states [ ] CameraState
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "get" , "cameras" , false , nil , & states )
2020-05-27 08:49:40 +00:00
if err != nil {
return nil , fmt . Errorf ( "getting associated cameras state: %v" , err )
2018-09-20 22:38:01 +00:00
}
2020-05-27 08:49:40 +00:00
return states , nil
}
2018-09-19 21:35:05 +00:00
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) GetRules ( ctx context . Context ) ( [ ] Rule , error ) {
2020-05-27 08:49:40 +00:00
var resp GetRulesResponse
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "get" , "rules" , false , nil , & resp )
2020-05-27 08:49:40 +00:00
if err != nil {
return nil , fmt . Errorf ( "getting rules: %v" , err )
}
return resp . Rules , nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) GetCalendarMode ( ctx context . Context ) ( * CalendarMode , error ) {
2020-05-27 11:35:02 +00:00
var calendarMode CalendarMode
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "get" , "schedule" , false , nil , & calendarMode )
2020-05-27 11:35:02 +00:00
if err != nil {
return nil , fmt . Errorf ( "getting calendar mode: %v" , err )
2018-09-19 21:35:05 +00:00
}
2020-05-27 11:35:02 +00:00
return & calendarMode , nil
2018-09-20 22:38:01 +00:00
}
2018-09-19 21:35:05 +00:00
2018-09-20 22:38:01 +00:00
// SetCalendarMode toggles calendar mode.
// NOTE: The Arlo API seems to disable calendar mode when switching to other modes, if it's enabled.
// You should probably do the same, although, the UI reflects the switch from calendar mode to say armed mode without explicitly setting calendar mode to inactive.
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) SetCalendarMode ( ctx context . Context , active bool ) error {
2020-05-27 08:49:40 +00:00
resp := make ( map [ string ] bool )
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "set" , "schedule" , true , struct {
2020-05-27 08:49:40 +00:00
Active bool ` json:"active" `
} {
Active : active ,
} , & resp )
if err != nil {
return fmt . Errorf ( "setting calendar mode %t: %v" , active , err )
2018-09-17 04:44:41 +00:00
}
2020-05-27 08:49:40 +00:00
activemode , ok := resp [ "active" ]
if ! ok {
return fmt . Errorf ( "active mode not present in response" )
}
if activemode != active {
return fmt . Errorf ( "active mode is not the mode requested: requested %t, set %t" , active , activemode )
}
return nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) GetModes ( ctx context . Context ) ( * GetModesResponse , error ) {
2020-05-27 08:49:40 +00:00
var resp GetModesResponse
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "get" , "modes" , false , nil , & resp )
2020-05-27 08:49:40 +00:00
if err != nil {
return nil , fmt . Errorf ( "getting modes: %v" , err )
2018-09-20 22:38:01 +00:00
}
2020-05-27 08:49:40 +00:00
return & resp , nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) SetCustomMode ( ctx context . Context , mode string ) error {
2020-05-27 08:49:40 +00:00
resp := make ( map [ string ] string )
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "set" , "modes" , true , struct {
2020-05-27 08:49:40 +00:00
Active string ` json:"active" `
} {
Active : mode ,
} , & resp )
if err != nil {
return fmt . Errorf ( "setting custom mode %s: %v" , mode , err )
2018-09-19 21:35:05 +00:00
}
2020-05-27 08:49:40 +00:00
activemode , ok := resp [ "active" ]
if ! ok {
return fmt . Errorf ( "active mode not present in response" )
}
if activemode != mode {
return fmt . Errorf ( "active mode is not the mode requested: requested %s, set %s" , mode , activemode )
}
return nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) DeleteMode ( ctx context . Context , mode string ) error {
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "delete" , fmt . Sprintf ( "modes/%s" , mode ) , true , nil , nil )
2020-05-27 11:35:02 +00:00
if err != nil {
return fmt . Errorf ( "deleting mode %s: %v" , mode , err )
2018-09-20 22:38:01 +00:00
}
2020-05-27 11:35:02 +00:00
return nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) Arm ( ctx context . Context ) error {
err := b . SetCustomMode ( ctx , "mode1" )
2020-05-27 08:49:40 +00:00
if err != nil {
return fmt . Errorf ( "arming (mode1): %v" , err )
}
return nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) Disarm ( ctx context . Context ) error {
err := b . SetCustomMode ( ctx , "mode0" )
2020-05-27 08:49:40 +00:00
if err != nil {
return fmt . Errorf ( "disarming (mode0): %v" , err )
}
return nil
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
type SetSirenResponse struct {
SirenState string ` json:"sirenState" `
SirenTrigger string ` json:"sirenTrigger" `
Duration int ` json:"duration" `
Timestamp int64 ` json:"timestamp" `
2018-09-20 22:38:01 +00:00
}
2020-05-27 19:03:26 +00:00
func ( b * Basestation ) SirenOn ( ctx context . Context ) error {
var response SetSirenResponse
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "set" , "siren" , true , SirenProperties {
2020-05-27 19:03:26 +00:00
SirenState : "on" ,
Duration : 300 ,
Volume : 8 ,
Pattern : "alarm" ,
} , & response )
if err != nil {
return fmt . Errorf ( "making request: %v" , err )
}
if response . SirenState != "on" {
return fmt . Errorf ( "siren not on in response" )
}
return nil
}
func ( b * Basestation ) SirenOff ( ctx context . Context ) error {
var response SetSirenResponse
2020-06-13 10:21:29 +00:00
err := b . arlo . makeRequest ( ctx , b . DeviceId , b . XCloudId , "set" , "siren" , true , SirenProperties {
2020-05-27 19:03:26 +00:00
SirenState : "off" ,
Duration : 300 ,
Volume : 8 ,
Pattern : "alarm" ,
} , & response )
if err != nil {
return fmt . Errorf ( "making request: %v" , err )
}
if response . SirenState != "off" {
return fmt . Errorf ( "siren not off in response" )
}
return nil
2018-09-17 04:44:41 +00:00
}