package device import ( "encoding/json" "errors" "fmt" mqtt "github.com/eclipse/paho.mqtt.golang" log "github.com/sirupsen/logrus" "github.com/spf13/cast" "strings" "sync" "time" ) var ( UWSTypeInfo1 = "info1" UWSTypeInfo2 = "info2" UWSTypeInfo3 = "info3" UWSTypeState = "state" UWSTypeSensor = "sensor" UWSTypePower = "power" UWSTypeResult = "result" ) type UstoneWifiSwitch struct { sync.Mutex brand string model string deviceId string client mqtt.Client callback Callback } func NewUstoneWifiSwitch(deviceId string, mqtt mqtt.Client, callback Callback) *UstoneWifiSwitch { u := &UstoneWifiSwitch{ brand: BrandUstone, model: "wsp1", client: mqtt, deviceId: deviceId, callback: callback, } if callback != nil { if deviceId == "#" { mqtt.Subscribe(fmt.Sprintf("v2/tele/%s/#", u.model), 2, u.Callback) mqtt.Subscribe(fmt.Sprintf("v2/stat/%s/#", u.model), 2, u.Callback) } else { mqtt.Subscribe(fmt.Sprintf("v2/tele/%s/%s/#", u.model, u.deviceId), 2, u.Callback) mqtt.Subscribe(fmt.Sprintf("v2/stat/%s/%s/#", u.model, u.deviceId), 2, u.Callback) } } return u } func (u *UstoneWifiSwitch) TurnOn() error { if u.deviceId == "#" { return nil } topic := fmt.Sprintf("v2/cmnd/%s/%s/Power0", u.model, u.deviceId) publishACK := u.client.Publish(topic, 0, false, "1") publishACK.WaitTimeout(time.Second) return publishACK.Error() } func (u *UstoneWifiSwitch) TurnOff() error { if u.deviceId == "#" { return nil } topic := fmt.Sprintf("v2/cmnd/%s/%s/Power0", u.model, u.deviceId) publishACK := u.client.Publish(topic, 0, false, "0") publishACK.WaitTimeout(time.Second) return publishACK.Error() } func (u *UstoneWifiSwitch) TurnOver() error { if u.deviceId == "#" { return nil } topic := fmt.Sprintf("v2/cmnd/%s/%s/Power0", u.model, u.deviceId) publishACK := u.client.Publish(topic, 0, false, "2") publishACK.WaitTimeout(time.Second) return publishACK.Error() } func (u *UstoneWifiSwitch) SetPeriod(sec int64) error { if u.deviceId == "#" { return nil } topic := fmt.Sprintf("v2/cmnd/%s/%s/TelePeriod", u.model, u.deviceId) publishACK := u.client.Publish(topic, 0, false, cast.ToString(sec)) publishACK.WaitTimeout(time.Second) return publishACK.Error() } func (u *UstoneWifiSwitch) Operate(cmd string) error { cmd = strings.ToLower(cmd) if cmd == "on" { return u.TurnOn() } else if cmd == "off" { return u.TurnOff() } else if cmd == "over" { return u.TurnOver() } else if cmd == "keepalive" { return u.KeepAlive() } return errors.New("不支持的命令[on|off|over|keepalive]") } func (u *UstoneWifiSwitch) KeepAlive() error { return nil } func (u *UstoneWifiSwitch) Callback(client mqtt.Client, message mqtt.Message) { u.Lock() defer u.Unlock() topic := message.Topic() payload := message.Payload() log.Debugf("[USTONE][%s] deviceId[%s] topic[%s] payloyad[%s]", u.model, u.deviceId, topic, string(payload)) if u.callback != nil { msgId := cast.ToString(message.MessageID()) if strings.HasSuffix(topic, "STATE") { u.updateState(msgId, topic, payload) } else if strings.HasSuffix(topic, "SENSOR") { u.updateSensor(msgId, topic, payload) } else if strings.HasSuffix(topic, "INFO1") || strings.HasSuffix(topic, "INFO2") || strings.HasSuffix(topic, "INFO3") { u.updateInfo(msgId, topic, payload) } } } func (u *UstoneWifiSwitch) getDeviceId(topic string) string { devId := u.deviceId if devId == "#" { fields := strings.Split(topic, "/") if len(fields) >= 4 { devId = fields[3] } } return devId } func (u *UstoneWifiSwitch) updateInfo(msgId, topic string, payload []byte) { mp := make(map[string]interface{}) if err := json.Unmarshal(payload, &mp); err != nil { log.Errorf("topic[%s] paylooad[%s] error :%s", topic, string(payload), err.Error()) return } devId := u.getDeviceId(topic) message := &Message{} message.DeviceId = devId message.Topic = topic message.MsgTime = time.Now().Unix() message.MsgId = msgId message.Data = make(map[string]interface{}) if strings.HasSuffix(topic, "INFO1") { i := cast.ToStringMap(mp["Info1"]) message.MsgType = UWSTypeInfo1 message.Data["module"] = cast.ToString(i["Module"]) message.Data["version"] = cast.ToString(i["Version"]) message.Data["raw"] = i } else if strings.HasSuffix(topic, "INFO2") { i := cast.ToStringMap(mp["Info2"]) message.MsgType = UWSTypeInfo2 message.Data["hostname"] = cast.ToString(i["Hostname"]) message.Data["ip_address"] = cast.ToString(i["IPAddress"]) message.Data["raw"] = i } else if strings.HasSuffix(topic, "INFO3") { i := cast.ToStringMap(mp["Info3"]) message.MsgType = UWSTypeInfo3 message.Data["boot_count"] = cast.ToString(i["BootCount"]) message.Data["raw"] = i } u.callback(message) } func (u *UstoneWifiSwitch) updateState(msgId, topic string, payload []byte) { mp := make(map[string]interface{}) if err := json.Unmarshal(payload, &mp); err != nil { log.Errorf("paylooad[%s] error :%s", string(payload), err.Error()) return } wifi := cast.ToStringMap(mp["Wifi"]) message := &Message{} message.DeviceId = u.getDeviceId(topic) message.Topic = topic message.MsgType = UWSTypeState message.MsgTime = time.Now().Unix() message.MsgId = msgId message.Data = make(map[string]interface{}) message.Data["power"] = cast.ToString(mp["POWER"]) message.Data["bssid"] = cast.ToString(wifi["BSSId"]) message.Data["ssid"] = cast.ToString(wifi["SSId"]) message.Data["raw"] = mp u.callback(message) } func (u *UstoneWifiSwitch) updateSensor(msgId, topic string, payload []byte) { mp := make(map[string]interface{}) if err := json.Unmarshal(payload, &mp); err != nil { log.Errorf("paylooad[%s] error :%s", string(payload), err.Error()) return } energy := cast.ToStringMap(mp["ENERGY"]) totalStartTime, _ := time.ParseInLocation("2006-01-02T15:04:05", cast.ToString(energy["TotalStartTime"]), time.Local) message := &Message{} message.DeviceId = u.getDeviceId(topic) message.Topic = topic message.MsgType = UWSTypeSensor message.MsgTime = time.Now().Unix() message.MsgId = msgId message.Data = make(map[string]interface{}) message.Data["total_start_time"] = totalStartTime.Unix() message.Data["total_energy"] = cast.ToFloat64(energy["Total"]) message.Data["today_energy"] = cast.ToFloat64(energy["Today"]) message.Data["yesterday_energy"] = cast.ToFloat64(energy["Yesterday"]) message.Data["raw"] = energy u.callback(message) }