From 3ccc02f8f1c08fc82f581e9b3eb4315b42614c8e Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Sat, 24 Sep 2016 16:41:32 -0700 Subject: Cleanup message unpacking --- inform/codec.go | 2 +- inform/inform.go | 44 +------------- inform/messages.go | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++ inform/rx_messages.go | 99 ------------------------------ inform/tx_messages.go | 28 --------- 5 files changed, 164 insertions(+), 171 deletions(-) create mode 100644 inform/messages.go delete mode 100644 inform/rx_messages.go delete mode 100644 inform/tx_messages.go diff --git a/inform/codec.go b/inform/codec.go index e74c3d7..e5c9296 100644 --- a/inform/codec.go +++ b/inform/codec.go @@ -8,7 +8,7 @@ import ( ) type Codec struct { - // KeyBag contains a mapping of comma-separated MAC addresses to their AES + // KeyBag contains a mapping of colon-separated MAC addresses to their AES // keys KeyBag map[string]string } diff --git a/inform/inform.go b/inform/inform.go index b159084..5c3ca1c 100644 --- a/inform/inform.go +++ b/inform/inform.go @@ -3,13 +3,11 @@ package inform import ( "bytes" "encoding/json" - "errors" "fmt" - "github.com/mitchellh/mapstructure" ) const ( - PROTOCOL_MAGIC int32 = 1414414933 // TNBU + PROTOCOL_MAGIC int32 = 1414414933 // UBNT INFORM_VERSION int32 = 0 DATA_VERSION int32 = 1 @@ -91,43 +89,3 @@ func (i *InformWrapper) SetCompressed(c bool) { i.Flags &= COMPRESSED_FLAG } } - -// Decode payload to a map and try to determine the inform type -func (i *InformWrapper) decodePayload() (map[string]interface{}, string, error) { - var m map[string]interface{} - - if err := json.Unmarshal(i.Payload, &m); err != nil { - return nil, "", err - } - - t, ok := m["_type"] - if !ok { - return nil, "", errors.New("Message contains no type") - } - - st, ok := t.(string) - if !ok { - return nil, "", errors.New("Message type is not a string") - } - - return m, st, nil -} - -// Decode payload JSON as a inform message -func (i *InformWrapper) JsonMessage() (interface{}, error) { - msg, t, err := i.decodePayload() - if err != nil { - return nil, err - } - - switch t { - case "noop": - var o NoopMessage - if err := mapstructure.Decode(msg, &o); err != nil { - return nil, err - } - return o, nil - } - - return nil, errors.New(fmt.Sprintf("Message type %s is invalid", t)) -} diff --git a/inform/messages.go b/inform/messages.go new file mode 100644 index 0000000..3dd8f6d --- /dev/null +++ b/inform/messages.go @@ -0,0 +1,162 @@ +package inform + +import ( + "encoding/json" + "strconv" + "time" +) + +type AdminMetadata struct { + Id string `json:"_id"` + Language string `json:"lang"` + Username string `json:"name"` + Password string `json:"x_password"` +} + +type CommandMessage struct { + Metadata *AdminMetadata `json:"_admin,omitempty"` + Id string `json:"_id,omitempty"` + Type string `json:"_type"` + Command string `json:"cmd"` + DateTime string `json:"datetime"` + DeviceId string `json:"device_id,omitempty"` + MacAddress string `json:"mac,omitempty"` + Model string `json:"model,omitempty"` + OffVoltage int `json:"off_volt,omitempty"` + Port int `json:"port"` + SensorId string `json:"sId,omitempty"` + ServerTime string `json:"server_time_in_utc"` + Time int64 `json:"time"` + Timer int `json:"timer"` + Value int `json:"val"` + Voltage int `json:"volt,omitempty"` +} + +func NewOutputCommand(port, val, timer int) *CommandMessage { + return &CommandMessage{ + Type: "cmd", + Command: "mfi-output", + DateTime: time.Now().Format(time.RFC3339), + Port: port, + ServerTime: unixMicroPSTString(), + Time: unixMicroPST(), + Timer: timer, + Value: val, + } +} + +type NoopMessage struct { + Type string `json:"_type"` + Interval int `json:"interval"` + ServerTimeUTC string `json:"server_time_in_utc"` +} + +func unixMicroPST() int64 { + l, _ := time.LoadLocation("America/Los_Angeles") + tnano := time.Now().In(l).UnixNano() + return tnano / int64(time.Millisecond) +} + +func unixMicroPSTString() string { + return strconv.FormatInt(unixMicroPST(), 10) +} + +func unixMicroUTCString() string { + tnano := time.Now().UTC().UnixNano() + t := tnano / int64(time.Millisecond) + return strconv.FormatInt(t, 10) +} + +func NewNoop(interval int) *NoopMessage { + return &NoopMessage{ + Type: "noop", + Interval: interval, + ServerTimeUTC: unixMicroUTCString(), + } +} + +type DeviceMessage struct { + IsDefault bool `json:"default"` + IP string `json:"ip"` + MacAddr string `json:"mac"` + ModelNumber string `json:"model"` + ModelName string `json:"model_display"` + Serial string `json:"serial"` + FirmwareVersion string `json:"version"` + Outputs []*OutputInfo +} + +func (m *DeviceMessage) UnmarshalJSON(data []byte) error { + type Alias DeviceMessage + aux := &struct { + Alarm []struct { + Entries []struct { + Tag string `json:"tag"` + Type string `json:"type"` + Val interface{} `json:"val"` + } `json:"entries"` + Sensor string `json:"sId"` + } `json:"alarm"` + *Alias + }{ + Alias: (*Alias)(m), + } + + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + m.Outputs = make([]*OutputInfo, len(aux.Alarm)) + + for i, a := range aux.Alarm { + o := &OutputInfo{ + Id: a.Sensor, + Port: i + 1, + Dimmer: m.ModelNumber == "IWD1U", + } + m.Outputs[i] = o + + for _, e := range a.Entries { + switch t := e.Val; e.Tag { + case "output": + o.OutputState = t.(float64) == 1 + case "pf": + o.PowerFactor = t.(float64) + case "energy_sum": + o.EnergySum = t.(float64) + case "v_rms": + o.VoltageRMS = t.(float64) + case "i_rms": + o.CurrentRMS = t.(float64) + case "active_pwr": + o.Watts = t.(float64) + case "thismonth": + o.ThisMonth = t.(float64) + case "lastmonth": + o.LastMonth = t.(float64) + case "dimmer_level": + o.DimmerLevel = int(t.(float64)) + case "dimmer_lock_setting": + o.DimmerLockSetting = int(t.(float64)) + } + } + } + + return nil +} + +type OutputInfo struct { + Id string + Port int + OutputState bool + EnergySum float64 + VoltageRMS float64 + PowerFactor float64 + CurrentRMS float64 + Watts float64 + ThisMonth float64 + LastMonth float64 + Dimmer bool + DimmerLevel int + DimmerLockSetting int +} diff --git a/inform/rx_messages.go b/inform/rx_messages.go deleted file mode 100644 index 3f80fcd..0000000 --- a/inform/rx_messages.go +++ /dev/null @@ -1,99 +0,0 @@ -package inform - -// TODO: Convert string time to time.Time -// Response packet -type NoopMessage struct { - Type string `json:"_type"` - Interval int `json:"interval"` - ServerTimeUTC string `json:"server_time_in_utc"` -} - -type AlarmEntry struct { - Tag string `json:"tag"` - Type string `json:"string"` - Value string `json:"val"` // float or int observed -} - -type AlarmMessage struct { - Entries []*AlarmEntry `json:"entries"` - Index string `json:"index"` - Id string `json:"sId"` - Time int `json:"time"` -} - -type InterfaceMessage struct { - IP string `json:"ip"` - MacAddress string `json:"mac"` - Name string `json:"name"` - Type string `json:"type"` - ReceivedBytes int `json:"rx_bytes"` - ReceivedDropped int `json:"rx_dropped"` - ReceivedErrors int `json:"rx_errors"` - ReceivedPackets int `json:"rx_packets"` - TransmittedBytes int `json:"tx_bytes"` - TransmittedDropped int `json:"tx_dropped"` - TransmittedErrors int `json:"tx_errors"` - TransmittedPackets int `json:"tx_packets"` -} - -type RadioMessage struct { - Gain int `json:"builtin_ant_gain"` - BuiltinAntenna bool `json:"builtin_antenna"` - MaxTransmitPower int `json:"max_txpower"` - Name string `json:"name"` - RadioProfile string `json:"radio"` - // "scan_table": [] -} - -type AccessPointMessage struct { - BasicSSID string `json:"bssid"` - ExtendedSSID string `json:"essid"` - ClientConnectionQuality int `json:"ccq"` - Channel int `json:"channel"` - Id string `json:"id"` - Name string `json:"name"` - StationNumber string `json:"num_sta"` // int? - RadioProfile string `json:"radio"` - Usage string `json:"usage"` - ReceivedBytes int `json:"rx_bytes"` - ReceivedDropped int `json:"rx_dropped"` - ReceivedErrors int `json:"rx_errors"` - ReceivedPackets int `json:"rx_packets"` - ReceivedCrypts int `json:"rx_crypts"` - ReceivedFragments int `json:"rx_frags"` - ReceivedNetworkIDs int `json:"rx_nwids"` - TransmittedBytes int `json:"tx_bytes"` - TransmittedDropped int `json:"tx_dropped"` - TransmittedErrors int `json:"tx_errors"` - TransmittedPackets int `json:"tx_packets"` - TransmitPower int `json:"tx_power"` - TransmitRetries int `json:"tx_retries"` -} - -// TODO: Convert time to time.Time -type IncomingMessage struct { - Alarms []*AlarmMessage `json:"alarm"` - ConfigVersion string `json:"cfgversion"` - Default bool `json:"default"` - GuestToken string `json:"guest_token"` - Hostname string `json:"hostname"` - InformURL string `json:"inform_url"` - IP string `json:"ip"` - Isolated bool `json:"isolated"` - LocalVersion string `json:"localversion"` - Locating bool `json:"locating"` - MacAddress string `json:"mac"` - IsMfi string `json:"mfi"` // boolean as string - Model string `json:"model"` - ModelDisplay string `json:"model_display"` - PortVersion string `json:"portversion"` - Version string `json:"version"` - Serial string `json:"serial"` - Time int `json:"time"` - Trackable string `json:"trackable"` // boolean as string - Uplink string `json:"uplink"` - Uptime int `json:"uptime"` - Interfaces []*InterfaceMessage `json:"if_table"` - Radios []*RadioMessage `json:"radio_table"` - AccessPoints []*AccessPointMessage `json:"vap_table"` -} diff --git a/inform/tx_messages.go b/inform/tx_messages.go deleted file mode 100644 index 5efddd6..0000000 --- a/inform/tx_messages.go +++ /dev/null @@ -1,28 +0,0 @@ -package inform - -type AdminMetadata struct { - Id string `json:"_id"` - Language string `json:"lang"` - Username string `json:"name"` - Password string `json:"x_password"` -} - -// TODO: Convert string time to time.Time -type CommandMessage struct { - Metadata *AdminMetadata `json:"_admin"` - Id string `json:"_id"` - Type string `json:"_type"` // cmd - Command string `json:"cmd"` // mfi-output - DateTime string `json:"datetime"` // 2016-07-28T01:17:55Z - DeviceId string `json:"device_id"` - MacAddress string `json:"mac"` - Model string `json:"model"` - OffVoltage int `json:"off_volt"` - Port int `json:"port"` - MessageId string `json:"sId"` // ?? - ServerTime string `json:"server_time_in_utc"` - Time string `json:"time"` - Timer int `json:"timer"` - Value int `json:"val"` - Voltage int `json:"volt"` -} -- cgit v1.2.3