-
Notifications
You must be signed in to change notification settings - Fork 0
/
command.go
189 lines (154 loc) · 4.86 KB
/
command.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package helvargo
import (
"fmt"
"regexp"
"strings"
)
var default_helvar_termination_char = "#"
type Command struct {
MessageType MessageType
CommandType CommandType
Params []CommandParameter
Address string
Result string
IsPartial bool
}
type CommandParameter struct {
Type CommandParameterType
Value string
}
func (cp *CommandParameter) ToString() string{
if cp.Type == ADDRESS { return fmt.Sprintf("%s%s", cp.Type, cp.Value) }
return fmt.Sprintf("%s:%s", cp.Type, cp.Value)
}
type CommandType string
const (
QUERY_CLUSTERS CommandType = "101"
QUERY_ROUTERS CommandType = "102"
QUERY_GROUP_DESCRIPTION CommandType = "105"
QUERY_DEVICE_DESCRIPTION CommandType = "106"
QUERY_DEVICE_TYPES_AND_ADDRESSES CommandType = "100"
QUERY_DEVICE_STATE CommandType = "110"
QUERY_WORKGROUP_NAME CommandType = "107"
QUERY_DEVICE_LOAD_LEVEL CommandType = "152"
QUERY_SCENE_INFO CommandType = "167"
QUERY_ROUTER_TIME CommandType = "185"
QUERY_LAST_SCENE_IN_GROUP CommandType = "109"
QUERY_LAST_SCENE_IN_BLOCK CommandType = "103"
QUERY_GROUP CommandType = "164"
QUERY_GROUPS CommandType = "165"
QUERY_SCENE_NAMES CommandType = "166"
QUERY_ROUTER_VERSION CommandType = "190"
QUERY_HELVARNET_VERSION CommandType = "191"
//Commands
DIRECT_LEVEL_DEVICE CommandType = "14"
DIRECT_LEVEL_GROUP CommandType = "13"
RECALL_SCENE CommandType = "11"
)
var COMMAND_TYPES_DONT_LISTEN_FOR_RESPONSE = []CommandType { RECALL_SCENE, DIRECT_LEVEL_DEVICE, DIRECT_LEVEL_GROUP}
type CommandParameterType string
const(
VERSION CommandParameterType = "V"
COMMAND CommandParameterType = "C"
ADDRESS CommandParameterType = "@"
GROUP CommandParameterType = "G"
SCENE CommandParameterType = "S"
BLOCK CommandParameterType = "B"
FADE_TIME CommandParameterType = "F"
LEVEL CommandParameterType = "L"
PROPORTION CommandParameterType = "P"
DISPLAY_SCREEN CommandParameterType = "D"
SEQUENCE_NUMBER CommandParameterType = "Q"
TIME CommandParameterType = "T"
ACK CommandParameterType = "A"
LATITUDE CommandParameterType = "L"
LONGITUDE CommandParameterType = "E"
TIME_ZONE_DIFFERENCE CommandParameterType = "Z"
DAYLIGHT_SAVING_TIME CommandParameterType = "Y"
CONSTANT_LIGHT_SCENE CommandParameterType = "K"
FORCE_STORE_SCENE CommandParameterType = "O"
)
type MessageType string
const(
MT_COMMAND MessageType = ">"
MT_INTERNAL_COMMAND MessageType = "<"
MT_REPLY MessageType = "?"
MT_ERROR MessageType = "!"
)
func NewCommand(messageType MessageType, commandType CommandType, params ...CommandParameter) Command{
return Command{
MessageType: messageType,
CommandType: commandType,
Params: params,
}
}
func (c *Command) buildBaseParameters() []CommandParameter {
return []CommandParameter {
{Type: VERSION, Value: "1"},
{Type: COMMAND, Value: string(c.CommandType)},
}
}
func (c *Command) ToIdentifier() string {
var parameters []CommandParameter
parameters = append(parameters, c.Params...)
if c.Address != "" {
parameters = append(parameters, CommandParameter{ADDRESS, c.Address})
}
var stringParams []string
for _, param := range parameters {
stringParams = append(stringParams, param.ToString())
}
result := strings.Join(stringParams, ",")
return fmt.Sprintf("%s:%s", c.CommandType, result)
}
func (c *Command) ToString() string {
parameters := c.buildBaseParameters()
parameters = append(parameters, c.Params...)
if c.Address != "" {
parameters = append(parameters, CommandParameter{ADDRESS, c.Address})
}
var stringParams []string
for _, param := range parameters {
stringParams = append(stringParams, param.ToString())
}
mainMessage := strings.Join(stringParams, ",")
if c.Result != "" {
mainMessage = fmt.Sprintf("%s=%s", mainMessage, c.Result)
}
return fmt.Sprintf("%s%s%s", c.MessageType, mainMessage, default_helvar_termination_char)
}
func ParseCommand(input string) (*Command, error) {
//regexp.Compile("^(?P<type>[<>?!])V\:(?P<version>\d),C\:(?P<command>\d+),?(?P<params>[^=@#]+)?(?P<address>@[^=#]+)?(=(?P<result>[^#]*))?#?$")
r, err := regexp.Compile("^(?P<type>[<>?!])V\\:(?P<version>\\d),C\\:(?P<command>\\d+),?(?P<params>[^=@#]+)?(?P<address>@[^=#]+)?(=(?P<result>[^#]*))?#?$")
if err != nil {
fmt.Println("Failed to parse command: ", input)
return nil, err
}
res := r.FindStringSubmatch (input)
messageType := res[1]
commandType := res[3]
params := parseParams(res[4])
address := strings.ReplaceAll(res[5], "@", "")
result := res[7]
return &Command{
CommandType: CommandType(commandType),
MessageType: MessageType(messageType),
Params: params,
Address: address,
Result: result,
}, nil
}
func parseParams(input string) []CommandParameter{
var parameters []CommandParameter
params := strings.Split(input, ",")
for _, p := range params {
parts := strings.Split(p, ":")
if len(parts) == 2 {
parameters = append(parameters, CommandParameter{
CommandParameterType(parts[0]),
parts[1],
})
}
}
return parameters
}