forked from danopstech/octopusenergy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
octopusenergy.go
142 lines (112 loc) Β· 3.37 KB
/
octopusenergy.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
//go:generate stringer -linecomment -type=FuelType
// Package octopusenergy proves an interface for Octopus Energy REST APIs.
package octopusenergy
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"reflect"
"github.com/google/go-querystring/query"
)
const (
// ProductCodeAgile180221 is the product code to Octopus current Agile tariff
ProductCodeAgile180221 = "AGILE-18-02-21"
defaultBaseURL = "https://api.octopus.energy/"
userAgent = "octopus-energy-api-client-go/0.0.0"
apiKeyEnvKey = "OCTOPUS_ENERGY_API_KEY"
)
type FuelType int
const (
FuelTypeElectricity FuelType = iota // electricity
FuelTypeGas // gas
)
type service struct {
client *Client
}
type Client struct {
// Base URL for API requests. Defaults to the public Octopus API.
BaseURL url.URL
//
auth string
// User agent used when communicating with the GitHub API.
userAgent string
// HTTP client used to communicate with the API.
HTTPClient *http.Client
common service // Reuse a single struct instead of allocating one for each service on the heap.
// Services used for talking to different parts of the Octopus API.
TariffCharge *TariffChargeService
MeterPoint *MeterPointService
Product *ProductService
GridSupplyPoint *GridSupplyPointService
Consumption *ConsumptionService
Account *AccountService
}
// NewClient accepts a config object and returns an initiated client ready to use.
func NewClient(cfg *Config) *Client {
url, _ := url.Parse(defaultBaseURL)
httpClient := http.DefaultClient
var auth string
if cfg.Endpoint != nil {
url, _ = url.Parse(*cfg.Endpoint)
}
if cfg.HTTPClient != nil {
httpClient = cfg.HTTPClient
}
if cfg.ApiKey != nil {
auth = base64.StdEncoding.EncodeToString([]byte(*cfg.ApiKey + ":"))
}
c := &Client{
BaseURL: *url,
auth: auth,
userAgent: userAgent,
HTTPClient: httpClient,
}
c.common.client = c
c.TariffCharge = (*TariffChargeService)(&c.common)
c.MeterPoint = (*MeterPointService)(&c.common)
c.Product = (*ProductService)(&c.common)
c.GridSupplyPoint = (*GridSupplyPointService)(&c.common)
c.Consumption = (*ConsumptionService)(&c.common)
c.Account = (*AccountService)(&c.common)
return c
}
func addParameters(url *url.URL, parameters interface{}) (*url.URL, error) {
v := reflect.ValueOf(parameters)
if v.Kind() == reflect.Ptr && v.IsNil() {
return url, nil
}
vs, err := query.Values(parameters)
if err != nil {
return url, err
}
url.RawQuery = vs.Encode()
return url, nil
}
func (c *Client) sendRequest(req *http.Request, authed bool, castTo interface{}) error {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.Header.Set("Accept", "application/json; charset=utf-8")
req.Header.Set("User-Agent", c.userAgent)
if authed && c.auth != "" {
req.Header.Set("Authorization", "Basic "+c.auth)
}
res, err := c.HTTPClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
var errRes errorResponse
if err = json.NewDecoder(res.Body).Decode(&errRes); err == nil {
// TODO: return common custom errors types
return errors.New(errRes.Detail)
}
return fmt.Errorf("unknown error, status code: %d", res.StatusCode)
}
if err = json.NewDecoder(res.Body).Decode(&castTo); err != nil {
return err
}
return nil
}