issue_25 #26
@@ -1,11 +1,14 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// DeviceCategory 定义了设备模板的宽泛类别
|
||||
// DeviceCategory 定义了设备模板的宽泛类别 (移除了 Compound)
|
||||
type DeviceCategory string
|
||||
|
||||
const (
|
||||
@@ -13,35 +16,51 @@ const (
|
||||
CategoryActuator DeviceCategory = "actuator"
|
||||
// CategorySensor 代表一个传感器,用于报告测量值(例如:温度计)
|
||||
CategorySensor DeviceCategory = "sensor"
|
||||
// CategoryCompound 代表一个复合设备,既是执行器也是传感器
|
||||
CategoryCompound DeviceCategory = "compound"
|
||||
)
|
||||
|
||||
// ValueDescriptor 描述了传感器可以报告的单个数值。
|
||||
// 它提供了必要的元数据,以便应用程序能够正确解释从设备读取的原始数据。
|
||||
type ValueDescriptor struct {
|
||||
Name string `json:"name"` // 值的业务名称, 例如 "temperature", "humidity"
|
||||
Unit string `json:"unit"` // 测量单位, 例如 "°C", "%RH", "ppm"
|
||||
DataType string `json:"data_type"` // 期望的数据类型, 例如 "float", "int", "boolean"
|
||||
Multiplier float64 `json:"multiplier"` // 乘以原始值的系数 (例如 0.1)
|
||||
Offset float64 `json:"offset"` // 乘法之后再增加的偏移量 (最终值 = 原始值 * multiplier + offset)
|
||||
Name string `json:"name"`
|
||||
Unit string `json:"unit"`
|
||||
DataType string `json:"data_type"`
|
||||
Multiplier float64 `json:"multiplier"`
|
||||
Offset float64 `json:"offset"`
|
||||
}
|
||||
|
||||
// DeviceCommands 定义了设备模板支持的指令集合。
|
||||
// 使用指针类型来表示指令的可选性,如果一个模板不支持某个指令,则该字段为 nil。
|
||||
// json tag 中的 "omitempty" 确保了在序列化回 JSON 时,nil 字段会被省略,保持数据库数据的整洁。
|
||||
type DeviceCommands struct {
|
||||
On *string `json:"on,omitempty"` // 开指令
|
||||
Off *string `json:"off,omitempty"` // 关指令
|
||||
Read *string `json:"read,omitempty"` // 读取传感器数值的指令
|
||||
// --- 指令结构体 (Command Structs) ---
|
||||
|
||||
// 为了未来的扩展性,可以预留一些通用指令
|
||||
SetSpeed *string `json:"set_speed,omitempty"` // 设置速度/档位
|
||||
SetValue *string `json:"set_value,omitempty"` // 设置某个具体值(例如设定温度)
|
||||
// SwitchCommands 定义了开关类指令
|
||||
type SwitchCommands struct {
|
||||
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 代表一种物理设备的类型。
|
||||
// 它作为一个蓝图,定义了设备的通用属性、操作指令和数据解释规则。
|
||||
type DeviceTemplate struct {
|
||||
gorm.Model
|
||||
|
||||
@@ -73,3 +92,63 @@ type DeviceTemplate struct {
|
||||
func (DeviceTemplate) TableName() string {
|
||||
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