-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmodel.go
More file actions
118 lines (103 loc) · 2.72 KB
/
model.go
File metadata and controls
118 lines (103 loc) · 2.72 KB
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 gosenml
import "fmt"
// Data model as described in
// https://tools.ietf.org/html/draft-jennings-senml-10
// Message is the root SenML variable
type Message struct {
BaseName string `json:"bn,omitempty"`
BaseTime int64 `json:"bt,omitempty"`
BaseUnits string `json:"bu,omitempty"`
Version int `json:"ver"`
Entries []Entry `json:"e"`
}
// Entry is a measurement of Parameter Entry
type Entry struct {
Name string `json:"n,omitempty"`
Units string `json:"u,omitempty"`
Value *float64 `json:"v,omitempty"`
StringValue *string `json:"sv,omitempty"`
BooleanValue *bool `json:"bv,omitempty"`
Sum *float64 `json:"s,omitempty"`
Time int64 `json:"t,omitempty"`
UpdateTime int64 `json:"ut,omitempty"`
}
// NewMessage creates a SenML message from a number of entries
func NewMessage(entries ...Entry) *Message {
return &Message{
Version: 1.0,
Entries: entries,
}
}
// Makes a deep copy of the message
func (m *Message) copy() Message {
mc := *m
entries := make([]Entry, len(m.Entries))
copy(entries, m.Entries)
mc.Entries = entries
return mc
}
// Validate validates a message
func (m *Message) Validate() error {
if len(m.Entries) == 0 {
return fmt.Errorf("Invalid Message: entries must be non-empty")
}
// Validate values in entries
// https://tools.ietf.org/html/draft-jennings-senml-10#section-4
for _, e := range m.Entries {
vars := 0
if e.Value != nil {
vars++
}
if e.StringValue != nil {
vars++
}
if e.BooleanValue != nil {
vars++
}
if e.Sum == nil && vars != 1 {
return fmt.Errorf("In an entry, exactly one of v, sv, or bv MUST appear when a sum value is not present")
} else if e.Sum != nil && vars > 1 {
return fmt.Errorf("In an entry, exactly one of v, sv, or bv CAN appear when a sum value is present")
}
}
// TODO: more validation
return nil
}
// Expand returns a copy of the message with all Entries expanded ("self-contained")
func (m *Message) Expand() Message {
m2 := m.copy()
for i, e := range m.Entries {
// BaseName
e.Name = m.BaseName + e.Name
// BaseTime
e.Time = m.BaseTime + e.Time
// BaseUnits
if e.Units == "" {
e.Units = m.BaseUnits
}
m2.Entries[i] = e
}
m2.BaseName = ""
m2.BaseTime = 0
m2.BaseUnits = ""
return m2
}
// Compact returns a copy of the message with all Entries compacted (common data put into Message)
func (m *Message) Compact() Message {
m2 := m.copy()
// TODO
// BaseName
// BaseTime
// BaseUnits
return m2
}
// Encoder interface
type Encoder interface {
EncodeMessage(*Message) ([]byte, error)
EncodeEntry(*Entry) ([]byte, error)
}
// Decoder interface
type Decoder interface {
DecodeEntry([]byte) (Entry, error)
DecodeMessage([]byte) (Message, error)
}