104 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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
 | |
| 
 | |
| 	deviceID uint // 区域主控的设备ID
 | |
| 
 | |
| 	// regionalController 是执行命令的区域主控, 所有的指令都会发往区域主控
 | |
| 	regionalController *models.Device
 | |
| 
 | |
| 	comm transport.Communicator
 | |
| }
 | |
| 
 | |
| // NewGeneralDeviceService 创建一个通用设备服务
 | |
| func NewGeneralDeviceService(deviceID uint, deviceRepo repository.DeviceRepository, logger *logs.Logger, comm transport.Communicator) *GeneralDeviceService {
 | |
| 	return &GeneralDeviceService{
 | |
| 		deviceID:   deviceID,
 | |
| 		deviceRepo: deviceRepo,
 | |
| 		logger:     logger,
 | |
| 		comm:       comm,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (g *GeneralDeviceService) Switch(device models.Device, action DeviceAction) error {
 | |
| 
 | |
| 	// 校验设备参数及生成指令
 | |
| 	if *device.ParentID != g.deviceID {
 | |
| 		return fmt.Errorf("设备 %v(id=%v) 的上级区域主控是(id=%v), 不是当前区域主控(id=%v)下属设备, 无法执行指令", device.Name, device.ID, device.ParentID, g.deviceID)
 | |
| 	}
 | |
| 
 | |
| 	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(g.deviceID)
 | |
| 	if err != nil {
 | |
| 		return fmt.Errorf("获取区域主控(id=%v)信息失败: %v", g.deviceID, 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)
 | |
| 
 | |
| }
 |