issue_25 #26
@@ -1,11 +1,14 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"gorm.io/datatypes"
|
"gorm.io/datatypes"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeviceCategory 定义了设备模板的宽泛类别
|
// DeviceCategory 定义了设备模板的宽泛类别 (移除了 Compound)
|
||||||
type DeviceCategory string
|
type DeviceCategory string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -13,35 +16,51 @@ const (
|
|||||||
CategoryActuator DeviceCategory = "actuator"
|
CategoryActuator DeviceCategory = "actuator"
|
||||||
// CategorySensor 代表一个传感器,用于报告测量值(例如:温度计)
|
// CategorySensor 代表一个传感器,用于报告测量值(例如:温度计)
|
||||||
CategorySensor DeviceCategory = "sensor"
|
CategorySensor DeviceCategory = "sensor"
|
||||||
// CategoryCompound 代表一个复合设备,既是执行器也是传感器
|
|
||||||
CategoryCompound DeviceCategory = "compound"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValueDescriptor 描述了传感器可以报告的单个数值。
|
// ValueDescriptor 描述了传感器可以报告的单个数值。
|
||||||
// 它提供了必要的元数据,以便应用程序能够正确解释从设备读取的原始数据。
|
// 它提供了必要的元数据,以便应用程序能够正确解释从设备读取的原始数据。
|
||||||
type ValueDescriptor struct {
|
type ValueDescriptor struct {
|
||||||
Name string `json:"name"` // 值的业务名称, 例如 "temperature", "humidity"
|
Name string `json:"name"`
|
||||||
Unit string `json:"unit"` // 测量单位, 例如 "°C", "%RH", "ppm"
|
Unit string `json:"unit"`
|
||||||
DataType string `json:"data_type"` // 期望的数据类型, 例如 "float", "int", "boolean"
|
DataType string `json:"data_type"`
|
||||||
Multiplier float64 `json:"multiplier"` // 乘以原始值的系数 (例如 0.1)
|
Multiplier float64 `json:"multiplier"`
|
||||||
Offset float64 `json:"offset"` // 乘法之后再增加的偏移量 (最终值 = 原始值 * multiplier + offset)
|
Offset float64 `json:"offset"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeviceCommands 定义了设备模板支持的指令集合。
|
// --- 指令结构体 (Command Structs) ---
|
||||||
// 使用指针类型来表示指令的可选性,如果一个模板不支持某个指令,则该字段为 nil。
|
|
||||||
// json tag 中的 "omitempty" 确保了在序列化回 JSON 时,nil 字段会被省略,保持数据库数据的整洁。
|
|
||||||
type DeviceCommands struct {
|
|
||||||
On *string `json:"on,omitempty"` // 开指令
|
|
||||||
Off *string `json:"off,omitempty"` // 关指令
|
|
||||||
Read *string `json:"read,omitempty"` // 读取传感器数值的指令
|
|
||||||
|
|
||||||
// 为了未来的扩展性,可以预留一些通用指令
|
// SwitchCommands 定义了开关类指令
|
||||||
SetSpeed *string `json:"set_speed,omitempty"` // 设置速度/档位
|
type SwitchCommands struct {
|
||||||
SetValue *string `json:"set_value,omitempty"` // 设置某个具体值(例如设定温度)
|
On string `json:"on"`
|
||||||
|
Off string `json:"off"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelfCheck 校验开关指令的有效性
|
||||||
|
func (sc *SwitchCommands) SelfCheck() error {
|
||||||
|
if sc.On == "" {
|
||||||
|
return errors.New("'switch' 指令集缺少 'on' 指令")
|
||||||
|
}
|
||||||
|
if sc.Off == "" {
|
||||||
|
return errors.New("'switch' 指令集缺少 'off' 指令")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SensorCommands 定义了传感器读取指令
|
||||||
|
type SensorCommands struct {
|
||||||
|
Read string `json:"read"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelfCheck 校验读取指令的有效性
|
||||||
|
func (sc *SensorCommands) SelfCheck() error {
|
||||||
|
if sc.Read == "" {
|
||||||
|
return errors.New("'sensor' 指令集缺少 'read' 指令")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeviceTemplate 代表一种物理设备的类型。
|
// DeviceTemplate 代表一种物理设备的类型。
|
||||||
// 它作为一个蓝图,定义了设备的通用属性、操作指令和数据解释规则。
|
|
||||||
type DeviceTemplate struct {
|
type DeviceTemplate struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|
||||||
@@ -73,3 +92,63 @@ type DeviceTemplate struct {
|
|||||||
func (DeviceTemplate) TableName() string {
|
func (DeviceTemplate) TableName() string {
|
||||||
return "device_templates"
|
return "device_templates"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseCommands ...
|
||||||
|
func (dt *DeviceTemplate) ParseCommands(v interface{}) error {
|
||||||
|
if dt.Commands == nil {
|
||||||
|
return errors.New("设备模板的 Commands 属性为空,无法解析")
|
||||||
|
}
|
||||||
|
return json.Unmarshal(dt.Commands, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseValues ...
|
||||||
|
func (dt *DeviceTemplate) ParseValues(v interface{}) error {
|
||||||
|
if dt.Values == nil {
|
||||||
|
return errors.New("设备模板的 Values 属性为空,无法解析")
|
||||||
|
}
|
||||||
|
return json.Unmarshal(dt.Values, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelfCheck 对 DeviceTemplate 进行彻底的、基于角色的校验
|
||||||
|
func (dt *DeviceTemplate) SelfCheck() error {
|
||||||
|
if dt.Commands == nil {
|
||||||
|
return errors.New("所有设备模板都必须有 Commands 定义")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch dt.Category {
|
||||||
|
case CategoryActuator:
|
||||||
|
var cmd SwitchCommands
|
||||||
|
if err := dt.ParseCommands(&cmd); err != nil {
|
||||||
|
return errors.New("执行器模板的 Commands 无法被解析为 'switch' 指令集")
|
||||||
|
}
|
||||||
|
if err := cmd.SelfCheck(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
case CategorySensor:
|
||||||
|
var cmd SensorCommands
|
||||||
|
if err := dt.ParseCommands(&cmd); err != nil {
|
||||||
|
return errors.New("传感器模板的 Commands 无法被解析为 'sensor' 指令集")
|
||||||
|
}
|
||||||
|
if err := cmd.SelfCheck(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if dt.Values == nil {
|
||||||
|
return errors.New("传感器类型的设备模板缺少 Values 定义")
|
||||||
|
}
|
||||||
|
var values []*ValueDescriptor
|
||||||
|
if err := dt.ParseValues(&values); err != nil {
|
||||||
|
return errors.New("无法解析传感器模板的 Values 属性")
|
||||||
|
}
|
||||||
|
// 黄金准则: 一个传感器模板只能定义一种数值的解析方式
|
||||||
|
if len(values) != 1 {
|
||||||
|
return errors.New("传感器模板的 Values 定义必须且只能包含一个描述符")
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New("未知的设备模板类别")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user