Skip to content

Commit

Permalink
exporter completed
Browse files Browse the repository at this point in the history
  • Loading branch information
ryancurrah committed Jan 3, 2021
1 parent 6f3c045 commit 987487b
Show file tree
Hide file tree
Showing 10 changed files with 1,305 additions and 3 deletions.
8 changes: 6 additions & 2 deletions .gitignore
Expand Up @@ -11,5 +11,9 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/
# Goreleaser
dist/

# Secrets
client_secret.json
refresh_token.json
36 changes: 36 additions & 0 deletions .goreleaser.yml
@@ -0,0 +1,36 @@
before:
hooks:
- go mod download
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
main: ./cmd/smartdevicemanagement_exporter/main.go
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
dockers:
- binaries:
- smartdevicemanagement_exporter
image_templates:
- "ryancurrah/smartdevicemanagement_exporter:{{ .Tag }}"
- "ryancurrah/smartdevicemanagement_exporter:v{{ .Major }}"
- "ryancurrah/smartdevicemanagement_exporter:v{{ .Major }}.{{ .Minor }}"
- "ryancurrah/smartdevicemanagement_exporter:latest"
6 changes: 6 additions & 0 deletions Dockerfile
@@ -0,0 +1,6 @@
ARG ALPINE_VERSION=3.12
FROM alpine:${ALPINE_VERSION}
WORKDIR /
RUN apk --no-cache add ca-certificates
COPY smartdevicemanagement_exporter /smartdevicemanagement_exporter
ENTRYPOINT ./smartdevicemanagement_exporter
97 changes: 96 additions & 1 deletion README.md
@@ -1,2 +1,97 @@
# smartdevicemanagement_exporter
Google Nest Smart Device Management exporter for Prometheus.

