黄学彪
2020-10-12 dc6493db59dcb0893eac50b72122f94c24056b3f
ZigbeeApp/Shared/Common/Device.cs
@@ -245,7 +245,7 @@
                {
                    continue;
                }
                var device = this.NewDeviceObjectByDeviceId((DeviceType)itemValue);
                var device = this.NewDeviceObjectByDeviceId((DeviceType)itemValue, 1);
                string strMsg = string.Empty;
                if (device == null)
                {
@@ -272,14 +272,14 @@
        /// <para>将指定网关的设备存入缓存中(从新获取镜像)</para>
        /// <para>-1:异常 1:正常 2:设备信息缺损</para>
        /// </summary>
        /// <param name="zbGateway">网关对象</param>
        /// <param name="gatewayId">网关Id</param>
        /// <param name="useLocalConnect">是否强制使用本地连接发送</param>
        public int SetDeviceToMemmoryByGateway(ZbGateway zbGateway, bool useLocalConnect)
        public int SetDeviceToMemmoryByGateway(string gatewayId, bool useLocalConnect)
        {
            //从网关获取全部的设备
            int statu = 0;
            List<CommonDevice> listDevice = new List<CommonDevice>();
            List<CommonDevice> list = this.GetDeviceListFromGateway(zbGateway, ref statu, useLocalConnect);
            List<CommonDevice> list = this.GetDeviceListFromGateway(gatewayId, ref statu, useLocalConnect);
            if (list == null)
            {
                return -1;
@@ -287,12 +287,11 @@
            listDevice.AddRange(list);
            //获取这个网关的本地所有设备
            string gwID = zbGateway.GwId;
            List<CommonDevice> listLocalDevices = this.GetDeviceByGatewayID(gwID);
            List<CommonDevice> listLocalDevices = this.GetDeviceByGatewayID(gatewayId);
            //获取ota设备
            foreach (var ota in this.dicOTADevice.Values)
            {
                if (ota.CurrentGateWayId == gwID)
                if (ota.CurrentGateWayId == gatewayId)
                {
                    listLocalDevices.Add(ota);
                }
@@ -1334,7 +1333,7 @@
        #region ■ 获取设备信息_______________________
        /// <summary>
        /// 读取单个端点回路设备信息
        /// 从网关读取单个端点回路设备信息
        /// </summary>
        /// <param name="device">设备对象</param>
        /// <returns></returns>
@@ -1348,6 +1347,145 @@
            }
            var info = Newtonsoft.Json.JsonConvert.DeserializeObject<CommonDevice.DeviceInfoData>(result.ReceiptData);
            return info;
        }
        /// <summary>
        /// 从网关读取指定Mac下的设备列表(返回的是网关回复的设备Json,调用ConvertJObjectToDevice方法转为Device对象)
        /// </summary>
        /// <param name="realGateway">真实网关对象</param>
        /// <param name="i_deviceMac">设备Mac</param>
        /// <param name="useLocalConnect">是否使用本地连接发送</param>
        /// <param name="listFucDevice">需要变更功能类型的回路</param>
        /// <param name="statu">状态-> -1:异常,会返回null, 1:没有异常, 2:数据接收不全</param>
        /// <returns></returns>
        public List<Newtonsoft.Json.Linq.JObject> ReadDeviceListByMacFromGateway(string gatewayId, string i_deviceMac, bool useLocalConnect, ref int statu)
        {
            //是否达成中断的时机
            bool canBreak = false;
            //超时时间
            int TimeOut = 0;
            //设备总数
            int deviceCount = -1;
            //接收数
            int receiveCount = 0;
            //设备列表
            var listDeviceJson = new List<Newtonsoft.Json.Linq.JObject>();
            HdlGatewayReceiveLogic.Current.AddGatewayReceiveEvent(gatewayId, (topic, message) =>
            {
                if (topic == gatewayId + "/GetStatusRecord_Respon")
                {
                    lock (listDeviceJson)
                    {
                        //设备接收数
                        receiveCount++;
                        TimeOut = 0;
                        var jobject = Newtonsoft.Json.Linq.JObject.Parse(message);
                        var totalNum = Newtonsoft.Json.JsonConvert.DeserializeObject<int>(jobject["Data"]["TotalNum"].ToString());
                        if (totalNum == 0)
                        {
                            //这个网关没有设备
                            canBreak = true;
                            return;
                        }
                        if (deviceCount == -1)
                        {
                            //设置需要接收多少个设备
                            deviceCount = totalNum;
                        }
                        listDeviceJson.Add(jobject);
                    }
                    if (receiveCount == deviceCount && deviceCount != -1)
                    {
                        //设备全部接收完成
                        canBreak = true;
                    }
                }
            });
            var jObject = new Newtonsoft.Json.Linq.JObject { { "DeviceAddr", i_deviceMac }, { "Epoint", 255 }, { "Cluster_ID", 0 }, { "Command", 80 } };
            HdlGatewayLogic.Current.SendJobjectData(gatewayId, "GetStatusRecord", jObject.ToString(), useLocalConnect);
            while (canBreak == false && TimeOut <= 150)
            {
                System.Threading.Thread.Sleep(20);
                TimeOut++;
            }
            //移除监听
            HdlGatewayReceiveLogic.Current.RemoveGatewayReceiveEvent();
            if (TimeOut > 150)
            {
                statu = listDeviceJson.Count == 0 ? -1 : 2;
            }
            else
            {
                statu = 1;
            }
            return listDeviceJson;
        }
        /// <summary>
        /// 将设备的Json转换为设备对象
        /// </summary>
        /// <param name="listIObjects">设备Json</param>
        /// <param name="gwId">网关id</param>
        /// <param name="listFucDevice">需要变更功能类型的回路</param>
        /// <returns></returns>
        public List<CommonDevice> ConvertJObjectToDevice(List<Newtonsoft.Json.Linq.JObject> listIObjects, string gwId, ref List<CommonDevice> listFucDevice)
        {
            //设备列表
            var listDevice = new List<CommonDevice>();
            //网关里面有可能会有重复的回路
            var listCheck = new HashSet<string>();
            foreach (var jobject in listIObjects)
            {
                var deviceID = (DeviceType)jobject.Value<int>("Device_ID");
                //根据设备类型创建设备对象的实例
                var device = this.NewDeviceObjectByDeviceId(deviceID, jobject, gwId);
                if (device != null)
                {
                    string mainkeys = this.GetDeviceMainKeys(device);
                    //网关里面有可能会有重复的回路
                    if (listCheck.Contains(mainkeys) == false)
                    {
                        listDevice.Add(device);
                        listCheck.Add(mainkeys);
                        //刷新一下本地缓存
                        var localDevice = this.GetDevice(mainkeys);
                        var tempDevice = localDevice == null ? device : localDevice;
                        //如果这个设备ID变更了的话
                        bool typeNotEquals = localDevice != null && deviceID != localDevice.Type;
                        if (typeNotEquals == true)
                        {
                            //重新New这个对象
                            typeNotEquals = this.ReNewDeviceOnTypeIsChanged(localDevice, deviceID);
                            //重新再次获取对象
                            tempDevice = this.GetDevice(mainkeys);
                        }
                        //刷新属性
                        this.SetDeviceInfoToMain(tempDevice, device);
                        if (this.RefreshDeviceFunctionType(tempDevice, device, false) == true)
                        {
                            //需要发送功能类型给网关
                            listFucDevice.Add(tempDevice);
                        }
                        if (typeNotEquals == true)
                        {
                            //重新生成缓存
                            tempDevice.ReSave();
                            HdlAutoBackupLogic.AddOrEditorFile(tempDevice.FilePath);
                            //全部主页菜单需要刷新
                            Phone.UserView.UserPage.Instance.RefreshAllForm = true;
                        }
                    }
                }
            }
            return listDevice;
        }
        #endregion
@@ -2775,62 +2913,43 @@
        #region ■ 获取设备列表的接口_________________
        /// <summary>
        /// <para>从网关重新获取设备列表(返回的设备为虚拟出来的)</para>
        /// <para>从网关重新获取设备列表(返回的设备为虚拟出来的),一次性全部获取</para>
        /// <para>statu状态 -1:异常,会返回null, 1:没有异常, 2:数据接收不全</para>
        /// </summary>
        /// <param name="zbGateway">网关对象</param>
        /// <param name="gatewayId">网关id</param>
        /// <param name="statu">状态-> -1:异常,会返回null, 1:没有异常, 2:数据接收不全</param>
        /// <param name="useLocalConnect">是否使用本地连接发送</param>
        /// <param name="mode">是否显示错误</param>
        /// <returns></returns>
        public List<CommonDevice> GetDeviceListFromGateway(ZbGateway zbGateway, ref int statu, bool useLocalConnect, ShowErrorMode mode = ShowErrorMode.YES)
        public List<CommonDevice> GetDeviceListFromGateway(string gatewayId, ref int statu, bool useLocalConnect, ShowErrorMode mode = ShowErrorMode.YES)
        {
            //如果切换到了别的界面,则不显示错误信息
            string nowFormId = UserCenterResourse.NowActionFormID;
            ZbGateway realWay = null;
            if (HdlGatewayLogic.Current.GetRealGateway(ref realWay, zbGateway) == false)
            {
                if (nowFormId == UserCenterResourse.NowActionFormID && mode == ShowErrorMode.YES)
                {
                    //错误:网关对象丢失
                    string msg = Language.StringByID(R.MyInternationalizationString.uErrorGatewayLostMsg);
                    this.ShowTipMsg(msg);
                }
                statu = -1;
                return null;
            }
            //需要变更功能类型的回路
            var listFucDevice = new List<CommonDevice>();
            //是否达成中断的时机
            bool canBreak = false;
            //网关ID
            string gatewayID = zbGateway.GwId;
            //超时时间
            int TimeOut = 0;
            //当前设备接收数
            int nowReceiveCount = 0;
            //设备总数
            int deviceCount = -1;
            //接收数
            int receiveCount = 0;
            //设备列表
            var listDevice = new List<CommonDevice>();
            //网关里面有可能会有重复的回路
            var listCheck = new HashSet<string>();
            Action<string, string> getDeviceAction = (topic, message) =>
            ///Mac的端点总数
            var dicMacPointCount = new Dictionary<string, int>();
            HdlGatewayReceiveLogic.Current.AddGatewayReceiveEvent(gatewayId, (topic, message) =>
            {
                if (topic == gatewayID + "/DeviceInfoRespon")
                {
                    try
                if (topic == gatewayId + "/DeviceInfoRespon")
                    {
                        lock (listDevice)
                        {
                            //设备接收数
                            receiveCount++;
                            TimeOut = 0;
                            var jobject = Newtonsoft.Json.Linq.JObject.Parse(message);
                            var totalNum = Newtonsoft.Json.JsonConvert.DeserializeObject<int>(jobject["Data"]["TotalNum"].ToString());
                        var totalNum = Convert.ToInt32(jobject["Data"]["TotalNum"].ToString());
                            if (totalNum == 0)
                            {
                                //这个网关没有设备
@@ -2842,10 +2961,19 @@
                                //设置需要接收多少个设备
                                deviceCount = totalNum;
                            }
                        nowReceiveCount++;
                        //设备回路数收集
                        string deviceMac = jobject.Value<string>("DeviceAddr");
                        if (dicMacPointCount.ContainsKey(deviceMac) == false)
                        {
                            dicMacPointCount[deviceMac] = 0;
                        }
                        dicMacPointCount[deviceMac]++;
                            var deviceID = (DeviceType)jobject.Value<int>("Device_ID");
                            //根据设备类型创建设备对象的实例
                            var device = this.NewDeviceObjectByDeviceId(deviceID, jobject, zbGateway);
                        var device = this.NewDeviceObjectByDeviceId(deviceID, jobject, gatewayId);
                            if (device != null)
                            {
                                string mainkeys = this.GetDeviceMainKeys(device);
@@ -2886,71 +3014,56 @@
                                }
                            }
                        }
                    }
                    //Log出力
                    catch (Exception ex) { HdlLogLogic.Current.WriteLog(ex); }
                    if (receiveCount == deviceCount && deviceCount != -1)
                    if (nowReceiveCount >= deviceCount)
                    {
                        //设备全部接收完成
                        canBreak = true;
                    }
                }
                else if (topic == gatewayID + "/DeviceInfoResponEnd")
                {
                }
            };
            realWay.Actions += getDeviceAction;
            try
            {
            });
            //发送命令
                var jObject = new Newtonsoft.Json.Linq.JObject { { "Cluster_ID", 0 }, { "Command", 93 } };
                if (useLocalConnect == false)
                {
                    realWay.Send("GetDeviceInfo", jObject.ToString());
                }
                else
                {
                    //强制使用本地连接
                    realWay.SendLocation("GetDeviceInfo", Encoding.UTF8.GetBytes(jObject.ToString()));
                }
            }
            catch { canBreak = true; }
            HdlGatewayLogic.Current.SendJobjectData(gatewayId, "GetDeviceInfo", jObject.ToString(), useLocalConnect);
            while (canBreak == false && TimeOut < 60)
            while (canBreak == false && TimeOut <= 30)
            {
                System.Threading.Thread.Sleep(100);
                TimeOut++;
            }
            //移除网关监听事件
            HdlGatewayReceiveLogic.Current.RemoveGatewayReceiveEvent();
            realWay.Actions -= getDeviceAction;
            getDeviceAction = null;
            if (TimeOut >= 60)
            if (TimeOut > 30)
            {
                if (listDevice.Count == 0)
                if (listDevice.Count > 0)
                {
                    if (nowFormId == UserCenterResourse.NowActionFormID && mode == ShowErrorMode.YES)
                    {
                        //获取设备列表失败
                        //[XXXX]网关回复超时,请稍后再试
                        string msg = Language.StringByID(R.MyInternationalizationString.uGetDeviceListFail);
                        msg += "\r\n[" + HdlGatewayLogic.Current.GetGatewayName(zbGateway).ToString() + "]";
                        msg = UserCenterLogic.CombineGatewayTimeOutMsg(msg, null, "回复超时", false);
                        this.ShowTipMsg(msg);
                    }
                    statu = -1;
                    return null;
                }
                else
                {
                    if (nowFormId == UserCenterResourse.NowActionFormID && mode == ShowErrorMode.YES)
                    //网络不稳定,设备列表信息缺损,则采用按序号获取设备
                    statu = this.GetDeviceListFromGatewayByMac(gatewayId, ref listDevice, ref listFucDevice, dicMacPointCount, useLocalConnect);
                    if (statu == 2)
                    {
                        //网络不稳定,设备列表信息缺损
                        string msg = Language.StringByID(R.MyInternationalizationString.uNetworkUnStableAndDeviceInfoIsNotFull);
                        this.ShowTipMsg(msg);
                    }
                    statu = 2;
                }
                else
                {
                    if (mode == ShowErrorMode.YES)
                    {
                        //获取设备列表失败
                        //[XXXX]网关回复超时,请稍后再试
                        string msg = Language.StringByID(R.MyInternationalizationString.uGetDeviceListFail);
                        var localGw = HdlGatewayLogic.Current.GetLocalGateway(gatewayId);
                        if (localGw != null)
                        {
                            msg += "\r\n[" + HdlGatewayLogic.Current.GetGatewayName(localGw).ToString() + "]";
                        }
                        msg = UserCenterLogic.CombineGatewayTimeOutMsg(msg, null, "回复超时", false);
                        this.ShowTipMsg(msg);
                    }
                    statu = -1;
                    return null;
                }
            }
            else
@@ -2971,6 +3084,60 @@
            }
            return listDevice;
        }
        /// <summary>
        /// 根据序号获取设备列表信息(只有在设备缺损的时候才调用这个函数) 1:正常 2:设备缺损
        /// </summary>
        /// <param name="gatewayId">网关id</param>
        /// <param name="listDevice">存储的设备对象集合</param>
        /// <param name="listFucDevice">需要变更功能类型的回路</param>
        /// <param name="dicNowPointCount">当前已经获取的Mac的端点总数</param>
        /// <param name="useLocalConnect">是否使用本地连接发送</param>
        /// <returns></returns>
        public int GetDeviceListFromGatewayByMac(string gatewayId, ref List<CommonDevice> listDevice, ref List<CommonDevice> listFucDevice, Dictionary<string, int> dicNowPointCount, bool useLocalConnect)
        {
            //首先先获取设备的mac列表
            var jObject33 = new Newtonsoft.Json.Linq.JObject { { "Cluster_ID", 0 }, { "Command", 87 } };
            var result = HdlGatewayLogic.Current.SendJobjectDataToGateway(gatewayId, "GetStatusRecord", jObject33.ToString(), "DeviceMACDeviceListRespon", 3, useLocalConnect);
            if (result.ErrorMsgDiv == -1 || result.ErrorMsgDiv == 0)
            {
                //如果网关没有对这个主题做出回应的话,则说明它是一个旧网关
                return 2;
            }
            var resultMac = Newtonsoft.Json.JsonConvert.DeserializeObject<ReceiptMacResult>(result.ReceiptData);
            //设备列表
            var listDeviceJson = new List<Newtonsoft.Json.Linq.JObject>();
            int statu = 0;
            foreach (var macInfo in resultMac.MACDeviceList)
            {
                if (dicNowPointCount.ContainsKey(macInfo.MacAddr) == true
                    && dicNowPointCount[macInfo.MacAddr] == macInfo.EPTotalNum)
                {
                    //如果这个mac的端点数一致,则说明已经接收齐了,不需要再次接收
                    continue;
                }
                //从网关读取指定Mac下的设备列表
                var jsonData = this.ReadDeviceListByMacFromGateway(gatewayId, macInfo.MacAddr, useLocalConnect, ref statu);
                foreach (var myData in jsonData)
                {
                    listDeviceJson.Add(myData);
                }
                if (statu != 1)
                {
                    //没有正常完成,则中断
                    break;
                }
            }
            //转化为设备列表
            var listTempDevice = this.ConvertJObjectToDevice(listDeviceJson, gatewayId, ref listFucDevice);
            for (int i = 0; i < listTempDevice.Count; i++)
            {
                listDevice.Add(listTempDevice[i]);
            }
            return statu == 1 ? 1 : 2;
        }
        /// <summary>
