diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/controllers/switch.go b/controllers/switch.go new file mode 100644 index 0000000..57400a8 --- /dev/null +++ b/controllers/switch.go @@ -0,0 +1,74 @@ +package controllers + +import ( + "github.com/gin-gonic/gin" + "iot-mqtt-gin/models" + "iot-mqtt-gin/service" + "net/http" + "time" +) + +type SwitchController struct { +} + +func NewSwitchController() *SwitchController { + controller := &SwitchController{} + + return controller +} + +func (s *SwitchController) GetDeviceInfo(c *gin.Context) { + devInfo := service.GetDeviceInfo() + ReturnSuccess(c, 200, "设备完整信息获取成功", devInfo, 0) +} +func (s *SwitchController) UpdateDeviceInfo(c *gin.Context) { + var req models.BaseDevice + if err := c.ShouldBindUri(&req); err != nil { + ReturnError(c, 400, "请求参数错误: "+err.Error()) + } + + /*var req dto.SystemSwitchRequest + if err := c.ShouldBindUri(&req); err != nil { + ReturnError(c, 400, "请求参数错误: "+err.Error()) + }*/ + // 补充时间信息 + if req.CreatedAt.IsZero() { + req.CreatedAt = time.Now() + } + req.UpdatedAt = time.Now() + req.LastActive = time.Now() + + info := service.UpdateDeviceInfo(req) + ReturnSuccess(c, 200, "设备完整信息获取成功", info, 0) +} +func (s *SwitchController) GetTSL(c *gin.Context) { + tsl := service.GetTSL() + ReturnSuccess(c, 200, "设备TSL模型获取成功", tsl, 0) +} +func (s *SwitchController) GetSwitchProperty(c *gin.Context) { + status := service.GetSwitchStatus() + ReturnSuccess(c, 200, "设备状态获取成功", status, 0) +} +func (s *SwitchController) SetSwitchProperty(c *gin.Context) { + var req struct { + PowerStatus bool `json:"powerStatus" binding:"required"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "无效参数: " + err.Error()}) + return + } + tsl := service.SetSwitchStatus(req.PowerStatus) + ReturnSuccess(c, 200, "设备状态更新成功", tsl, 0) +} +func (s *SwitchController) TurnOn(c *gin.Context) { + onStatus := service.TurnOn() + ReturnSuccess(c, 200, "设备开关打开成功", onStatus, 0) +} +func (s *SwitchController) TurnOff(c *gin.Context) { + offStatus := service.TurnOff() + ReturnSuccess(c, 200, "设备开关关闭成功", offStatus, 0) +} +func (s *SwitchController) Toggle(c *gin.Context) { + tsl := service.Toggle() + ReturnSuccess(c, 200, "设备状态切换成功", tsl, 0) +} diff --git a/dto/switch_dto.go b/dto/switch_dto.go new file mode 100644 index 0000000..67caf94 --- /dev/null +++ b/dto/switch_dto.go @@ -0,0 +1,15 @@ +package dto + +import "time" + +// SystemDeviceRequest 用户创建请求结构体 +type SystemSwitchRequest struct { + DeviceNumber string `uri:"device_number" binding:"required"` + CreatedAt time.Time `json:"created_at"` // 创建时间 + UpdatedAt time.Time `json:"updated_at"` // 更新时间 + LastActive time.Time `json:"last_active"` // 最后活动时间 +} + +// SystemDeviceResponse 用户创建返回结构体 +type SystemSwitchResponse struct { +} diff --git a/main.go b/main.go index 76542ca..af81df9 100644 --- a/main.go +++ b/main.go @@ -66,10 +66,11 @@ func main() { // 初始化所有控制器 mqttUserCtrl := controllers.NewMqttuserController() deviceCtrl := controllers.NewDeviceController(mqttClient, nsqProducer) + switchCtrl := controllers.NewSwitchController() // 设置MQTT消息处理 mqttClient.SetMessageHandler(deviceCtrl.HandleMQTTMessage) //引入路由 - r := router.SetupRouter(mqttUserCtrl, deviceCtrl) + r := router.SetupRouter(mqttUserCtrl, deviceCtrl, switchCtrl) r.Run(":9999") } diff --git a/models/switch.go b/models/switch.go index b1f1df6..afacf09 100644 --- a/models/switch.go +++ b/models/switch.go @@ -1,21 +1,50 @@ package models +import "sync" + // SwitchDevice 开关设备物模型 type SwitchDevice struct { BaseDevice // 嵌入公共设备模板,继承所有公共属性 - Status bool `json:"status"` // 开关状态:true-开,false-关 - LastChanged string `json:"last_changed"` // 最后状态变更时间 + PowerStatus bool `json:"powerStatus"` // 开关状态:true=开,false=关 + UpdatedAt string `json:"updatedAt"` // 最后更新时间 + mu sync.Mutex } -// SwitchStatus 开关状态模型 -type SwitchStatus struct { - ID string `json:"id"` // 设备ID - Status bool `json:"status"` // 开关状态: true-开, false-关 +// 全局开关设备实例 +var GlobalSwitch = &SwitchDevice{ + PowerStatus: false, // 初始状态为关闭 } -// SwitchRequest 设置开关状态请求参数 -type SwitchRequest struct { - OrgID string `json:"org_id" binding:"required"` - DeviceID string `json:"device_id" binding:"required"` - Status bool `json:"status" binding:"required"` +// 提供方法操作私有锁,避免直接访问 +func (s *SwitchDevice) Lock() { + s.mu.Lock() +} + +func (s *SwitchDevice) Unlock() { + s.mu.Unlock() +} + +// 简化的TSL模型定义 +func GetTSL() map[string]interface{} { + return map[string]interface{}{ + "schema": "https://iotx-tsl.oss-cn-shanghai.aliyuncs.com/schema.json", + "profile": map[string]string{ + "productKey": "switch_basic", + "version": "1.0.0", + }, + "properties": []map[string]interface{}{ + { + "id": "powerStatus", + "name": "开关状态", + "mode": "rw", + "type": "boolean", + "defaultValue": false, + }, + }, + "services": []map[string]interface{}{ + {"id": "turnOn", "name": "打开开关"}, + {"id": "turnOff", "name": "关闭开关"}, + {"id": "toggle", "name": "切换状态"}, + }, + } } diff --git a/router/routers.go b/router/routers.go index 29dc070..47499f8 100644 --- a/router/routers.go +++ b/router/routers.go @@ -11,6 +11,7 @@ import ( func SetupRouter( mqttuserCtrl *controllers.MqttuserController, deviceCtrl *controllers.DeviceController, + switchCtrl *controllers.SwitchController, ) *gin.Engine { r := gin.Default() r.Use(gin.LoggerWithConfig(logger.LoggerToFile())) @@ -27,12 +28,20 @@ func SetupRouter( devices := v1.Group("/devices") { devices.GET("/:device_number/onoff", deviceCtrl.DeviceOnOff) // 设备上下线 - - devices.GET("/tdengine/test", deviceCtrl.TDengineTest) // TDengine测试 - /*devices.GET("/:device_number/properties", controllers.DeviceController{}.DeviceOnOff) // 获取设备属性 - devices.GET("/:device_number/properties/:property", controllers.DeviceController{}.DeviceOnOff) // 更新设备属性 - devices.GET("/:device_number/command", controllers.DeviceController{}.DeviceOnOff) // 发送命令 - devices.GET("/:device_number/events", controllers.DeviceController{}.DeviceOnOff) // 获取事件*/ + devices.GET("/tdengine/test", deviceCtrl.TDengineTest) // TDengine测试 + switchs := devices.Group("/switch") + { + //开关物模型测试开始 + switchs.GET("/info", switchCtrl.GetDeviceInfo) // 获取设备完整信息(设备基础接口) + switchs.PUT("/info", switchCtrl.UpdateDeviceInfo) // 更新设备基础信息(设备基础接口) + switchs.GET("/tsl", switchCtrl.GetTSL) // 获取TSL模型定义(设备基础接口) + switchs.GET("/powerStatus", switchCtrl.GetSwitchProperty) // 读取开关状态(开关属性接口) + switchs.PUT("/powerStatus", switchCtrl.SetSwitchProperty) // 设置开关状态(开关属性接口) + switchs.POST("/turnOn", switchCtrl.TurnOn) // 打开开关(开关服务接口) + switchs.POST("/turnOff", switchCtrl.TurnOff) // 关闭开关(开关服务接口) + switchs.POST("/toggle", switchCtrl.Toggle) // 切换状态(开关服务接口)*/ + //开关物模型测试结束 + } } } return r diff --git a/runtime/log/success_2025-08-11.log b/runtime/log/success_2025-08-11.log new file mode 100644 index 0000000..a3781e5 --- /dev/null +++ b/runtime/log/success_2025-08-11.log @@ -0,0 +1,17 @@ +2025-08-11 18:43:21 - 127.0.0.1 "GET /swagger/index.html HTTP/1.1 200 3.9979ms "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" " +2025-08-11 18:43:21 - 127.0.0.1 "GET /swagger/swagger-ui.css HTTP/1.1 200 1.6015ms "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" " +2025-08-11 18:43:21 - 127.0.0.1 "GET /swagger/swagger-ui-standalone-preset.js HTTP/1.1 200 1.6221ms "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" " +2025-08-11 18:43:21 - 127.0.0.1 "GET /swagger/swagger-ui-bundle.js HTTP/1.1 200 9.7877ms "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" " +2025-08-11 18:43:22 - 127.0.0.1 "GET /swagger/doc.json HTTP/1.1 200 0s "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" " +2025-08-11 18:43:37 - 127.0.0.1 "GET /api/v1/devices/ttt/onoff HTTP/1.1 400 76.3752ms "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" " +2025-08-11 18:44:36 - 127.0.0.1 "GET /api/v1/devices/switch/info HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:04:00 - 127.0.0.1 "GET /api/v1/devices/switch/info HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:27:04 - 127.0.0.1 "GET /api/v1/devices/switch/tsl HTTP/1.1 200 517.2µs "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:33:39 - 127.0.0.1 "GET /api/v1/devices/switch/powerStatus HTTP/1.1 200 517.6µs "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:36:16 - 127.0.0.1 "GET /api/v1/devices/switch/powerStatus HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:38:48 - 127.0.0.1 "GET /api/v1/devices/switch/powerStatus HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:39:05 - 127.0.0.1 "PUT /api/v1/devices/switch/powerStatus HTTP/1.1 400 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:39:43 - 127.0.0.1 "PUT /api/v1/devices/switch/powerStatus HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:44:24 - 127.0.0.1 "PUT /api/v1/devices/switch/turnOn HTTP/1.1 404 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:44:40 - 127.0.0.1 "POST /api/v1/devices/switch/turnOn HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " +2025-08-11 19:44:46 - 127.0.0.1 "POST /api/v1/devices/switch/turnOff HTTP/1.1 200 0s "PostmanRuntime-ApipostRuntime/1.1.0" " diff --git a/service/switchService.go b/service/switchService.go new file mode 100644 index 0000000..4acf0a4 --- /dev/null +++ b/service/switchService.go @@ -0,0 +1,80 @@ +package service + +import ( + "iot-mqtt-gin/models" + "time" +) + +// 获取设备信息(包含公共属性和开关状态) +func GetDeviceInfo() models.SwitchDevice { + device := models.GlobalSwitch + device.Lock() + defer device.Unlock() + return *device +} + +// 更新设备信息 +func UpdateDeviceInfo(info models.BaseDevice) models.SwitchDevice { + device := models.GlobalSwitch + device.Lock() + defer device.Unlock() + + // 更新基础信息 + device.BaseDevice = info + if device.CreatedAt.IsZero() { + device.CreatedAt = time.Now() + } + device.UpdatedAt = time.Now().String() + device.LastActive = time.Now() + + return *device +} + +// 获取TSL模型 +func GetTSL() map[string]interface{} { + return models.GetTSL() +} + +// 获取开关状态 +func GetSwitchStatus() bool { + device := models.GlobalSwitch + device.Lock() + defer device.Unlock() + return device.PowerStatus +} + +// 设置开关状态 +func SetSwitchStatus(status bool) bool { + device := models.GlobalSwitch + device.Lock() + defer device.Unlock() + + // 更新最后活动时间 + device.LastActive = time.Now() + device.UpdatedAt = time.Now().String() + + device.PowerStatus = status + return true +} + +// 打开开关 +func TurnOn() bool { + return SetSwitchStatus(true) +} + +// 关闭开关 +func TurnOff() bool { + return SetSwitchStatus(false) +} + +// 切换开关状态 +func Toggle() bool { + device := models.GlobalSwitch + device.Lock() + current := device.PowerStatus + device.Unlock() + + // 切换状态 + newStatus := !current + return SetSwitchStatus(newStatus) +}