This repository was archived by the owner on May 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathobis_parser.go
141 lines (125 loc) · 3.43 KB
/
obis_parser.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
package main
import (
"bufio"
"context"
"io"
"log"
"regexp"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
)
const (
OBISRegex = `(?P<obis>\d-\d:\d{1,2}\.\d{1,2}\.\d\*\d{3})(?P<value>\(\S*\))`
ValueRegex = `(\d*\.\d*)\*(\S[^\)]*)`
)
const (
OBISMsgSeparator = "!"
OBIScodeTotalConsumptionPositive = "1-0:1.8.0*255" // 2248.01818051 kWh
OBIScodeT1ConsumptionPositive = "1-0:1.8.1*255" // 2248.01818051 kWh
OBIScodeT2ConsumptionPositive = "1-0:1.8.2*255" // 2248.01818051 kWh
OBIScodeTotalConsumptionNegative = "1-0:2.8.0*255" // 2248.01818051 kWh
OBIScodeT1ConsumptionNegative = "1-0:2.8.1*255" // 2248.01818051 kWh not used yet
OBIScodeT2ConsumptionNegative = "1-0:2.8.2*255" // 2248.01818051 kWh not used yet
OBIScodePt = "1-0:16.7.0*255" // 282.03 W
OBIScodeP1 = "1-0:36.7.0*255" // 63.33 W
OBIScodeP2 = "1-0:56.7.0*255" // 30.14 W
OBIScodeP3 = "1-0:76.7.0*255" // 188.56 W
OBIScodeV1 = "1-0:32.7.0*255" // 233.8 V
OBIScodeV2 = "1-0:52.7.0*255" // 236.1 V
OBIScodeV3 = "1-0:72.7.0*255" // 235.1 V
)
var (
obisExpress = regexp.MustCompile(OBISRegex)
valueExpress = regexp.MustCompile(ValueRegex)
)
type ObisParser struct {
msgSeparator string
lineValidator *regexp.Regexp
valueParser *regexp.Regexp
ctx context.Context
}
func NewObisParser(ctx context.Context) *ObisParser {
return &ObisParser{
msgSeparator: OBISMsgSeparator,
lineValidator: obisExpress,
valueParser: valueExpress,
ctx: ctx,
}
}
// reader is read until io.EOF
//
// MeasurementProcessor is called in a new Goroutine
func (parser ObisParser) Parse(reader io.Reader, mp MeasurementProcessor) {
scanner := bufio.NewScanner(reader)
var msg []string
for scanner.Scan() {
line := scanner.Text()
if line == parser.msgSeparator {
measurement, err := parseObis(msg)
go mp(measurement, err)
msg = []string{}
} else if obisExpress.MatchString(line) {
msg = append(msg, line)
}
select {
case <-parser.ctx.Done():
return
default:
}
}
}
func parseObis(msg []string) (Measurement, error) {
if len(msg) < 12 {
return Measurement{}, errors.Errorf("\nReading too short %v:\n%v", len(msg), strings.Join(msg, "\n"))
}
measurement := Measurement{
Created: time.Now(),
MeterID: 1, // use a real id if you have more then 1 meter
}
for _, v := range msg {
matches := obisExpress.FindStringSubmatch(v)[1:]
if len(matches) < 2 {
continue
}
key := matches[0]
value := matches[1]
if valueExpress.MatchString(value) {
values := valueExpress.FindStringSubmatch(value)[1:]
num, err := strconv.ParseFloat(values[0], 64)
if err != nil {
log.Println("Parse float", err)
continue
}
mapValues(key, num, &measurement)
}
}
return measurement, nil
}
func mapValues(obis string, value float64, m *Measurement) {
switch obis {
case OBIScodeTotalConsumptionNegative:
m.TotalKwhNeg = value
case OBIScodeTotalConsumptionPositive:
m.TotalKwhPos = value
case OBIScodeT1ConsumptionPositive:
m.TotalT1KwhPos = value
case OBIScodeT2ConsumptionPositive:
m.TotalT2KwhPos = value
case OBIScodePt:
m.PTotal = value
case OBIScodeP1:
m.P1 = value
case OBIScodeP2:
m.P2 = value
case OBIScodeP3:
m.P3 = value
case OBIScodeV1:
m.V1 = value
case OBIScodeV2:
m.V2 = value
case OBIScodeV3:
m.V3 = value
}
}