clampcontroller.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. package controllers
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "github.com/sirupsen/logrus"
  8. "github.com/astaxie/beego"
  9. validation "github.com/go-ozzo/ozzo-validation/v4"
  10. "github.com/go-ozzo/ozzo-validation/v4/is"
  11. "lc/common/models"
  12. "lc/common/mqtt"
  13. "lc/common/protocol"
  14. "lc/common/util"
  15. )
  16. // LampStrategyQueue redis缓存
  17. var LampStrategyQueue = "lamp_strategy_queue" //已修改的灯控编码列表,队列方式,先进先出
  18. var LampHlMqttDown = "hllk/113/lamp/longchi/down"
  19. var LampHlMqttUp = "hllk/113/lamp/longchi/up"
  20. type LampController struct {
  21. BaseController
  22. }
  23. type ConcentratorInfo struct {
  24. GID string
  25. TID int
  26. }
  27. type ReqLampController struct {
  28. Code string `json:"code"` //设备编号,禁止修改
  29. GID string `json:"gid"` //网关ID
  30. Tenant string `json:"tenant"` //租户ID
  31. Name string `json:"name"` //设备名称
  32. Brand int `json:"brand"` //品牌
  33. Model int `json:"model"` //型号
  34. CtlType int `json:"ctltype"` //单灯控制器类型,nb-iot:1,485:2,zigbee:3
  35. Concentrator string `json:"concentrator"` //集中器编号,zigbee灯控专用,其他类型灯控置空
  36. Netid int `json:"netid"` //网络号,zigbee灯控专用,其他类型灯控置0
  37. Channel int `json:"channel"` //通道号,zigbee灯控专用,其他类型灯控置0
  38. OrgNumber string `json:"orgnumber"` //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型
  39. Strategy string `json:"strategy"` //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个
  40. State int `json:"state"` //1启用,0禁用
  41. }
  42. func (a ReqLampController) Validate() error {
  43. var rules []*validation.FieldRules
  44. rules = append(rules, validation.Field(&a.Code, validation.Required, validation.Length(4, 32)))
  45. rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)))
  46. rules = append(rules, validation.Field(&a.CtlType, validation.Required, validation.In(1, 2, 3, 4)))
  47. rules = append(rules, validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)))
  48. rules = append(rules, validation.Field(&a.State, validation.In(0, 1)))
  49. if a.CtlType == 2 { //485需要网关ID,其他暂不需要
  50. rules = append(rules, validation.Field(&a.GID, validation.Required, validation.Length(4, 32)))
  51. } else if a.CtlType == 3 {
  52. rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
  53. rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 8)))
  54. } else if a.CtlType == 4 {
  55. rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
  56. rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 32)))
  57. }
  58. return validation.ValidateStruct(&a, rules...)
  59. }
  60. type LampControllerDev struct {
  61. Code string `json:"code"` //设备编号,禁止修改
  62. GID string `json:"gid"` //网关ID
  63. Name string `json:"name"` //设备名称
  64. Brand int `json:"brand"` //品牌
  65. Model int `json:"model"` //型号
  66. CtlType int `json:"ctltype"` //单灯控制器类型,nb-iot:1,485:2,zigbee:3
  67. Concentrator string `json:"concentrator"` //集中器编号,zigbee灯控专用,其他类型灯控置空
  68. Netid int `json:"netid"` //网络号,zigbee灯控专用,其他类型灯控置0
  69. Channel int `json:"channel"` //通道号,zigbee灯控专用,其他类型灯控置0
  70. OrgNumber string `json:"orgnumber"` //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型
  71. Strategy string `json:"strategy"` //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个
  72. State int `json:"state"` //1启用,0禁用
  73. }
  74. func (a LampControllerDev) Validate() error {
  75. var rules []*validation.FieldRules
  76. rules = append(rules, validation.Field(&a.Code, validation.Required, validation.Length(4, 32)))
  77. rules = append(rules, validation.Field(&a.CtlType, validation.Required, validation.In(1, 2, 3, 4)))
  78. rules = append(rules, validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)))
  79. rules = append(rules, validation.Field(&a.State, validation.In(0, 1)))
  80. if a.CtlType == 2 { //485需要网关ID,其他暂不需要
  81. rules = append(rules, validation.Field(&a.GID, validation.Required, validation.Length(4, 32)))
  82. } else if a.CtlType == 3 {
  83. rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
  84. rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 8)))
  85. } else if a.CtlType == 4 {
  86. rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32)))
  87. rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 32)))
  88. }
  89. return validation.ValidateStruct(&a, rules...)
  90. }
  91. type ReqImportLampControllerDev struct {
  92. Tenant string `json:"tenant"` //租户ID
  93. List []LampControllerDev `json:"list"` //灯控列表
  94. }
  95. func (a ReqImportLampControllerDev) Validate() error {
  96. var rules []*validation.FieldRules
  97. rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)))
  98. rules = append(rules, validation.Field(&a.List, validation.Required))
  99. return validation.ValidateStruct(&a, rules...)
  100. }
  101. // ReqStrategy 关联策略
  102. type ReqStrategy struct {
  103. Tenant string `json:"tenant"` //租户ID
  104. Codes []string `json:"codes"` //数组 灯控编码数组
  105. Strategy string `json:"strategy"` // 策略编码,无则置空,多个则用逗号分开,暂时只支持一个
  106. }
  107. func (a ReqStrategy) Validate() error {
  108. return validation.ValidateStruct(&a,
  109. validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)),
  110. validation.Field(&a.Codes, validation.Required),
  111. validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)),
  112. )
  113. }
  114. // LampStrategy 创建更新策略
  115. type LampStrategy struct {
  116. Ontime string `json:"ontime"` //开始时间,24小时制,格式{小时}:{分钟}:{秒}类似13:06:00,为13点6分
  117. Offtime string `json:"offtime"` //结束时间,24小时制,格式同ontime
  118. Brightness int `json:"brightness"` //亮度,1到100
  119. }
  120. func (a LampStrategy) Validate() error {
  121. return validation.ValidateStruct(&a,
  122. validation.Field(&a.Ontime, validation.Required, validation.Date("15:04:05")),
  123. validation.Field(&a.Offtime, validation.Required, validation.Date("15:04:05")),
  124. validation.Field(&a.Brightness, validation.Min(1), validation.Max(100)),
  125. )
  126. }
  127. type ReqLampStrategy struct {
  128. Tenant string `json:"tenant"` //租户ID
  129. Name string `json:"name"` //策略名称
  130. Code string `json:"code"` //策略编码,禁止修改
  131. TimeInfo []LampStrategy `json:"timeinfo"` //时间及亮度内容数组,最多4个元素,最少1个元素
  132. Sunset int `json:"sunset"` //是否启用
  133. Ctltype int `json:"ctltype"` //单灯控制器类型,nb-iot:1,485:2,zigbee:3 不同灯控可能支持的时间亮度有不同的设置,备用
  134. Start string `json:"start"` //时间格式,类似2020-07-20 06:06:06
  135. End string `json:"end"` //时间格式,类似2020-09-20 06:06:06
  136. Year int `json:"year"` //是否全年,1全年,0非全年
  137. Auto int `json:"auto"` //1,自动延续,0非自动延续
  138. Longitude string `json:"longitude"` //东正西负。双精度浮点数,整数最多3字符,小数最多6字符
  139. Latitude string `json:"latitude"` //北正南负,双精度浮点数,整数最多2字符,小数最多6字符
  140. }
  141. func (a ReqLampStrategy) Validate() error {
  142. var rules []*validation.FieldRules
  143. rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)))
  144. rules = append(rules, validation.Field(&a.Code, validation.Length(4, 32)))
  145. rules = append(rules, validation.Field(&a.TimeInfo, validation.Length(1, 4))) //最少1个,最多4个
  146. rules = append(rules, validation.Field(&a.Sunset, validation.In(0, 1)))
  147. rules = append(rules, validation.Field(&a.Year, validation.In(0, 1)))
  148. rules = append(rules, validation.Field(&a.Auto, validation.In(0, 1)))
  149. //rules = append(rules, validation.Field(&a.Ctltype, validation.Required, validation.In(1, 2, 3)))
  150. rules = append(rules, validation.Field(&a.Start, validation.Required, validation.Date("2006-01-02 15:04:05")))
  151. rules = append(rules, validation.Field(&a.End, validation.Required, validation.Date("2006-01-02 15:04:05")))
  152. rules = append(rules, validation.Field(&a.Longitude, validation.Required, is.Longitude))
  153. rules = append(rules, validation.Field(&a.Latitude, validation.Required, is.Latitude))
  154. return validation.ValidateStruct(&a, rules...)
  155. }
  156. // ReqSwitch 开/关灯
  157. type ReqSwitch struct {
  158. Tenant string `json:"tenant"` //租户ID
  159. Codes []string `json:"codes"` //数组 灯控编码数组,一次开关灯多个
  160. Recovery int `json:"recovery"` //恢复时间,即开或关灯时长,超过这个时间则自动恢复时控模式
  161. Brightness int `json:"brightness"` //0~100,0相当于关等,100最大亮度
  162. SwitchOn int `json:"switchon"` //1开灯,0关灯
  163. Whole int `json:"whole,omitempty"` //1为集控
  164. }
  165. func (a ReqSwitch) Validate() error {
  166. return validation.ValidateStruct(&a,
  167. validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)),
  168. validation.Field(&a.Codes, validation.Required),
  169. validation.Field(&a.Recovery, validation.Required, validation.Min(1), validation.Max(480)),
  170. validation.Field(&a.Brightness, validation.Min(0), validation.Max(100)),
  171. validation.Field(&a.SwitchOn, validation.In(0, 1)),
  172. // validation.Field(&a.Whole, validation.In(0, 1)),
  173. )
  174. }
  175. // ConvertNumber 长和zigbee单灯控制器编号,短横线连接
  176. func ConvertNumber(strNumber string) uint16 {
  177. strlist := strings.Split(strNumber, "-")
  178. if len(strlist) == 2 {
  179. hight, err0 := strconv.Atoi(strlist[0])
  180. low, err1 := strconv.Atoi(strlist[1])
  181. if err0 == nil && err1 == nil {
  182. return uint16(hight<<8 | low)
  183. }
  184. }
  185. return 0
  186. }
  187. // CreateLampController @Title 创建灯控设备
  188. // @Description 创建灯控设备
  189. // @Param body body controllers.ReqLampController true "数据"
  190. // @Success 0 {int} BaseResponse.Code "成功"
  191. // @Failure 1 {int} BaseResponse.Code "失败"
  192. // @router /v1/create [post]
  193. func (o *LampController) CreateLampController() {
  194. var obj ReqLampController
  195. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  196. beego.Debug(string(o.Ctx.Input.RequestBody))
  197. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  198. return
  199. }
  200. if err := obj.Validate(); err != nil {
  201. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  202. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  203. return
  204. }
  205. var number uint16 = 0
  206. if obj.CtlType == 3 { //长和zigbee集控器
  207. number = ConvertNumber(obj.OrgNumber)
  208. if number == 0 {
  209. beego.Error("请求的编号格式不正确,要求\"xx-xx\"")
  210. o.Response(Failure, "请求的编号格式不正确,要求\"xx-xx\"", nil)
  211. }
  212. }
  213. oo := models.DeviceLampController{
  214. ID: obj.Code, //设备ID,DID
  215. Name: obj.Name,
  216. GID: obj.GID, //网关ID
  217. Brand: obj.Brand, //品牌
  218. Model: obj.Model, //型号
  219. CtlType: obj.CtlType, //单灯控制器类型,nb-iot:1,485:2,zigbee:3
  220. Concentrator: obj.Concentrator, //集中器编号,zigbee灯控专用,其他类型灯控置空
  221. Netid: obj.Netid, //网络号,zigbee灯控专用,其他类型灯控置0
  222. Channel: obj.Channel, //通道号,zigbee灯控专用,其他类型灯控置0
  223. Number: number, //灯编号, zigbee灯控专用,其他类型灯控置0
  224. OrgNumber: obj.OrgNumber, //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型
  225. Strategy: obj.Strategy, //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个
  226. Tenant: obj.Tenant, //租户ID
  227. State: obj.State, //1启用,0禁用
  228. }
  229. //检查是否有网关ID
  230. if obj.CtlType == 3 || obj.CtlType == 4 { //查找灯控关联的zigbee集中器信息
  231. if concentrator, err := models.GetConcentratorbyID(obj.Concentrator); err == nil {
  232. oo.GID = concentrator.GID
  233. oo.TID = concentrator.TID
  234. } else {
  235. beego.Error(fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()))
  236. o.Response(Failure, fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()), nil)
  237. return
  238. }
  239. } else if obj.CtlType == 2 {
  240. oo.TID = 2
  241. }
  242. if err := oo.SaveFromWeb(obj.CtlType); err != nil {
  243. o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil)
  244. return
  245. }
  246. //存入redis,等待下发给设备
  247. if err := redisCltRawdata.LPush(LampStrategyQueue, obj.Code).Err(); err != nil {
  248. logrus.Errorf("LampController.CreateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", obj.Code, err.Error())
  249. }
  250. o.Response(Success, "成功", oo.ID)
  251. }
  252. // UpdateLampController @Title 更新灯控设备
  253. // @Description 更新灯控设备
  254. // @Param body body controllers.ReqLampController true "数据"
  255. // @Success 0 {int} BaseResponse.Code "成功"
  256. // @Failure 1 {int} BaseResponse.Code "失败"
  257. // @router /v1/update [post]
  258. func (o *LampController) UpdateLampController() {
  259. var obj ReqLampController
  260. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  261. beego.Debug(string(o.Ctx.Input.RequestBody))
  262. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  263. return
  264. }
  265. if err := obj.Validate(); err != nil {
  266. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  267. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  268. return
  269. }
  270. var number uint16 = 0
  271. if obj.CtlType == 3 { //长和zigbee集控器
  272. number = ConvertNumber(obj.OrgNumber)
  273. if number == 0 {
  274. beego.Error("请求的编号格式不正确,要求\"xx-xx\"")
  275. o.Response(Failure, "请求的编号格式不正确,要求\"xx-xx\"", nil)
  276. }
  277. }
  278. oo := models.DeviceLampController{
  279. ID: obj.Code, //设备ID,DID
  280. Name: obj.Name,
  281. GID: obj.GID, //网关ID
  282. Brand: obj.Brand, //品牌
  283. Model: obj.Model, //型号
  284. CtlType: obj.CtlType, //单灯控制器类型,nb-iot:1,485:2,zigbee:3
  285. Concentrator: obj.Concentrator, //集中器编号,zigbee灯控专用,其他类型灯控置空
  286. Netid: obj.Netid, //网络号,zigbee灯控专用,其他类型灯控置0
  287. Channel: obj.Channel, //通道号,zigbee灯控专用,其他类型灯控置0
  288. Number: number, //灯编号, zigbee灯控专用,其他类型灯控置0
  289. OrgNumber: obj.OrgNumber, //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型
  290. Strategy: obj.Strategy, //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个
  291. Tenant: obj.Tenant, //租户ID
  292. State: obj.State, //1启用,0禁用
  293. }
  294. //检查是否有网关ID
  295. if obj.CtlType == 3 { //查找灯控关联的zigbee集中器信息
  296. if concentrator, err := models.GetConcentratorbyID(obj.Concentrator); err == nil {
  297. oo.GID = concentrator.GID
  298. oo.TID = concentrator.TID
  299. } else {
  300. beego.Error(fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()))
  301. o.Response(Failure, fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()), nil)
  302. return
  303. }
  304. } else if obj.CtlType == 2 {
  305. oo.TID = 2
  306. }
  307. if err := oo.SaveFromWeb(obj.CtlType); err != nil {
  308. o.Response(Failure, fmt.Sprintf("数据更新失败:%s", err.Error()), nil)
  309. return
  310. }
  311. //存入redis,等待下发给设备
  312. if err := redisCltRawdata.LPush(LampStrategyQueue, obj.Code).Err(); err != nil {
  313. logrus.Errorf("LampController.UpdateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", obj.Code, err.Error())
  314. }
  315. o.Response(Success, "成功", oo.ID)
  316. }
  317. // DeleteLampController @Title 删除灯控设备
  318. // @Description 删除灯控设备
  319. // @Param code query string true "设备ID"
  320. // @Success 0 {int} BaseResponse.Code "成功"
  321. // @Failure 1 {int} BaseResponse.Code "失败"
  322. // @router /v1/delete [post]
  323. func (o *LampController) DeleteLampController() {
  324. code := strings.Trim(o.GetString("code"), " ")
  325. if err := validation.Validate(code, validation.Required, validation.Length(4, 100)); err != nil {
  326. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  327. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  328. return
  329. }
  330. c := models.DeviceLampController{
  331. ID: code,
  332. }
  333. if err := c.Delete(); err != nil {
  334. beego.Error(fmt.Sprintf("删除失败:%s", err.Error()))
  335. o.Response(Failure, fmt.Sprintf("数据删除失败:%s", err.Error()), nil)
  336. return
  337. }
  338. o.Response(Success, "成功", c.ID)
  339. }
  340. // UpdateState @Title 更新灯控设备启用禁用状态
  341. // @Description 更新灯控设备启用禁用状态
  342. // @Param body controllers.ProgramsState true "数据"
  343. // @Success 0 {int} BaseResponse.Code "成功"
  344. // @Failure 1 {int} BaseResponse.Code "失败"
  345. // @router /v1/update/state [POST]
  346. func (o *LampController) UpdateState() {
  347. code := o.GetString("code")
  348. state, err := o.GetUint8("state", 0)
  349. if code == "" || state > 1 || err != nil {
  350. beego.Error("参数错误")
  351. o.Response(Failure, "参数错误", nil)
  352. return
  353. }
  354. err = models.LampControllerUpdateState(code, int(state))
  355. if err != nil {
  356. beego.Error("更新灯控设备状态错误:", err.Error())
  357. o.Response(Failure, "失败", err.Error())
  358. return
  359. }
  360. o.Response(Success, "成功", code)
  361. }
  362. // ImportLampControllerDev @Title 导入灯控设备
  363. // @Description 导入灯控设备
  364. // @Param body body controllers.ReqImportLampControllerDev true "数据"
  365. // @Success 0 {int} BaseResponse.Code "成功"
  366. // @Failure 1 {int} BaseResponse.Code "失败"
  367. // @router /v1/import [post]
  368. func (o *LampController) ImportLampControllerDev() {
  369. var obj ReqImportLampControllerDev
  370. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  371. beego.Debug(string(o.Ctx.Input.RequestBody))
  372. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  373. return
  374. }
  375. if err := obj.Validate(); err != nil {
  376. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  377. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  378. return
  379. }
  380. var resp []RespImport
  381. mapConcentratorInfo := make(map[string]*ConcentratorInfo)
  382. for _, v := range obj.List {
  383. var aresp RespImport
  384. aresp.Code = v.Code
  385. var number uint16 = 0
  386. if v.CtlType == 3 { //长和zigbee集控器
  387. number = ConvertNumber(v.OrgNumber)
  388. }
  389. oo := models.DeviceLampController{
  390. ID: v.Code, //设备ID,DID
  391. Name: v.Name,
  392. GID: v.GID, //网关ID
  393. Brand: v.Brand, //品牌
  394. Model: v.Model, //型号
  395. CtlType: v.CtlType, //单灯控制器类型,nb-iot:1,485:2,zigbee:3
  396. Concentrator: v.Concentrator, //集中器编号,zigbee灯控专用,其他类型灯控置空
  397. Netid: v.Netid, //网络号,zigbee灯控专用,其他类型灯控置0
  398. Channel: v.Channel, //通道号,zigbee灯控专用,其他类型灯控置0
  399. Number: number, //灯编号, zigbee灯控专用,其他类型灯控置0
  400. OrgNumber: v.OrgNumber, //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型
  401. Strategy: v.Strategy, //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个
  402. Tenant: obj.Tenant, //租户ID
  403. State: v.State, //1启用,0禁用
  404. }
  405. //检查是否有网关ID
  406. if v.CtlType == 3 { //查找灯控关联的zigbee集中器信息
  407. if ci, ok := mapConcentratorInfo[v.Concentrator]; ok {
  408. oo.GID = ci.GID
  409. oo.TID = ci.TID
  410. } else {
  411. if concentrator, err := models.GetConcentratorbyID(v.Concentrator); err == nil {
  412. oo.GID = concentrator.GID
  413. oo.TID = concentrator.TID
  414. mapConcentratorInfo[v.Concentrator] = &ConcentratorInfo{GID: concentrator.GID, TID: concentrator.TID}
  415. } else {
  416. beego.Error(fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()))
  417. aresp.Error = err.Error()
  418. continue
  419. }
  420. }
  421. } else if v.CtlType == 2 {
  422. oo.TID = 2
  423. }
  424. err := oo.SaveFromWeb(v.CtlType)
  425. if err != nil {
  426. beego.Error(fmt.Sprintf("zigbee集控器数据导入失败,code=%s,失败原因:%s", v.Code, err.Error()))
  427. aresp.Error = err.Error()
  428. continue
  429. }
  430. //存入redis,等待下发给设备
  431. if err := redisCltRawdata.LPush(LampStrategyQueue, v.Code).Err(); err != nil {
  432. logrus.Errorf("LampController.CreateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", v.Code, err.Error())
  433. }
  434. }
  435. o.Response(Success, "成功", resp)
  436. }
  437. // RelateStrategy @Title 关联策略
  438. // @Description 关联策略
  439. // @Param body controllers.ReqStrategy true "数据"
  440. // @Success 0 {int} BaseResponse.Code "成功"
  441. // @Failure 1 {int} BaseResponse.Code "失败"
  442. // @router /v1/relate/strategy [post]
  443. func (o *LampController) RelateStrategy() {
  444. var obj ReqStrategy
  445. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  446. beego.Debug(string(o.Ctx.Input.RequestBody))
  447. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  448. return
  449. }
  450. if err := obj.Validate(); err != nil {
  451. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  452. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  453. return
  454. }
  455. if err := models.UpdateStrategy(obj.Codes, obj.Strategy); err != nil {
  456. beego.Error(fmt.Sprintf("关联策略失败:%s", err.Error()))
  457. o.Response(Failure, fmt.Sprintf("关联策略失败:%s", err.Error()), nil)
  458. return
  459. }
  460. //存入redis,等待下发给设备
  461. if len(obj.Codes) > 0 {
  462. codelist := make([]interface{}, 0, len(obj.Codes))
  463. for _, v := range obj.Codes {
  464. codelist = append(codelist, v)
  465. }
  466. if err := redisCltRawdata.LPush(LampStrategyQueue, codelist...).Err(); err != nil {
  467. logrus.Errorf("LampController.RelateStrategy:创建灯控缓存redis失败,灯控编码:%v,失败原因:%s", codelist, err.Error())
  468. }
  469. }
  470. o.Response(Success, "成功", nil)
  471. }
  472. // CreateStrategy @Title 创建灯控策略
  473. // @Description 创建灯控策略
  474. // @Param body controllers.ReqLampStrategy true "数据"
  475. // @Success 0 {int} BaseResponse.Code "成功"
  476. // @Failure 1 {int} BaseResponse.Code "失败"
  477. // @router /v1/create/strategy [post]
  478. func (o *LampController) CreateStrategy() {
  479. var obj ReqLampStrategy
  480. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  481. beego.Debug(string(o.Ctx.Input.RequestBody))
  482. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  483. return
  484. }
  485. if err := obj.Validate(); err != nil {
  486. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  487. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  488. return
  489. }
  490. tstart, err1 := util.MlParseTime(obj.Start)
  491. tend, err2 := util.MlParseTime(obj.End)
  492. if err1 != nil || err2 != nil || tstart.After(tend) {
  493. o.Response(Failure, "有效期时间错误", nil)
  494. return
  495. }
  496. timeInfo, _ := json.MarshalIndent(&obj.TimeInfo, "", " ")
  497. longitude, _ := strconv.ParseFloat(obj.Longitude, 64)
  498. latitude, _ := strconv.ParseFloat(obj.Latitude, 64)
  499. oo := models.Lampstrategy{
  500. ID: obj.Code,
  501. Name: obj.Name,
  502. CtlType: obj.Ctltype,
  503. TimeInfo: string(timeInfo),
  504. Sunset: obj.Sunset,
  505. Start: tstart,
  506. End: tend,
  507. Year: obj.Year,
  508. Auto: obj.Auto,
  509. Tenant: obj.Tenant,
  510. Longitude: longitude,
  511. Latitude: latitude,
  512. }
  513. if err := oo.SaveFromWeb(); err != nil {
  514. o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil)
  515. return
  516. }
  517. o.Response(Success, "成功", obj.Code)
  518. }
  519. // UpdateStrategy @Title 更新灯控策略
  520. // @Description 更新灯控策略
  521. // @Param body controllers.ReqLampStrategy true "数据"
  522. // @Success 0 {int} BaseResponse.Code "成功"
  523. // @Failure 1 {int} BaseResponse.Code "失败"
  524. // @router /v1/update/strategy [post]
  525. func (o *LampController) UpdateStrategy() {
  526. o.Response(Failure, "不允许更改照明策略,可新建照明策略,并关联新策略", nil)
  527. /* var obj ReqLampStrategy
  528. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  529. beego.Debug(string(o.Ctx.Input.RequestBody))
  530. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  531. return
  532. }
  533. if err := obj.Validate(); err != nil {
  534. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  535. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  536. return
  537. }
  538. tstart, err1 := util.MlParseTime(obj.Start)
  539. tend, err2 := util.MlParseTime(obj.End)
  540. if err1 != nil || err2 != nil || tstart.After(tend) {
  541. o.Response(Failure, "有效期时间错误", nil)
  542. return
  543. }
  544. time_info, _ := json.MarshalIndent(&obj.TimeInfo, "", " ")
  545. longitude, _ := strconv.ParseFloat(obj.Longitude, 64)
  546. latitude, _ := strconv.ParseFloat(obj.Latitude, 64)
  547. oo := models.Lampstrategy{
  548. ID: obj.Code,
  549. Name: obj.Name,
  550. CtlType: obj.Ctltype,
  551. TimeInfo: string(time_info),
  552. Sunset: obj.Sunset,
  553. Start: tstart,
  554. End: tend,
  555. Year: obj.Year,
  556. Auto: obj.Auto,
  557. Tenant: obj.Tenant,
  558. Longitude: longitude,
  559. Latitude: latitude,
  560. }
  561. if err := oo.SaveFromWeb(); err != nil {
  562. o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil)
  563. return
  564. }
  565. o.Response(Success, "成功", obj.Code)
  566. */
  567. }
  568. // DeleteStrategy @Title 删除灯控策略
  569. // @Description 删除灯控策略
  570. // @Param code query string true "设备ID"
  571. // @Success 0 {int} BaseResponse.Code "成功"
  572. // @Failure 1 {int} BaseResponse.Code "失败"
  573. // @router /v1/delete/strategy [post]
  574. func (o *LampController) DeleteStrategy() {
  575. code := strings.Trim(o.GetString("code"), " ")
  576. if err := validation.Validate(code, validation.Required, validation.Length(4, 100)); err != nil {
  577. beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error()))
  578. o.Response(Failure, err.Error(), nil)
  579. return
  580. }
  581. c := models.Lampstrategy{
  582. ID: code,
  583. }
  584. if err := models.G_db.Delete(c).Error; err != nil {
  585. beego.Error(fmt.Sprintf("删除失败:%s", err.Error()))
  586. o.Response(Failure, fmt.Sprintf("数据删除失败:%s", err.Error()), nil)
  587. return
  588. }
  589. o.Response(Success, "成功", c.ID)
  590. }
  591. // Switch @Title 开灯/关灯
  592. // @Description 开灯/关灯
  593. // @Param body controllers.ReqSwitch true "数据"
  594. // @Success 0 {int} BaseResponse.Code "成功"
  595. // @Failure 1 {int} BaseResponse.Code "失败"
  596. // @router /v1/switch [post]
  597. func (o *LampController) Switch() {
  598. var obj ReqSwitch
  599. if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil {
  600. beego.Debug(string(o.Ctx.Input.RequestBody))
  601. o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil)
  602. return
  603. }
  604. if err := obj.Validate(); err != nil {
  605. beego.Error(fmt.Sprintf("LampController.Switch:请求参数验证失败:%s", err.Error()))
  606. o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil)
  607. return
  608. }
  609. arr, err := models.GetLampControllerByID(obj.Codes)
  610. if err != nil {
  611. o.Response(Failure, err.Error(), nil)
  612. return
  613. }
  614. //处理zigbee单灯控制器
  615. var mapConcentrator = make(map[string][]uint32)
  616. var mapConcentratorGateway = make(map[string]string)
  617. for _, v := range arr {
  618. if v.CtlType == 3 && v.Concentrator != "" && v.Number > 0 { //长和zigbee
  619. mapConcentrator[v.Concentrator] = append(mapConcentrator[v.Concentrator], uint32(v.Number)) //集控器
  620. mapConcentratorGateway[v.Concentrator] = v.GID //网关
  621. }
  622. }
  623. for k, v := range mapConcentrator {
  624. seq := GetNextUint64()
  625. var sw protocol.Pack_CHZB_Switch
  626. str, err := sw.EnCode(k, mapConcentratorGateway[k], seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), v)
  627. if err != nil {
  628. beego.Error(fmt.Sprintf("LampController.Switch:编码错误:%s", err.Error()))
  629. continue
  630. }
  631. topic := GetTopic(obj.Tenant, protocol.DT_CONCENTRATOR, k, protocol.TP_CHZB_SET_SWITCH)
  632. err = GetMqttHandler().PublishString(topic, str, mqtt.AtLeastOnce)
  633. if err != nil {
  634. beego.Error(fmt.Sprintf("LampController.Switch:消息发布错误:%s", err.Error()))
  635. continue
  636. }
  637. //进入指令表
  638. var msg string
  639. if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
  640. msg = string(msg0)
  641. } else {
  642. msg = str
  643. }
  644. dcr := models.DeviceCmdRecord{
  645. ID: seq,
  646. GID: mapConcentratorGateway[k],
  647. DID: k, //集控器编号
  648. Topic: topic,
  649. State: 0,
  650. Message: msg,
  651. }
  652. if err := models.G_db.Create(&dcr).Error; err != nil {
  653. logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
  654. }
  655. }
  656. //处理裕明485单灯控制器
  657. for _, v := range arr {
  658. if v.CtlType == 2 {
  659. seq := GetNextUint64()
  660. var sw protocol.Pack_CHZB_Switch
  661. str, err := sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil)
  662. if err != nil {
  663. beego.Error(fmt.Sprintf("LampController.Switch:编码错误:%s", err.Error()))
  664. continue
  665. }
  666. topic := GetTopic(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH)
  667. err = GetMqttHandler().PublishString(topic, str, mqtt.AtLeastOnce)
  668. if err != nil {
  669. beego.Error(fmt.Sprintf("LampController.Switch:消息发布错误:%s", err.Error()))
  670. continue
  671. }
  672. //进入指令表
  673. var msg string
  674. if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
  675. msg = string(msg0)
  676. } else {
  677. msg = str
  678. }
  679. dcr := models.DeviceCmdRecord{
  680. ID: seq,
  681. GID: v.GID,
  682. DID: v.ID,
  683. Topic: topic,
  684. State: 0,
  685. Message: msg,
  686. }
  687. if err := models.G_db.Create(&dcr).Error; err != nil {
  688. logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
  689. }
  690. }
  691. }
  692. //海蓝zigbee单灯控制器
  693. for _, v := range arr {
  694. if v.CtlType == 4 {
  695. // seq := GetNextUint64()
  696. seq := uint64(util.MlNow().Unix())
  697. var str string
  698. var err error
  699. if obj.Whole == 0 { //集控器开关
  700. var sw protocol.HLWLZB_Switch
  701. str, err = sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil)
  702. if err != nil {
  703. beego.Error(fmt.Sprintf("HLWLLampController.Switch:编码错误:%s", err.Error()))
  704. continue
  705. }
  706. beego.Debug(fmt.Sprintf("HLWLLampController.Switch:%s", str))
  707. topic := GethltopicDown(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH)
  708. err = GetMqttHandlerHL().PublishString(topic, str, mqtt.AtLeastOnce)
  709. if err != nil {
  710. beego.Error(fmt.Sprintf("HLWLLampController.Switch:消息发布错误:%s", err.Error()))
  711. continue
  712. }
  713. //进入指令表
  714. var msg string
  715. if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
  716. msg = string(msg0)
  717. } else {
  718. msg = str
  719. }
  720. dcr := models.DeviceCmdRecord{
  721. ID: seq,
  722. GID: v.GID,
  723. DID: v.ID,
  724. Topic: topic,
  725. State: 0,
  726. Message: msg,
  727. }
  728. if err := models.G_db.Create(&dcr).Error; err != nil {
  729. logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
  730. }
  731. } else { //普通开关
  732. var sw protocol.HLWLZB_Whole_Switch
  733. str, err = sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil)
  734. if err != nil {
  735. beego.Error(fmt.Sprintf("HLWLLampController.Switch:编码错误:%s", err.Error()))
  736. continue
  737. }
  738. beego.Debug(fmt.Sprintf("HLWLLampController.Switch:%s", str))
  739. topic := GethltopicDown(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH)
  740. err = GetMqttHandlerHL().PublishString(topic, str, mqtt.AtLeastOnce)
  741. if err != nil {
  742. beego.Error(fmt.Sprintf("HLWLLampController.Switch:消息发布错误:%s", err.Error()))
  743. continue
  744. }
  745. //进入指令表
  746. var msg string
  747. if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil {
  748. msg = string(msg0)
  749. } else {
  750. msg = str
  751. }
  752. dcr := models.DeviceCmdRecord{
  753. ID: seq,
  754. GID: v.GID,
  755. DID: v.ID,
  756. Topic: topic,
  757. State: 0,
  758. Message: msg,
  759. }
  760. if err := models.G_db.Create(&dcr).Error; err != nil {
  761. logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error())
  762. }
  763. }
  764. }
  765. }
  766. var lsrs []models.LampSwitchRecord
  767. tt := util.MlNow()
  768. ttend := tt.Add(time.Duration(obj.Recovery) * time.Minute)
  769. for _, v := range obj.Codes {
  770. lsr := models.LampSwitchRecord{
  771. DID: v,
  772. SwitchOn: uint8(obj.SwitchOn),
  773. Duration: uint(obj.Recovery * 60),
  774. Brightness: uint8(obj.Brightness),
  775. TStart: tt,
  776. TEnd: ttend,
  777. CreatedAt: util.MlNow(),
  778. }
  779. lsrs = append(lsrs, lsr)
  780. }
  781. if err := models.MultiInsertLampSwitchRecord(lsrs); err != nil {
  782. beego.Error("LampController.Switch:批量插入开关灯记录错误:", err.Error())
  783. }
  784. o.Response(Success, "成功", nil)
  785. }
  786. // GetTopic 下发的控制命令
  787. //topic格式:{tenant}/{GID}/{did}/{TP}
  788. //func GetCtrlTopic(tenant, gid, did, tp string) string {
  789. // return tenant + "/" + gid + "/" + did + "/" + tp
  790. //}
  791. func GetTopic(tenant, devtype, id, topic string) string {
  792. return tenant + "/" + devtype + "/" + id + "/" + topic
  793. }
  794. // GethltopicDown 下发的控制命令先固定,再从配置文件读
  795. //topic格式:hllk/113/lamp/longchi/down
  796. func GethltopicDown(tenant, devtype, id, topic string) string {
  797. return "hllk/113/lamp/longchi/down"
  798. }