-
Notifications
You must be signed in to change notification settings - Fork 13
/
fireboard.go
157 lines (136 loc) · 4.15 KB
/
fireboard.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package fireboard
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/circonus-labs/circonus-unified-agent/cua"
"github.com/circonus-labs/circonus-unified-agent/internal"
"github.com/circonus-labs/circonus-unified-agent/plugins/inputs"
)
// Fireboard gathers statistics from the fireboard.io servers
type Fireboard struct {
AuthToken string `toml:"auth_token"`
URL string `toml:"url"`
HTTPTimeout internal.Duration `toml:"http_timeout"`
client *http.Client
}
// NewFireboard return a new instance of Fireboard with a default http client
func NewFireboard() *Fireboard {
tr := &http.Transport{ResponseHeaderTimeout: time.Duration(3 * time.Second)}
client := &http.Client{
Transport: tr,
Timeout: time.Duration(4 * time.Second),
}
return &Fireboard{client: client}
}
// RTT fireboardStats represents the data that is received from Fireboard
type RTT struct {
Temp float64 `json:"temp"`
Channel int64 `json:"channel"`
Degreetype int `json:"degreetype"`
Created string `json:"created"`
}
type fireboardStats struct {
Title string `json:"title"`
UUID string `json:"uuid"`
Latesttemps []RTT `json:"latest_temps"`
}
// A sample configuration to only gather stats from localhost, default port.
const sampleConfig = `
## Specify auth token for your account
auth_token = "invalidAuthToken"
## You can override the fireboard server URL if necessary
# url = https://fireboard.io/api/v1/devices.json
## You can set a different http_timeout if you need to
## You should set a string using an number and time indicator
## for example "12s" for 12 seconds.
# http_timeout = "4s"
`
// SampleConfig Returns a sample configuration for the plugin
func (r *Fireboard) SampleConfig() string {
return sampleConfig
}
// Description Returns a description of the plugin
func (r *Fireboard) Description() string {
return "Read real time temps from fireboard.io servers"
}
// Init the things
func (r *Fireboard) Init() error {
if len(r.AuthToken) == 0 {
return fmt.Errorf("You must specify an authToken")
}
if len(r.URL) == 0 {
r.URL = "https://fireboard.io/api/v1/devices.json"
}
// Have a default timeout of 4s
if r.HTTPTimeout.Duration == 0 {
r.HTTPTimeout.Duration = time.Second * 4
}
r.client.Timeout = r.HTTPTimeout.Duration
return nil
}
// Gather Reads stats from all configured servers.
func (r *Fireboard) Gather(acc cua.Accumulator) error {
// Perform the GET request to the fireboard servers
req, err := http.NewRequest("GET", r.URL, nil)
if err != nil {
return err
}
req.Header.Set("Authorization", "Token "+r.AuthToken)
resp, err := r.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// Successful responses will always return status code 200
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusForbidden {
return fmt.Errorf("fireboard server responded with %d [Forbidden], verify your authToken", resp.StatusCode)
}
return fmt.Errorf("fireboard responded with unexpected status code %d", resp.StatusCode)
}
// Decode the response JSON into a new stats struct
var stats []fireboardStats
if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil {
return fmt.Errorf("unable to decode fireboard response: %w", err)
}
// Range over all devices, gathering stats. Returns early in case of any error.
for _, s := range stats {
r.gatherTemps(s, acc)
}
return nil
}
// Return text description of degree type (scale)
func scale(n int) string {
switch n {
case 1:
return "Celsius"
case 2:
return "Fahrenheit"
default:
return ""
}
}
// Gathers stats from a single device, adding them to the accumulator
func (r *Fireboard) gatherTemps(s fireboardStats, acc cua.Accumulator) {
// Construct lookup for scale values
for _, t := range s.Latesttemps {
tags := map[string]string{
"title": s.Title,
"uuid": s.UUID,
"channel": strconv.FormatInt(t.Channel, 10),
"scale": scale(t.Degreetype),
}
fields := map[string]interface{}{
"temperature": t.Temp,
}
acc.AddFields("fireboard", fields, tags)
}
}
func init() {
inputs.Add("fireboard", func() cua.Input {
return NewFireboard()
})
}