Google Nest [Smart Device Management](https://developers.google.com/nest/device-access) exporter for Prometheus.

## Prerequisites

Guides you through the prerequisite items required to start using this exporter.

### Nest account migration

Ensure you migrate your Nest account to Google if you have not already done so https://www.blog.google/products/google-nest/its-time-nest-users-can-now-switch-google-accounts.

### Sign up for Google Device Access Console

Follow the getting started guide https://developers.google.com/nest/device-access/get-started.

When you are done you should have the following items completed.

1. Register for the Device Access program.
2. Activate a supported Nest device with a Google account.
3. Create a Google Cloud Platform (GCP) project to enable the SDM API and get an OAuth 2.0 client ID.
4. Create a Device Access project to receive a Project ID.

## Installation

You can download the binary for your `OS` and `Architecture` on the releases page. A Docker image is also provided which is also found on the releases page.

https://github.com/ryancurrah/smartdevicemanagement_exporter/releases

## Configuration

All the configuration parameters for this exporter.

- `-listen-address`. Envvar: `LISTEN_ADDRESS`. Default: `:8080`. Address to listen on for HTTP requests.
- `-project-id`. Envvar: `PROJECT_ID`. Default: . ID of the Smart Device Management project (Required).
- `-credentials`. Envvar: `CREDENTIALS`. Default: `client_secret.json`. Location on disk to the Oauth2 credentials JSON file.
- `-refresh-token`. Envvar: `REFRESH_TOKEN`. Default: `refresh_token.json`. Location on disk to store the Oauth2 refresh token JSON file.
- `-record-metrics-delay`. Envvar: `RECORD_METRICS_DELAY`. Default: `1m`. Delay between queries to the Smart Device Management API for recording metrics.

## Endpoints

All the HTTP endpoints for this exporter.

- `/metrics`. Prometheus metrics are exposed here for scraping.
- `/authstatus`. Provides the current authentication status of the exporter with Google APIs.
- `/authorize`. Starts or resets the authentication of the exporter with the Partner Connection Manager.

## Usage

Assuming you have stored the `client_secret.json` file in the current working directory start the exporter.

```shell
./smartdevicemanagement_exporter -project-id e14044ff-a995-4733-9672-ddad34c970d5
2021/01/03 14:19:48 running
```

Now authorize the exporter to use the Google APIs by visiting the authorize endpoint in your browser. You only have to do this once or when the `refresh_token.json` file is no longer valid.

```shell
open http://127.0.0.1:8080/authorize
```

Once your done filling out the prompts that authorize the exporter you will be redirected back to the exporter on a page that says: `authorization code received from partner connection manager`.

You can check the `stdout` and `/authstatus` page to see if the exporter has been successfully authorized.

```shell
open http://127.0.0.1:8080/authstatus
```

Now the exporter will start recording metrics.

```shell
open http://127.0.0.1:8080/metrics
```

## Metrics

Currently only Thermostat devices are supported.

```
# HELP sdm_thermostat_humidity_ambientHumidityPercent Percent humidity, measured at the device.
# TYPE sdm_thermostat_humidity_ambientHumidityPercent gauge
sdm_thermostat_humidity_ambientHumidityPercent{CustomName="",Name="DU1AeyLeA",Room="Hallway",Type="sdm.devices.types.THERMOSTAT"} 34
# HELP sdm_thermostat_temperature_ambientTemperatureCelsius Temperature in degrees Celsius, measured at the device.
# TYPE sdm_thermostat_temperature_ambientTemperatureCelsius gauge
sdm_thermostat_temperature_ambientTemperatureCelsius{CustomName="",Name="DU1AeyLeA",Room="Hallway",Type="sdm.devices.types.THERMOSTAT"} 22.189987
# HELP sdm_thermostat_thermostatTemperatureSetpoint_coolCelsius Target temperature in Celsius for thermostat COOL and HEATCOOL modes.
# TYPE sdm_thermostat_thermostatTemperatureSetpoint_coolCelsius gauge
sdm_thermostat_thermostatTemperatureSetpoint_coolCelsius{CustomName="",Name="DU1AeyLeA",Room="Hallway",Type="sdm.devices.types.THERMOSTAT"} 0
# HELP sdm_thermostat_thermostatTemperatureSetpoint_heatCelsius Target temperature in Celsius for thermostat HEAT and HEATCOOL modes.
# TYPE sdm_thermostat_thermostatTemperatureSetpoint_heatCelsius gauge
sdm_thermostat_thermostatTemperatureSetpoint_heatCelsius{CustomName="",Name="DU1AeyLeA",Room="Hallway",Type="sdm.devices.types.THERMOSTAT"} 22
```
104 changes: 104 additions & 0 deletions cmd/smartdevicemanagement_exporter/main.go
@@ -0,0 +1,104 @@
package main

import (
"context"
"flag"
"fmt"
"log"
"net/http"
"os"
"time"

"github.com/prometheus/client_golang/prometheus/promhttp"

smartdevicemanagementexporter "github.com/ryancurrah/smartdevicemanagement_exporter"
"github.com/ryancurrah/smartdevicemanagement_exporter/partnerconnmanager"
)

var addr = flag.String("listen-address", ":8080", "Address to listen on for HTTP requests.")
var pid = flag.String("project-id", "", "ID of the Smart Device Management project.")
var credentials = flag.String("credentials", "client_secret.json", "Location on disk to the Oauth2 credentials JSON file.")
var refreshToken = flag.String("refresh-token", "refresh_token.json", "Location on disk to store the Oauth2 refresh token JSON file.")
var recordMetricsDelay = flag.Duration("record-metrics-delay", time.Second*60, "Delay between queries to the Smart Device Management API for recording metrics.")

func main() {
flag.Parse()

addrEnv := os.Getenv("LISTEN_ADDRESS")
if addrEnv != "" {
*addr = addrEnv
}

pidEnv := os.Getenv("PROJECT_ID")
if pidEnv != "" {
*pid = pidEnv
}

credentialsEnv := os.Getenv("CREDENTIALS")
if credentialsEnv != "" {
*credentials = credentialsEnv
}

refreshTokenEnv := os.Getenv("REFRESH_TOKEN")
if refreshTokenEnv != "" {
*refreshToken = refreshTokenEnv
}

recordMetricsDelayEnv := os.Getenv("RECORD_METRICS_DELAY")

if recordMetricsDelayEnv != "" {
recordMetricsDelayDuration, err := time.ParseDuration(recordMetricsDelayEnv)
if err != nil {
log.Fatal(err)
}

*recordMetricsDelay = recordMetricsDelayDuration
}

ctx := context.Background()

config, err := smartdevicemanagementexporter.LoadOauth2Config(*credentials)
if err != nil {
log.Fatal(err)
}

authorizationCodeChan := make(chan partnerconnmanager.AuthorizationCode)

pcm := partnerconnmanager.PartnerConnManager{
AuthorizationCodeChan: authorizationCodeChan,
ClientID: config.ClientID,
ProjectID: *pid,
}

sdme := smartdevicemanagementexporter.SmartDeviceManagementExporter{
AuthorizationCodeChan: authorizationCodeChan,
Config: config,
ProjectID: *pid,
Ctx: ctx,
RefreshTokenFile: *refreshToken,
RecordMetricsDelay: *recordMetricsDelay,
}

go func() {
err := sdme.Start()
if err != nil {
log.Fatal(err)
}
}()

http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/authstatus", func(w http.ResponseWriter, r *http.Request) {
authStatus := "not authorized"
if sdme.IsClientRunning() {
authStatus = "authorized"
}

fmt.Fprint(w, authStatus)
})
http.HandleFunc("/authorize", pcm.AuthorizeHandler)
http.HandleFunc("/authorized", pcm.AuthorizedHandler)

log.Println("running")

log.Fatal(http.ListenAndServe(*addr, nil))
}
9 changes: 9 additions & 0 deletions go.mod
@@ -0,0 +1,9 @@
module github.com/ryancurrah/smartdevicemanagement_exporter

go 1.15

require (
github.com/prometheus/client_golang v1.9.0
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58
google.golang.org/api v0.36.0
)

0 comments on commit 987487b

Please sign in to comment.