using Ayay.SerilogLogs; using Newtonsoft.Json.Linq; using Serilog; using SHH.CameraSdk; using SHH.Contracts; namespace SHH.CameraService; /// /// 云台控制指令处理器 /// 响应 gRpc 指令:ProtocolCodes.Control_Ptz /// public class PtzControlHandler : ICommandHandler { private readonly ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core); private readonly CameraManager _cameraManager; /// 指令名称(需与网关下发的 CmdCode 一致) public string ActionName => ProtocolCodes.Ptz_Control; // 需在 ProtocolCodes 中新增该常量 public PtzControlHandler(CameraManager cameraManager) { _cameraManager = cameraManager ?? throw new ArgumentNullException(nameof(cameraManager)); } public async Task ExecuteAsync(JToken payload) { // 1. 解析 PTZ 控制参数(与网关下发的 JSON 结构匹配) var ptzDto = payload.ToObject(); if (ptzDto == null || ptzDto.DeviceId <= 0) { _sysLog.Warning("[PTZ] 无效指令:参数缺失或设备ID非法"); return; } // 2. 获取目标设备并校验能力 var device = _cameraManager.GetDevice(ptzDto.DeviceId); if (device == null) { _sysLog.Warning($"[PTZ] 设备 {ptzDto.DeviceId} 不存在"); return; } if (!device.IsPhysicalOnline) { _sysLog.Warning($"[PTZ] 设备 {ptzDto.DeviceId} 未在线,无法执行云台控制"); return; } if (!(device is IPtzFeature ptzFeature)) { _sysLog.Warning($"[PTZ] 设备 {ptzDto.DeviceId} 不支持云台控制"); return; } // 3. 执行云台控制(根据指令类型选择手动/点动模式) try { if (ptzDto.Duration > 0) { // 点动模式:自动复位(如持续300ms向上转动) int safeDuration = Math.Clamp(ptzDto.Duration, 50, 2000); // 限制单次最长2秒 await ptzFeature.PtzStepAsync(ptzDto.Action, safeDuration, ptzDto.Speed); _sysLog.Information($"[PTZ] 设备 {ptzDto.DeviceId} 点动控制:{ptzDto.Action},时长 {safeDuration}ms,速度 {ptzDto.Speed}"); } else { // 手动模式:按下/松开(如按住向上、松开停止) await ptzFeature.PtzControlAsync(ptzDto.Action, ptzDto.Stop, ptzDto.Speed); string actionDesc = ptzDto.Stop ? "停止" : "启动"; _sysLog.Information($"[PTZ] 设备 {ptzDto.DeviceId} 手动控制:{ptzDto.Action} {actionDesc},速度 {ptzDto.Speed}"); } } catch (Exception ex) { _sysLog.Error(ex, $"[PTZ] 设备 {ptzDto.DeviceId} 控制失败"); } } }