Skip to content

Commit b1079e6

Browse files
committed
init!
0 parents  commit b1079e6

13 files changed

+904
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea/

LICENCE

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Copyright (c) 2015, Serge Gebhardt <>
2+
Copyright (c) 2021, Sjur Fredriksen
3+
4+
Permission to use, copy, modify, and/or distribute this software for any
5+
purpose with or without fee is hereby granted, provided that the above
6+
copyright notice and this permission notice appear in all copies.
7+
8+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

client.go

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package smartcharge
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
"io"
9+
"io/ioutil"
10+
"net/http"
11+
"net/url"
12+
"strings"
13+
)
14+
15+
const (
16+
LibraryVersion = "0.1.0"
17+
defaultBaseUrl = "https://api.smartcharge.io/"
18+
userAgent = "smartcharge-go/" + LibraryVersion
19+
)
20+
21+
type Client struct {
22+
httpClient *http.Client
23+
24+
BaseURL *url.URL
25+
26+
UserAgent string
27+
28+
ChargePoint *ChargePointService
29+
Session *SessionService
30+
}
31+
32+
func NewClient(httpClient *http.Client) *Client {
33+
if httpClient == nil {
34+
httpClient = http.DefaultClient
35+
}
36+
baseUrl, _ := url.Parse(defaultBaseUrl)
37+
38+
c := &Client{
39+
httpClient: httpClient,
40+
BaseURL: baseUrl,
41+
UserAgent: userAgent,
42+
}
43+
44+
c.ChargePoint = &ChargePointService{client: c}
45+
c.Session = &SessionService{client: c}
46+
47+
return c
48+
}
49+
50+
func (c *Client) NewRequest(method string, urlStr string, body interface{}) (*http.Request, error) {
51+
rel, err := url.Parse(urlStr)
52+
if err != nil {
53+
return nil, err
54+
}
55+
56+
u := c.BaseURL.ResolveReference(rel)
57+
58+
bodyReader, ok := body.(io.Reader)
59+
if !ok && body != nil {
60+
buf := &bytes.Buffer{}
61+
err := json.NewEncoder(buf).Encode(body)
62+
if err != nil {
63+
return nil, err
64+
}
65+
bodyReader = buf
66+
}
67+
68+
req, err := http.NewRequest(method, u.String(), bodyReader)
69+
if err != nil {
70+
return nil, err
71+
}
72+
73+
if c.UserAgent != "" {
74+
req.Header.Add("User-Agent", c.UserAgent)
75+
}
76+
return req, nil
77+
}
78+
79+
func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
80+
resp, err := c.httpClient.Do(req)
81+
if err != nil {
82+
return nil, err
83+
}
84+
85+
if v != nil {
86+
defer resp.Body.Close()
87+
}
88+
89+
err = CheckResponse(resp)
90+
if err != nil {
91+
if v == nil {
92+
_ = resp.Body.Close()
93+
}
94+
return resp, err
95+
}
96+
97+
if v != nil {
98+
if w, ok := v.(io.Writer); ok {
99+
_, _ = io.Copy(w, resp.Body)
100+
} else {
101+
err = json.NewDecoder(resp.Body).Decode(v)
102+
}
103+
}
104+
return resp, err
105+
}
106+
107+
func CheckResponse(r *http.Response) error {
108+
c := r.StatusCode
109+
if 200 <= c && c <= 299 {
110+
return nil
111+
}
112+
113+
errBody := ""
114+
if data, err := ioutil.ReadAll(r.Body); err == nil {
115+
errBody = strings.TrimSpace(string(data))
116+
}
117+
118+
errMsg := fmt.Sprintf("HTTP code %v: %q: ", c, r.Status)
119+
if errBody == "" {
120+
errMsg += "no response body"
121+
} else {
122+
errMsg += fmt.Sprintf("response body: %q", errBody)
123+
}
124+
125+
return errors.New(errMsg)
126+
}

client_mock_test.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2015 Serge Gebhardt. All rights reserved.
2+
//
3+
// Use of this source code is governed by the ISC
4+
// license that can be found in the LICENSE file.
5+
6+
package smartcharge
7+
8+
import (
9+
"bytes"
10+
"io/ioutil"
11+
"net/http"
12+
)
13+
14+
// MockResponse is a static HTTP response.
15+
type MockResponse struct {
16+
Code int
17+
Body []byte
18+
}
19+
20+
// NewMockResponseOkString creates a new MockResponse with Code 200 (OK)
21+
// and Body built from string argument
22+
func NewMockResponseOkString(response string) *MockResponse {
23+
return &MockResponse{
24+
Code: 200,
25+
Body: []byte(response),
26+
}
27+
}
28+
29+
// mockTransport is a mocked Transport that always returns the same MockResponse.
30+
type mockTransport struct {
31+
resp MockResponse
32+
}
33+
34+
// Satisfies the RoundTripper interface.
35+
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
36+
r := http.Response{
37+
StatusCode: t.resp.Code,
38+
Proto: "HTTP/1.0",
39+
ProtoMajor: 1,
40+
ProtoMinor: 0,
41+
}
42+
43+
if len(t.resp.Body) > 0 {
44+
buf := bytes.NewBuffer(t.resp.Body)
45+
r.Body = ioutil.NopCloser(buf)
46+
}
47+
48+
return &r, nil
49+
}
50+
51+
// MockClient is a mocked Client that is used for tests.
52+
func NewMockClient(response MockResponse) *Client {
53+
t := &mockTransport{resp: response}
54+
c := &http.Client{Transport: t}
55+
return NewClient(c)
56+
}

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/sjurtf/smartcharge-go
2+
3+
go 1.15
4+
5+
require github.com/stretchr/testify v1.7.0

