From 74261a98d6cf34006a28bb90433ccf2ee4ec915d Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Thu, 4 Aug 2022 18:03:04 -0700 Subject: Remove old demo server --- inform/inform.go | 13 --- inform/rx_messages.go | 93 --------------------- inform/server.go | 218 -------------------------------------------------- inform/tx_messages.go | 83 ------------------- 4 files changed, 407 deletions(-) delete mode 100644 inform/rx_messages.go delete mode 100644 inform/server.go delete mode 100644 inform/tx_messages.go diff --git a/inform/inform.go b/inform/inform.go index 59f969c..da2e095 100644 --- a/inform/inform.go +++ b/inform/inform.go @@ -62,19 +62,6 @@ func (i *InformWrapper) UpdatePayload(v interface{}) error { } } -// Unmarshal a payload body that we received from a device. Does not work for -// user-set messages -func (i *InformWrapper) UnmarshalPayload() (*DeviceMessage, error) { - var m DeviceMessage - - err := json.Unmarshal(i.Payload, &m) - if err != nil { - return nil, err - } - - return &m, nil -} - // Format Mac address bytes as lowercase string with colons func (i *InformWrapper) FormattedMac() string { return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", diff --git a/inform/rx_messages.go b/inform/rx_messages.go deleted file mode 100644 index 68fd393..0000000 --- a/inform/rx_messages.go +++ /dev/null @@ -1,93 +0,0 @@ -package inform - -// Messages we receive from devices - -import ( - "encoding/json" -) - -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 -} - -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 -} - -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 -} diff --git a/inform/server.go b/inform/server.go deleted file mode 100644 index 710b8ac..0000000 --- a/inform/server.go +++ /dev/null @@ -1,218 +0,0 @@ -package inform - -import ( - "container/list" - "errors" - "fmt" - "log" - "net/http" - "sync" - "time" -) - -func Log(handler http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - handler.ServeHTTP(w, r) - t := time.Now().Format("02/Jan/2006 15:04:05") - log.Printf("%s - - [%s] \"%s %s %s\"", r.RemoteAddr, t, r.Method, r.URL, r.Proto) - }) -} - -type Device struct { - Initialized bool - CurrentState bool - DesiredState bool - *sync.Mutex -} - -type InformHandler struct { - Codec *Codec - ports map[string]map[int]*Device - queue map[string]*list.List - *sync.RWMutex -} - -func NewInformHandler(c *Codec) *InformHandler { - return &InformHandler{ - Codec: c, - ports: make(map[string]map[int]*Device), - queue: make(map[string]*list.List), - RWMutex: &sync.RWMutex{}, - } -} - -func (h *InformHandler) AddPort(dev string, port int) { - h.Lock() - defer h.Unlock() - - _, ok := h.ports[dev] - if !ok { - h.ports[dev] = make(map[int]*Device) - } - - _, ok = h.queue[dev] - if !ok { - log.Printf("Adding queue for %s", dev) - h.queue[dev] = list.New() - } - - log.Printf("Adding %s port %d", dev, port) - h.ports[dev][port] = &Device{ - Mutex: &sync.Mutex{}, - } -} - -func (h *InformHandler) getPort(dev string, port int) (*Device, error) { - h.RLock() - defer h.RUnlock() - - _, ok := h.ports[dev] - if !ok { - return nil, errors.New("No device found") - } - - p, ok := h.ports[dev][port] - if !ok { - return nil, errors.New("No port found") - } - - return p, nil -} - -func (h *InformHandler) SetState(dev string, port int, state bool) error { - p, err := h.getPort(dev, port) - if err != nil { - return err - } - - p.Lock() - defer p.Unlock() - - log.Printf("Set state to %t for %s port %d", state, dev, port) - p.DesiredState = state - return nil -} - -func (h *InformHandler) buildCommands(dev string, pl *DeviceMessage) error { - for _, o := range pl.Outputs { - ds, err := h.getPort(dev, o.Port) - if err != nil { - return err - } - ds.Lock() - - // Get initial state - if !ds.Initialized { - ds.CurrentState = o.OutputState - ds.Initialized = true - return nil - } - - // State didn't change at the sensor - if ds.CurrentState == o.OutputState { - if ds.DesiredState != o.OutputState { - log.Printf("Toggle state %t for %s port %d", ds.DesiredState, dev, o.Port) - // Generate change command - // TODO: Don't lock the whole handler - h.Lock() - h.queue[dev].PushFront(NewOutputCommand(o.Port, ds.DesiredState, 0)) - h.Unlock() - } - } else { // Sensor caused the change, leave it alone - log.Printf("Sensor state changed %s port %d", dev, o.Port) - ds.DesiredState = o.OutputState - } - - ds.CurrentState = o.OutputState - ds.Unlock() // Don't hold the lock the entire loop - } - - return nil -} - -func (h *InformHandler) pop(dev string) *CommandMessage { - // TODO: Don't lock the whole handler - h.Lock() - defer h.Unlock() - - q, ok := h.queue[dev] - if !ok { - log.Printf("No queue for %s", dev) - return nil - } - - e := q.Front() - if e != nil { - h.queue[dev].Remove(e) - cmd := e.Value.(*CommandMessage) - cmd.Freshen() - return cmd - } - - return nil -} - -func (h *InformHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed) - return - } - - msg, err := h.Codec.Unmarshal(r.Body) - if err != nil { - log.Printf("Unmarshal message: %s", err.Error()) - http.Error(w, "400 Bad Request", http.StatusBadRequest) - return - } - - pl, err := msg.UnmarshalPayload() - if err != nil { - log.Printf("Unmarshal payload: %s", err.Error()) - http.Error(w, "400 Bad Request", http.StatusBadRequest) - return - } - - dev := msg.FormattedMac() - ret := NewInformWrapperResponse(msg) - log.Printf("Inform from %s", dev) - - // Send a command until the queue is empty - if cmd := h.pop(dev); cmd != nil { - ret.UpdatePayload(cmd) - } else { - // Update internal state vs reality - if err := h.buildCommands(msg.FormattedMac(), pl); err != nil { - http.Error(w, "500 Server Error", 500) - return - } - - // If that generated a command send it - if cmd = h.pop(dev); cmd != nil { - ret.UpdatePayload(cmd) - } else { - // Otherwise noop - ret.UpdatePayload(NewNoop(10)) - } - } - - res, err := h.Codec.Marshal(ret) - if err != nil { - http.Error(w, "500 Server Error", 500) - return - } - - fmt.Fprintf(w, "%s", res) -} - -// Create a new server, returns the mux so users can add other methods (for -// example, if they want to share a process to build a console that also -// accepts informs) -func NewServer(handler *InformHandler) (*http.Server, *http.ServeMux) { - mux := http.NewServeMux() - mux.Handle("/inform", handler) - - return &http.Server{ - Addr: ":6080", - Handler: Log(mux), - }, mux -} diff --git a/inform/tx_messages.go b/inform/tx_messages.go deleted file mode 100644 index 8962cad..0000000 --- a/inform/tx_messages.go +++ /dev/null @@ -1,83 +0,0 @@ -package inform - -// Messages we send to devices - -import ( - "strconv" - "time" -) - -type CommandMessage struct { - 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"` -} - -// Freshen timestamps -func (m *CommandMessage) Freshen() { - m.DateTime = time.Now().Format(time.RFC3339) - m.ServerTime = unixMicroPSTString() - m.Time = unixMicroPST() -} - -func NewOutputCommand(port int, val bool, timer int) *CommandMessage { - m := &CommandMessage{ - Type: "cmd", - Command: "mfi-output", - DateTime: time.Now().Format(time.RFC3339), - Port: port, - ServerTime: unixMicroPSTString(), - Time: unixMicroPST(), - Timer: timer, - } - - if val { - m.Value = 1 - } else { - m.Value = 0 - } - - return m -} - -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(), - } -} -- cgit v1.2.3