package controllers import ( "fmt" "strconv" "strings" "time" "github.com/sirupsen/logrus" "github.com/astaxie/beego" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/go-ozzo/ozzo-validation/v4/is" "lc/common/models" "lc/common/mqtt" "lc/common/protocol" "lc/common/util" ) // LampStrategyQueue redis缓存 var LampStrategyQueue = "lamp_strategy_queue" //已修改的灯控编码列表,队列方式,先进先出 var LampHlMqttDown = "hllk/113/lamp/longchi/down" var LampHlMqttUp = "hllk/113/lamp/longchi/up" type LampController struct { BaseController } type ConcentratorInfo struct { GID string TID int } type ReqLampController struct { Code string `json:"code"` //设备编号,禁止修改 GID string `json:"gid"` //网关ID Tenant string `json:"tenant"` //租户ID Name string `json:"name"` //设备名称 Brand int `json:"brand"` //品牌 Model int `json:"model"` //型号 CtlType int `json:"ctltype"` //单灯控制器类型,nb-iot:1,485:2,zigbee:3 Concentrator string `json:"concentrator"` //集中器编号,zigbee灯控专用,其他类型灯控置空 Netid int `json:"netid"` //网络号,zigbee灯控专用,其他类型灯控置0 Channel int `json:"channel"` //通道号,zigbee灯控专用,其他类型灯控置0 OrgNumber string `json:"orgnumber"` //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型 Strategy string `json:"strategy"` //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个 State int `json:"state"` //1启用,0禁用 } func (a ReqLampController) Validate() error { var rules []*validation.FieldRules rules = append(rules, validation.Field(&a.Code, validation.Required, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8))) rules = append(rules, validation.Field(&a.CtlType, validation.Required, validation.In(1, 2, 3, 4))) rules = append(rules, validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32))) rules = append(rules, validation.Field(&a.State, validation.In(0, 1))) if a.CtlType == 2 { //485需要网关ID,其他暂不需要 rules = append(rules, validation.Field(&a.GID, validation.Required, validation.Length(4, 32))) } else if a.CtlType == 3 { rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 8))) } else if a.CtlType == 4 { rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 32))) } return validation.ValidateStruct(&a, rules...) } type LampControllerDev struct { Code string `json:"code"` //设备编号,禁止修改 GID string `json:"gid"` //网关ID Name string `json:"name"` //设备名称 Brand int `json:"brand"` //品牌 Model int `json:"model"` //型号 CtlType int `json:"ctltype"` //单灯控制器类型,nb-iot:1,485:2,zigbee:3 Concentrator string `json:"concentrator"` //集中器编号,zigbee灯控专用,其他类型灯控置空 Netid int `json:"netid"` //网络号,zigbee灯控专用,其他类型灯控置0 Channel int `json:"channel"` //通道号,zigbee灯控专用,其他类型灯控置0 OrgNumber string `json:"orgnumber"` //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型 Strategy string `json:"strategy"` //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个 State int `json:"state"` //1启用,0禁用 } func (a LampControllerDev) Validate() error { var rules []*validation.FieldRules rules = append(rules, validation.Field(&a.Code, validation.Required, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.CtlType, validation.Required, validation.In(1, 2, 3, 4))) rules = append(rules, validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32))) rules = append(rules, validation.Field(&a.State, validation.In(0, 1))) if a.CtlType == 2 { //485需要网关ID,其他暂不需要 rules = append(rules, validation.Field(&a.GID, validation.Required, validation.Length(4, 32))) } else if a.CtlType == 3 { rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 8))) } else if a.CtlType == 4 { rules = append(rules, validation.Field(&a.Concentrator, validation.Required, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.OrgNumber, validation.Required, validation.Length(3, 32))) } return validation.ValidateStruct(&a, rules...) } type ReqImportLampControllerDev struct { Tenant string `json:"tenant"` //租户ID List []LampControllerDev `json:"list"` //灯控列表 } func (a ReqImportLampControllerDev) Validate() error { var rules []*validation.FieldRules rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8))) rules = append(rules, validation.Field(&a.List, validation.Required)) return validation.ValidateStruct(&a, rules...) } // ReqStrategy 关联策略 type ReqStrategy struct { Tenant string `json:"tenant"` //租户ID Codes []string `json:"codes"` //数组 灯控编码数组 Strategy string `json:"strategy"` // 策略编码,无则置空,多个则用逗号分开,暂时只支持一个 } func (a ReqStrategy) Validate() error { return validation.ValidateStruct(&a, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)), validation.Field(&a.Codes, validation.Required), validation.Field(&a.Strategy, validation.Required, validation.Length(1, 32)), ) } // LampStrategy 创建更新策略 type LampStrategy struct { Ontime string `json:"ontime"` //开始时间,24小时制,格式{小时}:{分钟}:{秒}类似13:06:00,为13点6分 Offtime string `json:"offtime"` //结束时间,24小时制,格式同ontime Brightness int `json:"brightness"` //亮度,1到100 } func (a LampStrategy) Validate() error { return validation.ValidateStruct(&a, validation.Field(&a.Ontime, validation.Required, validation.Date("15:04:05")), validation.Field(&a.Offtime, validation.Required, validation.Date("15:04:05")), validation.Field(&a.Brightness, validation.Min(1), validation.Max(100)), ) } type ReqLampStrategy struct { Tenant string `json:"tenant"` //租户ID Name string `json:"name"` //策略名称 Code string `json:"code"` //策略编码,禁止修改 TimeInfo []LampStrategy `json:"timeinfo"` //时间及亮度内容数组,最多4个元素,最少1个元素 Sunset int `json:"sunset"` //是否启用 Ctltype int `json:"ctltype"` //单灯控制器类型,nb-iot:1,485:2,zigbee:3 不同灯控可能支持的时间亮度有不同的设置,备用 Start string `json:"start"` //时间格式,类似2020-07-20 06:06:06 End string `json:"end"` //时间格式,类似2020-09-20 06:06:06 Year int `json:"year"` //是否全年,1全年,0非全年 Auto int `json:"auto"` //1,自动延续,0非自动延续 Longitude string `json:"longitude"` //东正西负。双精度浮点数,整数最多3字符,小数最多6字符 Latitude string `json:"latitude"` //北正南负,双精度浮点数,整数最多2字符,小数最多6字符 } func (a ReqLampStrategy) Validate() error { var rules []*validation.FieldRules rules = append(rules, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8))) rules = append(rules, validation.Field(&a.Code, validation.Length(4, 32))) rules = append(rules, validation.Field(&a.TimeInfo, validation.Length(1, 4))) //最少1个,最多4个 rules = append(rules, validation.Field(&a.Sunset, validation.In(0, 1))) rules = append(rules, validation.Field(&a.Year, validation.In(0, 1))) rules = append(rules, validation.Field(&a.Auto, validation.In(0, 1))) //rules = append(rules, validation.Field(&a.Ctltype, validation.Required, validation.In(1, 2, 3))) rules = append(rules, validation.Field(&a.Start, validation.Required, validation.Date("2006-01-02 15:04:05"))) rules = append(rules, validation.Field(&a.End, validation.Required, validation.Date("2006-01-02 15:04:05"))) rules = append(rules, validation.Field(&a.Longitude, validation.Required, is.Longitude)) rules = append(rules, validation.Field(&a.Latitude, validation.Required, is.Latitude)) return validation.ValidateStruct(&a, rules...) } // ReqSwitch 开/关灯 type ReqSwitch struct { Tenant string `json:"tenant"` //租户ID Codes []string `json:"codes"` //数组 灯控编码数组,一次开关灯多个 Recovery int `json:"recovery"` //恢复时间,即开或关灯时长,超过这个时间则自动恢复时控模式 Brightness int `json:"brightness"` //0~100,0相当于关等,100最大亮度 SwitchOn int `json:"switchon"` //1开灯,0关灯 Whole int `json:"whole,omitempty"` //1为集控 } func (a ReqSwitch) Validate() error { return validation.ValidateStruct(&a, validation.Field(&a.Tenant, validation.Required, validation.Length(4, 8)), validation.Field(&a.Codes, validation.Required), validation.Field(&a.Recovery, validation.Required, validation.Min(1), validation.Max(480)), validation.Field(&a.Brightness, validation.Min(0), validation.Max(100)), validation.Field(&a.SwitchOn, validation.In(0, 1)), // validation.Field(&a.Whole, validation.In(0, 1)), ) } // ConvertNumber 长和zigbee单灯控制器编号,短横线连接 func ConvertNumber(strNumber string) uint16 { strlist := strings.Split(strNumber, "-") if len(strlist) == 2 { hight, err0 := strconv.Atoi(strlist[0]) low, err1 := strconv.Atoi(strlist[1]) if err0 == nil && err1 == nil { return uint16(hight<<8 | low) } } return 0 } // CreateLampController @Title 创建灯控设备 // @Description 创建灯控设备 // @Param body body controllers.ReqLampController true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/create [post] func (o *LampController) CreateLampController() { var obj ReqLampController if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } var number uint16 = 0 if obj.CtlType == 3 { //长和zigbee集控器 number = ConvertNumber(obj.OrgNumber) if number == 0 { beego.Error("请求的编号格式不正确,要求\"xx-xx\"") o.Response(Failure, "请求的编号格式不正确,要求\"xx-xx\"", nil) } } oo := models.DeviceLampController{ ID: obj.Code, //设备ID,DID Name: obj.Name, GID: obj.GID, //网关ID Brand: obj.Brand, //品牌 Model: obj.Model, //型号 CtlType: obj.CtlType, //单灯控制器类型,nb-iot:1,485:2,zigbee:3 Concentrator: obj.Concentrator, //集中器编号,zigbee灯控专用,其他类型灯控置空 Netid: obj.Netid, //网络号,zigbee灯控专用,其他类型灯控置0 Channel: obj.Channel, //通道号,zigbee灯控专用,其他类型灯控置0 Number: number, //灯编号, zigbee灯控专用,其他类型灯控置0 OrgNumber: obj.OrgNumber, //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型 Strategy: obj.Strategy, //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个 Tenant: obj.Tenant, //租户ID State: obj.State, //1启用,0禁用 } //检查是否有网关ID if obj.CtlType == 3 || obj.CtlType == 4 { //查找灯控关联的zigbee集中器信息 if concentrator, err := models.GetConcentratorbyID(obj.Concentrator); err == nil { oo.GID = concentrator.GID oo.TID = concentrator.TID } else { beego.Error(fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error())) o.Response(Failure, fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()), nil) return } } else if obj.CtlType == 2 { oo.TID = 2 } if err := oo.SaveFromWeb(obj.CtlType); err != nil { o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil) return } //存入redis,等待下发给设备 if err := redisCltRawdata.LPush(LampStrategyQueue, obj.Code).Err(); err != nil { logrus.Errorf("LampController.CreateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", obj.Code, err.Error()) } o.Response(Success, "成功", oo.ID) } // UpdateLampController @Title 更新灯控设备 // @Description 更新灯控设备 // @Param body body controllers.ReqLampController true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/update [post] func (o *LampController) UpdateLampController() { var obj ReqLampController if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } var number uint16 = 0 if obj.CtlType == 3 { //长和zigbee集控器 number = ConvertNumber(obj.OrgNumber) if number == 0 { beego.Error("请求的编号格式不正确,要求\"xx-xx\"") o.Response(Failure, "请求的编号格式不正确,要求\"xx-xx\"", nil) } } oo := models.DeviceLampController{ ID: obj.Code, //设备ID,DID Name: obj.Name, GID: obj.GID, //网关ID Brand: obj.Brand, //品牌 Model: obj.Model, //型号 CtlType: obj.CtlType, //单灯控制器类型,nb-iot:1,485:2,zigbee:3 Concentrator: obj.Concentrator, //集中器编号,zigbee灯控专用,其他类型灯控置空 Netid: obj.Netid, //网络号,zigbee灯控专用,其他类型灯控置0 Channel: obj.Channel, //通道号,zigbee灯控专用,其他类型灯控置0 Number: number, //灯编号, zigbee灯控专用,其他类型灯控置0 OrgNumber: obj.OrgNumber, //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型 Strategy: obj.Strategy, //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个 Tenant: obj.Tenant, //租户ID State: obj.State, //1启用,0禁用 } //检查是否有网关ID if obj.CtlType == 3 { //查找灯控关联的zigbee集中器信息 if concentrator, err := models.GetConcentratorbyID(obj.Concentrator); err == nil { oo.GID = concentrator.GID oo.TID = concentrator.TID } else { beego.Error(fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error())) o.Response(Failure, fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error()), nil) return } } else if obj.CtlType == 2 { oo.TID = 2 } if err := oo.SaveFromWeb(obj.CtlType); err != nil { o.Response(Failure, fmt.Sprintf("数据更新失败:%s", err.Error()), nil) return } //存入redis,等待下发给设备 if err := redisCltRawdata.LPush(LampStrategyQueue, obj.Code).Err(); err != nil { logrus.Errorf("LampController.UpdateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", obj.Code, err.Error()) } o.Response(Success, "成功", oo.ID) } // DeleteLampController @Title 删除灯控设备 // @Description 删除灯控设备 // @Param code query string true "设备ID" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/delete [post] func (o *LampController) DeleteLampController() { code := strings.Trim(o.GetString("code"), " ") if err := validation.Validate(code, validation.Required, validation.Length(4, 100)); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } c := models.DeviceLampController{ ID: code, } if err := c.Delete(); err != nil { beego.Error(fmt.Sprintf("删除失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("数据删除失败:%s", err.Error()), nil) return } o.Response(Success, "成功", c.ID) } // UpdateState @Title 更新灯控设备启用禁用状态 // @Description 更新灯控设备启用禁用状态 // @Param body controllers.ProgramsState true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/update/state [POST] func (o *LampController) UpdateState() { code := o.GetString("code") state, err := o.GetUint8("state", 0) if code == "" || state > 1 || err != nil { beego.Error("参数错误") o.Response(Failure, "参数错误", nil) return } err = models.LampControllerUpdateState(code, int(state)) if err != nil { beego.Error("更新灯控设备状态错误:", err.Error()) o.Response(Failure, "失败", err.Error()) return } o.Response(Success, "成功", code) } // ImportLampControllerDev @Title 导入灯控设备 // @Description 导入灯控设备 // @Param body body controllers.ReqImportLampControllerDev true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/import [post] func (o *LampController) ImportLampControllerDev() { var obj ReqImportLampControllerDev if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } var resp []RespImport mapConcentratorInfo := make(map[string]*ConcentratorInfo) for _, v := range obj.List { var aresp RespImport aresp.Code = v.Code var number uint16 = 0 if v.CtlType == 3 { //长和zigbee集控器 number = ConvertNumber(v.OrgNumber) } oo := models.DeviceLampController{ ID: v.Code, //设备ID,DID Name: v.Name, GID: v.GID, //网关ID Brand: v.Brand, //品牌 Model: v.Model, //型号 CtlType: v.CtlType, //单灯控制器类型,nb-iot:1,485:2,zigbee:3 Concentrator: v.Concentrator, //集中器编号,zigbee灯控专用,其他类型灯控置空 Netid: v.Netid, //网络号,zigbee灯控专用,其他类型灯控置0 Channel: v.Channel, //通道号,zigbee灯控专用,其他类型灯控置0 Number: number, //灯编号, zigbee灯控专用,其他类型灯控置0 OrgNumber: v.OrgNumber, //灯编号, zigbee灯控专用,设备上原始的编号,字符串类型 Strategy: v.Strategy, //关联的策略编码,无则置空,多个则用逗号分开,暂时只支持一个 Tenant: obj.Tenant, //租户ID State: v.State, //1启用,0禁用 } //检查是否有网关ID if v.CtlType == 3 { //查找灯控关联的zigbee集中器信息 if ci, ok := mapConcentratorInfo[v.Concentrator]; ok { oo.GID = ci.GID oo.TID = ci.TID } else { if concentrator, err := models.GetConcentratorbyID(v.Concentrator); err == nil { oo.GID = concentrator.GID oo.TID = concentrator.TID mapConcentratorInfo[v.Concentrator] = &ConcentratorInfo{GID: concentrator.GID, TID: concentrator.TID} } else { beego.Error(fmt.Sprintf("操作失败,请先创建zigbee集控器:%s", err.Error())) aresp.Error = err.Error() continue } } } else if v.CtlType == 2 { oo.TID = 2 } err := oo.SaveFromWeb(v.CtlType) if err != nil { beego.Error(fmt.Sprintf("zigbee集控器数据导入失败,code=%s,失败原因:%s", v.Code, err.Error())) aresp.Error = err.Error() continue } //存入redis,等待下发给设备 if err := redisCltRawdata.LPush(LampStrategyQueue, v.Code).Err(); err != nil { logrus.Errorf("LampController.CreateLampController:创建灯控缓存redis失败,灯控编码:%s,失败原因:%s", v.Code, err.Error()) } } o.Response(Success, "成功", resp) } // RelateStrategy @Title 关联策略 // @Description 关联策略 // @Param body controllers.ReqStrategy true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/relate/strategy [post] func (o *LampController) RelateStrategy() { var obj ReqStrategy if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } if err := models.UpdateStrategy(obj.Codes, obj.Strategy); err != nil { beego.Error(fmt.Sprintf("关联策略失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("关联策略失败:%s", err.Error()), nil) return } //存入redis,等待下发给设备 if len(obj.Codes) > 0 { codelist := make([]interface{}, 0, len(obj.Codes)) for _, v := range obj.Codes { codelist = append(codelist, v) } if err := redisCltRawdata.LPush(LampStrategyQueue, codelist...).Err(); err != nil { logrus.Errorf("LampController.RelateStrategy:创建灯控缓存redis失败,灯控编码:%v,失败原因:%s", codelist, err.Error()) } } o.Response(Success, "成功", nil) } // CreateStrategy @Title 创建灯控策略 // @Description 创建灯控策略 // @Param body controllers.ReqLampStrategy true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/create/strategy [post] func (o *LampController) CreateStrategy() { var obj ReqLampStrategy if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } tstart, err1 := util.MlParseTime(obj.Start) tend, err2 := util.MlParseTime(obj.End) if err1 != nil || err2 != nil || tstart.After(tend) { o.Response(Failure, "有效期时间错误", nil) return } timeInfo, _ := json.MarshalIndent(&obj.TimeInfo, "", " ") longitude, _ := strconv.ParseFloat(obj.Longitude, 64) latitude, _ := strconv.ParseFloat(obj.Latitude, 64) oo := models.Lampstrategy{ ID: obj.Code, Name: obj.Name, CtlType: obj.Ctltype, TimeInfo: string(timeInfo), Sunset: obj.Sunset, Start: tstart, End: tend, Year: obj.Year, Auto: obj.Auto, Tenant: obj.Tenant, Longitude: longitude, Latitude: latitude, } if err := oo.SaveFromWeb(); err != nil { o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil) return } o.Response(Success, "成功", obj.Code) } // UpdateStrategy @Title 更新灯控策略 // @Description 更新灯控策略 // @Param body controllers.ReqLampStrategy true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/update/strategy [post] func (o *LampController) UpdateStrategy() { o.Response(Failure, "不允许更改照明策略,可新建照明策略,并关联新策略", nil) /* var obj ReqLampStrategy if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } tstart, err1 := util.MlParseTime(obj.Start) tend, err2 := util.MlParseTime(obj.End) if err1 != nil || err2 != nil || tstart.After(tend) { o.Response(Failure, "有效期时间错误", nil) return } time_info, _ := json.MarshalIndent(&obj.TimeInfo, "", " ") longitude, _ := strconv.ParseFloat(obj.Longitude, 64) latitude, _ := strconv.ParseFloat(obj.Latitude, 64) oo := models.Lampstrategy{ ID: obj.Code, Name: obj.Name, CtlType: obj.Ctltype, TimeInfo: string(time_info), Sunset: obj.Sunset, Start: tstart, End: tend, Year: obj.Year, Auto: obj.Auto, Tenant: obj.Tenant, Longitude: longitude, Latitude: latitude, } if err := oo.SaveFromWeb(); err != nil { o.Response(Failure, fmt.Sprintf("数据插入失败:%s", err.Error()), nil) return } o.Response(Success, "成功", obj.Code) */ } // DeleteStrategy @Title 删除灯控策略 // @Description 删除灯控策略 // @Param code query string true "设备ID" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/delete/strategy [post] func (o *LampController) DeleteStrategy() { code := strings.Trim(o.GetString("code"), " ") if err := validation.Validate(code, validation.Required, validation.Length(4, 100)); err != nil { beego.Error(fmt.Sprintf("请求参数验证失败:%s", err.Error())) o.Response(Failure, err.Error(), nil) return } c := models.Lampstrategy{ ID: code, } if err := models.G_db.Delete(c).Error; err != nil { beego.Error(fmt.Sprintf("删除失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("数据删除失败:%s", err.Error()), nil) return } o.Response(Success, "成功", c.ID) } // Switch @Title 开灯/关灯 // @Description 开灯/关灯 // @Param body controllers.ReqSwitch true "数据" // @Success 0 {int} BaseResponse.Code "成功" // @Failure 1 {int} BaseResponse.Code "失败" // @router /v1/switch [post] func (o *LampController) Switch() { var obj ReqSwitch if err := json.Unmarshal(o.Ctx.Input.RequestBody, &obj); err != nil { beego.Debug(string(o.Ctx.Input.RequestBody)) o.Response(Failure, fmt.Sprintf("数据包解析错误:%s", err.Error()), nil) return } if err := obj.Validate(); err != nil { beego.Error(fmt.Sprintf("LampController.Switch:请求参数验证失败:%s", err.Error())) o.Response(Failure, fmt.Sprintf("请求参数验证失败:%s", err.Error()), nil) return } arr, err := models.GetLampControllerByID(obj.Codes) if err != nil { o.Response(Failure, err.Error(), nil) return } //处理zigbee单灯控制器 var mapConcentrator = make(map[string][]uint32) var mapConcentratorGateway = make(map[string]string) for _, v := range arr { if v.CtlType == 3 && v.Concentrator != "" && v.Number > 0 { //长和zigbee mapConcentrator[v.Concentrator] = append(mapConcentrator[v.Concentrator], uint32(v.Number)) //集控器 mapConcentratorGateway[v.Concentrator] = v.GID //网关 } } for k, v := range mapConcentrator { seq := GetNextUint64() var sw protocol.Pack_CHZB_Switch str, err := sw.EnCode(k, mapConcentratorGateway[k], seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), v) if err != nil { beego.Error(fmt.Sprintf("LampController.Switch:编码错误:%s", err.Error())) continue } topic := GetTopic(obj.Tenant, protocol.DT_CONCENTRATOR, k, protocol.TP_CHZB_SET_SWITCH) err = GetMqttHandler().PublishString(topic, str, mqtt.AtLeastOnce) if err != nil { beego.Error(fmt.Sprintf("LampController.Switch:消息发布错误:%s", err.Error())) continue } //进入指令表 var msg string if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil { msg = string(msg0) } else { msg = str } dcr := models.DeviceCmdRecord{ ID: seq, GID: mapConcentratorGateway[k], DID: k, //集控器编号 Topic: topic, State: 0, Message: msg, } if err := models.G_db.Create(&dcr).Error; err != nil { logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error()) } } //处理裕明485单灯控制器 for _, v := range arr { if v.CtlType == 2 { seq := GetNextUint64() var sw protocol.Pack_CHZB_Switch str, err := sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil) if err != nil { beego.Error(fmt.Sprintf("LampController.Switch:编码错误:%s", err.Error())) continue } topic := GetTopic(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH) err = GetMqttHandler().PublishString(topic, str, mqtt.AtLeastOnce) if err != nil { beego.Error(fmt.Sprintf("LampController.Switch:消息发布错误:%s", err.Error())) continue } //进入指令表 var msg string if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil { msg = string(msg0) } else { msg = str } dcr := models.DeviceCmdRecord{ ID: seq, GID: v.GID, DID: v.ID, Topic: topic, State: 0, Message: msg, } if err := models.G_db.Create(&dcr).Error; err != nil { logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error()) } } } //海蓝zigbee单灯控制器 for _, v := range arr { if v.CtlType == 4 { // seq := GetNextUint64() seq := uint64(util.MlNow().Unix()) var str string var err error if obj.Whole == 0 { //集控器开关 var sw protocol.HLWLZB_Switch str, err = sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil) if err != nil { beego.Error(fmt.Sprintf("HLWLLampController.Switch:编码错误:%s", err.Error())) continue } beego.Debug(fmt.Sprintf("HLWLLampController.Switch:%s", str)) topic := GethltopicDown(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH) err = GetMqttHandlerHL().PublishString(topic, str, mqtt.AtLeastOnce) if err != nil { beego.Error(fmt.Sprintf("HLWLLampController.Switch:消息发布错误:%s", err.Error())) continue } //进入指令表 var msg string if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil { msg = string(msg0) } else { msg = str } dcr := models.DeviceCmdRecord{ ID: seq, GID: v.GID, DID: v.ID, Topic: topic, State: 0, Message: msg, } if err := models.G_db.Create(&dcr).Error; err != nil { logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error()) } } else { //普通开关 var sw protocol.HLWLZB_Whole_Switch str, err = sw.EnCode(v.ID, v.GID, seq, uint8(obj.SwitchOn), uint8(obj.Brightness), uint(obj.Recovery*60), nil) if err != nil { beego.Error(fmt.Sprintf("HLWLLampController.Switch:编码错误:%s", err.Error())) continue } beego.Debug(fmt.Sprintf("HLWLLampController.Switch:%s", str)) topic := GethltopicDown(obj.Tenant, protocol.DT_LAMPCONTROLLER, v.ID, protocol.TP_YM_SET_SWITCH) err = GetMqttHandlerHL().PublishString(topic, str, mqtt.AtLeastOnce) if err != nil { beego.Error(fmt.Sprintf("HLWLLampController.Switch:消息发布错误:%s", err.Error())) continue } //进入指令表 var msg string if msg0, errmsg := json.MarshalIndent(sw, "", " "); errmsg == nil { msg = string(msg0) } else { msg = str } dcr := models.DeviceCmdRecord{ ID: seq, GID: v.GID, DID: v.ID, Topic: topic, State: 0, Message: msg, } if err := models.G_db.Create(&dcr).Error; err != nil { logrus.Errorf("LampController.Switch:开关灯指令插入指令表:%s", err.Error()) } } } } var lsrs []models.LampSwitchRecord tt := util.MlNow() ttend := tt.Add(time.Duration(obj.Recovery) * time.Minute) for _, v := range obj.Codes { lsr := models.LampSwitchRecord{ DID: v, SwitchOn: uint8(obj.SwitchOn), Duration: uint(obj.Recovery * 60), Brightness: uint8(obj.Brightness), TStart: tt, TEnd: ttend, CreatedAt: util.MlNow(), } lsrs = append(lsrs, lsr) } if err := models.MultiInsertLampSwitchRecord(lsrs); err != nil { beego.Error("LampController.Switch:批量插入开关灯记录错误:", err.Error()) } o.Response(Success, "成功", nil) } // GetTopic 下发的控制命令 //topic格式:{tenant}/{GID}/{did}/{TP} //func GetCtrlTopic(tenant, gid, did, tp string) string { // return tenant + "/" + gid + "/" + did + "/" + tp //} func GetTopic(tenant, devtype, id, topic string) string { return tenant + "/" + devtype + "/" + id + "/" + topic } // GethltopicDown 下发的控制命令先固定,再从配置文件读 //topic格式:hllk/113/lamp/longchi/down func GethltopicDown(tenant, devtype, id, topic string) string { return "hllk/113/lamp/longchi/down" }