using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using Common; using Dao; using RCUHost.Protocols; using uPLibrary.Networking.M2Mqtt; using uPLibrary.Networking.M2Mqtt.Messages; using System.Text; using System.Threading.Tasks; using System.IO; using CommonEntity; using RestSharp; using System.Configuration; using Dao.Implement; using Domain; using System.Threading; using System.Collections; using Newtonsoft.Json; using Microsoft.IO; namespace RCUHost.Implement { public class State { internal State(int bufferSize) { Buffer = new byte[bufferSize]; } internal byte[] Buffer = null; } /// /// HostServer /// 服务器与RCU主机所有往来命令消息都会经过 HostServer 进行统一处理。 /// 对于 RCU 发往服务器的消息,首先进行校验,解析出消息头部,分发给其对应的 Receiver /// 再由 Receiver 对数据部分进行解析处理。 /// 服务器发往 RCU 的消息,首先由 Receiver 对命令数据进行封包,再经由 HostServer 将 /// 数据发送出去。 /// HostServer 维护一个 Receiver 列表,如果需要 HostServer 处理 RCU 发给服务器的 /// 某种类型消息,就需要将其对应的 Receiver 附加到 Receiver 列表中,否则 HostServer 就 /// 会忽略该消息。 /// public class HostServer : IHostServer, IDisposable { #region Private Properties public ISysOauth2Repository SysOauth2Repository { get; set; } public IHostModalRepository HostModalRepository { get; set; } private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(HostServer)); private Object _lock = new Object(); private UdpClient udpClient; //private Socket udpClient; private ConcurrentDictionary receivers = new ConcurrentDictionary(); private ConcurrentBag commandQueue = new ConcurrentBag();//BlockingCollection //private System.Threading.Timer timer = null; //private Object _lock1 = new Object(); private static long _customer = 0; private Object _lock2 = new Object(); #endregion #region Public Properies /// /// BeforeStart事件 /// HostServer 启动之前调用 /// //public event EventHandler BeforeStart; /// /// AfterStart事件 /// HostServer 启动后调用 /// //public event EventHandler AfterStart; #endregion #region 由Spring调用 /// /// 由 Spring 在创建 HostServer 后调用 /// public void Init() { Start(); } /// /// 由 Spring 在销毁 HostServer 前调用 /// public void Destroy() { Close(); } #endregion public void AddReceiver(IReceiver receiver) { if (receiver != null) { receivers[receiver.CommandType] = receiver; } } public void RemoveReceiver(IReceiver receiver) { if (receiver != null) { IReceiver takeReceiver = null; receivers.TryRemove(receiver.CommandType, out takeReceiver); } } public static string UDPAllDataKey = "All_UDPPackage_Data"; public void StreamConsume(string group = "UDPData", string consumer = "Crics1", string task_key = "task1") { try { var redis = CSRedisCacheHelper.redis1; var data = redis.XReadGroup(group, consumer, 500, 10, new ValueTuple(UDPAllDataKey, ">")); if (data != null) { //var pending = redis.XPending(UDPAllDataKey, group); foreach (var item in data) { var idarray = item.Item2; string nsa = string.Concat(task_key, "#", idarray.Count().ToString()); CSRedisCacheHelper.Publish("udp_package_consumer", nsa); foreach (var SerializeNo in idarray) { var id1 = SerializeNo.Item1; var str = SerializeNo.Item2[1]; var GGG = JsonConvert.DeserializeObject(str); redis.XAck(UDPAllDataKey, group, id1); redis.XDel(UDPAllDataKey, id1); ProcessData(GGG); } } } } catch (Exception ex) { } } /// /// 启动 HostServer /// public void Start() { Close(); //CSRedisCacheHelper.StreamAdd(1,UDPAllDataKey, data); //CSRedisCacheHelper.StreamConsume(1, UDPAllDataKey); try { udpClient = new UdpClient(3339); uint IOC_IN = 0x80000000; uint IOC_VENDOR = 0x18000000; uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; udpClient.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null); udpClient.BeginReceive(ReceiveCallback, new UdpState(udpClient)); logger.Error("Host Server启动成功,端口:3339"); CSRedisCacheHelper.redis1.Del(UDPAllDataKey); CSRedisCacheHelper.redis1.XGroupCreate(UDPAllDataKey, "UDPData", "0", true); Task.Factory.StartNew(() => { while (true) { StreamConsume("UDPData", "Crics1", "task1"); } }, TaskCreationOptions.LongRunning); Task.Factory.StartNew(() => { while (true) { StreamConsume("UDPData", "Crics2", "task2"); } }, TaskCreationOptions.LongRunning); Task.Factory.StartNew(() => { while (true) { StreamConsume("UDPData", "Crics3", "task3"); } }, TaskCreationOptions.LongRunning); Task.Factory.StartNew(() => { while (true) { StreamConsume("UDPData", "Crics4", "task4"); } }, TaskCreationOptions.LongRunning); Task.Factory.StartNew(() => { while (true) { StreamConsume("UDPData", "Crics5", "task5"); } }, TaskCreationOptions.LongRunning); } catch (Exception ex) { logger.Error("Host Server启动失败,端口:3339"); Close(); //throw ex;//不能去掉,否则重启iis服务,通讯服务不会再次启动 } } /// /// 关闭 HostServer /// public void Close() { if (udpClient != null) { udpClient.Close(); udpClient = null; } } public static MqttClient client { get; set; } public static void StartMQTTClient() { try { if (client == null || client.IsConnected == false) { client = new MqttClient("127.0.0.1"); client.MqttMsgPublishReceived += client_MqttMsgPublishReceived; client.ConnectionClosed += new MqttClient.ConnectionClosedEventHandler(client_ConnectionClosed); string clientId = Guid.NewGuid().ToString("N"); client.Connect(clientId); client.Subscribe(new string[] { "/blw/mqtt/test" }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE }); Console.ReadKey(); } } catch (Exception) { } } static void client_ConnectionClosed(object sender, EventArgs e) { bool bbb = client.IsConnected; } static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e) { string sss = Encoding.UTF8.GetString(e.Message); logger.Error("收到了测试数据:" + sss); } public static void PublishMessage(byte[] message) { string topic = "/blw/2024/registerinfo"; if (client != null && client.IsConnected) { client.Publish(topic, message); } else { StartMQTTClient(); client.Publish(topic, message); } } #region 数据发送 /// /// 将命令数据报发送到指定的远程主机上的指定端口。 /// /// byte类型数据,表示将要发送到远程主机的命令数据 /// 远程主机IP地址 /// 远程主机端口 public void Send(byte[] data, string ip, int port) { Send(data, new IPEndPoint(IPAddress.Parse(ip), port), false); } /// /// 将命令数据发送到位于指定远程终结点的主机。 /// /// byte类型数据,表示将要发送到远程主机的命令数据 /// IPEndPoint类型,表示要将命令数据发送到的主机和端口 public void Send(byte[] data, IPEndPoint endPoint) { Send(data, endPoint, false); } /// /// 将命令数据报发送到指定的远程主机上的指定端口。 /// /// byte类型数据,表示将要发送到远程主机的命令数据 /// 远程主机IP地址 /// 远程主机端口 public void SendAndPushCommandQueue(byte[] data, string ip, int port) { Send(data, new IPEndPoint(IPAddress.Parse(ip), port), true); } /// /// 将命令数据发送到位于指定远程终结点的主机。 /// /// byte类型数据,表示将要发送到远程主机的命令数据 /// IPEndPoint类型,表示要将命令数据发送到的主机和端口 public void SendAndPushCommandQueue(byte[] data, IPEndPoint endPoint) { Send(data, endPoint, true); } /// /// 将命令数据发送到位于指定远程终结点的主机。 /// /// byte类型数据,表示将要发送到远程主机的命令数据 /// IPEndPoint类型,表示要将命令数据发送到的主机和端口 /// 是否需要将命令放入队列 public void Send(byte[] data, IPEndPoint endPoint, bool needPushCommandQueue) { if (udpClient != null) { #region 去掉lock ushort crc = Tools.CRC16(data, data.Length - 2);//最后两个字节,加CRC16校验 data[data.Length - 2] = Convert.ToByte(crc & 0xff); data[data.Length - 1] = Convert.ToByte((crc >> 8) & 0xff); //[AA 55 2C 00 //54 33 53 41 //0E //FF AA //3D 04 //hotelcode 04 3D 1085 //60 //CB //00 00 00 00 00 00 00 03 04 00 08 00 01 00 34 01 08 00 02 00 01 06 01 00 02 00 00 52 A4 ] var HotelCode = data.Skip(11).Take(2).ToArray(); var N1 = HotelCode[0]; var N2 = HotelCode[1]; if (N1 == 0xFF && N2 == 0xFF) { //return; } var N3 = Convert.ToInt64(Convert.ToInt16(N1.ToString("000")) + Convert.ToInt16(N2.ToString("000")) * 256).ToString(); var TotalKey = "UDPPackage_TotalSendPackage"; UDPPackageCount LLL_T = null; DataTongJi.TotalCount.TryGetValue(TotalKey, out LLL_T); if (LLL_T != null) { LLL_T.Count = LLL_T.Count + 1; long UUU = 0; LLL_T.FenLei.TryGetValue(N3, out UUU); UUU = UUU + 1; long UUU1 = 0; LLL_T.FenLei.TryRemove(N3, out UUU1); LLL_T.FenLei.TryAdd(N3, UUU); } else { UDPPackageCount u = new UDPPackageCount(); u.Count = 1; u.FenLei = new ConcurrentDictionary(); u.FenLei.TryAdd(N3, 1); DataTongJi.TotalCount.TryAdd(TotalKey, u); } udpClient.Send(data, data.Length, endPoint); // 使用同一个 Socket 发送回复 //udpClient.SendTo(data, endPoint); #endregion } } #endregion /// /// 自定义序号:用于推送通讯命令 /// /// private long GetNextCustomer() { lock (_lock2) { if (_customer < 16000000) { _customer++; } else { _customer = 0; } } //if (_customer < 16000000) //{ // Interlocked.Increment(ref _customer); //} //else //{ // Interlocked.Exchange(ref _customer, 0); //} return _customer; } public IHostRepository HostRepository { get; set; } public ISysHotelRepository SysHotelRepository { get; set; } /// /// 异步接收回调函数 /// /// private void ReceiveCallback(IAsyncResult ar) { UdpState state = ar.AsyncState as UdpState; try { IPEndPoint remoteEP111 = new IPEndPoint(IPAddress.Any, 0); byte[] receiveBuffer111 = state.UdpClient.EndReceive(ar, ref remoteEP111); if (receiveBuffer111.Length > 0) { #region 接收的数据包总数 Interlocked.Increment(ref YUANZI_TongJi.TotalReceiveCount); #endregion ReceiverContext context = new ReceiverContext(receiveBuffer111, remoteEP111, GetNextCustomer()); int length = context.Data.Length; if (length < 3 || length != BitConverter.ToInt16(context.Data, 2)) { //错误数据 Interlocked.Increment(ref YUANZI_TongJi.TotalErrorPackageReceiveCount); return;//非正确的数据包 } context.SystemHeader = DecodeSystemHeader(context.Data); if (context.SystemHeader.HasValue) { if (!String.Equals(new String(context.SystemHeader.Value.SystemID), SystemHeader.SYSTEM_ID, StringComparison.OrdinalIgnoreCase)) { //错误数据 Interlocked.Increment(ref YUANZI_TongJi.TotalErrorPackageReceiveCount); return;//非系统数据包 } try { //透传是新增加的 var VVV = context.SystemHeader.Value; string KKKHNH = CacheKey.TouChuanKey; var HHHostNo = context.SystemHeader.Value.HostNumber.ToString(); var da1 = CSRedisCacheHelper.HMGet(1, KKKHNH, HHHostNo); if (!string.IsNullOrEmpty(da1[0])) { string nns = Tools.ByteToString(context.Data); if (VVV.CmdType == 0x71) { BLWMQTT.MQTTPublishData("blw/touchuan/report/" + HHHostNo, nns); } } #region 只处理正确的 if (VVV.CmdType != 0xD6 && VVV.CmdType != 0x0C) { var hostnumber1 = VVV.HostNumber; string hotelCode = hostnumber1.ToHotelCode().ToString();//获取酒店编码 var hostnumber2 = hostnumber1.ToString(); //时间拦截 超过2秒就不再处理 string ShiJianLanJie = CacheKey.TimeIntercept + "_" + hostnumber2; string ShiJianLanJieSync = CacheKey.SyncTimeIntercept + "_" + hostnumber2; if (VVV.CmdType == 0x0E) { //MemoryCacheHelper.Set(ShiJianLanJie, 1, DateTimeOffset.Now.AddSeconds(DataTongJi.LostPackage_Interval)); //有错误的0x19数据,所有的 在0x19数据触发后的5秒内的后续数据就不再接收 string key123 = RoomStatusReceiver.PoolOverFlowKey + "_" + hostnumber2; var OOObj = MemoryCacheHelper.Get(key123); if (OOObj != null) { //错误数据 Interlocked.Increment(ref YUANZI_TongJi.TotalErrorPackageReceiveCount); return; } } ///消息ID +1 Interlocked.Increment(ref StepTongJi.EveryMessageIDNo); //因为0E不会被拦截所以可以在这里写 if (VVV.CmdType == 0x0E || VVV.CmdType == 0X01) { //StepTongJi.EveryMessageID = Guid.NewGuid().ToString("N"); //计数器+1 Interlocked.Increment(ref StepTongJi.LookDataCounter); //开始监听 Interlocked.Increment(ref StepTongJi.Every_0E_01_MessageID); if (StepTongJi.LookDataCounter == 500) { //监听的ID //Interlocked.Exchange(ref StepTongJi.GlobalListenID, StepTongJi.EveryMessageID); context.MessageID = Guid.NewGuid().ToString("N"); context.IsMonitor = true; int maxWorker = 0; int maxIo = 0; int availWorker = 0; int availIo = 0; // 获取最大线程数 ThreadPool.GetMaxThreads(out maxWorker, out maxIo); // 获取可用线程数 ThreadPool.GetAvailableThreads(out availWorker, out availIo); // 计算忙碌线程数 int busyWorker = maxWorker - availWorker; int busyIo = maxIo - availIo; int minWorker = 0; int minIo = 0; // 获取最小线程数 ThreadPool.GetMinThreads(out minWorker, out minIo); int tid = Thread.CurrentThread.ManagedThreadId; string NNN1 = string.Format("工作线程{8}: 最小={0}, 最大={1}, 可用={2}, 使用中={3},IO线程: 最小={4}, 最大={5}, 可用={6}, 使用中={7}", minWorker, maxWorker, availWorker, busyWorker, minIo, maxIo, availIo, busyIo, tid); StepTongJi.SendInfo(0.1, NNN1, context.MessageID, context.IsMonitor); string NNN7 = string.Format("HostNUMBER:{0},端点:{1}", hostnumber2, context.RemoteEndPoint.ToString()); StepTongJi.SendInfo(0.2, NNN7, context.MessageID, context.IsMonitor); StepInfo s = new StepInfo(); s.Step = 1; s.MessageId = context.MessageID; s.StepDescription = "进入UDPCallBack"; //string ti = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffffff"); string ti = CPUData.GetNowPrecise().ToString("yyyy-MM-dd HH:mm:ss.ffffff"); s.TriggerTime = ti; s.Content = context.Data; s.EveryMessageId = StepTongJi.EveryMessageIDNo; s.Monitor_0E_01 = StepTongJi.Every_0E_01_MessageID; s.HotelCode = hotelCode; s.HostNumber = hostnumber2; string NNN = Newtonsoft.Json.JsonConvert.SerializeObject(s); CSRedisCacheHelper.Publish("redis-roomstatus-monitor", NNN); Interlocked.Exchange(ref StepTongJi.LookDataCounter, 0); } } if (VVV.CmdType == 0x08) { MemoryCacheHelper.Set(ShiJianLanJieSync, 1, DateTimeOffset.Now.AddSeconds(DataTongJi.LostPackage_Interval)); } if (VVV.CmdType == 0x02) { MemoryCacheHelper.Set(ShiJianLanJie, 1, DateTimeOffset.Now.AddSeconds(50)); } if (VVV.CmdType == 0x01) { //升级之后,会上报注册指令,不能被跳过 string Key = "Upgrade_UpdateSQL_" + hostnumber1; object OOO1 = MemoryCacheHelper.Get(Key); if (OOO1 == null) { //string RegisterKey2 = "SearchHostFilter"; //上报注册指令太快会被拦截 //string KKK = "RegisterKey_" + hostnumber1; //object OOO = MemoryCacheHelper.Get(KKK); //if (OOO != null) //{ // RCUHost.RCUHostCommon.tools.LanJieData(RegisterKey2, hotelCode); // return; //} } } string LanJieKey = "Intercept"; ConcurrentBag RoomNumberList = null; bool isexists = DataTongJi.BlockLowerMachineList.TryGetValue(hotelCode, out RoomNumberList); //如果存在数据 if (isexists) { //如果 设备序号存在就过滤掉 if (RoomNumberList != null && RoomNumberList.Count > 0) { //只过滤这些数据 if (RoomNumberList.ToList().Contains(hostnumber1.ToString())) { if (VVV.CmdType == 0x0E) { string KeyFilter = "StatusFilter"; RCUHost.RCUHostCommon.tools.LanJieData(KeyFilter, hotelCode); } LanJieData(LanJieKey, hotelCode); StepTongJi.SendInfo(1.01, "进入黑名单,不再有后续处理", context.MessageID, context.IsMonitor); } //如果不存在就处理 else { GaiXie g = new GaiXie(); g.Data = receiveBuffer111; g.IPEndPoint = remoteEP111.ToString(); var data = Newtonsoft.Json.JsonConvert.SerializeObject(g); CSRedisCacheHelper.StreamAdd(1, "All_UDPPackage_Data", data); //ProcessData(context, hotelCode); //var ts1 = new Tuple(context, hotelCode); //Task.Factory.StartNew((actor_state) => // { // var gg = actor_state as Tuple; // ProcessData(gg.Item1, gg.Item2); // }, ts1); } } else { if (VVV.CmdType == 0x0E) { string KeyFilter = "StatusFilter"; RCUHost.RCUHostCommon.tools.LanJieData(KeyFilter, hotelCode); } //如果存在,且 设备列表为0 LanJieData(LanJieKey, hotelCode); StepTongJi.SendInfo(1.01, "进入黑名单,不再有后续处理", context.MessageID, context.IsMonitor); } } else { //ProcessData(context, hotelCode); GaiXie g = new GaiXie(); g.Data = receiveBuffer111; g.IPEndPoint = remoteEP111.ToString(); var data = Newtonsoft.Json.JsonConvert.SerializeObject(g); CSRedisCacheHelper.StreamAdd(1, "All_UDPPackage_Data", data); var ts1 = new Tuple(context, hotelCode); //Task.Factory.StartNew((actor_state) => // { // var gg = actor_state as Tuple; // ProcessData(gg.Item1, gg.Item2); // }, ts1); } } #endregion else { //错误数据 Interlocked.Increment(ref YUANZI_TongJi.TotalErrorPackageReceiveCount); } } catch (Exception ex) { logger.Error("统计Error:" + ex.Message); } } else { Interlocked.Increment(ref YUANZI_TongJi.TotalErrorPackageReceiveCount); } } } catch (Exception ex) { logger.Error(string.Format("接收数据失败:{0}", ex.ToString())); } finally { try { if (this.udpClient != null) { state.UdpClient.BeginReceive(ReceiveCallback, new UdpState(this.udpClient)); } } catch { } } } public static void LanJieData(string Key11, string hotelCode) { var Key = "UDPPackage_" + Key11.ToString(); UDPPackageCount LLL = null; DataTongJi.TotalCount.TryGetValue(Key, out LLL); if (LLL != null) { var dic = LLL.FenLei; LLL.Count = LLL.Count + 1; long hotel_count = 0; if (dic.TryGetValue(hotelCode, out hotel_count)) { dic[hotelCode] = dic[hotelCode] + 1; } else { dic.TryAdd(hotelCode, 1); } } else { UDPPackageCount u = new UDPPackageCount(); u.Count = 1; var list = new ConcurrentDictionary(); list.TryAdd(hotelCode, 1); u.FenLei = list; DataTongJi.TotalCount.TryAdd(Key, u); } } public static Status NewStatusParse(Stream stream) { Status roomStatus = new Status(); try { // 重要:将流的位置重置到开始,以便读取 //stream.Seek(0, SeekOrigin.Begin); using (BinaryReader reader = new BinaryReader(stream)) { roomStatus.SysLock = reader.ReadBoolean(); //RCU是否锁定:0/否,1/是 roomStatus.CardType = reader.ReadByte(); //房卡类型:0/无人,1/有人,2/客人,3/经理,4/服务员 roomStatus.Door = reader.ReadBoolean(); //门磁开关:1/开,2/关 roomStatus.ElecQty = reader.ReadUInt16(); //门锁电量,单位:MV roomStatus.HostTemp = reader.ReadByte(); //主机温度 //空调数量,默认0,新的回路方式,此处无用,兼容老版本 int airConditionNumber = reader.ReadByte(); for (int i = 0; i < airConditionNumber; i++) { byte airNo = reader.ReadByte(); if (!roomStatus.AirConditions.ContainsKey(airNo)) { roomStatus.AirConditions[airNo] = new AirConditionStatus(); } roomStatus.AirConditions[airNo].AirNo = airNo; roomStatus.AirConditions[airNo].CurrentTemp = reader.ReadSByte(); roomStatus.AirConditions[airNo].SettingTemp = reader.ReadSByte(); roomStatus.AirConditions[airNo].OnOff = reader.ReadBoolean(); roomStatus.AirConditions[airNo].Speed = reader.ReadByte(); roomStatus.AirConditions[airNo].Mode = reader.ReadByte(); roomStatus.AirConditions[airNo].Valve = reader.ReadByte(); roomStatus.AirConditions[airNo].CompensatoryTemp = reader.ReadByte(); roomStatus.AirConditions[airNo].KeepTemp = reader.ReadByte(); roomStatus.AirConditions[airNo].ColdHotMode = reader.ReadByte(); roomStatus.AirConditions[airNo].DeadTemp = reader.ReadByte(); roomStatus.AirConditions[airNo].HotDevition = reader.ReadByte(); roomStatus.AirConditions[airNo].ColdDevition = reader.ReadByte(); } //设备状态数量,包含所有回路状态 int deviceNumber = reader.ReadByte(); long originalPosition = reader.BaseStream.Position; // 读取前先记录当前位置 try { //0x19数据缓冲区异常问题处理 //0x19 取电数据不处理 //非0x19 取电数据处理,但是不触发 欢迎词 for (int i = 0; i < deviceNumber; i++) { var QA = reader.ReadBytes(4); var Status = reader.ReadUInt16(); string address = new DeviceAddress(QA).ToString(); if (!roomStatus.Devices.ContainsKey(address)) { roomStatus.Devices[address] = new Device(); } roomStatus.Devices[address].Address = address;//设备地址 roomStatus.Devices[address].StatusReceiver = Status;//设备状态改为2个字节,Modified By 20181213 originalPosition = reader.BaseStream.Position; } } catch (Exception) { // 发生异常时回退到原始位置 reader.BaseStream.Position = originalPosition; //logger.Error("device_count error"); } return roomStatus; } } catch (Exception) { return null; } } private static readonly List TakeCardSeq = new List() { 0x04, 0x00, 0x01 }; public void Reply(ReceiverContext context, byte[] framenolist) { var headerLen = StructConverter.SizeOf(context.SystemHeader); var headerData = new byte[headerLen + 2]; Array.Copy(context.Data, headerData, headerLen); headerData[2] = 0x11; headerData[3] = 0x00; headerData[9] = framenolist[0]; headerData[10] = framenolist[1]; Send(headerData, context.RemoteEndPoint); } protected void ReplyWithContent(ReceiverContext context, byte[] content, byte[] framenolist) { var headerLen = StructConverter.SizeOf(context.SystemHeader); var headerData = new byte[headerLen + 2]; Array.Copy(context.Data, headerData, headerLen); headerData[2] = 0x12; headerData[3] = 0x00; headerData[9] = framenolist[0]; headerData[10] = framenolist[1]; var HHH = headerData.ToList(); HHH.AddRange(content); Send(HHH.ToArray(), context.RemoteEndPoint); } public static string SameStatus0E = "处理过0E"; public static string SameStatus01 = "处理过01"; /// /// 欢迎词触发 /// /// /// /// private void VoiceRobotTrigger(int flag1, string hotelcode1, string HostNumberOnly1) { var TS = new Tuple(flag1, hotelcode1, HostNumberOnly1); Task.Factory.StartNew((state1) => { var UUU = (Tuple)state1; int flag = UUU.Item1; string hotelcode = UUU.Item2; string HostNumberOnly = UUU.Item3; Host host = null; string Key = CacheKey.HostInfo_Key_HostNumber + "_" + HostNumberOnly; object obj = MemoryCacheHelper.Get(Key); if (obj != null) { host = obj as Host; } else { Host host_O = HostRepository.GetByHostNumber(HostNumberOnly); MemoryCacheHelper.SlideSet(Key, host_O); host = host_O; } if (host != null) { string roomnumber = host.RoomNumber; //小度 string XiaoDuCUID = host.XiaoDuCUID; //天猫 string TianMaoCUID = host.TianMaoCUID; //欢迎词 string WelcomeSpeech = host.SysHotel.WelcomeSpeech; string WelcomeBGM = host.SysHotel.WelcomeBGM; //欢送词 string GoodbyeSpeech = host.SysHotel.GoodbyeSpeech; //断电重置 bool IsPowerOffResetXiaoDu = host.SysHotel.IsPowerOffResetXiaoDu; //1、如果有绑定小度,小度处理 if (!string.IsNullOrEmpty(XiaoDuCUID)) { #region 小度 string accessToken1 = SysOauth2Repository.GetXiaoDuToken(); if (!string.IsNullOrEmpty(accessToken1)) { if (flag == 1 && !string.IsNullOrEmpty(WelcomeSpeech))//取电打开时,播放欢迎词 { var ttt = new Tuple(accessToken1, XiaoDuCUID, WelcomeSpeech, hotelcode, roomnumber); Task.Factory.StartNew((state) => { var tuple_a = state as Tuple; string accessToken = tuple_a.Item1; var myarray = tuple_a.Item2.Split(','); var a1 = tuple_a.Item3; var a2 = tuple_a.Item4; var a3 = tuple_a.Item5; //foreach (string cuid in host.XiaoDuCUID.Split(','))//多个小度英文逗号隔开 foreach (string cuid in myarray)//多个小度英文逗号隔开 { //XiaoDuOperation.UploadWebhook(accessToken, cuid, host.SysHotel.WelcomeSpeech, host.SysHotel.Code, host.RoomNumber); XiaoDuOperation.UploadWebhook(accessToken, cuid, a1, a2, a3); Interface3Log w1 = new Interface3Log(); w1.HotelCode = a2; w1.RoomNumber = a3; w1.TriggerTime = DateTime.Now; w1.CommandType = ChangLiangValue.XiaoDu; WelcomeAction w2 = new WelcomeAction(); w2.VoiceDeviceClass = "小度"; w2.CUID = cuid; w2.CommandType = "欢迎词"; w1.ActionData = new HttpActionData() { RequestData = Newtonsoft.Json.JsonConvert.SerializeObject(w2) }; var q1 = Newtonsoft.Json.JsonConvert.SerializeObject(w1); CSRedisCacheHelper.Publish(CacheKey.InvokeHttpInterface, q1); } }, ttt); } else if (flag == 0) { if (IsPowerOffResetXiaoDu)//断电重置小度 { var ttt = new Tuple(accessToken1, XiaoDuCUID, WelcomeSpeech, hotelcode, roomnumber); Task.Factory.StartNew((state) => { var tuple_a = state as Tuple; string accessToken = tuple_a.Item1; var myarray = tuple_a.Item2.Split(','); var a1 = tuple_a.Item3; var a2 = tuple_a.Item4; var a3 = tuple_a.Item5; foreach (string cuid in myarray)//多个小度英文逗号隔开 { //XiaoDuOperation.PostWebRequestToXiaoDu(accessToken, cuid, new XiaoDuParamJson() { method = "reset" }, host.SysHotel.Code, host.RoomNumber);//重置小度 XiaoDuOperation.PostWebRequestToXiaoDu(accessToken, cuid, new XiaoDuParamJson() { method = "reset" }, a2, a3);//重置小度 Interface3Log w1 = new Interface3Log(); w1.HotelCode = a2; w1.RoomNumber = a3; w1.TriggerTime = DateTime.Now; w1.CommandType = ChangLiangValue.XiaoDu; WelcomeAction w2 = new WelcomeAction(); w2.VoiceDeviceClass = "小度"; w2.CUID = cuid; w2.CommandType = "断电重置"; //w1.ActionData = new HttpActionData() { RequestData = w2 }; w1.ActionData = new HttpActionData() { RequestData = Newtonsoft.Json.JsonConvert.SerializeObject(w2) }; var q1 = Newtonsoft.Json.JsonConvert.SerializeObject(w1); CSRedisCacheHelper.Publish(CacheKey.InvokeHttpInterface, q1); } }, ttt); } else if (!string.IsNullOrEmpty(GoodbyeSpeech))//断电,播放离房提示 { var ttt = new Tuple(accessToken1, XiaoDuCUID, WelcomeSpeech, hotelcode, roomnumber); Task.Factory.StartNew((state) => { var tuple_a = state as Tuple; string accessToken = tuple_a.Item1; var myarray = tuple_a.Item2.Split(','); var a1 = tuple_a.Item3; var a2 = tuple_a.Item4; var a3 = tuple_a.Item5; foreach (string cuid in myarray)//多个小度英文逗号隔开 { XiaoDuOperation.UploadWebhook(accessToken, cuid, a1, a2, a3); Interface3Log w1 = new Interface3Log(); w1.HotelCode = a2; w1.RoomNumber = a3; w1.TriggerTime = DateTime.Now; w1.CommandType = ChangLiangValue.XiaoDu; WelcomeAction w2 = new WelcomeAction(); w2.VoiceDeviceClass = "小度"; w2.CUID = cuid; w2.CommandType = "欢送词"; w1.ActionData = new HttpActionData() { RequestData = Newtonsoft.Json.JsonConvert.SerializeObject(w2) }; //w1.ActionData = new HttpActionData() { RequestData = w2 }; var q1 = Newtonsoft.Json.JsonConvert.SerializeObject(w1); CSRedisCacheHelper.Publish(CacheKey.InvokeHttpInterface, q1); } }, ttt); } } } #endregion } //2、如果有绑定天猫精灵,天猫精灵处理 if (!string.IsNullOrEmpty(TianMaoCUID)) { #region 天猫 if (flag == 1 && !string.IsNullOrEmpty(WelcomeSpeech))//取电打开时,播放欢迎词 { var TTT = new Tuple(TianMaoCUID, WelcomeSpeech, hotelcode, roomnumber, WelcomeBGM); Task.Factory.StartNew((state) => { var hhh = state as Tuple; var a = hhh.Item1.Split(','); var b = hhh.Item2; var c = hhh.Item3; var d = hhh.Item4; var e = hhh.Item5; foreach (string cuid in a)//多个英文逗号隔开 { if (!string.IsNullOrEmpty(e)) { string ffg = "https://www.boonlive-rcu.com/welcomebgm/" + e; TianMaoOperation.PostWebRequestToTianMao("PushWelcome", Newtonsoft.Json.JsonConvert.SerializeObject(new { HotelId = cuid.Split('&')[0], RoomNo = cuid.Split('&')[1], WelcomeText = b, MusicUrl = ffg }), c, d);//通知天猫精灵播放欢迎词 } else { TianMaoOperation.PostWebRequestToTianMao("PushWelcome", Newtonsoft.Json.JsonConvert.SerializeObject(new { HotelId = cuid.Split('&')[0], RoomNo = cuid.Split('&')[1], WelcomeText = b }), c, d);//通知天猫精灵播放欢迎词 } Interface3Log w1 = new Interface3Log(); w1.HotelCode = c; w1.RoomNumber = d; w1.TriggerTime = DateTime.Now; w1.CommandType = ChangLiangValue.TianMao; WelcomeAction w2 = new WelcomeAction(); w2.VoiceDeviceClass = "天猫"; w2.CUID = cuid; w2.CommandType = "欢送词"; w1.ActionData = new HttpActionData() { RequestData = Newtonsoft.Json.JsonConvert.SerializeObject(w2) }; //w1.ActionData = new HttpActionData() { RequestData = w2 }; var q1 = Newtonsoft.Json.JsonConvert.SerializeObject(w1); CSRedisCacheHelper.Publish(CacheKey.InvokeHttpInterface, q1); } }, TTT); } else if (flag == 0) { if (IsPowerOffResetXiaoDu)//断电重置 { var TTT = new Tuple(TianMaoCUID, WelcomeSpeech, hotelcode, roomnumber); Task.Factory.StartNew((state) => { var hhh = state as Tuple; var a = hhh.Item1.Split(','); var b = hhh.Item2; var c = hhh.Item3; var d = hhh.Item4; foreach (string cuid in a)//多个英文逗号隔开 { TianMaoOperation.PostWebRequestToTianMao("CheckoutWithAK", Newtonsoft.Json.JsonConvert.SerializeObject(new { HotelId = cuid.Split('&')[0], RoomNo = cuid.Split('&')[1] }), c, d);//重置天猫精灵 Interface3Log w1 = new Interface3Log(); w1.HotelCode = c; w1.RoomNumber = d; w1.TriggerTime = DateTime.Now; w1.CommandType = ChangLiangValue.TianMao; WelcomeAction w2 = new WelcomeAction(); w2.VoiceDeviceClass = "天猫"; w2.CUID = cuid; w2.CommandType = "断电重置"; w1.ActionData = new HttpActionData() { RequestData = Newtonsoft.Json.JsonConvert.SerializeObject(w2) }; //w1.ActionData = new HttpActionData() { RequestData = w2 }; var q1 = Newtonsoft.Json.JsonConvert.SerializeObject(w1); CSRedisCacheHelper.Publish(CacheKey.InvokeHttpInterface, q1); } }, TTT); } else if (!string.IsNullOrEmpty(GoodbyeSpeech))//取电关闭时,播放离房提示 { var TTT = new Tuple(TianMaoCUID, WelcomeSpeech, hotelcode, roomnumber); Task.Factory.StartNew((state) => { var hhh = state as Tuple; var a = hhh.Item1.Split(','); var b = hhh.Item2; var c = hhh.Item3; var d = hhh.Item4; foreach (string cuid in a)//多个英文逗号隔开 { TianMaoOperation.PostWebRequestToTianMao("PushWelcome", Newtonsoft.Json.JsonConvert.SerializeObject(new { HotelId = cuid.Split('&')[0], RoomNo = cuid.Split('&')[1], WelcomeText = b }), c, d);//通知天猫精灵播放离房提示 Interface3Log w1 = new Interface3Log(); w1.HotelCode = c; w1.RoomNumber = d; w1.TriggerTime = DateTime.Now; w1.CommandType = ChangLiangValue.TianMao; WelcomeAction w2 = new WelcomeAction(); w2.VoiceDeviceClass = "天猫"; w2.CUID = cuid; w2.CommandType = "欢送词"; w1.ActionData = new HttpActionData() { RequestData = Newtonsoft.Json.JsonConvert.SerializeObject(w2) }; //w1.ActionData = new HttpActionData() { RequestData = w2 }; var q1 = Newtonsoft.Json.JsonConvert.SerializeObject(w1); CSRedisCacheHelper.Publish(CacheKey.InvokeHttpInterface, q1); } }, TTT); } } #endregion } } }, TS); } //private static readonly RecyclableMemoryStreamManager manager = new RecyclableMemoryStreamManager(); /// /// 处理数据 /// /// //private void ProcessData(ReceiverContext context111, string hotelCode) private void ProcessData(GaiXie gga) { //GaiXie gga = new GaiXie(); string[] III = gga.IPEndPoint.Split(':'); int PPP = int.Parse(III[1]); IPEndPoint ip = new IPEndPoint(IPAddress.Parse(III[0]), PPP); ReceiverContext context111 = new ReceiverContext(gga.Data, ip, GetNextCustomer()); context111.SystemHeader = DecodeSystemHeader(context111.Data); byte cmdType = context111.SystemHeader.Value.CmdType; ushort MyFrameNO = context111.SystemHeader.Value.FrameNo; byte[] framenolist = BitConverter.GetBytes(MyFrameNO); string IP_PORTStr = context111.RemoteEndPoint.ToString(); string HostNNN = context111.SystemHeader.Value.HostNumber.ToString(); string CODE = context111.SystemHeader.Value.HostNumber.ToHotelCode().ToString(); string hotelCode = CODE; string EndPoint = context111.RemoteEndPoint.ToString(); //if (cmdType != 0x01) //在线状态 不排队 注册0x01 if (true) { #region 只要有数据包,就是心跳 string Key = context111.SystemHeader.Value.HostNumber.ToString(); string EEE = CSRedisCacheHelper.Get(Key); if (string.IsNullOrEmpty(EEE)) { OnOffLineData o = new OnOffLineData(); o.HostNumber = Key; o.HotelCode = hotelCode; o.CurrentStatus = "on"; o.CurrentTime = DateTime.Now; o.EndPoint = context111.RemoteEndPoint.ToString(); //新来的数据 var n = Newtonsoft.Json.JsonConvert.SerializeObject(o); //CSRedisCacheHelper.Publish("redis-on_off_line", n); } string EndPointStr = context111.RemoteEndPoint.ToString(); CSRedisCacheHelper.Set(context111.SystemHeader.Value.HostNumber.ToString(), context111.RemoteEndPoint.Address.ToString() + ":" + context111.RemoteEndPoint.Port.ToString());//主机编码 string KKF = context111.SystemHeader.Value.HostNumber.ToString(); RCUOnLineExtra xe = new RCUOnLineExtra(); xe.CurrentDateTime = DateTime.Now; xe.HotelCode = hotelCode; if (!DataTongJi.ONLINERCU.ContainsKey(KKF)) { DataTongJi.ONLINERCU.TryAdd(KKF, xe); } else { RCUOnLineExtra outv; DataTongJi.ONLINERCU.TryRemove(KKF, out outv); DataTongJi.ONLINERCU.TryAdd(KKF, xe); } //RCUHost.RCUHostCommon.tools.LanJieData(KKK, hotelCode); #endregion } #region 如果是0E 01就直接回复 //36 就是新版本的0E //if (cmdType == 0x0E || cmdType == 0x01) if (cmdType == 0x0E || cmdType == 0x01 || cmdType == 0x36) { StepTongJi.SendInfo(1.1, "0E 01指令回复开始", context111.MessageID, context111.IsMonitor); Reply(context111, framenolist); StepTongJi.SendInfo(1.2, "0E 01指令回复结束", context111.MessageID, context111.IsMonitor); } #endregion try { byte[] OriginalByte = context111.Data; int offset = StructConverter.SizeOf(context111.SystemHeader); int length = context111.Data.Length - offset - 2; string HostNUMBER = HostNNN; if (length > 0) { #region 新版协议 if (cmdType == 0x32 || cmdType == 0x33 || cmdType == 0x34 || cmdType == 0x35 || cmdType == 0x36) { NewXieYi(context111, hotelCode, HostNNN, framenolist, cmdType, EndPoint); } else { #region 01指令 if (cmdType == 0x01) { //注册指令 //AA 55 68 00 54 33 53 41 01 FF FF 95 05 68 E4 //00 00 00 00 FF FF FE 00 AC 14 00 FE 0D 0D 34 D0 B8 11 68 E4 43 31 46 5F 41 5F 4C 34 5F 33 35 5F 32 34 30 38 32 39 00 00 26 00 00 DF 05 05 05 CB AB B4 B2 B1 A6 D2 D7 00 00 00 00 00 00 00 00 31 30 31 37 00 00 00 00 00 00 00 00 00 00 00 00 F6 12 00 00 96 B0 00 00 //3D 89 //升级之后,会上报注册指令,不能被跳过 string Key = "Upgrade_UpdateSQL_" + HostNUMBER; object OOO1 = MemoryCacheHelper.Get(Key); if (OOO1 == null) { int lll = OriginalByte.Length; var A1 = OriginalByte.Skip(15).Take(lll - 15 - 2).ToArray(); string YiJingChuLiGuo = CacheKey.AllReadyDealWith01_Prefix + "_" + HostNUMBER; object ooo = MemoryCacheHelper.Get(YiJingChuLiGuo); if (ooo != null) { byte[] bbb = ooo as byte[]; if (A1.SequenceEqual(bbb)) { RCUHost.RCUHostCommon.tools.LanJieData(SameStatus01, hotelCode); return; } } } } #endregion #region 0E if (cmdType == 0x0E) { //using (var stream = manager.GetStream()) //{ //stream.Write(context111.Data, offset, length); //} using (MemoryStream stream = new MemoryStream(context111.Data, offset, length)) { Status status = NewStatusParse(stream); if (status != null) { var LG = status.Devices; Device UXV = null; //找出取电 LG.TryGetValue("004000001", out UXV); if (UXV != null) { byte bfg = Convert.ToByte(UXV.StatusReceiver); string KKK1 = CacheKey.TakeCardOnLine + "_" + HostNUMBER; CommonEntity.DataTongJi.MTakeCardData t = new DataTongJi.MTakeCardData(); t.HostNUMBER = HostNUMBER; t.HotelCode = hotelCode; t.Status = bfg; t.LastUpdateTime = DateTime.Now; var data = CSRedisCacheHelper.Get_Partition(KKK1, 5); if (data != null) { //说明是拔卡 if ((data.Status == 0x01 && bfg == 0x02)) { string sss = Newtonsoft.Json.JsonConvert.SerializeObject(t); CSRedisCacheHelper.Publish("redis-takecard_change", sss); } //插卡 if ((data.Status == 0x02 && bfg == 0x01)) { string sss = Newtonsoft.Json.JsonConvert.SerializeObject(t); CSRedisCacheHelper.Publish("redis-takecard_change", sss); } } else { string sss = Newtonsoft.Json.JsonConvert.SerializeObject(t); CSRedisCacheHelper.Publish("redis-takecard_change", sss); } CSRedisCacheHelper.Set_Partition(KKK1, t, 5); if (DataTongJi.TakeCardOnLine.ContainsKey(HostNUMBER)) { CommonEntity.DataTongJi.MTakeCardData ooo = null; DataTongJi.TakeCardOnLine.TryRemove(HostNUMBER, out ooo); DataTongJi.TakeCardOnLine.TryAdd(HostNUMBER, t); } else { DataTongJi.TakeCardOnLine.TryAdd(HostNUMBER, t); } } if (status.Devices.Count > 0) { foreach (var item in status.Devices) { string ItemKKK = item.Key; Device VVV = item.Value; if (item.Key.StartsWith("004000") && !item.Key.Equals("004000001")) { CommonEntity.DataTongJi.OtherServiceInfo oth = new DataTongJi.OtherServiceInfo(); oth.HotelCode = hotelCode; oth.HostNumber = HostNUMBER; oth.LastUpdateTime = DateTime.Now; oth.StatusReceiver = item.Value.StatusReceiver; oth.Address = item.Value.Address; string NKKK1 = CacheKey.ServiceInfoOther + "_" + HostNUMBER + "_" + item.Key; var data = CSRedisCacheHelper.Get_Partition(NKKK1, 5); if (data != null) { ushort UUU = data.StatusReceiver; //说明是有变化 if (UUU != item.Value.StatusReceiver) { string sss = Newtonsoft.Json.JsonConvert.SerializeObject(oth); CSRedisCacheHelper.Publish("redis-serviceinfo_change", sss); } } else { string sss = Newtonsoft.Json.JsonConvert.SerializeObject(oth); CSRedisCacheHelper.Publish("redis-serviceinfo_change", sss); } } } } if (status.Devices.Count > 0) { try { var LLL = status.Devices.OrderBy(A => A.Key); var KKK1 = LLL.Select(A => A.Key).ToArray(); var KKK2 = LLL.Select(A => A.Value.StatusReceiver.ToString("00")).ToArray(); if (KKK1.Length > 0 && KKK2.Length > 0) { var VVV1 = string.Join("", KKK1); var VVV2 = string.Join("", KKK2); //StringBuilder sb = new StringBuilder(); //sb.Clear(); //sb.Append(VVV1); //sb.Append(VVV2); string sb = string.Concat(VVV1, VVV2); string YiJingChuLiGuo = CacheKey.AllReadyDealWith0E_Prefix + "_" + HostNUMBER; object data = MemoryCacheHelper.Get(YiJingChuLiGuo); if (data != null) { string shuju = data.ToString(); if (shuju.Equals(sb)) { RCUHost.RCUHostCommon.tools.LanJieData(SameStatus0E, hotelCode); return; } } } } catch (Exception) { } } } } } #endregion } #endregion } } catch (Exception ex) { logger.Error("取电数据上报出问题了:" + ex.Message); logger.Error("取电数据上报出问题了:" + ex.StackTrace); } #region 故意让UDP丢掉的数据包总数 //insertcard 保留 //if (cmdType != 0x0E||cmdType!=0x01) if (cmdType != 0E || cmdType != 0x03) { if (DataTongJi.DefineLostPackage != 0) { Interlocked.Increment(ref DataTongJi.RecordLostPackage); if (DataTongJi.RecordLostPackage == DataTongJi.DefineLostPackage) { Interlocked.Exchange(ref DataTongJi.RecordLostPackage, 0); string Key = "AllocateUDPLostPackage"; UDPPackageCount a1 = null; DataTongJi.TotalCount.TryGetValue(Key, out a1); if (a1 != null) { a1.Count = a1.Count + 1; long NNN = 0; bool bbn = a1.FenLei.TryGetValue(hotelCode, out NNN); if (bbn) { NNN = NNN + 1; } long take = 0; a1.FenLei.TryRemove(hotelCode, out take); a1.FenLei.TryAdd(hotelCode, NNN); } else { UDPPackageCount u = new UDPPackageCount(); u.Count = 1; u.FenLei = new ConcurrentDictionary(); u.FenLei.TryAdd(hotelCode, 1); DataTongJi.TotalCount.TryAdd(Key, u); }; //RCUHost.RCUHostCommon.tools.LanJieData(KKK, hotelCode); return; } } } #endregion string KKK = "StatusPass"; if (context111.SystemHeader.Value.CmdType == 0x0E) { RCUHost.RCUHostCommon.tools.LanJieData(KKK, hotelCode); } var Key10 = (CommandType)context111.SystemHeader.Value.CmdType; var Key11 = Key10.ToString(); LanJieData(Key11, hotelCode); //添加统计 StepTongJi.SendInfo(2, "UDPCallBack执行完,即将分配Task", context111.MessageID, context111.IsMonitor); //如果是心跳,直接处理 if (cmdType == 0x02) { if (context111.SystemHeader.Value.FrameNo > 0x7FFF) { IReceiver receiver = receivers[((CommandType)context111.SystemHeader.Value.CmdType)]; if (receiver != null) { (receiver as HeartReceiver).Process(context111);//处理业务逻辑 } } else { //帧序号≤32767,则表示主机收到回复确认,可取消命令重发 RemoveCommandDataFromCommandQueueByFrameNo(context111.SystemHeader.Value.FrameNo); } } else { Task.Factory.StartNew((State) => { ReceiverContext context = State as ReceiverContext; //添加统计信息 StepTongJi.SendInfo(3, "Task分配成功,即将开始执行", context.MessageID, context.IsMonitor); if (cmdType == 0x36) { IReceiver receiver = receivers[(CommandType)0x36]; if (receiver != null) { (receiver as GenericReceiverBase).Process(context);//处理业务逻辑 } } else { //必须过滤帧号,否则时间同步一直互相发送信息 if (context.SystemHeader.Value.FrameNo > 0x7FFF || (CommandType)context.SystemHeader.Value.CmdType == CommandType.RCUInfo || (CommandType)context.SystemHeader.Value.CmdType == CommandType.UpdateProgressBar || (CommandType)context.SystemHeader.Value.CmdType == CommandType.TFTPLog) { if (receivers.ContainsKey((CommandType)context.SystemHeader.Value.CmdType)) { IReceiver receiver = receivers[((CommandType)context.SystemHeader.Value.CmdType)]; if (receiver != null) { (receiver as GenericReceiverBase).Process(context);//处理业务逻辑 } } } else { //帧序号≤32767,则表示主机收到回复确认,可取消命令重发 RemoveCommandDataFromCommandQueueByFrameNo(context.SystemHeader.Value.FrameNo); } } StepTongJi.SendInfo(6, "Task执行完,即将切换下一个Task", context.MessageID, context.IsMonitor); var FFF = DataTongJi.CPU_Data; if (FFF.Count > 0) { double avg_d = FFF.Average(); StepTongJi.SendInfo(0, avg_d.ToString(), context.MessageID, context.IsMonitor); } }, context111); } } public static object oo = new object(); private void NewXieYi(ReceiverContext context_1, string hotelCode_1, string HostNNN_1, byte[] framenolist_1, byte cmdType_1, string EndPoint_1) { var Tuple = new Tuple(context_1, hotelCode_1, HostNNN_1, framenolist_1, cmdType_1, EndPoint_1); Task.Factory.StartNew((state) => { var ts = state as Tuple; ReceiverContext context111 = ts.Item1; string hotelCode = ts.Item2; string HostNNN = ts.Item3; byte[] framenolist = ts.Item4; byte cmdType = ts.Item5; string EndPoint = ts.Item6; if (cmdType == 0x33) { // RCU重启原因: AA 55 26 00 54 33 53 41 35 02 80 EB 03 6B 24 // 4C 61 75 6E 63 68 65 72 5F 43 31 46 5F 56 30 34 2E 37 20 20 //"Launcher_C1F_V04.7 " // 01 重启原因 0x01:软件复位,0x02:上电复位,0x03:外部手动复位,0x04:下电复位,0x05:看门狗复位,其他值:未知复位 // D5 40 ReplyWithContent(context111, new byte[] { 0x00 }, framenolist); byte[] OriginalByte = context111.Data; int offset = StructConverter.SizeOf(context111.SystemHeader); int length = context111.Data.Length - offset - 2; var data = OriginalByte.Skip(offset).ToArray(); var LauncherVersion = data.Take(20); var RestartReason = data.Skip(20).Take(1); NewVersionHexData ns = new NewVersionHexData(); ns.CmdType = 0x33; ns.HotelCode = hotelCode; ns.HostNumber = HostNNN; ns.RemoteEndPoint = EndPoint; ns.CurrentTime = DateTime.Now; ns.HexData = Tools.ByteToString(context111.Data); string mns1 = Newtonsoft.Json.JsonConvert.SerializeObject(ns); CSRedisCacheHelper.Publish("redis-rcu-restart", mns1); } if (cmdType == 0x35) { ReplyWithContent(context111, new byte[] { 0x00 }, framenolist); //P0:取电动作状态 // 0x00:无动作 // 0x01:取电动作 // 0x02:断电动作 //P1:插卡状态 // 0x00:无插卡动作 // 0x01:插卡动作 // 0x02:拔卡动作 //P2:身份信息 //P3:无卡逻辑状态(对应事件状态) //取电变化上报: AA 55 15 00 54 33 53 41 35 20 80 EB 03 6B 24 01 00 00 00 D7 74 // AA 55 15 00 54 33 53 41 35 20 80 EB 03 6B 24 // 01 //取电动作 // 00 //插卡动作 // 00 //身份信息 // 00 //无卡逻辑事件 // D7 74 byte[] OriginalByte = context111.Data; int offset = StructConverter.SizeOf(context111.SystemHeader); int length = context111.Data.Length - offset - 2; var data = OriginalByte.Skip(offset).ToArray(); var qudian = data[0]; var chaka = data[1]; var shenfen = data[2]; var noka_event = data[3]; if (qudian == 0x01) { VoiceRobotTrigger(1, hotelCode, HostNNN); } else if (qudian == 0x02) { VoiceRobotTrigger(0, hotelCode, HostNNN); } else { } NewVersionHexData ns = new NewVersionHexData(); ns.CmdType = 0x35; ns.HotelCode = hotelCode; ns.HostNumber = HostNNN; ns.RemoteEndPoint = EndPoint; ns.CurrentTime = DateTime.Now; ns.HexData = Tools.ByteToString(context111.Data); string mns1 = Newtonsoft.Json.JsonConvert.SerializeObject(ns); CSRedisCacheHelper.Publish("redis-rcu-card_action", mns1); string HostID = CSRedisCacheHelper.HMGet(5, CacheKey.HostId_HostNumber, HostNNN)[0]; if (!string.IsNullOrEmpty(HostID)) { string KKey = CacheKey.HostModalStatus_Prefix + "_" + HostID + "_" + "004000001"; var OldHostModal = CSRedisCacheHelper.Get_Partition(KKey); if (OldHostModal != null) { if (qudian == 0x01) { OldHostModal.Status = 1; } else if (qudian == 0x02) { OldHostModal.Status = 2; } else { } CSRedisCacheHelper.Set_Partition(KKey, OldHostModal); } } } // AA 55 35 00 54 33 53 41 34 10 80 EB 03 6B 24 // 01 //协议版本 // 01 //取电状态 // 00 //身份信息 // 00 //无卡逻辑 // 00 00 00 00 00 00 00 00 //服务信息全部回路状态 1~64 64Bit 0 :关 1:开 // 01 //PMS状态 // 01 //碳达人 // 01 //上报设备数 // 39 //设备类型 - 能耗设备 // 01 //设备地址 // 01 00 //设备回路 // 10 //设备数据长度 // 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 //设备数据 // 07 //设备类型 - 温控 // 01 //设备地址 // 01 00 //设备回路 // 02 //设备数据长度 // 00 00 //设备数据 // F4 AA //CRC16 //能耗设备 - 上报数据格式 //P15:设备类型 //P16:设备地址 //P17~P18:设备回路 //P19:设备数据长度 //P20~P21:通道电压,单位:10mV //P22~P23:通道电流,单位:10mA //P24~P25:通道有功功率,单位:mW //P26~P29:通道能耗,单位:Wh(1度电 = 1KWh) //P30~P33:通道总能耗,单位:Wh(1度电 = 1KWh) if (cmdType == 0x36) { //Reply(context111); string hexdata = Tools.ByteToString(context111.Data); NewVersionHexData ns = new NewVersionHexData(); ns.CmdType = 0x36; ns.HotelCode = hotelCode; ns.HostNumber = HostNNN; ns.RemoteEndPoint = EndPoint; ns.CurrentTime = DateTime.Now; ns.HexData = Tools.ByteToString(context111.Data); //CSRedisCacheHelper.Publish("redis-rcu-hexdata", Newtonsoft.Json.JsonConvert.SerializeObject(ns)); } if (cmdType == 0x34) { ReplyWithContent(context111, new byte[] { 0x00 }, framenolist); byte[] OriginalByte = context111.Data; int offset = StructConverter.SizeOf(context111.SystemHeader); int length = context111.Data.Length - offset - 2; //给宝镜发送完整的数据 string hexdata = Tools.ByteToString(context111.Data); CSRedisCacheHelper.Publish("redis-baojing-powerdata", hexdata); try { NewVersionHexData ns = new NewVersionHexData(); ns.CmdType = 0x34; ns.HotelCode = hotelCode; ns.HostNumber = HostNNN; ns.RemoteEndPoint = EndPoint; ns.CurrentTime = DateTime.Now; ns.HexData = hexdata; //CSRedisCacheHelper.Publish("redis-rcu-timer_data", Newtonsoft.Json.JsonConvert.SerializeObject(ns)); string HostID = CSRedisCacheHelper.HMGet(5, CacheKey.HostId_HostNumber, HostNNN)[0]; string RoomNUMBER = CSRedisCacheHelper.HMGet(5, CacheKey.RoomNumber_HostNumber, HostNNN)[0]; List DeviceList = new List(); var DS1 = CSRedisCacheHelper.Get_Partition>(CacheKey.DingShiReportData + "_" + HostID, 3); if (DS1 != null) { DeviceList = DS1; } else { //logger.Error("定时上报的HostId:" + HostID); //定时上报要查询 当前房间配置了哪些设备 //这里根据主机Id 号查询当前房间,有哪些设备 if (!string.IsNullOrEmpty(HostID)) { lock (oo) { var list2 = HostModalRepository.LoadByHostID(int.Parse(HostID)); var list = list2.Where(r => r.Modal.IsUploadBaoJing).OrderBy(r => r.Modal.ModalAddress);//只装置标志启动的 List dingls = new List(); foreach (HostModal item in list) { DingShiReportDate ddd = new DingShiReportDate(); ddd.HostID = item.HostID; ddd.Address = item.Modal.ModalAddress; ddd.DeviceType = item.Modal.Type.ToString(); dingls.Add(ddd); } DeviceList = dingls; CSRedisCacheHelper.Set_PartitionWithForever>(CacheKey.DingShiReportData + "_" + HostID, dingls, 3); } } } List DeviceStatusList = new List(); foreach (DingShiReportDate item in DeviceList) { string KKey = CacheKey.HostModalStatus_Prefix + "_" + item.HostID + "_" + item.Address; var hostModal = CSRedisCacheHelper.Get_Partition(KKey); if (hostModal != null) { DingShiReportDate ddd = new DingShiReportDate(); ddd.HostID = item.HostID; ddd.Address = item.Address; ddd.DeviceType = item.DeviceType; ddd.Status = hostModal.Status; ddd.Brightness = hostModal.Brightness; var aaa = hostModal.AirConditionData; ddd.CurrentTemp = aaa.CurrentTemp; ddd.SettingTemp = aaa.SettingTemp; ddd.FanSpeed = aaa.FanSpeed; ddd.Mode = aaa.Mode; ddd.Valve = aaa.Valve; DeviceStatusList.Add(ddd); } } using (MemoryStream stream = new MemoryStream(context111.Data, offset, length)) { using (BinaryReader reader = new BinaryReader(stream)) { //版本 var Version = reader.ReadByte(); //取电 var TakeCardStatus = reader.ReadByte(); //string QUDIANKey = CacheKey.NewVersionDeviceStatus + "_" + HostNNN; //var hostModal = CSRedisCacheHelper.HMGet(1, QUDIANKey, "004000001"); //if (hostModal[0] != null) //{ // hostModal[0].Status = TakeCardStatus; // CSRedisCacheHelper.HMSet(1, QUDIANKey, "004000001", hostModal); //} //else //{ // NewVersionDeviceStatus n = new NewVersionDeviceStatus(); // n.Status = TakeCardStatus; // n.HotelCode = CODE; // n.HostNumber = HostNNN; // n.ModalType = DeviceType.ServiceInfo; // n.UpdateTime = DateTime.Now; // CSRedisCacheHelper.HMSet(1, QUDIANKey, "004000001", n); //} //身份 var IdentityInfo = reader.ReadByte(); var NOCardInfo = reader.ReadByte(); //服务信息全部回路状态 1~64 64Bit 0 :关 1:开 //把8个字节转换成64个二进制位 var N = reader.ReadBytes(8); BitArray bitlist = new BitArray(N); for (int i = 0; i < bitlist.Length; i++) { if (i == 1) { continue; } string SerNo = i.ToString("000"); //界面上显示,为了 兼容老版的 界面 显示逻辑,所以这样写 if (!string.IsNullOrEmpty(HostID)) { string KKey = CacheKey.HostModalStatus_Prefix + "_" + HostID + "_" + "004000" + SerNo; var OldHostModal = CSRedisCacheHelper.Get_Partition(KKey); if (OldHostModal != null) { if (bitlist[i]) { OldHostModal.Status = 1; } else { OldHostModal.Status = 2; } } } //var hostModal1 = CSRedisCacheHelper.HMGet(1, QUDIANKey, "004000" + SerNo); //if (hostModal1[0] != null) //{ // if (bitlist[i]) // { // hostModal1[0].Status = 1; // } // else // { // hostModal1[0].Status = 2; // } // CSRedisCacheHelper.HMSet(1, QUDIANKey, "004000" + SerNo, hostModal1[0]); //} //else //{ // NewVersionDeviceStatus n = new NewVersionDeviceStatus(); // n.Status = 2; // n.HotelCode = CODE; // n.HostNumber = HostNNN; // n.ModalType = DeviceType.ServiceInfo; // n.UpdateTime = DateTime.Now; // CSRedisCacheHelper.HMSet(1, QUDIANKey, "004000" + SerNo, n); //} } //PMS房态 //定时上报,之后要设置房态,要用0C //只会上报 01 出租,02退房 var PMS = reader.ReadByte(); //if (PMS != 0x01 && PMS != 0x02) if (true) { string Key = CacheKey.SyncRoomStatus + "_" + HostNNN; var Q = CSRedisCacheHelper.Get_Partition(Key); //测试使用 //IReceiver receiver1 = receivers[CommandType.RoomStatusChanged]; //(receiver1 as RoomStatusChangedReceiver).SendRoomStatusSelfWithFrameNo("111", "2222", new RoomStatus { ID = 10 }, framenolist);//处理业务逻辑 if (Q != null && PMS != Q.Status.ID) { IReceiver receiver = receivers[CommandType.RoomStatusChanged]; if (Q != null) { (receiver as RoomStatusChangedReceiver).SendRoomStatusSelfWithFrameNo(Q.HostNumber, Q.MAC, Q.Status, framenolist);//处理业务逻辑 } else { Domain.RoomStatus RS = new RoomStatus(); RS.Name = "空房"; RS.ID = 16; (receiver as RoomStatusChangedReceiver).SendRoomStatusSelfWithFrameNo(HostNNN, "", RS, framenolist);//处理业务逻辑 } } } //碳达人 var CarbonVIP = reader.ReadByte(); var DeviceCount = reader.ReadByte(); int DeviceCount_I = (int)DeviceCount; for (int i = 0; i < DeviceCount_I; i++) { var QA = reader.ReadBytes(4); //说明是能耗设备 #region 能耗 if (QA[0] == 0x39) { string address = new DeviceAddress(QA).ToString(); //设备数据长度 var DeviceInfoLen = reader.ReadByte(); var Len = Convert.ToInt32(DeviceInfoLen); //设备数据 var Data = reader.ReadBytes(Len); //byte Len = Data.Skip(28).Take(1).FirstOrDefault(); byte[] DianYa = Data.Take(2).ToArray(); byte[] DianLiu = Data.Skip(2).Take(2).ToArray(); byte[] Power = Data.Skip(4).Take(4).ToArray(); byte[] PowerUsed = Data.Skip(8).Take(4).ToArray(); byte[] TotalPowerUsed = Data.Skip(12).Take(4).ToArray(); uint dianya = BitConverter.ToUInt16(DianYa, 0); uint dianliu = BitConverter.ToUInt16(DianLiu, 0); uint gonglv = BitConverter.ToUInt32(Power, 0); uint nenghao = BitConverter.ToUInt32(PowerUsed, 0); uint zongnenghao = BitConverter.ToUInt32(TotalPowerUsed, 0); double V = (double)dianya * 10 / 1000; double A = (double)dianliu * 10 / 1000; double P = (double)gonglv / 1000; double KW_H = (double)nenghao / 1000; double Sum_KW_H = (double)zongnenghao / 1000; NengHao n = new NengHao(); n.HotelCode = long.Parse(hotelCode); n.HostNumber = HostNNN; n.RoomNumber = RoomNUMBER; n.CarbonVIP = CarbonVIP; n.Mac = ""; n.EndPoint = EndPoint; n.Version = ((int)Version).ToString(); if (TakeCardStatus == 0x01) { n.IsTakeCard = true; } else { n.IsTakeCard = false; } n.V = Math.Round(V, 2); n.A = Math.Round(A, 2); n.P = Math.Round(P, 2); n.KW_H = KW_H; n.Sum_KW_H = Sum_KW_H; long ti = Tools.GetUnixTime(); n.CreateTime = ti; string KKey = CacheKey.NengHao + "_" + HostNNN; CSRedisCacheHelper.Set_PartitionWithTime(KKey, n, 30, 1); //这里不再发送这个了,改发送全部的数据 NengHao4BaoJing ns2 = new NengHao4BaoJing() { HotelCode = n.HotelCode, HostNumber = n.HostNumber, RoomNumber = n.RoomNumber, Mac = n.Mac, EndPoint = n.EndPoint, Version = n.Version, IsTakeCard = n.IsTakeCard, CarbonVIP = n.CarbonVIP, V = dianya, A = dianliu, P = gonglv, Energy_Consumption = nenghao, Sum_Energy_Consumption = zongnenghao, CreateTime = n.CreateTime, ReportTime = n.ReportTime.ToString("yyyy-MM-dd HH:mm:ss"), AllDeviceData = DeviceStatusList, IdentityInfo = IdentityInfo }; string mns = Newtonsoft.Json.JsonConvert.SerializeObject(ns2); CSRedisCacheHelper.Publish("redis-power", mns); string KeyFilter = "能耗"; RCUHost.RCUHostCommon.tools.LanJieData(KeyFilter, hotelCode.ToString()); } #endregion #region 是温控 //定期上报, //原本的0E 修改了命令字,改成其它命令字,内容不变,但是空调 只有操作上报。 //空调定期上报的数据,改为在这里上报 else if (QA[0] == 0x07) { //07 //设备类型 - 温控 //01 //设备地址 //01 00 //设备回路 //02 //设备数据长度 //00 00 //设备数据 string address = new DeviceAddress(QA).ToString(); //设备数据长度 var WenKongQiDataLen = reader.ReadByte(); //温控器 var DataLen1 = Convert.ToInt32(WenKongQiDataLen); ///ushort StatusReceiver = reader.ReadUInt16(); ushort StatusReceiver = BitConverter.ToUInt16(reader.ReadBytes(2).Reverse().ToArray(), 0); if (true) { //int status = StatusReceiver >> 15;//开关 //int mode = (StatusReceiver >> 13) & 0x03;//模式 //int fanSpeed = (StatusReceiver >> 11) & 0x03;//风速 int valve = (StatusReceiver >> 10) & 0x01;//阀门 //int temperature = (StatusReceiver >> 5) & 0x1F;//设定温度 //int currentTemp = StatusReceiver & 0x01F;//当前温度(室内温度) int status = 0; int mode; int fanspeed; int temperature = 0;//设定温度 int currentTemp = 0;//当前温度(室内温度) KongTiaoReport(StatusReceiver, out status, out temperature, out mode, out fanspeed, out currentTemp); if (!string.IsNullOrEmpty(HostID)) { string KKey = CacheKey.HostModalStatus_Prefix + "_" + HostID + "_" + address; var HHostModalData = CSRedisCacheHelper.Get_Partition(KKey); if (HHostModalData != null) { HHostModalData.AirConditionData.AirStatus = status; HHostModalData.AirConditionData.Mode = mode; HHostModalData.AirConditionData.FanSpeed = fanspeed; HHostModalData.AirConditionData.Valve = valve == 1 ? 1 : 2; HHostModalData.AirConditionData.UpdateTime = DateTime.Now; if (temperature == 0 || temperature > 32) { HHostModalData.AirConditionData.SettingTemp = 32; } else if (temperature < 16) { HHostModalData.AirConditionData.SettingTemp = 16; } else { HHostModalData.AirConditionData.SettingTemp = temperature; } if (currentTemp == 0 || currentTemp > 32) { HHostModalData.AirConditionData.CurrentTemp = 32; } else if (currentTemp < 16) { HHostModalData.AirConditionData.CurrentTemp = 16; } else { HHostModalData.AirConditionData.CurrentTemp = currentTemp; } CSRedisCacheHelper.Set_Partition(KKey, HHostModalData); } } } } #endregion } } } } catch (Exception ex) { logger.Error("定是上报出错:" + ex.Message); logger.Error("定是上报出错:" + ex.StackTrace); } } //向服务器获取房态 if (cmdType == 0x32) { try { IReceiver receiver = receivers[CommandType.AskRoomStatus]; if (receiver != null) { string Key = CacheKey.SyncRoomStatus + "_" + HostNNN; var Q = CSRedisCacheHelper.Get_Partition(Key); if (Q != null) { (receiver as AskRoomStatusChangedReceiver).SendRoomStatusSelf(HostNNN, Q.MAC, Q.Status, framenolist);//处理业务逻辑 } else { Domain.RoomStatus RS = new RoomStatus(); RS.Name = "空房"; RS.ID = 16; (receiver as AskRoomStatusChangedReceiver).SendRoomStatusSelf(HostNNN, "FF-FF-FF-FF-FF-FF", RS, framenolist);//处理业务逻辑 } } } catch (Exception ex) { logger.Error("CmdType Error" + ex.StackTrace); } } }, Tuple); } /// /// 空调上报解析 /// /// /// /// /// private static void KongTiaoReport(ushort StatusReceiver, out int status, out int temperature, out int mode, out int fanspeed, out int currenttemp) { mode = 0; fanspeed = 0; status = 0; //StringBuilder sssasa = new StringBuilder(); byte[] b_data = BitConverter.GetBytes(StatusReceiver); b_data = b_data.Reverse().ToArray(); BitArray bit = new BitArray(b_data); //BitArray bit2 = new BitArray(new byte[] { b_data[1] }); BitArray bit3 = new BitArray(5); BitArray bit4 = new BitArray(5); //00 0011 1010 //Bit9~5:设置温度 16~32℃ //Bit4~0:室内温度 16~32℃ bit3[0] = bit[5]; bit3[1] = bit[6]; bit3[2] = bit[7]; bit3[3] = bit[8]; bit3[4] = bit[9]; bit4[0] = bit[0]; bit4[1] = bit[1]; bit4[2] = bit[2]; bit4[3] = bit[3]; bit4[4] = bit[4]; int[] array1 = new int[1]; int[] array2 = new int[1]; bit3.CopyTo(array1, 0); bit4.CopyTo(array2, 0); temperature = array1[0]; currenttemp = array2[0]; bool b000 = bit[15]; if (b000 == true) { status = 1; } else { status = 2; } bool b111 = bit[14]; bool b222 = bit[13]; bool b333 = bit[12]; bool b444 = bit[11]; //1制冷,2制热,3送风 if (b222 == true && b111 == false) { mode = 1; } else if (b222 == false && b111 == true) { mode = 2; } else if (b222 == true && b111 == true) { mode = 3; } else { } //0自动,1低速,2中速,3高速 if (b444 == true && b333 == false) { fanspeed = 1; } else if (b444 == false && b333 == true) { fanspeed = 2; } else if (b444 == true && b333 == true) { fanspeed = 3; } else if (b444 == false && b333 == false) { fanspeed = 0; } else { } } /// /// 解码 SystemHeader /// /// /// private SystemHeader? DecodeSystemHeader(byte[] data) { return StructConverter.BytesToStruct(data, typeof(SystemHeader)) as SystemHeader?; } #region Command Queue Methods /// /// 将命令放入队列 /// /// private void PushCommandToQueue(byte[] data, IPEndPoint endPoint) { CommandData commandData = new CommandData(); commandData.RemoteEndPoint = endPoint; commandData.FrameNo = BitConverter.ToUInt16(data, 9); commandData.Data = data; commandData.ResendTime = 2; commandQueue.Add(commandData); } /// /// 清理命令队列 /// private void CleanCommandQueue() { RemoveCommandData(commandQueue.Where(r => r.ResendTime < 1)); } private void RemoveCommandDataFromCommandQueueByFrameNo(ushort frameNo) { RemoveCommandData(commandQueue.Where(r => r.FrameNo == frameNo)); } private void RemoveCommandData(IEnumerable commands) { CommandData takeCommand; foreach (var command in commands) { commandQueue.TryTake(out takeCommand); } } #endregion /// /// 阿宝 /// public void Start_AirConditionMisson() { } public void Dispose() { Destroy(); } } internal class UdpState { private UdpClient udpClient; public UdpState(UdpClient client) { this.udpClient = client; } public UdpClient UdpClient { get { return this.udpClient; } } } }