forked from evcc-io/evcc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtibber.go
118 lines (95 loc) Β· 2.2 KB
/
tibber.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
package tariff
import (
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/evcc-io/evcc/api"
"github.com/evcc-io/evcc/tariff/tibber"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/request"
"github.com/shurcooL/graphql"
"golang.org/x/oauth2"
)
type Tibber struct {
mux sync.Mutex
log *util.Logger
Token string
HomeID string
Cheap float64
client *graphql.Client
data []tibber.PriceInfo
}
var _ api.Tariff = (*Tibber)(nil)
func NewTibber(other map[string]interface{}) (*Tibber, error) {
t := &Tibber{
log: util.NewLogger("tibber"),
}
if err := util.DecodeOther(other, &t); err != nil {
return nil, err
}
ctx := context.WithValue(
context.Background(),
oauth2.HTTPClient,
request.NewHelper(t.log).Client,
)
client := oauth2.NewClient(ctx, oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: t.Token,
}))
t.client = graphql.NewClient(tibber.URI, client)
if t.HomeID == "" {
var res struct {
Viewer struct {
Homes []tibber.Home
}
}
if err := t.client.Query(context.Background(), &res, nil); err != nil {
return nil, err
}
if len(res.Viewer.Homes) != 1 {
return nil, fmt.Errorf("could not determine home id: %v", res.Viewer.Homes)
}
t.HomeID = res.Viewer.Homes[0].ID
}
go t.Run()
return t, nil
}
func (t *Tibber) Run() {
for ; true; <-time.NewTicker(time.Hour).C {
var res struct {
Viewer struct {
Home struct {
ID string
TimeZone string
CurrentSubscription tibber.Subscription
} `graphql:"home(id: $id)"`
}
}
v := map[string]interface{}{
"id": graphql.ID(t.HomeID),
}
if err := t.client.Query(context.Background(), &res, v); err != nil {
t.log.ERROR.Println(err)
continue
}
t.mux.Lock()
t.data = res.Viewer.Home.CurrentSubscription.PriceInfo.Today
t.mux.Unlock()
}
}
func (t *Tibber) CurrentPrice() (float64, error) {
t.mux.Lock()
defer t.mux.Unlock()
for i := len(t.data) - 1; i >= 0; i-- {
pi := t.data[i]
if pi.StartsAt.Before(time.Now()) {
return pi.Total, nil
}
}
return 0, errors.New("unable to find current tibber price")
}
func (t *Tibber) IsCheap() (bool, error) {
price, err := t.CurrentPrice()
return price <= t.Cheap, err
}