From 450d2ea15aea0c4f14d70692b448911c8cce0e09 Mon Sep 17 00:00:00 2001 From: huang <1724659546@qq.com> Date: Mon, 1 Dec 2025 17:29:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0AreaControllerProperties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ota-upgrade-and-log-monitoring/index.md | 2 ++ internal/infra/models/device.go | 29 +++++++++++++++++++ .../repository/area_controller_repository.go | 21 ++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/design/ota-upgrade-and-log-monitoring/index.md b/design/ota-upgrade-and-log-monitoring/index.md index 735a818..5f07f69 100644 --- a/design/ota-upgrade-and-log-monitoring/index.md +++ b/design/ota-upgrade-and-log-monitoring/index.md @@ -11,6 +11,8 @@ http://git.huangwc.com/pig/pig-farm-controller/issues/71 ## OTA 升级 - [x] 增加一个proto对象, 用于封装ota升级包 +- [ ] 区域主控增加版本号 +- [ ] 实现ota升级逻辑 ## Lora 监听逻辑重构 diff --git a/internal/infra/models/device.go b/internal/infra/models/device.go index 6801110..20a852b 100644 --- a/internal/infra/models/device.go +++ b/internal/infra/models/device.go @@ -3,6 +3,7 @@ package models import ( "encoding/json" "errors" + "fmt" "strings" "gorm.io/datatypes" @@ -16,6 +17,11 @@ type Bus485Properties struct { BusAddress uint8 `json:"bus_address"` // 485 总线地址 } +// AreaControllerProperties 定义了区域主控的特有属性 +type AreaControllerProperties struct { + FirmwareVersion string `json:"firmware_version,omitempty"` // 主控程序版本 +} + // AreaController 是一个LoRa转总线(如485)的通信网关 type AreaController struct { Model @@ -45,6 +51,29 @@ func (ac *AreaController) SelfCheck() error { return nil } +// ParseProperties 解析 JSON 属性到一个具体的结构体中。 +// 调用方需要传入一个指向目标结构体实例的指针。 +func (ac *AreaController) ParseProperties(v interface{}) error { + if ac.Properties == nil { + return errors.New("区域主控属性为空,无法解析") + } + return json.Unmarshal(ac.Properties, v) +} + +// SetProperties 将一个结构体编码为 JSON 并设置到 Properties 字段。 +func (ac *AreaController) SetProperties(v interface{}) error { + if v == nil { + ac.Properties = nil + return nil + } + jsonBytes, err := json.Marshal(v) + if err != nil { + return fmt.Errorf("无法编码区域主控的属性 (Properties): %w", err) + } + ac.Properties = jsonBytes + return nil +} + // TableName 自定义 GORM 使用的数据库表名 func (AreaController) TableName() string { return "area_controllers" diff --git a/internal/infra/repository/area_controller_repository.go b/internal/infra/repository/area_controller_repository.go index d9ed656..90e2f3d 100644 --- a/internal/infra/repository/area_controller_repository.go +++ b/internal/infra/repository/area_controller_repository.go @@ -18,6 +18,8 @@ type AreaControllerRepository interface { Create(ctx context.Context, ac *models.AreaController) error ListAll(ctx context.Context) ([]*models.AreaController, error) Update(ctx context.Context, ac *models.AreaController) error + // UpdateFirmwareVersion 更新指定ID的区域主控的固件版本号。 + UpdateFirmwareVersion(ctx context.Context, id uint32, version string) error Delete(ctx context.Context, id uint32) error // IsAreaControllerUsedByTasks 检查区域主控是否被特定任务类型使用,可以忽略指定任务类型 IsAreaControllerUsedByTasks(ctx context.Context, areaControllerID uint32, ignoredTaskTypes []models.TaskType) (bool, error) @@ -59,6 +61,25 @@ func (r *gormAreaControllerRepository) Update(ctx context.Context, ac *models.Ar return r.db.WithContext(repoCtx).Save(ac).Error } +// UpdateFirmwareVersion 使用 jsonb_set 函数原子性地更新 properties 字段中的固件版本号。 +func (r *gormAreaControllerRepository) UpdateFirmwareVersion(ctx context.Context, id uint32, version string) error { + repoCtx := logs.AddFuncName(ctx, r.ctx, "UpdateFirmwareVersion") + + // 使用 gorm.Expr 包装 PostgreSQL 的 jsonb_set 函数 + // jsonb_set(properties, '{firmware_version}', '"new_version"', true) + // 注意:jsonb_set 的第三个参数需要是有效的 JSON 值,所以字符串需要被双引号包围。 + jsonbExpr := gorm.Expr(`jsonb_set(COALESCE(properties, '{}'::jsonb), '{firmware_version}', ?::jsonb)`, fmt.Sprintf(`"%s"`, version)) + + result := r.db.WithContext(repoCtx).Model(&models.AreaController{}).Where("id = ?", id).Update("properties", jsonbExpr) + if result.Error != nil { + return result.Error + } + if result.RowsAffected == 0 { + return fmt.Errorf("更新固件版本失败:未找到ID为 %d 的区域主控", id) + } + return nil +} + // Delete 删除一个 AreaController 记录。 func (r *gormAreaControllerRepository) Delete(ctx context.Context, id uint32) error { repoCtx := logs.AddFuncName(ctx, r.ctx, "Delete")