Files
2025-09-29 23:46:28 +08:00

125 lines
4.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package models
import (
"encoding/json"
"errors"
"strings"
"gorm.io/datatypes"
"gorm.io/gorm"
)
// --- Properties 结构体定义 ---
// Bus485Properties 定义了总线设备的特有属性
type Bus485Properties struct {
BusNumber uint8 `json:"bus_number"` // 485 总线号
BusAddress uint8 `json:"bus_address"` // 485 总线地址
}
// AreaController 是一个LoRa转总线(如485)的通信网关
type AreaController struct {
gorm.Model
// Name 是主控的业务名称,例如 "1号猪舍主控"
Name string `gorm:"not null;unique" json:"name"`
// NetworkID 是主控在通信网络中的唯一标识,例如 LoRaWAN 的 DevEUI。
// 这是 transport 层用来寻址的关键。
NetworkID string `gorm:"not null;unique;index" json:"network_id"`
// Location 描述了主控的物理安装位置。
Location string `gorm:"index" json:"location"`
// Status 表示主控的在线状态等,可以后续扩展。
Status string `gorm:"default:'unknown'" json:"status"`
// Properties 用于存储其他与主控相关的属性,例如硬件版本、固件版本等。
Properties datatypes.JSON `json:"properties"`
}
// SelfCheck 对 AreaController 的关键字段进行业务逻辑验证。
func (ac *AreaController) SelfCheck() error {
if strings.TrimSpace(ac.NetworkID) == "" {
return errors.New("区域主控的 NetworkID 不能为空")
}
return nil
}
// TableName 自定义 GORM 使用的数据库表名
func (AreaController) TableName() string {
return "area_controllers"
}
// Device 代表系统中的所有普通设备
type Device struct {
// gorm.Model 内嵌了标准模型字段 (ID, CreatedAt, UpdatedAt, DeletedAt)
gorm.Model
// Name 是设备的业务名称,应清晰可读,例如 "1号猪舍温度传感器"
Name string `gorm:"not null" json:"name"`
// DeviceTemplateID 是设备模板的外键
DeviceTemplateID uint `gorm:"not null;index" json:"device_template_id"`
// DeviceTemplate 是设备的模板,包含了设备的通用信息
DeviceTemplate DeviceTemplate `json:"device_template"`
// AreaControllerID 是区域主控的外键
AreaControllerID uint `gorm:"not null;index" json:"area_controller_id"`
// AreaController 是设备所属的区域主控
AreaController AreaController `json:"area_controller"`
// Location 描述了设备的物理安装位置,例如 "1号猪舍东侧",方便运维。建立索引以优化按位置查询。
Location string `gorm:"index" json:"location"`
// Properties 用于存储特定类型设备的独有属性采用JSON格式。
// 建议在应用层为不同子类型的设备定义专用的属性结构体,以保证数据一致性。
Properties datatypes.JSON `json:"properties"`
}
// SelfCheck 对 Device 的关键字段和属性进行业务逻辑验证。
func (d *Device) SelfCheck() error {
if d.AreaControllerID == 0 {
return errors.New("设备必须关联一个区域主控 (AreaControllerID不能为0)")
}
if d.DeviceTemplateID == 0 {
return errors.New("设备必须关联一个设备模板 (DeviceTemplateID不能为0)")
}
// 验证 Properties 是否包含必要的总线地址信息
if d.Properties == nil {
return errors.New("设备属性 (Properties) 不能为空")
}
var props Bus485Properties
if err := json.Unmarshal(d.Properties, &props); err != nil {
return errors.New("无法解析设备属性 (Properties)")
}
if props.BusAddress == 0 {
return errors.New("设备属性 (Properties) 中缺少总线地址 (bus_address)")
}
return nil
}
// TableName 自定义 GORM 使用的数据库表名
func (Device) TableName() string {
return "devices"
}
// ParseProperties 解析 JSON 属性到一个具体的结构体中。
// 调用方需要传入一个指向目标结构体实例的指针。
// 示例:
//
// var props LoraProperties
// if err := device.ParseProperties(&props); err != nil { ... }
func (d *Device) ParseProperties(v interface{}) error {
if d.Properties == nil {
return errors.New("设备属性为空,无法解析")
}
return json.Unmarshal(d.Properties, v)
}