@@ -3012,6 +3179,36 @@
            return true;
        }
        /// <summary>
        /// 接收设备Mac列表的类
        /// </summary>
        private class ReceiptMacResult
        {
            /// <summary>
            /// mac总数
            /// </summary>
            public int MACDeviceTotalNum = 0;
            /// <summary>
            /// 设备mac列表
            /// </summary>
            public List<MacResult> MACDeviceList = new List<MacResult>();
        }
        /// <summary>
        /// 设备Mac的内容
        /// </summary>
        private class MacResult
        {
            /// <summary>
            /// 设备Mac
            /// </summary>
            public string MacAddr = string.Empty;
            /// <summary>
            /// mac端点的总数
            /// </summary>
            public int EPTotalNum = 0;
        }
        #endregion
        #region ■ 创建新设备对象相关_________________
@@ -3021,14 +3218,12 @@
        /// </summary>
        /// <param name="deviceType">设备类型</param>
        /// <param name="jobject">主题Data</param>
        /// <param name="zbGateway">网关对象</param>
        /// <param name="gwid">网关id</param>
        /// <returns></returns>
        private CommonDevice NewDeviceObjectByDeviceId(DeviceType deviceType, Newtonsoft.Json.Linq.JObject jobject, ZbGateway zbGateway)
        private CommonDevice NewDeviceObjectByDeviceId(DeviceType deviceType, Newtonsoft.Json.Linq.JObject jobject, string gwid)
        {
            string gwId = zbGateway.GwId;
            //根据设备类型创建设备对象的实例
            CommonDevice device = this.NewDeviceObjectByDeviceId(deviceType);
            CommonDevice device = this.NewDeviceObjectByDeviceId(deviceType, jobject.Value<int>("Epoint"));
            if (device == null)
            {
                return null;
@@ -3043,7 +3238,7 @@
            //设置设备主键类
            this.SetNewDeviceMainKeys(device, jobject);
            device.CurrentGateWayId = gwId;
            device.CurrentGateWayId = gwid;
            return device;
        }
@@ -3115,11 +3310,12 @@
        /// 根据设备Type创建对应的设备对象
        /// </summary>
        /// <param name="deviceType">设备Type</param>
        /// <param name="DeviceEpoint">设备端点(没有什么特殊需求的话,填0即可)</param>
        /// <returns></returns>
        public CommonDevice NewDeviceObjectByDeviceId(DeviceType deviceType)
        public CommonDevice NewDeviceObjectByDeviceId(DeviceType deviceType, int DeviceEpoint)
        {
            //根据设备类型创建设备对象的实例
            var device = CommonDevice.CommonDeviceByByteString((int)deviceType, "{\"DeviceID\":" + (int)deviceType + "}");
            var device = CommonDevice.CommonDeviceByByteString((int)deviceType, "{\"DeviceID\":" + (int)deviceType + ",\"DeviceEpoint\":" + DeviceEpoint + "}");
            if (device == null)
            {
                return null;
@@ -3592,17 +3788,17 @@
        /// </summary>
        Relay_FangyueFreshAirModul = 2310,
        /// <summary>
        /// 国标3路10A继电器小模块 镜像id:2311(临时)
        /// 国标3路10A继电器小模块 镜像id:2301
        /// </summary>
        Relay_NationalThreeLoadTenA = 2311,
        Relay_NationalThreeLoadTenA = 2301,
        /// <summary>
        /// 欧标2路5A继电器小模块 镜像id:2312(临时)
        /// 欧标2路5A继电器小模块 镜像id:2315
        /// </summary>
        Relay_EuropeanTwoLoadFiveA = 2312,
        Relay_EuropeanTwoLoadFiveA = 2315,
        /// <summary>
        /// 欧标14路干接点小模块 镜像id:2313(临时)
        /// 7路干接点输入输出模块 镜像id:2320
        /// </summary>
        Relay_EuropeanFourteenLoadDryContact = 2313,
        Relay_SevenLoadInOutPutDryContact = 2320,
        //=========★★调光器类(2500-2799)★★=========
        /// <summary>