|
|
package m9z
|
|
|
|
|
|
// 手动控制指令
|
|
|
import (
|
|
|
"encoding/binary"
|
|
|
"fmt"
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
|
|
|
|
"strings"
|
|
|
"tgk-touch/internal/global"
|
|
|
)
|
|
|
|
|
|
type ManualData struct {
|
|
|
Able bool `json:"disable"` //是否是手动控制状态
|
|
|
BackupByte1 byte `json:"backup_byte1"` //备用字节下标1
|
|
|
Loops []Loop `json:"loops"` //回路数据
|
|
|
BackupByte4 byte `json:"backup_byte4"` //备用字节下标4
|
|
|
}
|
|
|
type Loop struct {
|
|
|
Index int `json:"index"` // 0 D0 回路0
|
|
|
Name string `json:"name"` // 0 #1 回路
|
|
|
IsOpen bool `json:"is_open"`
|
|
|
Pwm int `json:"pwm"` // 功率百分比
|
|
|
}
|
|
|
|
|
|
func BuildManualData(enable, isOpen bool, pwm int) *ManualData {
|
|
|
md := &ManualData{
|
|
|
Able: enable,
|
|
|
}
|
|
|
loops := make([]Loop, 10)
|
|
|
for i := range loops {
|
|
|
loops[i].Index = i
|
|
|
loops[i].IsOpen = isOpen
|
|
|
loops[i].Pwm = pwm
|
|
|
}
|
|
|
md.Loops = loops
|
|
|
return md
|
|
|
}
|
|
|
func (md *ManualData) Write(deviceId string) error {
|
|
|
return ManualWrite(deviceId, md)
|
|
|
}
|
|
|
func (md *ManualData) Display() string {
|
|
|
// 改用strings.Builder提升拼接性能(避免不可变字符串频繁创建临时对象)
|
|
|
var sb strings.Builder
|
|
|
// 遍历循环列表
|
|
|
for _, l := range md.Loops {
|
|
|
// 将bool类型的IsOpen转为1(true)或0(false)
|
|
|
isOpenNum := 0
|
|
|
if l.IsOpen {
|
|
|
isOpenNum = 1
|
|
|
}
|
|
|
// 拼接格式:索引-开关状态(1/0)-调光值,
|
|
|
fmt.Fprintf(&sb, "%d-%d-%d,", l.Index, isOpenNum, l.Pwm)
|
|
|
}
|
|
|
// 转换为字符串并去除末尾多余的逗号(若字符串非空)
|
|
|
result := sb.String()
|
|
|
return fmt.Sprintf("%v-%s", md.Able, strings.TrimSuffix(result, ","))
|
|
|
|
|
|
}
|
|
|
func ManualRead(deviceId string) (*ManualData, error) {
|
|
|
|
|
|
manualResult := new(ManualData)
|
|
|
readResp, err := ReadCmd(deviceId, manual, "读取手动控制参数")
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
manualResult.Able = readResp.Data[0] == 01
|
|
|
manualResult.BackupByte1 = readResp.Data[1]
|
|
|
manualResult.BackupByte4 = readResp.Data[4]
|
|
|
// 解析10路的继电器动作状态
|
|
|
relayBits := BytesToUint16LE(readResp.Data[2:4])
|
|
|
g.Log().Debugf("继电器状态(二进制): %016b ,% X", relayBits, readResp.Data[2:4]) // 补零显示16位
|
|
|
|
|
|
loops := make([]Loop, 10)
|
|
|
for i := 0; i < 10; i++ {
|
|
|
var loop Loop
|
|
|
bit := (relayBits >> i) & 0x01 // 取第i位的值
|
|
|
loop.IsOpen = bit == 1
|
|
|
loop.Index = i
|
|
|
loop.Name = fmt.Sprintf("#%+v", i+1)
|
|
|
loops[i] = loop
|
|
|
}
|
|
|
pwms := readResp.Data[5:len(readResp.Data)]
|
|
|
// 确定要处理的元素数量,取两者中的较小值
|
|
|
processCount := len(pwms)
|
|
|
if len(loops) < processCount {
|
|
|
processCount = len(loops)
|
|
|
}
|
|
|
|
|
|
// 只循环到有效的索引范围
|
|
|
for index := 0; index < processCount; index++ {
|
|
|
loops[index].Pwm = hexToPercent(pwms[index])
|
|
|
}
|
|
|
manualResult.Loops = loops
|
|
|
|
|
|
return manualResult, err
|
|
|
}
|
|
|
func ManualWrite(deviceId string, manualData *ManualData) error {
|
|
|
// 1. 准备数据缓冲区(15字节:1+1+2+1+10)
|
|
|
data := make([]byte, 15)
|
|
|
|
|
|
// 2. 填充手动控制状态(Byte0)
|
|
|
if manualData.Able {
|
|
|
data[0] = 0x01
|
|
|
} else {
|
|
|
data[0] = 0x00
|
|
|
}
|
|
|
|
|
|
// 3. 填充备用字节1(Byte1)
|
|
|
data[1] = manualData.BackupByte1
|
|
|
|
|
|
// 4. 计算继电器控制位(Byte2-3)
|
|
|
var relayBits uint16
|
|
|
for i, loop := range manualData.Loops {
|
|
|
if loop.IsOpen {
|
|
|
relayBits |= (1 << i) // 设置对应位为1
|
|
|
}
|
|
|
}
|
|
|
binary.LittleEndian.PutUint16(data[2:4], relayBits) // 小端序写入
|
|
|
|
|
|
// 5. 填充备用字节4(Byte4)
|
|
|
data[4] = manualData.BackupByte4
|
|
|
|
|
|
// 6. 填充回路PWM百分比(Byte5-14)
|
|
|
for i, loop := range manualData.Loops {
|
|
|
if loop.Pwm < 0 {
|
|
|
loop.Pwm = 0
|
|
|
} else if loop.Pwm > 100 {
|
|
|
loop.Pwm = 100
|
|
|
}
|
|
|
data[5+i] = byte(loop.Pwm) // 直接转换百分比
|
|
|
}
|
|
|
//EE 01 02 00 0F 01 00 64 64 00 3F 37 3C 3D 37 40 1C 37 40 1C 23 FF
|
|
|
//EE 01 02 00 0F 01 01 FF 03 00 32 32 32 32 32 32 32 32 32 32 3D FF
|
|
|
//g.Log().Debugf("manualData: % X", data)
|
|
|
// 8. 发送命令
|
|
|
writeResp, err := WriteCmd(deviceId, manual, data, "写入手动模式")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if !writeResp.Success {
|
|
|
return gerror.New("设置失败")
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// Enable 使能
|
|
|
func (md *ManualData) Enable(deviceId string) error {
|
|
|
md.Able = true
|
|
|
return ManualWrite(deviceId, md)
|
|
|
|
|
|
}
|
|
|
|
|
|
// Disable 禁用
|
|
|
func (md *ManualData) Disable(deviceId string) error {
|
|
|
md.Able = false
|
|
|
return ManualWrite(deviceId, md)
|
|
|
}
|
|
|
|
|
|
// StartLoops 启动指定回路(如果index为空则启动所有)
|
|
|
func (md *ManualData) StartLoops(deviceId string, indexes ...int) error {
|
|
|
if !md.Able {
|
|
|
err := md.Enable(deviceId)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
// 如果没有指定index,则操作所有回路
|
|
|
if len(indexes) == 0 {
|
|
|
for i := range md.Loops {
|
|
|
md.Loops[i].IsOpen = true
|
|
|
}
|
|
|
} else {
|
|
|
// 否则只操作指定回路
|
|
|
for _, idx := range indexes {
|
|
|
if idx >= 0 && idx < len(md.Loops) {
|
|
|
md.Loops[idx].IsOpen = true
|
|
|
} else {
|
|
|
return fmt.Errorf("无效的回路索引: %d", idx)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return ManualWrite(deviceId, md)
|
|
|
}
|
|
|
|
|
|
// StopLoops 停止指定回路(如果index为空则停止所有)
|
|
|
func (md *ManualData) StopLoops(deviceId string, indexes ...int) error {
|
|
|
if !md.Able {
|
|
|
err := md.Enable(deviceId)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
// 如果没有指定index,则操作所有回路
|
|
|
if len(indexes) == 0 {
|
|
|
for i := range md.Loops {
|
|
|
md.Loops[i].IsOpen = false
|
|
|
}
|
|
|
} else {
|
|
|
// 否则只操作指定回路
|
|
|
for _, idx := range indexes {
|
|
|
if idx >= 0 && idx < len(md.Loops) {
|
|
|
md.Loops[idx].IsOpen = false
|
|
|
} else {
|
|
|
return fmt.Errorf("无效的回路索引: %d", idx)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return ManualWrite(deviceId, md)
|
|
|
}
|
|
|
|
|
|
// SetLoopPWM 设置指定回路的功率百分比
|
|
|
// 参数:
|
|
|
//
|
|
|
// pwm: 功率百分比 (0-100)
|
|
|
// indexes: 回路索引(可变参数,不传则设置所有回路)
|
|
|
func (md *ManualData) SetLoopPWM(deviceId string, pwm int, indexes ...int) error {
|
|
|
if !md.Able {
|
|
|
err := md.Enable(deviceId)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
// 校验PWM值范围
|
|
|
if pwm < 0 || pwm > 100 {
|
|
|
return fmt.Errorf("功率百分比必须在0-100之间,当前值: %d", pwm)
|
|
|
}
|
|
|
|
|
|
// 如果没有指定index,则操作所有回路
|
|
|
if len(indexes) == 0 {
|
|
|
for i := range md.Loops {
|
|
|
md.Loops[i].Pwm = pwm
|
|
|
}
|
|
|
} else {
|
|
|
// 操作指定回路
|
|
|
for _, idx := range indexes {
|
|
|
if idx >= 0 && idx < len(md.Loops) {
|
|
|
md.Loops[idx].Pwm = pwm
|
|
|
} else {
|
|
|
return fmt.Errorf("无效的回路索引: %d (可用范围: 0-%d)",
|
|
|
idx, len(md.Loops)-1)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 自动提交修改到设备
|
|
|
return ManualWrite(deviceId, md)
|
|
|
}
|
|
|
|
|
|
// GetLoopPWM 获取指定回路的功率百分比
|
|
|
// 参数:index 回路索引(0-based)
|
|
|
// 返回值:(百分比, 错误信息)
|
|
|
func (md *ManualData) GetLoopPWM(index int) (int, error) {
|
|
|
if index < 0 || index >= len(md.Loops) {
|
|
|
return 0, fmt.Errorf("回路索引超出范围(可用:0-%d)", len(md.Loops)-1)
|
|
|
}
|
|
|
return md.Loops[index].Pwm, nil
|
|
|
}
|