forked from jsgoecke/tesla
-
Notifications
You must be signed in to change notification settings - Fork 18
/
energysite.go
176 lines (150 loc) · 5.71 KB
/
energysite.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package tesla
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
// this represents site_info endpoint
type EnergySite struct {
ID string `json:"id"`
SiteName string `json:"site_name"`
BackupReservePercent int64 `json:"backup_reserve_percent,omitempty"`
DefaultRealMode string `json:"default_real_mode,omitempty"`
productId int64
c *Client
}
type EnergySiteStatus struct {
ResourceType string `json:"resource_type"`
SiteName string `json:"site_name"`
GatewayId string `json:"gateway_id"`
EnergyLeft float64 `json:"energy_left"`
TotalPackEnergy uint64 `json:"total_pack_energy"`
PercentageCharged float64 `json:"percentage_charged"`
BatteryType string `json:"battery_type"`
BackupCapable bool `json:"backup_capable"`
BatteryPower int64 `json:"battery_power"`
c *Client
}
type EnergySiteHistory struct {
SerialNumber string `json:"serial_number"`
Period string `json:"period"`
TimeSeries []EnergySiteHistoryTimeSeries `json:"time_series"`
c *Client
}
type EnergySiteHistoryTimeSeries struct {
Timestamp time.Time `json:"timestamp"`
SolarEnergyExported float64 `json:"solar_energy_exported"`
GeneratorEnergyExported float64 `json:"generator_energy_exported"`
GridEnergyImported float64 `json:"grid_energy_imported"`
GridServicesEnergyImported float64 `json:"grid_services_energy_imported"`
GridServicesEnergyExported float64 `json:"grid_services_energy_exported"`
GridEnergyExportedFromSolar float64 `json:"grid_energy_exported_from_solar"`
GridEnergyExportedFromGenerator float64 `json:"grid_energy_exported_from_generator"`
GridEnergyExportedFromBattery float64 `json:"grid_energy_exported_from_battery"`
BatteryEnergyExported float64 `json:"battery_energy_exported"`
BatteryEnergyImportedFromGrid float64 `json:"battery_energy_imported_from_grid"`
BatteryEnergyImportedFromSolar float64 `json:"battery_energy_imported_from_solar"`
BatteryEnergyImportedFromGenerator float64 `json:"battery_energy_imported_from_generator"`
ConsumerEnergyImportedFromGrid float64 `json:"consumer_energy_imported_from_grid"`
ConsumerEnergyImportedFromSolar float64 `json:"consumer_energy_imported_from_solar"`
ConsumerEnergyImportedFromBattery float64 `json:"consumer_energy_imported_from_battery"`
ConsumerEnergyImportedFromGenerator float64 `json:"consumer_energy_imported_from_generator"`
}
type SiteInfoResponse struct {
Response *EnergySite `json:"response"`
}
type SiteStatusResponse struct {
Response *EnergySiteStatus `json:"response"`
}
type SiteHistoryResponse struct {
Response *EnergySiteHistory `json:"response"`
}
// SiteCommandResponse is the response from the Tesla API after POSTing a command.
type SiteCommandResponse struct {
Response struct {
Code int `json:"code"`
Message string `json:"message"`
} `json:"response"`
}
// return fetches the energy site for the given product ID
func (c *Client) EnergySite(productID int64) (*EnergySite, error) {
siteInfoResponse := &SiteInfoResponse{}
if err := c.getJSON(c.baseURL+"/energy_sites/"+strconv.FormatInt(productID, 10)+"/site_info", siteInfoResponse); err != nil {
return nil, err
}
siteInfoResponse.Response.c = c
siteInfoResponse.Response.productId = productID
return siteInfoResponse.Response, nil
}
func (s *EnergySite) EnergySiteStatus() (*EnergySiteStatus, error) {
siteStatusResponse := &SiteStatusResponse{}
if err := s.c.getJSON(s.statusPath(), siteStatusResponse); err != nil {
return nil, err
}
siteStatusResponse.Response.c = s.c
return siteStatusResponse.Response, nil
}
type HistoryPeriod string
const (
HistoryPeriodDay HistoryPeriod = "day"
HistoryPeriodWeek HistoryPeriod = "week"
HistoryPeriodMonth HistoryPeriod = "month"
HistoryPeriodYear HistoryPeriod = "year"
)
func (s *EnergySite) EnergySiteHistory(period HistoryPeriod) (*EnergySiteHistory, error) {
historyResponse := &SiteHistoryResponse{}
if err := s.c.getJSON(s.historyPath(period), historyResponse); err != nil {
return nil, err
}
historyResponse.Response.c = s.c
return historyResponse.Response, nil
}
func (s *EnergySite) basePath() string {
return strings.Join([]string{s.c.baseURL, "energy_sites", strconv.FormatInt(s.productId, 10)}, "/")
}
func (s *EnergySite) statusPath() string {
return strings.Join([]string{s.basePath(), "site_status"}, "/")
}
func (s *EnergySite) historyPath(period HistoryPeriod) string {
v := url.Values{}
v.Set("kind", "energy")
v.Set("period", string(period))
return strings.Join([]string{s.basePath(), "history"}, "/") + fmt.Sprintf("?%s", v.Encode())
}
func (s *EnergySite) SetBatteryReserve(percent uint64) error {
url := s.basePath() + "/backup"
payload := fmt.Sprintf(`{"backup_reserve_percent":%d}`, percent)
body, err := s.sendCommand(url, []byte(payload))
if err != nil {
return err
}
response := SiteCommandResponse{}
if err := json.Unmarshal(body, &response); err != nil {
return err
}
if response.Response.Code != 201 {
return fmt.Errorf("batteryReserve failed: %s", response.Response.Message)
}
return nil
}
// Sends a command to the vehicle
func (s *EnergySite) sendCommand(url string, reqBody []byte) ([]byte, error) {
body, err := s.c.post(url, reqBody)
if err != nil {
return nil, err
}
if len(body) > 0 {
response := &CommandResponse{}
if err := json.Unmarshal(body, response); err != nil {
return nil, err
}
if !response.Response.Result && response.Response.Reason != "" {
return nil, errors.New(response.Response.Reason)
}
}
return body, nil
}