go.sum

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
6+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
7+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
8+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
9+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
10+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
11+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

session.go

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package smartcharge
2+
3+
import (
4+
"net/http"
5+
"strconv"
6+
)
7+
8+
type LiveDataResult struct {
9+
Result LiveData
10+
}
11+
12+
type LiveData struct {
13+
Currency string `json:"Currency"`
14+
IsSuspended bool `json:"isSuspended"`
15+
TotalWh float64 `json:"TotalWh"`
16+
LiveKWH float64 `json:"LiveKWH"`
17+
LiveAmps float64 `json:"LiveAmps"`
18+
LiveKW float64 `json:"LiveKW"`
19+
LiveVolts float64 `json:"LiveVolts"`
20+
LiveAmps_L1 float64 `json:"LiveAmps_L3"`
21+
LiveAmps_L2 float64 `json:"LiveAmps_L3"`
22+
LiveAmps_L3 float64 `json:"LiveAmps_L3"`
23+
CurrentCost float64 `json:"CurrentCost"`
24+
CurrentCostCharging float64 `json:"CurrentCostCharging"`
25+
CurrentCostChargingTime float64 `json:"CurrentCostChargingTime"`
26+
CurrentCostOccupied float64 `json:"CurrentCostOccupied"`
27+
StartupCost float64 `json:"StartupCost"`
28+
IsFinished bool `json:"IsFinished"`
29+
}
30+
31+
func (s *SessionService) GetLiveData(sessionId int) (*LiveDataResult, *http.Response, error) {
32+
33+
reqUrl := "v2/ServiceSessions/LiveData/" + strconv.Itoa(sessionId)
34+
req, err := s.client.NewRequest("GET", reqUrl, nil)
35+
if err != nil {
36+
return nil, nil, err
37+
}
38+
39+
liveData := &LiveDataResult{}
40+
resp, err := s.client.Do(req, liveData)
41+
if err != nil {
42+
return nil, resp, err
43+
}
44+
45+
return liveData, resp, err
46+
}
47+
48+
type SessionService struct {
49+
client *Client
50+
}
51+
52+
type SessionsResult struct {
53+
Result []Session
54+
}
55+
56+
type SessionResult struct {
57+
Result Session
58+
}
59+
60+
type Session struct {
61+
SessionId int `json:"PK_ServiceSessionID"`
62+
SessionStart string `json:"SessionStart"`
63+
SessionEnd string `json:"SessionEnd"`
64+
DurationCharging int `json:"DurationCharging"`
65+
ChargingBoxID int `json:"ChargingBoxID"`
66+
ChargingPointID int `json:"ChargingPointID"`
67+
CustomerID int `json:"FK_CustomerID"`
68+
TotalkWh float64 `json:"TotalkWh"`
69+
LivekW float64 `json:"LivekW"`
70+
PointName string `json:"PointName"`
71+
MaxKWH float64 `json:"MaxKWH"`
72+
StartMethod string `json:"StartMethod"`
73+
}
74+
75+
func (s *SessionService) GetSession(sessionId int) (*SessionResult, *http.Response, error) {
76+
77+
reqUrl := "v2/ServiceSessions/" + strconv.Itoa(sessionId)
78+
req, err := s.client.NewRequest("GET", reqUrl, nil)
79+
if err != nil {
80+
return nil, nil, err
81+
}
82+
83+
session := &SessionResult{}
84+
resp, err := s.client.Do(req, session)
85+
if err != nil {
86+
return nil, resp, err
87+
}
88+
89+
return session, resp, err
90+
}
91+
92+
func (s *SessionService) GetActiveSessions(userId int) (*SessionsResult, *http.Response, error) {
93+
94+
reqUrl := "v2/ServiceSessions/Active/" + strconv.Itoa(userId)
95+
req, err := s.client.NewRequest("GET", reqUrl, nil)
96+
if err != nil {
97+
return nil, nil, err
98+
}
99+
100+
sessions := &SessionsResult{}
101+
resp, err := s.client.Do(req, sessions)
102+
if err != nil {
103+
return nil, resp, err
104+
}
105+
106+
return sessions, resp, err
107+
}
108+
109+
type MeterValuesResult struct {
110+
Result MeterValues
111+
}
112+
113+
type MeterValues struct {
114+
Items []Item `json:"Items"`
115+
TotalLogs int `json:"TotalLogs"`
116+
}
117+
118+
type Item struct {
119+
Date string `json:"Date"`
120+
KWh float64 `json:"kWh"`
121+
Amps float64 `json:"Amps"`
122+
Kw float64 `json:"kW"`
123+
}
124+
125+
// Defaults to fetch last 60 values. /<num> can be added behind sessionId to fetch more
126+
func (s *SessionService) GetMeterValues(sessionId int) (*MeterValuesResult, *http.Response, error) {
127+
128+
reqUrl := "v2/Metervalues/SessionResult/" + strconv.Itoa(sessionId)
129+
req, err := s.client.NewRequest("GET", reqUrl, nil)
130+
if err != nil {
131+
return nil, nil, err
132+
}
133+
134+
meterValues := &MeterValuesResult{}
135+
resp, err := s.client.Do(req, meterValues)
136+
if err != nil {
137+
return nil, resp, err
138+
}
139+
140+
return meterValues, resp, err
141+
}

0 commit comments

Comments
 (0)