package device import ( "fmt" "strconv" "git.huangwc.com/pig/pig-farm-controller/internal/app/service/device/proto" "git.huangwc.com/pig/pig-farm-controller/internal/infra/logs" "git.huangwc.com/pig/pig-farm-controller/internal/infra/models" "git.huangwc.com/pig/pig-farm-controller/internal/infra/repository" "git.huangwc.com/pig/pig-farm-controller/internal/infra/transport" gproto "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" ) type GeneralDeviceService struct { deviceRepo repository.DeviceRepository logger *logs.Logger comm transport.Communicator } // NewGeneralDeviceService 创建一个通用设备服务 func NewGeneralDeviceService(deviceRepo repository.DeviceRepository, logger *logs.Logger, comm transport.Communicator) *GeneralDeviceService { return &GeneralDeviceService{ deviceRepo: deviceRepo, logger: logger, comm: comm, } } func (g *GeneralDeviceService) Switch(device models.Device, action DeviceAction) error { // 校验设备参数及生成指令 if *device.ParentID == 0 { return fmt.Errorf("设备 %v(id=%v) 的上级区域主控(id=%v) ID不合理, 无法执行指令", device.Name, device.ID, *device.ParentID) } if !device.SelfCheck() { return fmt.Errorf("设备 %v(id=%v) 缺少必要信息, 无法发送指令", device.Name, device.ID) } deviceInfo := make(map[string]interface{}) if err := device.ParseProperties(&deviceInfo); err != nil { return fmt.Errorf("解析设备 %v(id=%v) 配置失败: %v", device.Name, device.ID, err) } busNumber, err := strconv.Atoi(fmt.Sprintf("%v", deviceInfo[models.BusNumber])) if err != nil { return fmt.Errorf("无效的总线号: %v", err) } busAddress, err := strconv.Atoi(fmt.Sprintf("%v", deviceInfo[models.BusAddress])) if err != nil { return fmt.Errorf("无效的总线地址: %v", err) } relayChannel, err := strconv.Atoi(fmt.Sprintf("%v", deviceInfo[models.RelayChannel])) if err != nil { return fmt.Errorf("无效的继电器通道: %v", err) } data, err := anypb.New(&proto.Switch{ DeviceAction: string(action), BusNumber: int32(busNumber), BusAddress: int32(busAddress), RelayChannel: int32(relayChannel), }) if err != nil { return fmt.Errorf("创建指令失败: %v", err) } instruction := &proto.Instruction{ Method: proto.MethodType_SWITCH, Data: data, } // 获取自身LoRa设备ID, 因为可能变更, 所以每次都现获取 thisDevice, err := g.deviceRepo.FindByID(*device.ParentID) if err != nil { return fmt.Errorf("获取区域主控(id=%v)信息失败: %v", *device.ParentID, err) } if !thisDevice.SelfCheck() { return fmt.Errorf("区域主控 %v(id=%v) 缺少必要信息, 无法发送指令", thisDevice.Name, thisDevice.ID) } thisDeviceinfo := make(map[string]interface{}) if err := thisDevice.ParseProperties(&thisDeviceinfo); err != nil { return fmt.Errorf("解析区域主控 %v(id=%v) 配置失败: %v", device.Name, device.ID, err) } loraAddress := fmt.Sprintf("%v", thisDeviceinfo[models.LoRaAddress]) // 生成消息并发送 message, err := gproto.Marshal(instruction) if err != nil { return fmt.Errorf("序列化指令失败: %v", err) } return g.comm.Send(loraAddress, message) }