-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmeterdata.go
145 lines (127 loc) · 3.39 KB
/
meterdata.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
package main
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"strconv"
"sync"
"time"
)
type MeterData struct {
Time time.Time
buf []byte
parsed bool
parseErr error
PlusEnergyTar1 float64 // opgenomen energie tarief 1 in kWh
MinEnergyTar1 float64 // teruggeleverde energie tarief 1 in kWh
PlusEnergyTar2 float64 // opgenomen energie tarief 2 in kWh
MinEnergyTar2 float64 // teruggeleverde tarief 2 in kWh
CurrentTarNumber float64 // huidige tarief nr
CurrentPlusPower float64 // huidige opgenomen vermogen in kW
CurrentMinPower float64 // huidige teruggeleverde vermogen in kW
GasUsed float64 // gas verbruik in m3
sync.Mutex
}
// Append adds data to md.buf and returns true if the block is complete.
// The last line begins with ! followed by 4 characters and CRLF, since we do not use these we
// can stop at ! although usually we get the full line it could be we end with !.
func (md *MeterData) Append(b []byte) (bool, error) {
md.Lock()
defer md.Unlock()
if md.Time.IsZero() {
md.Time = time.Now().UTC()
}
md.buf = append(md.buf, b...)
if bytes.ContainsRune(b, '!') {
return true, nil
}
if len(md.buf) > 4096 {
return true, errors.New("buffer too big, receiving invalid data")
}
return false, nil
}
// Parse fills our variables from buf
func (md *MeterData) Parse() error {
md.Lock()
defer md.Unlock()
if md.parsed || len(md.buf) == 0 {
return nil
}
scanner := bufio.NewScanner(bytes.NewReader(md.buf))
for scanner.Scan() {
b := scanner.Bytes()
switch string(b[:9]) {
case "1-0:1.8.1":
md.setVal(&md.PlusEnergyTar1, b, kWhVal)
case "1-0:1.8.2":
md.setVal(&md.PlusEnergyTar2, b, kWhVal)
case "1-0:2.8.1":
md.setVal(&md.MinEnergyTar1, b, kWhVal)
case "1-0:2.8.2":
md.setVal(&md.MinEnergyTar2, b, kWhVal)
case "0-0:96.14":
md.setVal(&md.CurrentTarNumber, b, tarVal)
case "1-0:1.7.0":
md.setVal(&md.CurrentPlusPower, b, kWVal)
case "1-0:2.7.0":
md.setVal(&md.CurrentMinPower, b, kWVal)
case "0-1:24.2.":
md.setVal(&md.GasUsed, b, m3Val)
}
if md.parseErr != nil {
return md.parseErr
}
}
if err := scanner.Err(); err != nil {
return fmt.Errorf("error scanning data: %s", err)
}
md.parsed = true
return nil
}
func (md *MeterData) Json() ([]byte, error) {
md.Lock()
defer md.Unlock()
return json.Marshal(md)
}
func (md *MeterData) setVal(f *float64, line []byte, pf parseFunc) {
if md.parseErr != nil {
return
}
val, err := pf(line)
if err != nil {
md.parseErr = err
return
}
*f = val
}
type parseFunc func(line []byte) (float64, error)
func kWhVal(line []byte) (float64, error) {
if len(line) < 20 {
return 0, errors.New("unexpected line length")
}
//fmt.Println(string(line[10:20]))
return strconv.ParseFloat(string(line[10:20]), 64)
}
func kWVal(line []byte) (float64, error) {
if len(line) < 16 {
return 0, errors.New("unexpected line length")
}
//fmt.Println(string(line[10:16]))
return strconv.ParseFloat(string(line[10:16]), 64)
}
func m3Val(line []byte) (float64, error) {
if len(line) < 35 {
return 0, errors.New("unexpected line length")
}
//fmt.Println(string(line[26:35]))
return strconv.ParseFloat(string(line[26:35]), 64)
}
func tarVal(line []byte) (float64, error) {
if len(line) < 16 {
return 0, errors.New("unexpected line length")
}
//fmt.Println(string(line[12:16]))
return strconv.ParseFloat(string(line[12:16]), 64)
}