From 75306941c2fc214399e0320bf27ac8bdb68dbad6 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Mon, 10 Nov 2025 21:32:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E6=89=80=E6=9C=89Regional=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E4=B8=BAArea?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/exceeding-threshold-alarm/index.md | 3 +- docs/docs.go | 6 +-- docs/swagger.json | 6 +-- docs/swagger.yaml | 4 +- internal/app/dto/monitor_converter.go | 10 ++--- internal/app/dto/monitor_dto.go | 10 ++--- internal/app/webhook/chirp_stack.go | 38 +++++++++---------- internal/domain/device/device_service.go | 2 +- .../domain/device/general_device_service.go | 18 ++++----- internal/infra/models/sensor_data.go | 4 +- .../lora_mesh_uart_passthrough_transport.go | 20 +++++----- 11 files changed, 61 insertions(+), 60 deletions(-) diff --git a/design/exceeding-threshold-alarm/index.md b/design/exceeding-threshold-alarm/index.md index b4ea6af..a3fdc40 100644 --- a/design/exceeding-threshold-alarm/index.md +++ b/design/exceeding-threshold-alarm/index.md @@ -143,4 +143,5 @@ 11. 实现区域阈值告警和设备阈值告警的增删改查 12. 实现任务11应的八个web接口 13. 实现根据区域ID或设备ID清空对应阈值告警任务 -14. 设备和区域主控删除时清除对应区域阈值告警或设备阈值告警任务 \ No newline at end of file +14. 设备和区域主控删除时清除对应区域阈值告警或设备阈值告警任务 +15. 将所有Regional更改为Area \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index 05aa23a..61485a4 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -6816,6 +6816,9 @@ const docTemplate = `{ "dto.SensorDataDTO": { "type": "object", "properties": { + "area_controller_id": { + "type": "integer" + }, "data": { "type": "array", "items": { @@ -6825,9 +6828,6 @@ const docTemplate = `{ "device_id": { "type": "integer" }, - "regional_controller_id": { - "type": "integer" - }, "sensor_type": { "$ref": "#/definitions/models.SensorType" }, diff --git a/docs/swagger.json b/docs/swagger.json index b3cfe1a..dfa71b7 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -6808,6 +6808,9 @@ "dto.SensorDataDTO": { "type": "object", "properties": { + "area_controller_id": { + "type": "integer" + }, "data": { "type": "array", "items": { @@ -6817,9 +6820,6 @@ "device_id": { "type": "integer" }, - "regional_controller_id": { - "type": "integer" - }, "sensor_type": { "$ref": "#/definitions/models.SensorType" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c228a4f..0230576 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1369,14 +1369,14 @@ definitions: type: object dto.SensorDataDTO: properties: + area_controller_id: + type: integer data: items: type: integer type: array device_id: type: integer - regional_controller_id: - type: integer sensor_type: $ref: '#/definitions/models.SensorType' time: diff --git a/internal/app/dto/monitor_converter.go b/internal/app/dto/monitor_converter.go index f7192f0..84c7ac2 100644 --- a/internal/app/dto/monitor_converter.go +++ b/internal/app/dto/monitor_converter.go @@ -11,11 +11,11 @@ func NewListSensorDataResponse(data []models.SensorData, total int64, page, page dtos := make([]SensorDataDTO, len(data)) for i, item := range data { dtos[i] = SensorDataDTO{ - Time: item.Time, - DeviceID: item.DeviceID, - RegionalControllerID: item.RegionalControllerID, - SensorType: item.SensorType, - Data: json.RawMessage(item.Data), + Time: item.Time, + DeviceID: item.DeviceID, + AreaControllerID: item.AreaControllerID, + SensorType: item.SensorType, + Data: json.RawMessage(item.Data), } } diff --git a/internal/app/dto/monitor_dto.go b/internal/app/dto/monitor_dto.go index 0eeee8f..7129998 100644 --- a/internal/app/dto/monitor_dto.go +++ b/internal/app/dto/monitor_dto.go @@ -22,11 +22,11 @@ type ListSensorDataRequest struct { // SensorDataDTO 是用于API响应的传感器数据结构 type SensorDataDTO struct { - Time time.Time `json:"time"` - DeviceID uint `json:"device_id"` - RegionalControllerID uint `json:"regional_controller_id"` - SensorType models.SensorType `json:"sensor_type"` - Data json.RawMessage `json:"data"` + Time time.Time `json:"time"` + DeviceID uint `json:"device_id"` + AreaControllerID uint `json:"area_controller_id"` + SensorType models.SensorType `json:"sensor_type"` + Data json.RawMessage `json:"data"` } // ListSensorDataResponse 是获取传感器数据列表的响应结构 diff --git a/internal/app/webhook/chirp_stack.go b/internal/app/webhook/chirp_stack.go index 1af2d83..60e6fe4 100644 --- a/internal/app/webhook/chirp_stack.go +++ b/internal/app/webhook/chirp_stack.go @@ -162,17 +162,17 @@ func (c *ChirpStackListener) handleUpEvent(ctx context.Context, event *UpEvent) logger.Infof("开始处理 'up' 事件, DevEui: %s", event.DeviceInfo.DevEui) // 1. 查找区域主控设备 - regionalController, err := c.areaControllerRepo.FindByNetworkID(reqCtx, event.DeviceInfo.DevEui) + areaController, err := c.areaControllerRepo.FindByNetworkID(reqCtx, event.DeviceInfo.DevEui) if err != nil { logger.Errorf("处理 'up' 事件失败:无法通过 DevEui '%s' 找到区域主控设备: %v", event.DeviceInfo.DevEui, err) return } // 依赖 SelfCheck 确保区域主控有效 - if err := regionalController.SelfCheck(); err != nil { - logger.Errorf("处理 'up' 事件失败:区域主控 %v(ID: %d) 未通过自检: %v", regionalController.Name, regionalController.ID, err) + if err := areaController.SelfCheck(); err != nil { + logger.Errorf("处理 'up' 事件失败:区域主控 %v(ID: %d) 未通过自检: %v", areaController.Name, areaController.ID, err) return } - logger.Infof("找到区域主控: %s (ID: %d)", regionalController.Name, regionalController.ID) + logger.Infof("找到区域主控: %s (ID: %d)", areaController.Name, areaController.ID) // 2. 记录区域主控的信号强度 (如果存在) if len(event.RxInfo) > 0 { @@ -187,8 +187,8 @@ func (c *ChirpStackListener) handleUpEvent(ctx context.Context, event *UpEvent) } // 记录信号强度 - c.recordSensorData(reqCtx, regionalController.ID, regionalController.ID, event.Time, models.SensorTypeSignalMetrics, signalMetrics) - logger.Infof("已记录区域主控 (ID: %d) 的信号强度: RSSI=%d, SNR=%.2f", regionalController.ID, rx.Rssi, rx.Snr) + c.recordSensorData(reqCtx, areaController.ID, areaController.ID, event.Time, models.SensorTypeSignalMetrics, signalMetrics) + logger.Infof("已记录区域主控 (ID: %d) 的信号强度: RSSI=%d, SNR=%.2f", areaController.ID, rx.Rssi, rx.Snr) } else { logger.Warnf("处理 'up' 事件时未找到 RxInfo,无法记录信号数据。DevEui: %s", event.DeviceInfo.DevEui) } @@ -316,7 +316,7 @@ func (c *ChirpStackListener) handleUpEvent(ctx context.Context, event *UpEvent) } // 5.5 记录传感器数据 - c.recordSensorData(reqCtx, regionalController.ID, dev.ID, event.Time, valueDescriptor.Type, dataToRecord) + c.recordSensorData(reqCtx, areaController.ID, dev.ID, event.Time, valueDescriptor.Type, dataToRecord) logger.Infof("成功记录传感器数据: 设备ID=%d, 类型=%s, 原始值=%f, 解析值=%.2f", dev.ID, valueDescriptor.Type, rawSensorValue, parsedValue) } @@ -334,7 +334,7 @@ func (c *ChirpStackListener) handleStatusEvent(ctx context.Context, event *Statu logger.Infof("处接收到理 'status' 事件: %+v", event) // 查找区域主控设备 - regionalController, err := c.areaControllerRepo.FindByNetworkID(reqCtx, event.DeviceInfo.DevEui) + areaController, err := c.areaControllerRepo.FindByNetworkID(reqCtx, event.DeviceInfo.DevEui) if err != nil { logger.Errorf("处理 'status' 事件失败:无法通过 DevEui '%s' 找到区域主控设备: %v", event.DeviceInfo.DevEui, err) return @@ -344,8 +344,8 @@ func (c *ChirpStackListener) handleStatusEvent(ctx context.Context, event *Statu signalMetrics := models.SignalMetrics{ MarginDb: event.Margin, } - c.recordSensorData(reqCtx, regionalController.ID, regionalController.ID, event.Time, models.SensorTypeSignalMetrics, signalMetrics) - logger.Infof("已记录区域主控 (ID: %d) 的信号状态: %+v", regionalController.ID, signalMetrics) + c.recordSensorData(reqCtx, areaController.ID, areaController.ID, event.Time, models.SensorTypeSignalMetrics, signalMetrics) + logger.Infof("已记录区域主控 (ID: %d) 的信号状态: %+v", areaController.ID, signalMetrics) // 记录电量 batteryLevel := models.BatteryLevel{ @@ -353,8 +353,8 @@ func (c *ChirpStackListener) handleStatusEvent(ctx context.Context, event *Statu BatteryLevelUnavailable: event.BatteryLevelUnavailable, ExternalPower: event.ExternalPower, } - c.recordSensorData(reqCtx, regionalController.ID, regionalController.ID, event.Time, models.SensorTypeBatteryLevel, batteryLevel) - logger.Infof("已记录区域主控 (ID: %d) 的电池状态: %+v", regionalController.ID, batteryLevel) + c.recordSensorData(reqCtx, areaController.ID, areaController.ID, event.Time, models.SensorTypeBatteryLevel, batteryLevel) + logger.Infof("已记录区域主控 (ID: %d) 的电池状态: %+v", areaController.ID, batteryLevel) } // handleAckEvent 处理下行确认事件 @@ -425,11 +425,11 @@ func (c *ChirpStackListener) handleIntegrationEvent(ctx context.Context, event * } // recordSensorData 是一个通用方法,用于将传感器数据存入数据库。 -// regionalControllerID: 区域主控设备的ID +// areaControllerID: 区域主控设备的ID // sensorDeviceID: 实际产生传感器数据的普通设备的ID // sensorType: 传感器值的类型 (例如 models.SensorTypeTemperature) // data: 具体的传感器数据结构体实例 (例如 models.TemperatureData) -func (c *ChirpStackListener) recordSensorData(ctx context.Context, regionalControllerID uint, sensorDeviceID uint, eventTime time.Time, sensorType models.SensorType, data interface{}) { +func (c *ChirpStackListener) recordSensorData(ctx context.Context, areaControllerID uint, sensorDeviceID uint, eventTime time.Time, sensorType models.SensorType, data interface{}) { reqCtx, logger := logs.Trace(ctx, c.ctx, "recordSensorData") // 1. 将传入的结构体序列化为 JSON jsonData, err := json.Marshal(data) @@ -440,11 +440,11 @@ func (c *ChirpStackListener) recordSensorData(ctx context.Context, regionalContr // 2. 构建 SensorData 模型 sensorData := &models.SensorData{ - Time: eventTime, - DeviceID: sensorDeviceID, - RegionalControllerID: regionalControllerID, - SensorType: sensorType, - Data: datatypes.JSON(jsonData), + Time: eventTime, + DeviceID: sensorDeviceID, + AreaControllerID: areaControllerID, + SensorType: sensorType, + Data: datatypes.JSON(jsonData), } // 3. 调用仓库创建记录 diff --git a/internal/domain/device/device_service.go b/internal/domain/device/device_service.go index 9dd6a1b..bd892dd 100644 --- a/internal/domain/device/device_service.go +++ b/internal/domain/device/device_service.go @@ -28,7 +28,7 @@ type Service interface { Switch(ctx context.Context, device *models.Device, action DeviceAction) error // Collect 用于发起对指定区域主控下的多个设备的批量采集请求。 - Collect(ctx context.Context, regionalControllerID uint, devicesToCollect []*models.Device) error + Collect(ctx context.Context, areaControllerID uint, devicesToCollect []*models.Device) error } // 设备操作指令通用结构(最外层) diff --git a/internal/domain/device/general_device_service.go b/internal/domain/device/general_device_service.go index cfdc9d5..1a33e1c 100644 --- a/internal/domain/device/general_device_service.go +++ b/internal/domain/device/general_device_service.go @@ -133,7 +133,7 @@ func (g *GeneralDeviceService) Switch(ctx context.Context, device *models.Device } // Collect 实现了 Service 接口,用于发起对指定区域主控下的多个设备的批量采集请求。 -func (g *GeneralDeviceService) Collect(ctx context.Context, regionalControllerID uint, devicesToCollect []*models.Device) error { +func (g *GeneralDeviceService) Collect(ctx context.Context, areaControllerID uint, devicesToCollect []*models.Device) error { serviceCtx, logger := logs.Trace(ctx, g.ctx, "Collect") if len(devicesToCollect) == 0 { logger.Info("待采集设备列表为空,无需执行采集任务。") @@ -141,12 +141,12 @@ func (g *GeneralDeviceService) Collect(ctx context.Context, regionalControllerID } // 1. 从设备列表中获取预加载的区域主控,并进行校验 - regionalController := &devicesToCollect[0].AreaController - if regionalController.ID != regionalControllerID { - return fmt.Errorf("设备列表与指定的区域主控ID (%d) 不匹配", regionalControllerID) + areaController := &devicesToCollect[0].AreaController + if areaController.ID != areaControllerID { + return fmt.Errorf("设备列表与指定的区域主控ID (%d) 不匹配", areaControllerID) } - if err := regionalController.SelfCheck(); err != nil { - return fmt.Errorf("区域主控 (ID: %d) 未通过自检: %w", regionalControllerID, err) + if err := areaController.SelfCheck(); err != nil { + return fmt.Errorf("区域主控 (ID: %d) 未通过自检: %w", areaControllerID, err) } // 2. 准备采集任务列表 @@ -208,13 +208,13 @@ func (g *GeneralDeviceService) Collect(ctx context.Context, regionalControllerID } // 3. 构建并发送指令 - networkID := regionalController.NetworkID + networkID := areaController.NetworkID // 4. 创建待处理请求记录 correlationID := uuid.New().String() pendingReq := &models.PendingCollection{ CorrelationID: correlationID, - DeviceID: regionalController.ID, + DeviceID: areaController.ID, CommandMetadata: childDeviceIDs, Status: models.PendingStatusPending, CreatedAt: time.Now(), @@ -223,7 +223,7 @@ func (g *GeneralDeviceService) Collect(ctx context.Context, regionalControllerID logger.Errorf("创建待采集请求失败 (CorrelationID: %s): %v", correlationID, err) return err } - logger.Infof("成功创建待采集请求 (CorrelationID: %s, DeviceID: %d)", correlationID, regionalController.ID) + logger.Infof("成功创建待采集请求 (CorrelationID: %s, DeviceID: %d)", correlationID, areaController.ID) // 5. 构建最终的空中载荷 batchCmd := &proto.BatchCollectCommand{ diff --git a/internal/infra/models/sensor_data.go b/internal/infra/models/sensor_data.go index fe683a9..804b164 100644 --- a/internal/infra/models/sensor_data.go +++ b/internal/infra/models/sensor_data.go @@ -57,8 +57,8 @@ type SensorData struct { // DeviceID 是传感器的唯一标识符,作为复合主键的另一部分。 DeviceID uint `gorm:"primaryKey" json:"device_id"` - // RegionalControllerID 是上报此数据的区域主控的ID。 - RegionalControllerID uint `json:"regional_controller_id"` + // AreaControllerID 是上报此数据的区域主控的ID。 + AreaControllerID uint `json:"area_controller_id"` // SensorType 是传感数据的类型 SensorType SensorType `gorm:"not null;index" json:"sensor_type"` diff --git a/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go b/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go index bd51957..acebfcf 100644 --- a/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go +++ b/internal/infra/transport/lora/lora_mesh_uart_passthrough_transport.go @@ -406,13 +406,13 @@ func (t *LoRaMeshUartPassthroughTransport) handleUpstreamMessage(ctx context.Con logger.Infof("成功解析采集响应 (CorrelationID: %s),包含 %d 个值。", correlationID, len(collectResp.Values)) // 3. 查找区域主控 (注意:LoRa Mesh 的 SourceAddr 对应于区域主控的 NetworkID) - regionalController, err := t.areaControllerRepo.FindByNetworkID(loraCtx, msg.SourceAddr) + areaController, err := t.areaControllerRepo.FindByNetworkID(loraCtx, msg.SourceAddr) if err != nil { logger.Errorf("处理上行消息失败:无法通过源地址 '%s' 找到区域主控设备: %v", msg.SourceAddr, err) return } - if err := regionalController.SelfCheck(); err != nil { - logger.Errorf("处理上行消息失败:区域主控 %v(ID: %d) 未通过自检: %v", regionalController.Name, regionalController.ID, err) + if err := areaController.SelfCheck(); err != nil { + logger.Errorf("处理上行消息失败:区域主控 %v(ID: %d) 未通过自检: %v", areaController.Name, areaController.ID, err) return } @@ -489,7 +489,7 @@ func (t *LoRaMeshUartPassthroughTransport) handleUpstreamMessage(ctx context.Con dataToRecord = map[string]float64{"value": parsedValue} } - t.recordSensorData(loraCtx, regionalController.ID, dev.ID, time.Now(), valueDescriptor.Type, dataToRecord) + t.recordSensorData(loraCtx, areaController.ID, dev.ID, time.Now(), valueDescriptor.Type, dataToRecord) logger.Infof("成功记录传感器数据: 设备ID=%d, 类型=%s, 原始值=%f, 解析值=%.2f", dev.ID, valueDescriptor.Type, rawSensorValue, parsedValue) } @@ -502,7 +502,7 @@ func (t *LoRaMeshUartPassthroughTransport) handleUpstreamMessage(ctx context.Con } // recordSensorData 是一个通用方法,用于将传感器数据存入数据库。 -func (t *LoRaMeshUartPassthroughTransport) recordSensorData(ctx context.Context, regionalControllerID uint, sensorDeviceID uint, eventTime time.Time, sensorType models.SensorType, data interface{}) { +func (t *LoRaMeshUartPassthroughTransport) recordSensorData(ctx context.Context, areaControllerID uint, sensorDeviceID uint, eventTime time.Time, sensorType models.SensorType, data interface{}) { loraCtx, logger := logs.Trace(ctx, t.ctx, "recordSensorData") jsonData, err := json.Marshal(data) @@ -512,11 +512,11 @@ func (t *LoRaMeshUartPassthroughTransport) recordSensorData(ctx context.Context, } sensorData := &models.SensorData{ - Time: eventTime, - DeviceID: sensorDeviceID, - RegionalControllerID: regionalControllerID, - SensorType: sensorType, - Data: datatypes.JSON(jsonData), + Time: eventTime, + DeviceID: sensorDeviceID, + AreaControllerID: areaControllerID, + SensorType: sensorType, + Data: datatypes.JSON(jsonData), } if err := t.sensorDataRepo.Create(loraCtx, sensorData); err != nil {