调整 device和模板
This commit is contained in:
@@ -9,30 +9,12 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 设备属性名大全
|
||||
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 {
|
||||
BusNumber int `json:"bus_number"` // 485 总线号
|
||||
BusAddress int `json:"bus_address"` // 485 总线地址
|
||||
RelayChannel int `json:"relay_channel"` // 继电器通道号
|
||||
// Bus485Properties 定义了总线设备的特有属性
|
||||
type Bus485Properties struct {
|
||||
BusNumber uint8 `json:"bus_number"` // 485 总线号
|
||||
BusAddress uint8 `json:"bus_address"` // 485 总线地址
|
||||
}
|
||||
|
||||
// AreaController 是一个LoRa转总线(如485)的通信网关
|
||||
@@ -93,7 +75,7 @@ type Device struct {
|
||||
Location string `gorm:"index" json:"location"`
|
||||
|
||||
// Properties 用于存储特定类型设备的独有属性,采用JSON格式。
|
||||
// 建议在应用层为不同子类型的设备定义专用的属性结构体(如 LoraProperties, BusProperties),以保证数据一致性。
|
||||
// 建议在应用层为不同子类型的设备定义专用的属性结构体,以保证数据一致性。
|
||||
Properties datatypes.JSON `json:"properties"`
|
||||
}
|
||||
|
||||
@@ -111,12 +93,12 @@ func (d *Device) SelfCheck() error {
|
||||
return errors.New("设备属性 (Properties) 不能为空")
|
||||
}
|
||||
|
||||
var props map[string]interface{}
|
||||
var props Bus485Properties
|
||||
if err := json.Unmarshal(d.Properties, &props); err != nil {
|
||||
return errors.New("无法解析设备属性 (Properties)")
|
||||
}
|
||||
|
||||
if _, ok := props[BusAddress]; !ok {
|
||||
if props.BusAddress == 0 {
|
||||
return errors.New("设备属性 (Properties) 中缺少总线地址 (bus_address)")
|
||||
}
|
||||
|
||||
|
||||
@@ -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("未知的设备模板类别")
|
||||
|
||||
Reference in New Issue
Block a user