ym485.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "runtime/debug"
  6. "time"
  7. "github.com/go-redis/redis/v7"
  8. "lc/common/mqtt"
  9. "lc/common/protocol"
  10. "lc/common/util"
  11. "lc/edge/ipole/ym485"
  12. "strings"
  13. "sync"
  14. )
  15. var YmProtocol = "yuming485"
  16. var mutex sync.Mutex
  17. var oldstate uint8
  18. type YmLampController struct {
  19. devinfo *protocol.DevInfo
  20. model *protocol.IotModel
  21. downQueue *util.MlQueue
  22. mapTopicHandle map[string]func(m mqtt.Message)
  23. mapLamps2OOT []protocol.CHZB_OnOffTime //时控策略
  24. mapTempLampsOOT *LampTimeRange //临时手动控时间段,手动控制开关灯
  25. mapLampAlarm *LampAlarmInfo //告警数据
  26. State []ym485.DeviceState //当前灯控状态 开关灯,电流,电压,电度
  27. ctx context.Context
  28. cancel context.CancelFunc
  29. chanDevInfo chan *protocol.DevInfo //设备管理更新
  30. chanModelInfo chan *ModelInfo //设备管理更新
  31. tswitch time.Time //手动控执行时间
  32. }
  33. func NewYmLampController(info *protocol.DevInfo) Device {
  34. ctx, cancel := context.WithCancel(context.Background())
  35. dev := &YmLampController{
  36. devinfo: info,
  37. downQueue: util.NewQueue(200),
  38. mapTopicHandle: make(map[string]func(m mqtt.Message)),
  39. ctx: ctx,
  40. cancel: cancel,
  41. chanDevInfo: make(chan *protocol.DevInfo),
  42. chanModelInfo: make(chan *ModelInfo),
  43. }
  44. iot, err := loadModel(info.TID)
  45. if err != nil {
  46. util.GetTagLog().Errorf("ym485", "NewYmLampController:加载模型[tid=%d]文件发生错误:%s", info.TID, err.Error())
  47. } else {
  48. if iot.Protocol == YmProtocol {
  49. dev.model = iot
  50. } else {
  51. util.GetTagLog().Error("ym485", "NewYmLampController:物模型错误,非YmProtocol协议")
  52. }
  53. }
  54. dev.SetTopicHandle()
  55. return dev
  56. }
  57. func (o *YmLampController) SetTopicHandle() {
  58. o.mapTopicHandle[GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_SET_SWITCH)] = o.HandleTpYmSetSwitch
  59. o.mapTopicHandle[GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_SET_ONOFFTIME)] = o.HandleTpYmSetOnofftime
  60. }
  61. func (o *YmLampController) MQTTSubscribe() {
  62. GetMQTTMgr().Subscribe(GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_SET_SWITCH), mqtt.ExactlyOnce, o.HandleCache, ToAll) //开关灯
  63. GetMQTTMgr().Subscribe(GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_SET_ONOFFTIME), mqtt.ExactlyOnce, o.HandleCache, ToCloud) //设置时间
  64. }
  65. func (o *YmLampController) HandleCache(m mqtt.Message) {
  66. util.GetTagLog().Infof("ym485", "Topic:%v,message:%v\n", m.Topic(), m.PayloadString())
  67. o.downQueue.Put(m)
  68. }
  69. func (o *YmLampController) Start() {
  70. o.MQTTSubscribe()
  71. retry := 3
  72. sleep := time.Duration(2)
  73. for i := 0; i < retry; i++ {
  74. if err := o.ReloadOOTFromRedis(); err == nil {
  75. break
  76. }
  77. time.Sleep(sleep * time.Second)
  78. }
  79. for i := 0; i < retry; i++ {
  80. if err := o.ReloadSwitchOOTFromRedis(); err == nil {
  81. break
  82. }
  83. time.Sleep(sleep * time.Second)
  84. }
  85. for i := 0; i < retry; i++ {
  86. if err := o.ReloadLampAlarmFromRedis(); err == nil {
  87. break
  88. }
  89. time.Sleep(sleep * time.Second)
  90. }
  91. go o.HandleData()
  92. }
  93. func (o *YmLampController) Stop() {
  94. //停止采集和处理
  95. o.cancel()
  96. }
  97. func (o *YmLampController) UpdateInfo(devinfo protocol.DevInfo) {
  98. o.chanDevInfo <- &devinfo
  99. }
  100. func (o *YmLampController) GetDevInfo() *protocol.DevInfo {
  101. return o.devinfo
  102. }
  103. func (o *YmLampController) UpdateModel(tid uint16, flag int) {
  104. if tid > 0 {
  105. mi := ModelInfo{
  106. TID: tid,
  107. Flag: flag,
  108. }
  109. o.chanModelInfo <- &mi
  110. }
  111. }
  112. func (o *YmLampController) UpdateModel2(mi *ModelInfo) {
  113. if o.devinfo.TID != mi.TID {
  114. return
  115. }
  116. if mi.Flag == 0 {
  117. util.GetTagLog().Errorf("ym485", "设备[%s]的物模型[tid=%d]模型文件被删除,下次启动即将生效。", o.devinfo.DevCode, mi.TID)
  118. return
  119. }
  120. util.GetTagLog().Debugf("ym485", "YmLampController.UpdateModel2:更新设备[%s]的物模型[%d]", o.devinfo.DevCode, mi.TID)
  121. iot, err := loadModel(mi.TID)
  122. if err != nil {
  123. util.GetTagLog().Errorf("ym485", "YmLampController.UpdateModel2:加载模型[%d]文件错误:%s", mi.TID, err.Error())
  124. return
  125. }
  126. if iot.Protocol == YmProtocol { //合法的物模型
  127. o.model = iot
  128. util.GetTagLog().Infof("ym485", "YmLampController.UpdateModel2:更新设备[%s]的物模型[%d]成功", o.devinfo.DevCode, mi.TID)
  129. } else {
  130. util.GetTagLog().Error("ym485", "YmLampController.UpdateModel2:物模型错误,TID和文件名tid不一致或协议非ModbusRTU协议")
  131. }
  132. }
  133. func (o *YmLampController) GetDevType() string {
  134. if o.devinfo.DevType == 3 {
  135. return protocol.DT_LAMPCONTROLLER
  136. }
  137. return "unknown"
  138. }
  139. // HandleData 数据处理协程
  140. func (o *YmLampController) HandleData() {
  141. defer func() {
  142. if err := recover(); err != nil {
  143. util.GetTagLog().Error("ym485", "YmLampController.HandleData:panic:", err)
  144. util.GetTagLog().Error("ym485", "stack:", string(debug.Stack()))
  145. time.Sleep(5 * time.Second)
  146. go o.HandleData()
  147. }
  148. }()
  149. o.QueryLampControllerAddr() //线上挂了两个灯控,则不能
  150. util.GetTagLog().Infof("ym485", "lamp state:%d", oldstate)
  151. nextFillTime := time.Time{}
  152. for {
  153. select {
  154. case <-o.ctx.Done():
  155. util.GetTagLog().Errorf("ym485", "设备[%s]的HandleData退出,原因:%v", o.devinfo.DevCode, o.ctx.Err())
  156. return
  157. case devinfo_ := <-o.chanDevInfo:
  158. o.devinfo = devinfo_
  159. case mi := <-o.chanModelInfo:
  160. o.UpdateModel2(mi)
  161. default:
  162. //从队列钟获取指令执行
  163. if m, ok, _ := o.downQueue.Get(); ok {
  164. if mm, ok := m.(mqtt.Message); ok {
  165. if fn, ok := o.mapTopicHandle[mm.Topic()]; ok {
  166. fn(mm)
  167. } else {
  168. util.GetTagLog().Errorf("ym485", "YmLampController.Handle:不支持的主题:%s", mm.Topic())
  169. }
  170. }
  171. } else {
  172. if nextFillTime.IsZero() || nextFillTime.Before(util.MlNow()) { //定时读取和发送
  173. t := util.MlNow()
  174. o.QueryDeviceState() //获取灯的数据
  175. // QueryDeviceState失败时State为过期数据,跳过ConfirmState避免误操作
  176. if len(o.State) > 0 {
  177. o.ConfirmState(t) //获取设置灯的开/关
  178. }
  179. nextFillTime = util.MlNow().Add(time.Duration(o.devinfo.SendCloud) * time.Millisecond)
  180. }
  181. time.Sleep(time.Millisecond * 1000)
  182. }
  183. }
  184. }
  185. }
  186. func (o *YmLampController) SendRecvData(aduRequest []byte, retry int) (aduResponse []byte, err error) {
  187. defer mutex.Unlock()
  188. mutex.Lock()
  189. // time.Sleep(time.Millisecond * 10)
  190. serial := GetSerialMgr().GetSerialPort(o.devinfo.Code)
  191. if serial == nil {
  192. util.GetTagLog().Errorf("ym485", "YM串口未找到: Code=%d", o.devinfo.Code) // ← 加这行
  193. return nil, ErrClosedConnection
  194. }
  195. if !serial.IsConnected() {
  196. util.GetTagLog().Errorf("ym485", "YM串口未连接: Code=%d", o.devinfo.Code) // ← 加这行
  197. }
  198. if retry <= 0 {
  199. retry = 1
  200. }
  201. for ; retry > 0; retry-- {
  202. aduResponse, err = serial.SendRecvData(aduRequest, FlagYm485, o.devinfo.WaitTime)
  203. if err == nil {
  204. break
  205. }
  206. }
  207. return aduResponse, err
  208. }
  209. func (o *YmLampController) SendData(aduRequest []byte, retry int) (err error) {
  210. serial := GetSerialMgr().GetSerialPort(o.devinfo.Code)
  211. if serial == nil {
  212. return ErrClosedConnection
  213. }
  214. if retry <= 0 {
  215. retry = 1
  216. }
  217. for ; retry > 0; retry-- {
  218. if err = serial.SendData(aduRequest, FlagYm485, o.devinfo.WaitTime); err == nil {
  219. break
  220. }
  221. }
  222. return err
  223. }
  224. func (o *YmLampController) QueryLampControllerAddr() {
  225. var obj ym485.QueryAddr
  226. buf, err := obj.EnCode()
  227. defer ym485.ReleaseByteBuffer(buf)
  228. if err != nil {
  229. return
  230. }
  231. recvbuf, err := o.SendRecvData(buf.Bytes(), 2)
  232. if err != nil {
  233. return
  234. }
  235. var ret ym485.QueryAddrACK
  236. if err = ret.DeCode(recvbuf); err == nil {
  237. util.GetTagLog().Infof("ym485", "灯控地址:%s", ret.Addr)
  238. }
  239. if ret.Addr != o.devinfo.DevCode {
  240. util.GetTagLog().Errorf("ym485", "请将DevCode配置为灯控地址!")
  241. }
  242. }
  243. func (o *YmLampController) QuerySoftVer() {
  244. var obj ym485.PackingMark
  245. buf, err := obj.EnCode(o.devinfo.DevCode, 0x1E, [4]byte{0x00, 0x00, 0x60, 0x12})
  246. defer ym485.ReleaseByteBuffer(buf)
  247. if err != nil {
  248. return
  249. }
  250. recvbuf, err := o.SendRecvData(buf.Bytes(), 1)
  251. if err != nil {
  252. return
  253. }
  254. var ret ym485.QuerySoftVerAck
  255. if err = ret.DeCode(recvbuf); err == nil {
  256. util.GetTagLog().Infof("ym485", "灯控型号:%s,软件版本:%s", ret.Model, ret.Version)
  257. }
  258. }
  259. func (o *YmLampController) QueryBasicsettings() {
  260. var obj ym485.PackingMark
  261. buf, err := obj.EnCode(o.devinfo.DevCode, 0x1E, [4]byte{0x00, 0x00, 0x60, 0x02})
  262. defer ym485.ReleaseByteBuffer(buf)
  263. if err != nil {
  264. return
  265. }
  266. recvbuf, err := o.SendRecvData(buf.Bytes(), 1)
  267. if err != nil {
  268. return
  269. }
  270. var ret ym485.PackingBasic
  271. if err = ret.DeCode(recvbuf); err == nil {
  272. util.GetTagLog().Infof("ym485", "灯控使能状态:%d,是否上电开灯:%d", ret.Enabled, ret.OnOff)
  273. }
  274. }
  275. // QueryDeviceState 查询设备状态
  276. func (o *YmLampController) QueryDeviceState() {
  277. var obj ym485.DataPack //串口协议
  278. buf, err := obj.EnCode(o.devinfo.DevCode, 0x1E, []byte{0x00, 0x00, 0x60, 0x13, 0x01})
  279. defer ym485.ReleaseByteBuffer(buf)
  280. if err != nil {
  281. return
  282. }
  283. recvbuf, err := o.SendRecvData(buf.Bytes(), 1) //根据地址得到数据
  284. if err != nil {
  285. util.GetTagLog().Errorf("ym485", "单灯状态数据查询错误,DevCode=%s,err=%v", o.devinfo.DevCode, err)
  286. return
  287. }
  288. var ret ym485.QueryDeviceStateAck
  289. if err = ret.DeCode(recvbuf); err == nil { //解码串口返回的数据
  290. // if ret.Dp.Addr != o.devinfo.DevCode { //不是本灯数据
  291. if !strings.Contains(o.devinfo.DevCode, ret.Dp.Addr) { //不是本灯数据
  292. o.State = nil
  293. return
  294. }
  295. if len(ret.State) == 0 {
  296. o.State = nil
  297. return
  298. }
  299. if len(o.State) != len(ret.State) {
  300. o.State = make([]ym485.DeviceState, len(ret.State))
  301. }
  302. copy(o.State, ret.State)
  303. //状态改变记录日志
  304. if oldstate != o.State[0].State {
  305. oldstate = o.State[0].State
  306. util.GetTagLog().Infof("ym485", "lamp state:%d", oldstate)
  307. }
  308. }
  309. mapData := make(map[string]*protocol.CHZB_LampData)
  310. var data protocol.CHZB_LampData
  311. data.Data = make(map[uint16]float64)
  312. data.SetStateErrorData(err)
  313. if len(o.State) > 0 { //只要第一路
  314. if o.State[0].State == 1 { //开灯
  315. data.Data[1] = float64(o.State[0].BrightnessState)
  316. } else {
  317. data.Data[1] = 0.0
  318. }
  319. data.Data[2] = float64(0)
  320. data.Data[3] = o.State[0].Voltage
  321. data.Data[4] = 0.0
  322. data.Data[5] = 0.0
  323. data.Data[6] = o.State[0].Current
  324. data.Data[7] = 0.0
  325. data.Data[8] = o.State[0].Degree //by hxz 1,2,3,6,8为有效
  326. data.Data[9] = 0.0
  327. }
  328. mapData[o.devinfo.DevCode] = &data
  329. var ret1 protocol.Pack_CHZB_UploadData
  330. if str, err := ret1.EnCode(o.devinfo.DevCode, appConfig.GID, GetNextUint64(), o.devinfo.TID, mapData); err == nil {
  331. topic := GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_DATA)
  332. GetMQTTMgr().Publish(topic, str, mqtt.AtLeastOnce, ToCloud)
  333. }
  334. }
  335. func (o *YmLampController) TurnOnOff(flag uint8) error {
  336. kenabled := uint8(0x00)
  337. if flag > 0 {
  338. kenabled = 0xff
  339. }
  340. var obj ym485.PackingTurnOnOff
  341. buf, err := obj.EnCode(o.devinfo.DevCode, [4]byte{0x00, 0x00, 0x60, 0x07}, 0xff, kenabled)
  342. defer ym485.ReleaseByteBuffer(buf)
  343. if err != nil {
  344. return err
  345. }
  346. recvbuf, err := o.SendRecvData(buf.Bytes(), 3)
  347. if err != nil {
  348. util.GetTagLog().Errorf("ym485", "TurnOnOff:串口通信失败,DevCode=%s,flag=%d,err=%v", o.devinfo.DevCode, flag, err)
  349. return err
  350. }
  351. var ret ym485.PackingResult
  352. err = ret.DeCode(recvbuf)
  353. if err == nil {
  354. if ret.Result == 89 { //字母Y
  355. return nil
  356. }
  357. }
  358. util.GetTagLog().Errorf("ym485", "TurnOnOff:设备返回失败,DevCode=%s,flag=%d,Result=0x%02X", o.devinfo.DevCode, flag, ret.Result)
  359. return errors.New(protocol.FAILED_STR)
  360. }
  361. func (o *YmLampController) SetBrightness(brightness uint8) error {
  362. var obj ym485.PackingBrightnessColor
  363. buf, err := obj.EnCode(o.devinfo.DevCode, [4]byte{0x00, 0x00, 0x60, 0x09}, 0xff, []byte{brightness})
  364. defer ym485.ReleaseByteBuffer(buf)
  365. if err != nil {
  366. return err
  367. }
  368. recvbuf, err := o.SendRecvData(buf.Bytes(), 1)
  369. if err != nil {
  370. return err
  371. }
  372. var ret ym485.PackingResult
  373. err = ret.DeCode(recvbuf)
  374. if err == nil {
  375. if ret.Result == 89 { //字母'Y'
  376. return nil
  377. }
  378. }
  379. return errors.New(protocol.FAILED_STR)
  380. }
  381. func (o *YmLampController) SetBasicsettings(enabled, on uint8) {
  382. var obj ym485.PackingBasic
  383. buf, err := obj.EnCode(o.devinfo.DevCode, 0x1E, [4]byte{0x00, 0x00, 0x60, 0x01}, enabled, on, nil)
  384. defer ym485.ReleaseByteBuffer(buf)
  385. if err != nil {
  386. return
  387. }
  388. recvbuf, err := o.SendRecvData(buf.Bytes(), 1)
  389. if err != nil {
  390. return
  391. }
  392. var ret ym485.PackingResult
  393. if err = ret.DeCode(recvbuf); err == nil {
  394. if ret.Result == 89 { //字母'Y'
  395. util.GetTagLog().Info("ym485", "设置灯控基本信息执行成功")
  396. } else {
  397. util.GetTagLog().Error("ym485", "设置灯控基本信息执行失败")
  398. }
  399. }
  400. }
  401. func (o *YmLampController) Switch(Switch, Brightness uint8) error {
  402. if Switch == 0 {
  403. return o.TurnOnOff(0)
  404. } else {
  405. err := o.SetBrightness(Brightness)
  406. if err != nil {
  407. util.GetTagLog().Errorf("ym485", "调节亮度失败:%s", err.Error())
  408. }
  409. return o.TurnOnOff(Switch)
  410. }
  411. }
  412. func (o *YmLampController) ConfirmState(t time.Time) {
  413. //刚开/关灯,则不判断,避免采集数据误差导致误判
  414. if !o.tswitch.IsZero() {
  415. if t.After(o.tswitch) && t.Sub(o.tswitch).Seconds() < float64(o.devinfo.SendCloud/1000.0) {
  416. return
  417. }
  418. if t.Before(o.tswitch) && o.tswitch.Sub(t).Seconds() < float64(o.devinfo.SendCloud/1000.0) {
  419. return
  420. }
  421. }
  422. if len(o.State) == 0 {
  423. return
  424. }
  425. s := o.State[0]
  426. if o.mapTempLampsOOT != nil { //优先手动控制
  427. if t.After(time.Time(o.mapTempLampsOOT.End)) { //过时,则清除
  428. if err := redisEdgeData.Del(LampSwitchPrefix + o.devinfo.DevCode).Err(); err == nil {
  429. o.mapTempLampsOOT = nil
  430. o.tswitch = time.Time{}
  431. }
  432. } else if o.mapTempLampsOOT.isInTimeRange(t) {
  433. if o.mapTempLampsOOT.Brightness > 0 && s.State == 0 { //应开未开
  434. o.Switch(1, o.mapTempLampsOOT.Brightness) //开灯
  435. } else if o.mapTempLampsOOT.Brightness == 0 && s.State == 1 { //应关闭未关
  436. o.Switch(0, o.mapTempLampsOOT.Brightness) //关灯
  437. }
  438. return
  439. }
  440. }
  441. isInRange := false
  442. for _, v := range o.mapLamps2OOT { //其次时间策略
  443. if v.InTimeRange(t) { //在开灯区间
  444. if v.Brightness > 0 && s.State == 0 { //应开未开
  445. o.Switch(1, v.Brightness) //开灯
  446. } else if v.Brightness == 0 && s.State == 1 { //应关闭未关
  447. o.Switch(0, v.Brightness) //关灯
  448. }
  449. isInRange = true
  450. break
  451. }
  452. }
  453. if isInRange {
  454. return
  455. }
  456. if s.State == 1 {
  457. o.Switch(0, 0)
  458. }
  459. }
  460. func (o *YmLampController) HandleTpYmSetSwitch(m mqtt.Message) {
  461. var obj protocol.Pack_CHZB_Switch
  462. if err := obj.DeCode(m.PayloadString()); err != nil {
  463. util.GetTagLog().Errorf("ym485", "协议解析错误:%s,协议主题:%s,协议内容:%s", err.Error(), m.Topic(), m.PayloadString())
  464. return
  465. }
  466. if obj.Id != o.devinfo.DevCode {
  467. return
  468. }
  469. brightness := uint8(0)
  470. if obj.Data.Switch == 1 {
  471. brightness = obj.Data.Brightness
  472. }
  473. err := o.Switch(obj.Data.Switch, obj.Data.Brightness)
  474. if err != nil {
  475. util.GetTagLog().Errorf("ym485", "HandleTpYmSetSwitch:开关灯失败,DevCode=%s,Switch=%d,err=%v", o.devinfo.DevCode, obj.Data.Switch, err)
  476. } else {
  477. o.tswitch = util.MlNow()
  478. mapRedisTempLampsOOT := make(map[string]interface{}) //临时开关灯记录,用于排除异常亮灯正常亮灯的情况
  479. ltr := LampTimeRange{
  480. Start: util.MLTime(o.tswitch),
  481. End: util.MLTime(o.tswitch.Add(time.Duration(obj.Data.Recovery) * time.Second)), //延迟2分钟,以防指令在队列中未及时执行
  482. Brightness: brightness,
  483. }
  484. ltrstr, _ := json.MarshalToString(ltr)
  485. o.mapTempLampsOOT = &ltr //内存
  486. mapRedisTempLampsOOT[o.devinfo.DevCode] = ltrstr //redis
  487. if err := redisEdgeData.HSet(LampSwitchPrefix+o.devinfo.DevCode, mapRedisTempLampsOOT).Err(); err != nil {
  488. util.GetTagLog().Errorf("ym485", "手动开关灯时间设置[内容:%v]缓存到redis失败:%s", mapRedisTempLampsOOT, err.Error())
  489. }
  490. }
  491. var ret protocol.Pack_Ack
  492. if str, err := ret.EnCode(o.devinfo.DevCode, appConfig.GID, obj.Seq, err); err == nil {
  493. GetMQTTMgr().Publish(GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_SET_SWITCH_ACK), str, mqtt.AtMostOnce, ToAll)
  494. }
  495. }
  496. func (o *YmLampController) HandleTpYmSetOnofftime(m mqtt.Message) {
  497. var obj protocol.Pack_SetOnOffTime
  498. if err := obj.DeCode(m.PayloadString()); err != nil {
  499. util.GetTagLog().Errorf("ym485", "协议解析错误:%s,协议主题:%s,协议内容:%s", err.Error(), m.Topic(), m.PayloadString())
  500. return
  501. }
  502. if obj.Id != o.devinfo.DevCode {
  503. return
  504. }
  505. if len(obj.Data.OnOffTime) == 0 {
  506. util.GetTagLog().Errorf("ym485", "Handle_TP_YM_SET_ONOFFTIME:错误,灯控编号[%v],时间段个数:%v", obj.Id, obj.Data.OnOffTime)
  507. return
  508. }
  509. mapRedisOOT := make(map[string]interface{})
  510. datastr, _ := json.MarshalToString(obj.Data.OnOffTime)
  511. mapRedisOOT[obj.Id] = datastr //缓存到redis
  512. o.mapLamps2OOT = obj.Data.OnOffTime //缓存在内存中
  513. //持久缓存到redis,以便于重启后读取进内存中
  514. err := redisEdgeData.HSet(LampOotPrefix+o.devinfo.DevCode, mapRedisOOT).Err()
  515. if err != nil {
  516. util.GetTagLog().Errorf("ym485", "灯控时间设置[内容:%v]缓存到redis失败:%s", mapRedisOOT, err.Error())
  517. }
  518. var ret protocol.Pack_Ack
  519. if str, err := ret.EnCode(o.devinfo.DevCode, appConfig.GID, obj.Seq, err); err == nil {
  520. GetMQTTMgr().Publish(GetTopic(protocol.DT_LAMPCONTROLLER, o.devinfo.DevCode, protocol.TP_YM_SET_ONOFFTIME_ACK), str, mqtt.AtMostOnce, ToCloud)
  521. }
  522. }
  523. func (o *YmLampController) ReloadOOTFromRedis() error {
  524. mapdata, err := redisEdgeData.HGetAll(LampOotPrefix + o.devinfo.DevCode).Result()
  525. if err != nil {
  526. if err == redis.Nil {
  527. return nil
  528. }
  529. util.GetTagLog().Errorf("ym485", "YmLampController.ReloadOOTFromRedis设备[%s]从redis加载时间策略失败:%s", o.devinfo.DevCode, err.Error())
  530. return err
  531. }
  532. for k, v := range mapdata {
  533. if k == o.devinfo.DevCode {
  534. var oot []protocol.CHZB_OnOffTime
  535. if err := json.UnmarshalFromString(v, &oot); err == nil {
  536. o.mapLamps2OOT = oot
  537. }
  538. break
  539. }
  540. }
  541. return nil
  542. }
  543. func (o *YmLampController) ReloadSwitchOOTFromRedis() error {
  544. mapdata, err := redisEdgeData.HGetAll(LampSwitchPrefix + o.devinfo.DevCode).Result()
  545. if err != nil {
  546. if err == redis.Nil {
  547. return nil
  548. }
  549. util.GetTagLog().Errorf("ym485", "YmLampController.ReloadSwitchOOTFromRedis设备[%s]从redis加载时间策略失败:%s", o.devinfo.DevCode, err.Error())
  550. return err
  551. }
  552. for k, v := range mapdata {
  553. if k == o.devinfo.DevCode {
  554. var ltr LampTimeRange
  555. if err := json.UnmarshalFromString(v, &ltr); err == nil {
  556. o.mapTempLampsOOT = &ltr
  557. }
  558. break
  559. }
  560. }
  561. return nil
  562. }
  563. func (o *YmLampController) ReloadLampAlarmFromRedis() error {
  564. mapAlarm, err := redisEdgeData.HGetAll(LampAlarmPrefix + o.devinfo.DevCode).Result()
  565. if err != nil {
  566. if err == redis.Nil {
  567. return nil
  568. }
  569. util.GetTagLog().Errorf("ym485", "YmLampController.ReloadLampAlarmFromRedis设备[%s]从redis加载广播恢复截止时间失败:%s", o.devinfo.DevCode, err.Error())
  570. return err
  571. }
  572. for k, v := range mapAlarm {
  573. if k == o.devinfo.DevCode {
  574. var lai LampAlarmInfo
  575. if err := json.UnmarshalFromString(v, &lai); err == nil {
  576. o.mapLampAlarm = &lai
  577. }
  578. break
  579. }
  580. }
  581. return nil
  582. }