using System; using System.Collections.Generic; using System.Text; using HDL_ON.Entity; using HDL_ON.UI; using Shared; namespace HDL_ON.DriverLayer { /// /// 通讯方式 /// public enum CommunicationMode { none, /// /// 本地udp /// local_BusUdp, /// /// 本地tcp客户端 /// tcp_local_client, } public class Control { static Control _control; public static Control Ins { get { if (_control == null) { _control = new Control(); } return _control; } } int _msg_id = 1; /// /// 通讯ID /// public int msg_id { get { return _msg_id++; } } ///// ///// 获取13位时间戳 ///// ///// //public string Get_TimeStamp() //{ // long t = DateTime.Now.Ticks / 10000; // return t.ToString(); //} /// /// 是否搜索本地网关成功 /// public bool IsSearchLocalGatewaySuccessful = false; bool _GatewayOnline_Local = false; /// /// 网关在线-局域网 /// public bool GatewayOnline_Local { get { return _GatewayOnline_Local; } set { if (_GatewayOnline_Local != value) { _GatewayOnline_Local = value; if (value) { //修改主页连接状态 HomePage.LoadEvent_CheckLinkStatus(); MainPage.Log($"网关局域网在线,刷新设备状态"); new System.Threading.Thread(() => { System.Threading.Thread.Sleep(1000); FunctionList.List.ReadAllFunctionStatus(); }) { IsBackground = true, Priority = System.Threading.ThreadPriority.AboveNormal }.Start(); } else { //修改主页连接状态 HomePage.LoadEvent_CheckLinkStatus(); } } } } bool _GatewayOnline_Cloud = false; /// /// 网关在线-云端 /// public bool GatewayOnline_Cloud { get { return _GatewayOnline_Cloud; } set { if (_GatewayOnline_Cloud != value) { _GatewayOnline_Cloud = value; if(GatewayOnline_Local) { return; } if (value) { if (DB_ResidenceData.Instance.HomeGateway == null) { return; } if (!DB_ResidenceData.Instance.HomeGateway.gatewayStatus)//远程情况下,网关未链接服务器不能修改主页网关状态 { new System.Threading.Thread(() => { System.Threading.Thread.Sleep(3000); var pm = new DAL.Server.HttpServerRequest(); pm.GetGatewayInfo(); }) { IsBackground = true }.Start(); return; } //修改主页连接状态 HomePage.LoadEvent_CheckLinkStatus(); MainPage.Log($"网关云端在线,刷新设备状态"); new System.Threading.Thread(() => { System.Threading.Thread.Sleep(1000); FunctionList.List.ReadAllFunctionStatus(); }) { IsBackground = true, Priority = System.Threading.ThreadPriority.AboveNormal }.Start(); } else { //修改主页连接状态 HomePage.LoadEvent_CheckLinkStatus(); } } } } /// /// 网关通讯ID /// public string GatewayId = ""; /// /// 是否为远程连接 /// //public bool IsRemote = false; /// /// 通讯地址IP /// public string reportIp = "255.255.255.255"; /// /// tcp服务端 /// public Control_TcpServer myTcpServer = null; /// /// tcp客服端 /// public Control_TcpClient myTcpClient = null; /// /// 本地udp /// public Control_Udp myUdp1 = null; /// /// 通讯方式 /// public CommunicationMode communicationMode; /// /// 打开tcp服务端 /// public void OpenTcpServer() { myTcpServer = new Control_TcpServer(); myTcpServer.OpenServer(); } /// /// 打开Udp /// public void OpenUdp(int port) { UdpSocket._BusSocket.Start(port); } /// /// 关闭udp /// public void CloseUdp() { UdpSocket._BusSocket.Stop(); } /// /// 打开tcp客服端 /// public void OpenTcpClent() { if (myTcpClient == null) { myTcpClient = new Control_TcpClient(reportIp); myTcpClient.Connect(); } } /// /// 搜索本地网关列表 /// public void SearchLoaclGateway() { //2021-01-15 : 住宅没有绑定网关的时候不用搜索,并且不能链接mqtt if(DB_ResidenceData.Instance.HomeGateway == null || string.IsNullOrEmpty(DB_ResidenceData.Instance.HomeGateway.gatewayId)) { return; } Ins.GatewayOnline_Local = false; var ggg = DB_ResidenceData.Instance.GatewayType == 0 ? "一端口" : "A网关"; var ggg1 = MainPage.InternetStatus == 1 ? "4G" : "wifi"; MainPage.Log($"搜索网关列表,网关类型:{ggg};网络类型:{ggg1}"); if (MainPage.InternetStatus == 0) { Ins.GatewayOnline_Cloud = false; return; } else if (MainPage.InternetStatus == 1) { DAL.Mqtt.MqttClient.InitState(); } else if (MainPage.InternetStatus == 2) { OpenUdp(DB_ResidenceData.Instance.GatewayType == 0 ? 6000 : 8585); //重置搜索网关标志 IsSearchLocalGatewaySuccessful = false; new System.Threading.Thread(() => { for (int i = 0; i < 5; i++) { if (IsSearchLocalGatewaySuccessful) { Ins.GatewayOnline_Local = true; break; } if (DB_ResidenceData.Instance.GatewayType == 0) { new Control_Udp().ControlBytesSend(Command.ReadGateway, 255, 255, new byte[] { (byte)new Random().Next(255), (byte)new Random().Next(255) }); } else if (DB_ResidenceData.Instance.GatewayType == 1) { new Control_Udp().SearchLocalGateway(); } System.Threading.Thread.Sleep(500); } DAL.Mqtt.MqttClient.InitState(); }) { IsBackground = true }.Start(); } } /// /// 场景控制入口 /// public void ControlScene(Scene scene) { if (!Ins.GatewayOnline_Local || DB_ResidenceData.Instance.GatewayType == 1) { new System.Threading.Thread(() => { ControlAProtocolScene(scene); }) { IsBackground = true }.Start(); } else { if (DB_ResidenceData.Instance.GatewayType == 0) { new Control_Udp().ControlBusScenes(scene); } } } /// /// 发送命令 /// 自动判断是否为A协议设备, /// 不是A协议,自动转化bus命令数据 /// /// /// /// 是否直接使用远程发送 /// public void SendWriteCommand(Function function, Dictionary commandDictionary, bool useRemote = false) { function.controlCounter++; function.refreshTime = DateTime.Now; //如果是控制调光的开时,亮度值不能为0 if (commandDictionary.Count > 2) { if (commandDictionary.ContainsKey(FunctionAttributeKey.OnOff) && commandDictionary.ContainsKey(FunctionAttributeKey.Brightness)) { if (commandDictionary[FunctionAttributeKey.OnOff] == "on") { if (commandDictionary[FunctionAttributeKey.Brightness] == "0") { commandDictionary[FunctionAttributeKey.Brightness] = "100"; } } if (commandDictionary[FunctionAttributeKey.OnOff] == "off") { if (commandDictionary[FunctionAttributeKey.Brightness] != "0") { commandDictionary[FunctionAttributeKey.Brightness] = "0"; } } } } //MainPage.Log($"发送数据:{Newtonsoft.Json.JsonConvert.SerializeObject(commandDictionary)}"); ///第三方涂鸦设备统一使用远程控制 switch(function.spk) { case SPK.ElectricTuyaAirCleaner: case SPK.ElectricTuyaFan: case SPK.ElectricTuyaWaterValve: case SPK.ElectricTuyaWeepRobot: useRemote = true; break; } //远程通讯 --涂鸦设备必须需要远程 if (useRemote == true) { DAL.Server.HttpServerRequest httpServer = new DAL.Server.HttpServerRequest(); //ALink控制、Bus控制使用同一个接口控制,由云端负责解析 var apiControlData = function.GetApiControlData(commandDictionary); var actionObjs = new List(); actionObjs.Add(apiControlData); var pack = httpServer.ControlDevice(actionObjs); } else { ////远程通讯 //if (Ins.GatewayOnline_Local == false && Ins.GatewayOnline_Cloud == true) //{ // DAL.Server.HttpServerRequest httpServer = new DAL.Server.HttpServerRequest(); // //ALink控制、Bus控制使用同一个接口控制,由云端负责解析 // var apiControlData = function.GetApiControlData(commandDictionary); // var actionObjs = new List(); // actionObjs.Add(apiControlData); // var pack = httpServer.ControlDevice(actionObjs); //} //本地通讯 if (Ins.GatewayOnline_Local) { //Bus控制 if (DB_ResidenceData.Instance.GatewayType == 0) { try { new Control_Udp().WriteBusData(function, commandDictionary); } catch (Exception ex) { MainPage.Log($"发送数据异常: {ex.Message}"); } } //ALink控制 else { var functionControlDataObj = function.GetGatewayAlinkControlData(commandDictionary); var functionControlDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(functionControlDataObj); var sendBytes = Ins.ConvertSendBodyData(CommunicationTopic.ct.ControlFunctionTopic, functionControlDataJson); new Control_Udp().SendLocalHdlLinkData(sendBytes, functionControlDataObj.id); MainPage.Log($"本地通讯 发送HDL-Link数据:{functionControlDataJson}"); } } //远程通讯 else { DAL.Server.HttpServerRequest httpServer = new DAL.Server.HttpServerRequest(); //ALink控制、Bus控制使用同一个接口控制,由云端负责解析 var apiControlData = function.GetApiControlData(commandDictionary); var actionObjs = new List(); actionObjs.Add(apiControlData); var pack = httpServer.ControlDevice(actionObjs); } } } /// /// 全开全关功能 /// public void SwtichFunctions(bool open,List functions) { var count = 0; var logString = open ? "打开\r\n" : "关闭\r\n"; List actionObjs = new List(); Dictionary d = new Dictionary(); d.Add(FunctionAttributeKey.OnOff, open ? "on" : "off"); var pm = new DAL.Server.HttpServerRequest(); foreach (var temp in functions) { logString += temp.spk + ":" + temp.sid + "\r\n"; var apiControlData = temp.GetApiControlData(d); actionObjs.Add(apiControlData); count++; if (count > 9) { var result = pm.ControlDevice(actionObjs); actionObjs = new List(); count = 0; MainPage.Log(logString); logString = ""; } } var pack = pm.ControlDevice(actionObjs); MainPage.Log(logString); } public void SendApiReadCommand(List functionIds) { var pm = new DAL.Server.HttpServerRequest(); var pack = pm.RefreshDeviceStatus(functionIds); } /// /// 读取功能详细数据 /// /// public void ReadFunctionsInfo(List functionIds) { var pm = new DAL.Server.HttpServerRequest(); var pack = pm.GetDeviceInfoList(functionIds); if(pack!= null&& pack.Data!=null) { //待测试2021-03-04 var ddd = Newtonsoft.Json.JsonConvert.DeserializeObject>(pack.Data.ToString()); if(ddd!= null) { foreach(var function in ddd) { var temp = FunctionList.List.GetDeviceFunctionList().Find((obj) => obj.deviceId == function.deviceId); if(temp!= null) { if (SPK.Get3tySpk(SPK.BrandType.Tuya).Contains(temp.spk)) { Stan.HdlDeviceStatuPushLogic.Current.UpdateDeviceStatu(temp.sid, function.status); } } } } } } /// /// 发送读取命令 /// 自动判断是否为A协议设备 /// public void SendReadCommand(Function function) { function.refreshTime = DateTime.Now; if (Ins.GatewayOnline_Local) { if (DB_ResidenceData.Instance.GatewayType == 0) { try { new Control_Udp().ReadBusData(function); } catch (Exception ex) { MainPage.Log($"发送数据异常: {ex.Message}"); } } else { var readKey = new Dictionary(); readKey.Add("sid", function.sid); var readDataObj = new AlinkReadFunctionStatusObj() { id = Ins.msg_id.ToString(), objects = new List>() { readKey }, time_stamp = Utlis.GetTimestamp() }; var functionControlDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(readDataObj); var sendBytes = Ins.ConvertSendBodyData(CommunicationTopic.ct.ReadStatus, functionControlDataJson); MainPage.Log($"本地通讯 发送HDL-Link数据:{functionControlDataJson}"); new Control_Udp().SendLocalHdlLinkData(sendBytes, readDataObj.id); } } else { var pm = new DAL.Server.HttpServerRequest(); var pack = pm.RefreshDeviceStatus(new List() { function.deviceId }); } } /// /// a协议控制场景 /// /// static void ControlAProtocolScene(Scene scene) { if (!Ins.GatewayOnline_Local)//网关本地不在线 { var pm = new DAL.Server.HttpServerRequest(); var result = pm.ExecuteScene(scene.userSceneId); } else { Dictionary keys = new Dictionary(); keys.Add("sid", scene.sid); var aLinkData = new AlinkReadFunctionStatusObj() { id = Ins.msg_id.ToString(), objects = new List>() { keys }, time_stamp = Utlis.GetTimestamp() }; var aLinkJson = Newtonsoft.Json.JsonConvert.SerializeObject(aLinkData); var sendBytes = Ins.ConvertSendBodyData(CommunicationTopic.ct.ControlScene, aLinkJson); new Control_Udp().SendLocalHdlLinkData(sendBytes, aLinkData.id); } } /// /// 转换通讯数据 /// public byte[] ConvertSendBodyData(string topic, string bodyDataString) { string topicString = "Topic:" + topic + "\r\n"; byte[] bodyBytes = Encoding.ASCII.GetBytes(bodyDataString); string lengthString = "Length:" + bodyBytes.Length.ToString() + "\r\n" + "\r\n"; string sendDataString = topicString + lengthString + bodyDataString; byte[] sendDataBytes = Encoding.ASCII.GetBytes(sendDataString); MainPage.Log($"转换HDL-Link数据\r\n{sendDataString}\r\n"); return sendDataBytes; } /// /// 转换接收到的数据 /// /// public void ConvertReceiveData(byte[] receiveBytes) { var reString = Encoding.UTF8.GetString(receiveBytes); AnalysisReceiveData(reString); } /// /// 转换接收到的数据 /// /// public LocalCommunicationData AnalysisReceiveData(string receiveString) { LocalCommunicationData receiveObj = new LocalCommunicationData(); var res = receiveString.Split("\r\n\r\n"); if (res.Length == 2) { var topics = res[0].Split("\r\n"); //MainPage.Log(res[1]); foreach (var ts in topics) { var key = ts.Split(":"); switch (key[0]) { case "Topic": receiveObj.Topic = key[1]; break; case "Length": receiveObj.Length = Convert.ToInt32(key[1]); break; } } MainPage.Log($"局域网信息: {receiveObj.Topic} : 内容: {res[1]}"); //验证有效数据长度 //if (res[1].Length != receiveObj.Length) //{ // MainPage.Log($"收到数据包长度不够"); // return receiveObj; //} receiveObj.BodyDataString = res[1]; if (receiveObj.Topic == CommunicationTopic.SearchLoaclGatewayReply) { var bodyJObj = Newtonsoft.Json.JsonConvert.DeserializeObject(res[1]); if (bodyJObj == null) { return receiveObj; } var device = Newtonsoft.Json.JsonConvert.DeserializeObject(bodyJObj.objects.ToString()); if (device.device_mac.ToUpper() == DB_ResidenceData.Instance.HomeGateway.mac.ToUpper()) { MainPage.Log("本地搜索网关成功"); Ins.IsSearchLocalGatewaySuccessful = true; Ins.GatewayOnline_Local = true; if (!string.IsNullOrEmpty(device.gatewayId)) { Ins.GatewayId = device.gatewayId; } else { Ins.GatewayId = device.device_mac; } reportIp = "239.0.168.188";// device.ip_address;//主播地址也能控制设备 } } else if (receiveObj.Topic == CommunicationTopic.ct.ReadStatus + "_reply" || receiveObj.Topic == CommunicationTopic.ct.ControlFunctionTopic + "_reply" || receiveObj.Topic == CommunicationTopic.ct.GatewayUpStatus) { //TODO 暂时不传正确的数据上去,如果后面要优化前面这些代码 UpdataFunctionStatus(receiveObj.BodyDataString, null); } else { //一些特殊的主题处理(为了执行速度,尽可能的别加耗时的操作) Stan.HdlCloudReceiveLogic.Current.CloudOverallMsgReceiveEx(receiveObj.Topic, receiveObj.BodyDataString); } } return receiveObj; } /// /// 更新设备状态 /// A协议数据 /// /// public void UpdataFunctionStatus(string revString, byte[] usefulBytes,bool isCloudData = false) { if (Ins.GatewayOnline_Local && isCloudData)//本地链接,除了涂鸦设备数据之外的云端数据不处理 { if (FunctionList.List.GetDeviceFunctionList(SPK.BrandType.Tuya).Count == 0) { //MainPage.Log($"A协议更新状态:本地链接,除了涂鸦设备数据之外的云端数据不处理..."); return; } } var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(revString); if (temp != null) { Control_Udp.ReceiveRepeatManager(temp.id, usefulBytes); var allLocalFuntion = FunctionList.List.GetDeviceFunctionList(); foreach (var updateTemp in temp.objects) { try { var localFunction = allLocalFuntion.Find((obj) => obj.sid == updateTemp.sid); if (localFunction == null) { continue; } if (Ins.GatewayOnline_Local && isCloudData)//本地链接,除了涂鸦设备数据之外的云端数据不处理 { if (!SPK.Get3tySpk(SPK.BrandType.All3tyBrand).Contains(localFunction.spk)) { //MainPage.Log($"A协议更新状态:本地链接,除了涂鸦设备数据之外的云端数据不处理........"); return; } } MainPage.Log($"A协议更新状态:{revString}"); foreach (var attr in updateTemp.status) { localFunction.time_stamp = temp.time_stamp; localFunction.SetAttrState(attr.key, attr.value); } //更新界面状态 Function localObj = null; switch (localFunction.spk) { case SPK.ElectricEnergy: EnergyMainPage.UpdataStatus(localFunction); break; case SPK.LightSwitch: RelayPage.UpdataState(localFunction); break; case SPK.LightDimming: localFunction.lastState = Language.StringByID(StringId.Brightness) + " : " + localFunction.GetAttrState(FunctionAttributeKey.Brightness) + "%"; DimmerPage.UpdataStates(localFunction); break; case SPK.ElectricFan: localFunction.lastState = Language.StringByID(StringId.Level) + " : " + localFunction.GetAttrState(FunctionAttributeKey.OpenLevel); FanPage.UpdataState(localFunction); break; case SPK.LightRGB: localFunction.lastState = Language.StringByID(StringId.Brightness) + " : " + localFunction.GetAttrState(FunctionAttributeKey.Brightness) + "%"; RGBPage.UpdataStates(localFunction); break; case SPK.LightRGBW: break; case SPK.LightCCT: localFunction.lastState = Language.StringByID(StringId.Brightness) + " : " + localFunction.GetAttrState(FunctionAttributeKey.Brightness) + "%"; ColorTureLampPage.UpdataStatus(localFunction); break; case SPK.CurtainSwitch: localFunction.lastState = localFunction.trait_on_off.curValue.ToString() == "on" ? Language.StringByID(StringId.Open) : Language.StringByID(StringId.Close); CurtainModulePage.UpdataState(localFunction); break; case SPK.CurtainTrietex: localFunction.lastState = Language.StringByID(StringId.Open) + localFunction.GetAttrState(FunctionAttributeKey.Percent) + "%"; MotorCurtainPage.UpdataState(localFunction); break; case SPK.CurtainRoller: localFunction.lastState = Language.StringByID(StringId.Open) + localFunction.GetAttrState(FunctionAttributeKey.Percent) + "%"; RollingShutterPage.UpdataState(localFunction); break; case SPK.CurtainShades: break; case SPK.AcStandard: Stan.HdlDeviceStatuPushLogic.Current.UpdateDeviceStatu(updateTemp.sid, updateTemp.status); if (localFunction != null) { localFunction.lastState = ""; switch (localFunction.GetAttrState(FunctionAttributeKey.Mode)) { case "cool": localFunction.lastState = Language.StringByID(StringId.Cool); break; case "heat": localFunction.lastState = Language.StringByID(StringId.Heat); break; case "dry": localFunction.lastState = Language.StringByID(StringId.Dry); break; case "auto": localFunction.lastState = Language.StringByID(StringId.Auto); break; case "fan": localFunction.lastState = Language.StringByID(StringId.AirSupply); break; } switch (localFunction.GetAttrState(FunctionAttributeKey.FanSpeed)) { case "high": localFunction.lastState += " " + Language.StringByID(StringId.HighWindSpeed); break; case "medium": localFunction.lastState += " " + Language.StringByID(StringId.MiddleWindSpeed); break; case "low": localFunction.lastState += " " + Language.StringByID(StringId.LowWindSpeed); break; case "auto": localFunction.lastState += " " + Language.StringByID(StringId.Auto); break; } localFunction.lastState += " " + localFunction.GetAttrState(FunctionAttributeKey.SetTemp) + new AC().GetTempUnitString(localFunction); ACPage.UpdataStates(localFunction); } break; case SPK.FloorHeatStandard: switch (localFunction.GetAttrState(FunctionAttributeKey.Mode)) { case "normal": localFunction.lastState = Language.StringByID(StringId.Normal); break; case "day": localFunction.lastState = Language.StringByID(StringId.Day); break; case "night": localFunction.lastState = Language.StringByID(StringId.Night); break; case "timer": localFunction.lastState = Language.StringByID(StringId.Auto); break; case "away": localFunction.lastState = Language.StringByID(StringId.Away); break; } localFunction.lastState += " " + localFunction.GetAttrState(FunctionAttributeKey.SetTemp) + new FloorHeating().GetTempUnitString(localFunction); FloorHeatingPage.UpdataStates(localFunction); break; case SPK.SensorPm25: case SPK.SensorCO2: case SPK.SensorTVOC: case SPK.SensorTemperature: case SPK.SensorHumidity: EnvironmentalPage.LoadEvent_UpdataStatus(localFunction); break; case SPK.ElectricSocket: SocketPage.UpdataState(localFunction); break; case SPK.ElectricTV: break; case SPK.ElectricTuyaAirCleaner: case SPK.ElectricTuyaFan: case SPK.ElectricTuyaWeepRobot: case SPK.ElectricTuyaWaterValve: case SPK.SensorPir: case SPK.SensorDoorWindow: case SPK.SensorSmoke: case SPK.SensorWater: case SPK.ClothesHanger: case SPK.AcIr: //设备状态推送 Stan.HdlDeviceStatuPushLogic.Current.UpdateDeviceStatu(updateTemp.sid, updateTemp.status); break; } HomePage.UpdataFunctionStates(localFunction); RoomPage.UpdataStates(localFunction); FunctionPage.UpdataStates(localFunction); ClassificationPage.UpdataInfo(localFunction); } catch (Exception ex) { MainPage.Log($"A协议更新状态异常:{ex.Message}"); } } } } } }