package models import ( "encoding/json" "errors" "gorm.io/datatypes" "gorm.io/gorm" ) // DeviceType 定义了设备的高级类别 type DeviceType string const ( // DeviceTypeAreaController 区域主控,负责管理一个片区的设备 DeviceTypeAreaController DeviceType = "area_controller" // DeviceTypeDevice 普通设备,如传感器、阀门等 DeviceTypeDevice DeviceType = "device" ) // DeviceSubType 定义了普通设备的具体子类别 type DeviceSubType string const ( // SubTypeNone 未指定或不适用的子类型 SubTypeNone DeviceSubType = "" // SubTypeSensorTemp 温度传感器 SubTypeSensorTemp DeviceSubType = "temperature" // SubTypeSensorHumidity 湿度传感器 SubTypeSensorHumidity DeviceSubType = "humidity" // SubTypeSensorAmmonia 氨气传感器 SubTypeSensorAmmonia DeviceSubType = "ammonia" // SubTypeValveFeed 下料阀门 SubTypeValveFeed DeviceSubType = "feed_valve" // SubTypeFan 风机 SubTypeFan DeviceSubType = "fan" // SubTypeWaterCurtain 水帘 SubTypeWaterCurtain DeviceSubType = "water_curtain" ) // 设备属性名大全 var ( // 普通开关式设备 BusNumber = "bus_number" // 总线号 BusAddress = "bus_address" // 总线地址 RelayChannel = "relay_channel" // 继电器通道号 // 区域主控 LoRaAddress = "lora_address" // 区域主控 LoRa 地址, 如果使用LoRa网关也可能是LoRa网关记录的设备ID ) // --- Properties 结构体定义 --- // LoraProperties 定义了区域主控的特有属性 type LoraProperties struct { LoraAddress string `json:"lora_address"` // LoRa 地址 } // BusProperties 定义了总线设备的特有属性 type BusProperties struct { BusID int `json:"bus_id"` // 485 总线号 BusAddress int `json:"bus_address"` // 485 总线地址 } // Device 代表系统中的所有设备 type Device struct { // gorm.Model 内嵌了标准模型字段 (ID, CreatedAt, UpdatedAt, DeletedAt) gorm.Model // Name 是设备的业务名称,应清晰可读,例如 "1号猪舍温度传感器" 或 "做料车间主控" Name string `gorm:"unique;not null" json:"name"` // Type 是设备的高级类别,用于区分区域主控和普通设备。建立索引以优化按类型查询。 Type DeviceType `gorm:"not null;index" json:"type"` // SubType 是设备的子类别,用于描述普通设备的具体功能,例如 "temperature", "fan" 等。建立索引以优化按子类型查询。 SubType DeviceSubType `gorm:"index" json:"sub_type"` // ParentID 指向其父级设备的ID。对于顶层设备(如区域主控),此值为 NULL。 // 使用指针类型 *uint 来允许 NULL 值,从而清晰地表示“无父级”,避免了使用 0 作为魔术数字的歧义。建立索引以优化层级查询。 ParentID *uint `gorm:"index" json:"parent_id"` // Location 描述了设备的物理安装位置,例如 "1号猪舍东侧",方便运维。建立索引以优化按位置查询。 Location string `gorm:"index" json:"location"` // Properties 用于存储特定类型设备的独有属性,采用JSON格式。 // 建议在应用层为不同子类型的设备定义专用的属性结构体(如 LoraProperties, BusProperties),以保证数据一致性。 Properties datatypes.JSON `json:"properties"` } // 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) } // SelfCheck 进行参数自检, 返回检测结果 // 方法会根据自身类型进行参数检查, 参数不全时返回false // TODO 没写单测 func (d *Device) SelfCheck() bool { properties := make(map[string]interface{}) if err := d.ParseProperties(&properties); err != nil { return false } has := func(key string) bool { _, ok := properties[key] return ok } switch d.SubType { case SubTypeFan: if !has(BusNumber) || !has(BusAddress) || !has(RelayChannel) { return false } default: // 不应该有类型未知的设备 return false } return true }