调整 device和模板

This commit is contained in:
2025-09-29 23:46:28 +08:00
parent bc97c6bfed
commit 35c2d03602
3 changed files with 52 additions and 312 deletions

View File

@@ -3,12 +3,14 @@ package models
import (
"encoding/json"
"errors"
"fmt"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/utils/command_generater"
"gorm.io/datatypes"
"gorm.io/gorm"
)
// DeviceCategory 定义了设备模板的宽泛类别 (移除了 Compound)
// DeviceCategory 定义了设备模板的宽泛类别
type DeviceCategory string
const (
@@ -22,38 +24,52 @@ const (
// 它提供了必要的元数据,以便应用程序能够正确解释从设备读取的原始数据。
type ValueDescriptor struct {
Type SensorType `json:"type"`
Multiplier float64 `json:"multiplier"`
Offset float64 `json:"offset"`
Multiplier float64 `json:"multiplier"` // 乘数,用于原始数据转换
Offset float64 `json:"offset"` // 偏移量,用于原始数据转换
}
// --- 指令结构体 (Command Structs) ---
// SwitchCommands 定义了开关类指令
// SwitchCommands 定义了开关类指令所需的Modbus参数
type SwitchCommands struct {
On string `json:"on"`
Off string `json:"off"`
// ModbusStartAddress 记录Modbus寄存器的起始地址用于生成指令。
ModbusStartAddress uint16 `json:"modbus_start_address"`
// ModbusQuantity 记录Modbus寄存器的数量对于开关通常为1。
ModbusQuantity uint16 `json:"modbus_quantity"`
}
// SelfCheck 校验开关指令的有效性
// SelfCheck 校验开关指令参数的有效性
func (sc *SwitchCommands) SelfCheck() error {
if sc.On == "" {
return errors.New("'switch' 指令集缺少 'on' 指令")
}
if sc.Off == "" {
return errors.New("'switch' 指令集缺少 'off' 指令")
// 对于开关数量通常为1
if sc.ModbusQuantity != 1 {
return errors.New("'switch' 指令集 ModbusQuantity 必须为1")
}
return nil
}
// SensorCommands 定义了传感器读取指令
// SensorCommands 定义了传感器读取指令所需的Modbus参数
type SensorCommands struct {
Read string `json:"read"`
// ModbusFunctionCode 记录Modbus功能码例如 ReadHoldingRegisters。
ModbusFunctionCode command_generater.ModbusFunctionCode `json:"modbus_function_code"`
// ModbusStartAddress 记录Modbus寄存器的起始地址用于生成指令。
ModbusStartAddress uint16 `json:"modbus_start_address"`
// ModbusQuantity 记录Modbus寄存器的数量用于生成指令。
ModbusQuantity uint16 `json:"modbus_quantity"`
}
// SelfCheck 校验读取指令的有效性
// SelfCheck 校验读取指令参数的有效性
func (sc *SensorCommands) SelfCheck() error {
if sc.Read == "" {
return errors.New("'sensor' 指令集缺少 'read' 指令")
// 校验ModbusFunctionCode是否为读取类型
switch sc.ModbusFunctionCode {
case command_generater.ReadCoils, command_generater.ReadDiscreteInputs, command_generater.ReadHoldingRegisters, command_generater.ReadInputRegisters:
// 支持的读取功能码
default:
return fmt.Errorf("'sensor' 指令集 ModbusFunctionCode %X 无效或不是读取类型", sc.ModbusFunctionCode)
}
// 校验ModbusQuantity的合理性例如不能为0且在常见Modbus读取数量限制内
if sc.ModbusQuantity == 0 || sc.ModbusQuantity > 125 {
return fmt.Errorf("'sensor' 指令集 ModbusQuantity 无效: %d, 必须在1-125之间", sc.ModbusQuantity)
}
return nil
}
@@ -74,14 +90,14 @@ type DeviceTemplate struct {
// Category 将模板分类为传感器、执行器
Category DeviceCategory `gorm:"not null;index" json:"category"`
// Commands 存储了一个从“动作名称”到“原始指令”的映射
// Commands 存储了生成Modbus指令所需的参数而不是原始指令字符串
// 使用 JSON 格式,具有良好的可扩展性。
// 例如,对于风机: {"ON": "01050000FF008C3A", "OFF": "010500000000CDCA"}
// 例如,对于传感器: {"READ": "010300000001840A"}
// 例如,对于执行器 (开关): {"modbus_start_address": 0, "modbus_quantity": 1}
// 例如,对于传感器: {"modbus_function_code": 3, "modbus_start_address": 0, "modbus_quantity": 1}
Commands datatypes.JSON `json:"commands"`
// Values 描述了传感器模板所能提供的数据点。
// 当 Category 是 "sensor" 或 "compound" 时,此字段尤为重要。
// 当 Category 是 "sensor" 时,此字段尤为重要。
// 它是一个 ValueDescriptor 对象的 JSON 数组。
Values datatypes.JSON `json:"values"`
}
@@ -117,7 +133,7 @@ func (dt *DeviceTemplate) SelfCheck() error {
case CategoryActuator:
var cmd SwitchCommands
if err := dt.ParseCommands(&cmd); err != nil {
return errors.New("执行器模板的 Commands 无法被解析为 'switch' 指令集")
return errors.New("执行器模板的 Commands 无法被解析为 'switch' 指令集: " + err.Error())
}
if err := cmd.SelfCheck(); err != nil {
return err
@@ -126,7 +142,7 @@ func (dt *DeviceTemplate) SelfCheck() error {
case CategorySensor:
var cmd SensorCommands
if err := dt.ParseCommands(&cmd); err != nil {
return errors.New("传感器模板的 Commands 无法被解析为 'sensor' 指令集")
return errors.New("传感器模板的 Commands 无法被解析为 'sensor' 指令集: " + err.Error())
}
if err := cmd.SelfCheck(); err != nil {
return err
@@ -135,9 +151,13 @@ func (dt *DeviceTemplate) SelfCheck() error {
if dt.Values == nil {
return errors.New("传感器类型的设备模板缺少 Values 定义")
}
var values *ValueDescriptor
// 这里应该解析为 ValueDescriptor 的切片,因为传感器可能提供多个数据点
var values []ValueDescriptor
if err := dt.ParseValues(&values); err != nil {
return errors.New("无法解析传感器模板的 Values 属性")
return errors.New("无法解析传感器模板的 Values 属性: " + err.Error())
}
if len(values) == 0 {
return errors.New("传感器类型的设备模板 Values 属性不能为空")
}
default:
return errors.New("未知的设备模板类别")