This commit is contained in:
jwalter1-quest 2020-04-20 16:56:45 -05:00
commit 6818ec9971
10 changed files with 73 additions and 77 deletions

View File

@ -1,34 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/mitchellh/mapstructure"
[[constraint]]
branch = "master"
name = "github.com/pkg/errors"
[[constraint]]
branch = "master"
name = "github.com/r3labs/sse"

12
Makefile Normal file
View File

@ -0,0 +1,12 @@
all: test build
build:
go build -v ./...
test:
go test -v ./...
clean:
go clean

View File

@ -1,4 +1,7 @@
# arlo-go # arlo-go
![](https://godoc.org/github.com/jeffreydwalter/arlo-go?status.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/jeffreydwalter/arlo-go)](https://goreportcard.com/report/github.com/jeffreydwalter/arlo-go)
![](gopher-arlo.png) ![](gopher-arlo.png)
> Go package for interacting with Netgear's Arlo camera system. > Go package for interacting with Netgear's Arlo camera system.
@ -10,9 +13,9 @@ My goal is to bring parity to the Python version asap. If you know what you're d
--- ---
It is by no means complete, although it does expose quite a bit of the Arlo interface in an easy to use Go pacakge. As such, this package does not come with unit tests (feel free to add them, or I will eventually) or guarantees. It is by no means complete, although it does expose quite a bit of the Arlo interface in an easy to use Go pacakge. As such, this package does not come with unit tests (feel free to add them, or I will eventually) or guarantees.
**All [contributions](https://github.com/jeffreydwalter/arlo/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) are welcome and appreciated!** **All [contributions](https://github.com/jeffreydwalter/arlo-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) are welcome and appreciated!**
**Please, feel free to [contribute](https://github.com/jeffreydwalter/arlo/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) to this repo or buy Jeff a beer!** [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=R77B7UXMLA6ML&lc=US&item_name=Jeff%20Needs%20Beer&item_number=buyjeffabeer&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) **Please, feel free to [contribute](https://github.com/jeffreydwalter/arlo-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) to this repo or buy Jeff a beer!** [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=R77B7UXMLA6ML&lc=US&item_name=Jeff%20Needs%20Beer&item_number=buyjeffabeer&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted)
--- ---
### Generous Benefactors (Thank you!) ### Generous Benefactors (Thank you!)
@ -20,13 +23,13 @@ No beers for Jeff yet! 🍺
--- ---
### Awesomely Smart Contributors (Thank you!) ### Awesomely Smart Contributors (Thank you!)
Just me so far... * [bwagner5](https://github.com/bwagner5) - Dec 8, 2019 - Migrated package from dep to go modules.
If You'd like to make a diffrence in the world and get your name on this most prestegious list, have a look at our [help wanted](https://github.com/jeffreydwalter/arlo/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) section! If You'd like to make a diffrence in the world and get your name on this most prestegious list, have a look at our [help wanted](https://github.com/jeffreydwalter/arlo-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) section!
--- ---
### Filing an Issue ### Filing an Issue
Please read the [Issue Guidelines and Policies](https://github.com/jeffreydwalter/arlo/wiki/Issue-Guidelines-and-Policies) wiki page **BEFORE** you file an issue. Thanks. Please read the [Issue Guidelines and Policies](https://github.com/jeffreydwalter/arlo-go/wiki/Issue-Guidelines-and-Policies) wiki page **BEFORE** you file an issue. Thanks.
--- ---
@ -34,15 +37,8 @@ Please read the [Issue Guidelines and Policies](https://github.com/jeffreydwalte
```bash ```bash
# Install latest stable package # Install latest stable package
$ go get github.com/jeffreydwalter/arlo-go $ go get github.com/jeffreydwalter/arlo-go
# Note: This package uses the `go dep` package for dependency management. If you plan on contributing to this package, you will be required to use [dep](https://github.com/golang/dep). Setting it up is outside the scope of this README, but if you want to contribute and aren't familiar with `dep`, I'm happy to get you.
``` ```
**NOTE 1:** arlo.netgear.com requires TLS 1.2 for their API. So, if you're getting ssl errors, it's most likely related to your version of openssl. You may need to upgrade your openssl library.
If you're running this library on OSX or macOS, they ship with `openssl v0.9.x` which does not support TLS 1.2. You should follow the instructions found [here](https://comeroutewithme.com/2016/03/13/python-osx-openssl-issue/) to upgrade your openssl library.
After installing all of the required libraries, you can import and use this library like so:
```golang ```golang
package main package main
@ -92,14 +88,19 @@ func main() {
// The go func() here makes this script download the files concurrently. // The go func() here makes this script download the files concurrently.
// If you want to download them serially for some reason, just remove the go func() call. // If you want to download them serially for some reason, just remove the go func() call.
go func() { go func() {
filename := fmt.Sprintf("%s %s.mp4", time.Unix(0, recording.UtcCreatedDate*int64(time.Millisecond)).Format(("2006-01-02 15:04:05")), recording.UniqueId) fileToWrite, err := os.Create(fmt.Sprintf("downloads/%s_%s.mp4", time.Unix(0, recording.UtcCreatedDate*int64(time.Millisecond)).Format(("2006-01-02_15.04.05")), recording.UniqueId))
defer fileToWrite.Close()
if err != nil {
log.Fatal(err)
}
// The videos produced by Arlo are pretty small, even in their longest, best quality settings. // The videos produced by Arlo are pretty small, even in their longest, best quality settings.
// DownloadFile() efficiently streams the file from the http.Response.Body directly to a file. // DownloadFile() efficiently streams the file from the http.Response.Body directly to a file.
if err := arlo.DownloadFile(recording.PresignedContentUrl, fmt.Sprintf("videos/%s", filename)); err != nil { if err := arlo.DownloadFile(recording.PresignedContentUrl, fileToWrite); err != nil {
log.Println(err) log.Println(err)
} else { } else {
log.Printf("Downloaded video %s from %s", recording.CreatedDate) log.Printf("Downloaded video %s from %s", recording.CreatedDate, recording.PresignedContentUrl)
} }
// Mark this go routine as done in the wait group. // Mark this go routine as done in the wait group.
@ -110,15 +111,19 @@ func main() {
// Wait here until all of the go routines are done. // Wait here until all of the go routines are done.
wg.Wait() wg.Wait()
// Delete all of the videos you just downloaded from the Arlo library.
// The below example demonstrates how you could delete the cloud recordings after downloading them.
// Simply uncomment the below code to start using it.
// Delete all of the videos you just downloaded from the Arlo library.
// Notice that you can pass the "library" object we got back from the GetLibrary() call. // Notice that you can pass the "library" object we got back from the GetLibrary() call.
if err := arlo.BatchDeleteRecordings(library); err != nil { /* if err := arlo.BatchDeleteRecordings(library); err != nil {
log.Println(err) log.Println(err)
return return
} } */
// If we made it here without an exception, then the videos were successfully deleted. // If we made it here without an exception, then the videos were successfully deleted.
log.Println("Batch deletion of videos completed successfully.") /* log.Println("Batch deletion of videos completed successfully.") */
} }
``` ```

View File

@ -43,8 +43,8 @@ func newArlo(user string, pass string) (arlo *Arlo) {
baseHeaders := make(http.Header) baseHeaders := make(http.Header)
baseHeaders.Add("DNT", "1") baseHeaders.Add("DNT", "1")
baseHeaders.Add("schemaVersion", "1") baseHeaders.Add("schemaVersion", "1")
baseHeaders.Add("Host", "arlo.netgear.com") baseHeaders.Add("Host", "my.arlo.com")
baseHeaders.Add("Referer", "https://arlo.netgear.com/") baseHeaders.Add("Referer", "https://my.arlo.com/")
c, _ := request.NewClient(BaseUrl, baseHeaders) c, _ := request.NewClient(BaseUrl, baseHeaders)

View File

@ -25,7 +25,7 @@ const (
DeviceTypeSiren = "siren" DeviceTypeSiren = "siren"
TransIdPrefix = "web" TransIdPrefix = "web"
BaseUrl = "https://arlo.netgear.com/hmsweb" BaseUrl = "https://my.arlo.com/hmsweb"
// TODO: Implement all of the following urls. There are many here I don't have devices for. :/ // TODO: Implement all of the following urls. There are many here I don't have devices for. :/
ActiveAutomationUri = "/users/devices/automation/active" ActiveAutomationUri = "/users/devices/automation/active"

View File

@ -111,7 +111,7 @@ func (e *eventStream) listen() (connected chan bool) {
connected <- true connected <- true
} else if notifyResponse.Status == "disconnected" { } else if notifyResponse.Status == "disconnected" {
e.disconnect() e.disconnect()
} else if notifyResponse.Action == "logout" { } else if notifyResponse.Action == "logout" {
e.disconnect() e.disconnect()
} else { } else {
e.subscriptions.rwmutex.RLock() e.subscriptions.rwmutex.RLock()

9
go.mod Normal file
View File

@ -0,0 +1,9 @@
module github.com/jeffreydwalter/arlo-go
go 1.13
require (
github.com/pkg/errors v0.8.1
github.com/r3labs/sse v0.0.0-20191120111931-24eacf438413
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933
)

18
go.sum Normal file
View File

@ -0,0 +1,18 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/r3labs/sse v0.0.0-20191120111931-24eacf438413 h1:bF3heZD0lrJF16uVKKJsorZjBS7ET5Y9QKYtgno7X4Q=
github.com/r3labs/sse v0.0.0-20191120111931-24eacf438413/go.mod h1:S8xSOnV3CgpNrWd0GQ/OoQfMtlg2uPRSuTzcSGrzwK8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk=
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -62,7 +62,7 @@ type Account struct {
type AppStore struct { type AppStore struct {
Enforce bool `json:"enforce"` Enforce bool `json:"enforce"`
LatestVersion string `json:"latestVersion"` LatestVersion string `json:"latestVersion"`
updateLink string `json:"updateLink"` UpdateLink string `json:"updateLink"`
} }
type Session struct { type Session struct {
@ -235,7 +235,7 @@ type BaseNightLightProperties struct {
Brightness int `json:"brightness,omitempty"` Brightness int `json:"brightness,omitempty"`
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
Mode string `json:"mode,omitempty"` Mode string `json:"mode,omitempty"`
RGB NightLightRGBProperties `json:"mode,omitempty"` RGB NightLightRGBProperties `json:"rgb,omitempty"`
SleepTime int64 `json:"sleepTime,omitempty"` SleepTime int64 `json:"sleepTime,omitempty"`
SleepTimeRel int `json:"sleepTimeRel,omitempty"` SleepTimeRel int `json:"sleepTimeRel,omitempty"`
} }

20
util.go
View File

@ -103,10 +103,12 @@ func (a *Arlo) DownloadFile(url, to string) error {
func (a *Arlo) DownloadFile(url string, w io.Writer) error { func (a *Arlo) DownloadFile(url string, w io.Writer) error {
msg := fmt.Sprintf("failed to download file (%s)", url) msg := fmt.Sprintf("failed to download file (%s)", url)
resp, err := a.get(url, "", nil)
resp, err := http.Get(url)
if err != nil { if err != nil {
return errors.WithMessage(err, msg) return errors.WithMessage(err, msg)
} }
defer resp.Body.Close() defer resp.Body.Close()
_, err = io.Copy(w, resp.Body) _, err = io.Copy(w, resp.Body)
@ -117,22 +119,6 @@ func (a *Arlo) DownloadFile(url string, w io.Writer) error {
return nil return nil
} }
func UnixMicro(t time.Time) int64 {
ns := t.UnixNano()
if ns < 0 {
return (ns - 999) / 1000
}
return ns / 1000
}
func UnixMilli(t time.Time) int64 {
ns := t.UnixNano()
if ns < 0 {
return (ns - 999999) / 1000000
}
return ns / 1000000
}
func FromUnixMicro(µs int64) time.Time { return time.Unix(0, 1000*µs) } func FromUnixMicro(µs int64) time.Time { return time.Unix(0, 1000*µs) }
func FromUnixMilli(ms int64) time.Time { return time.Unix(0, 1000000*ms) } func FromUnixMilli(ms int64) time.Time { return time.Unix(0, 1000000*ms) }