using System; using System.Collections.Generic; using System.Text; using Newtonsoft.Json.Linq; namespace ZigBee.Device { [System.Serializable] public class CommonDevice { #region 需要保存的变量 /// /// 是否是自定义图片 /// public bool IsCustomizeImage = false; /// /// 设备图片 /// public string IconPath = string.Empty; /// /// 设备图片--在线或者选中状态 /// /// The online icon path. [Newtonsoft.Json.JsonIgnore] public string OnlineIconPath { get { if (string.IsNullOrEmpty(IconPath)) { return string.Empty; } var pathArr = IconPath.Split('.'); if (pathArr == null || string.IsNullOrEmpty(pathArr[0])) { return string.Empty; } return $"{pathArr[0]}Selected.png"; } } /// /// 当前网关的ID /// public string CurrentGateWayId; /// /// 当前设备类型 /// [Newtonsoft.Json.JsonIgnore] public DeviceType Type = DeviceType.UnKown; /// /// 设备的功能类型(此类型目前只针对继电器回路有效,默认未指定) /// public DeviceFunctionType DfunctionType = DeviceFunctionType.A未定义; /// /// MAC地址 /// public string DeviceAddr; /// /// 设备端口号 /// public int DeviceEpoint; /// /// 实际的设备id /// 258:color dimmable light,调关灯 /// 10:Door lock,门锁 /// 514:Window covering device,窗帘 /// 515:Window covering controller,窗帘控制器 /// 769:Thermostat,恒温面板/空调 /// 770:Temperature Sensor,温度传感器 /// 775:Temperature Sensor,湿度传感器 /// 262:Light sensor,光照传感器 /// 1026:sensor,传感器,具体类型的传感器DeviceType来区分 /// public int DeviceID; /// /// 2020.09.21追加:为了对应第三方设备,以及之后的多设备ID问题,追加的变量 /// 这是个特殊的,并且不保存在文件当中的ID, DeviceType由此值映射出来 /// 当设备是河东设备时,它与DeviceID相等 /// 当是真正的第三方设备时,它有可能与DeviceID不相等 /// 比如:2和256都是继电器,那么【DeviceID为2 或者 DeviceID为256】 而 【ExDeviceID固定为2】,【DeviceType为OnOffOutput】 /// 通俗来说:DeviceID是实际正确的ID,而【ExDeviceID是一种所属概念的ID】 /// [Newtonsoft.Json.JsonIgnore] public int ExDeviceID; /// /// 该字段主要针对IAS安防设备设立。所有IAS安防设备共用一个DeviceID为1026。所以要区分子设备类型,需要该字段。 /// 瞬间数据上报的传感器 (MomentStatus=1 TriggerZoneStatus>=1<报警>) /// 13:Motion sensor (运动传感器) /// 40 Fire sensor 烟雾传感器 /// 42 Water sensor 水侵传感器 /// 43 Carbon Monoxide (CO) 燃气传感器 /// 44 Personal emergency device 紧急按钮 /// 277 Key fob 钥匙扣 /// 持续数据上报(MomentStatus=0 TriggerZoneStatus>=1<报警> TriggerZoneStatus=0<取消报警>) /// 21: Door/Window 门窗传感器(有21和22,这里没有写错) /// 22:Door/Window 门窗传感器(有21和22,这里没有写错 /// public int IasDeviceType; /// /// 设备名称,以设备的MAC命名 /// public string DeviceName = "UnKown"; /// /// 设备端点名称,以设备端点名称命名 /// public string DeviceEpointName = "UnKown"; /// /// 用于判断设备的zigbee协议版本。 ///49246:ZLL1.0标准设备。 ///260: ZHA1.2标准设备、 Z3.0标准设备。 ///41440:ZGP3.0标准设备。 ///265:ZSE1.4标准设备。 /// [Newtonsoft.Json.JsonIgnore] public int Profile; /// /// 0:设备不在线 /// 1:设备在线 /// public int IsOnline; /// /// 1:路由设备 /// 2:终端设备,电池设备 /// public int ZigbeeType; /// /// 固件版本 /// public int ImgVersion; /// /// 硬件版本 /// public int HwVersion; /// /// 当前镜像类型id /// public int ImgTypeId; /// /// 驱动代码。为0时,表示zigbee协调器设备。其他值表示为虚拟驱动设备 /// public int DriveCode; /// /// 生产商名字 /// public string ManufacturerName = string.Empty; /// /// 模块ID(这个东西也叫【型号码】) /// public string ModelIdentifier = string.Empty; /// /// 生产日期 /// public string ProductionDate = string.Empty; /// /// 电源 /// public int PowerSource = -1; /// /// 序列号 /// public string SerialNumber = string.Empty; /// /// 输入簇列表 /// public List InClusterList = new List(); /// /// 输出簇列表 /// public List OutClusterList = new List(); /// /// 用于记录设备最新上报的属性状态信息 /// public List AttributeStatus = new List(); [Newtonsoft.Json.JsonIgnore] public DateTime LastDateTime = DateTime.MinValue; /// /// 是否已经读取了设备状态(此属性是给主页使用的) /// [Newtonsoft.Json.JsonIgnore] public bool HadReadDeviceStatu = false; /// /// 是否是低电量(这个变量目前是给传感器用的) /// [Newtonsoft.Json.JsonIgnore] public bool IsBatteryDown = false; /// /// 等待从网关接收数据的时间 /// /// The wait receive data time. [Newtonsoft.Json.JsonIgnore] public virtual int WaitReceiveDataTime { get { if (Device.ZbGateway.RemoteMqttClient != null && Device.ZbGateway.RemoteMqttClient.IsConnected) { return 10000; } else { return 3000; } } } /// /// 通过设备调用网关 /// [Newtonsoft.Json.JsonIgnore] public ZbGateway Gateway { get { if (string.IsNullOrEmpty(CurrentGateWayId)) { return null; } var gateWay = ZbGateway.GateWayList.Find(obj => (obj != null) && (obj.GwId == CurrentGateWayId)); if (gateWay == null) { gateWay = new ZbGateway { IsVirtual = true, }; gateWay.GwId = CurrentGateWayId; gateWay.HomeId = Shared.Common.Config.Instance.HomeId; ZbGateway.GateWayList.Add(gateWay); } return gateWay; } } /// /// 保存设备数据的文件名 /// [Newtonsoft.Json.JsonIgnore] public virtual string FilePath { get { //2020.09.21 对应第三方设备可以入网,设备文件名字,去掉 deviceType return "Device_" + DeviceAddr + "_" + DeviceEpoint.ToString().PadLeft(2, '0'); } } #endregion #region 设备保存及生成 /// /// 由设备字符串比特恢复设备对象 /// /// 设备DeviceType的整型值 /// 设备Json文件转为比特后再转为的字符串 /// public static CommonDevice CommonDeviceByByteString(int intDeviceType, string strDeviceByte) { //这是河东的特殊端点,不需要处理 if (intDeviceType == 49408) { return null; } CommonDevice device = null; if (intDeviceType == (int)DeviceType.DimmableLight || intDeviceType == 3) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); device.ExDeviceID = (int)DeviceType.DimmableLight; } else if (intDeviceType == (int)DeviceType.OnOffOutput || intDeviceType == 256) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); device.ExDeviceID = (int)DeviceType.OnOffOutput; } else if (intDeviceType == (int)DeviceType.ColorDimmerSwitch) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.LevelControlSwitch) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.WindowCoveringDevice) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.WindowCoveringController) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.OnOffSwitch) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.IASZone) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.OtaDevice || intDeviceType == (int)DeviceType.OtaPanelDevice) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.AirSwitch) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.Repeater) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.Thermostat) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.Transverter) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.DoorLock) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.TemperatureSensor) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.FreshAirHumiditySensor) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.FreshAir) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.PMSensor) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.ColorTemperatureLight) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.Buzzer) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.ColorDimmableLight) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else if (intDeviceType == (int)DeviceType.DimmerSwitch) { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } else { device = Newtonsoft.Json.JsonConvert.DeserializeObject(strDeviceByte); } //这是河东的特殊端点,不需要处理 if (device.DeviceEpoint == 242 && intDeviceType == 97) { return null; } if (device.ExDeviceID == 0) { //赋初始值 device.ExDeviceID = device.DeviceID; } //能少存一个变量就少存一个 device.Type = (DeviceType)device.ExDeviceID; return device; } /// /// 保存设备 /// public void Save() { if (Shared.Common.Global.IsExistsByHomeId(FilePath)) { return; } ReSave(); } /// /// 重新保存设备 /// public void ReSave() { if (Shared.Common.Config.Instance.Home.IsShowTemplate == true) { //展示模板时,不允许保存文件(防止属性上报用的) return; } if (IconPath == string.Empty) { //保存设备图标(这里会保存一次,下面就不用保存了) this.SaveDeviceIcon(); return; } Shared.Common.Global.WriteFileByBytesByHomeId(FilePath, System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(this))); } /// /// 保存设备图标 /// private void SaveDeviceIcon() { if (IconPath == string.Empty) { //干接点 if (this.Type == DeviceType.OnOffSwitch) { IconPath = "Device/DryContact.png"; } else if (this.Type == DeviceType.ColorDimmableLight) { //彩灯 IconPath = "Device/ColorLight.png"; } else if (this.Type == DeviceType.DimmableLight) { //调光器 IconPath = "Device/Light.png"; } else if (this.Type == DeviceType.ColorTemperatureLight) { //色温灯 IconPath = "Device/ColorLightTemperature.png"; } else if (this.Type == DeviceType.OnOffOutput) { //继电器 IconPath = "Device/RelayEpoint.png"; } else if (this.Type == DeviceType.Thermostat) { //空调 IconPath = "Device/AirConditionerEpoint.png"; } else if (this.Type == DeviceType.FreshAir) { //新风 IconPath = "Device/FreshAirEpoint.png"; } else if (this.Type == DeviceType.PMSensor) { //PM2.5空气质量传感器 IconPath = "Device/AirQualitySensorEpoint.png"; } else if (this.Type == DeviceType.FreshAirHumiditySensor) { //湿度传感器 IconPath = "Device/SensorHumidity.png"; } else if (this.Type == DeviceType.TemperatureSensor) { if (((TemperatureSensor)this).SensorDiv == 1) { //温度传感器 IconPath = "Device/SensorTemperature.png"; } else if (((TemperatureSensor)this).SensorDiv == 2) { //湿度传感器 IconPath = "Device/SensorHumidity.png"; } } else if (this.Type != DeviceType.UnKown) { //其他的图标有点特殊 string unSelectPic = string.Empty; string selectPic = string.Empty; Shared.Phone.HdlDeviceCommonLogic.Current.GetDeviceObjectIcon(new List { this }, ref unSelectPic, ref selectPic); IconPath = unSelectPic; } Shared.Common.Global.WriteFileByBytesByHomeId(FilePath, System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(this))); } } #endregion #region 输入输出镞定义 /// /// 设备最新上报的属性状态信息 /// [System.Serializable] public class AttributeStatusObj { /// /// 属性簇id /// public int ClusterId; /// /// 属性id /// public int AttributeId; /// /// 属性值,这个东西不需要什么高位在后低位在前,它已经是转为了10进制 /// public int AttributeData; /// /// 属性状态最后更新的utc时间戳 /// public int ReportTime; } /// /// 输入簇 /// [System.Serializable] public class InClusterObj { /// /// 设备支持的输入功能 /// 0:Basic,设备支持“基础属性” /// 3:Identify,设备支持“识别功能” /// 4:Groups,设备支持“组功能” /// 5:Scenes,设备支持“场景功能” /// 6:on/off,设备支持“开关功能” /// 开关功能的设备如:调关灯/继电器/窗帘等。。。 /// 8:Level Control,设备支持“亮度调节功能” /// 亮度调节功能的设备如:调关灯。。。 /// 257:Door Lock,设备支持“门锁功能” /// 门锁功能的设备如:门锁。。。 /// 258:Window Covering,设备支持“窗帘控制功能” /// 窗帘控制功能的设备如:窗帘/开合帘/卷帘。。。 /// 513:Thermostat,设备支持“恒温器功能” /// 恒温器功能的设备如:空调。。。 /// 768:Color Control,设备支持“颜色调节功能” /// 颜色调节功能的设备如:调光灯。。。 /// 1026:Temperature Measurement,设备支持“温度测量功能” /// 温度测量功能的设备如:温度传感器。。。 /// 1029:Relative Humidity Measurement,设备支持“湿度测量功能” /// 湿度测量功能的设备如:湿度传感器。。。 /// 1066:Pm2.5 Measurement,设备支持“pm2.5测量功能” /// Pm2.5测量功能的设备如:Pm2.5传感器。。。 /// public int InCluster; } /// /// 输出簇 /// [System.Serializable] public class OutClusterObj { /// /// 设备支持的输出功能 /// 0:Basic,设备支持“基础属性” /// 3:Identify,设备支持“识别功能” /// 4:Groups,设备支持“组功能” /// 5:Scenes,设备支持“场景功能” /// 6:on/off,设备支持“开关功能” /// 开关功能的设备如:调关灯/继电器/窗帘等。。。 /// 8:Level Control,设备支持“亮度调节功能” /// 亮度调节功能的设备如:调关灯。。。 /// 257:Door Lock,设备支持“门锁功能” /// 门锁功能的设备如:门锁。。。 /// 258:Window Covering,设备支持“窗帘控制功能” /// 窗帘控制功能的设备如:窗帘/开合帘/卷帘。。。 /// 513:Thermostat,设备支持“恒温器功能” /// 恒温器功能的设备如:空调。。。 /// 768:Color Control,设备支持“颜色调节功能” /// 颜色调节功能的设备如:调光灯。。。 /// 1026:Temperature Measurement,设备支持“温度测量功能” /// 温度测量功能的设备如:温度传感器。。。 /// 1029:Relative Humidity Measurement,设备支持“湿度测量功能” /// 湿度测量功能的设备如:湿度传感器。。。 /// public int OutCluster; } /// /// 支持的属性数据 /// [System.Serializable] public class AttributeObj { /// /// 响应的属性ID /// public int AttributeId; /// /// 属性值的数据类型 /// public int AttributeType; } /// /// 设备上报的属性数据 /// [System.Serializable] public class AttributeDataObj { /// /// 属性id /// public int AttributeId; /// /// 要报告属性的数据类型 /// public int AttriButeDataType; /// /// AttriButeData占用的字节数 /// public int AttriButeDataLength; /// /// 属性值 /// public int AttriButeData = 999; /// /// 属性数据16进制转字符 /// public string AttriButeDataHex; } /// /// Command数组 /// [System.Serializable] public class CommandObj { /// /// 支持的命令id /// public int commandId; } #endregion #region 获取已入网设备信息 /// /// 网关中的设备信息 /// [Newtonsoft.Json.JsonIgnore] public DeviceInfoData DeviceInfo = null; /// /// 网关中的设备信息 /// [System.Serializable] public class DeviceInfoData { /// /// 入网设备总数。等于0时,表示没有设备信息,下面字段将不存在。 /// public int TotalNum; /// /// 标识当前设备是发送的是第几个设备。DeviceNum从1开始每发送一个设备信息,下一个设备信息的DeviceNum将加1。直到DeviceNum等于TotalNum说明所有设备信息发送完毕。 /// public int DeviceNum; /// /// 入网的utc时间戳 /// public int JoinTime; /// /// 1:路由器设备 /// 2:终端设备 /// public int ZigbeeType; /// /// 设备网络地址 /// public int NwkAddr; /// /// 该字段主要针对IAS安防设备设立。所有IAS安防设备共用一个DeviceID为1026。所以要区分子设备类型,需要该字段。 /// 13:Motion sensor (运动传感器) /// 43:Carbon Monoxide sensor (一氧化碳传感器) /// 44:Personal emergency device (紧急按钮) /// public int DeviceType; /// /// 用于判断设备的zigbee协议版本。 ///49246:ZLL1.0标准设备。 ///260: ZHA1.2标准设备、 Z3.0标准设备。 ///41440:ZGP3.0标准设备。 ///265:ZSE1.4标准设备。 /// public int Profile; /// /// 设备mac名称 /// public string MacName; /// /// 设备名(Mac+断点命名的) /// public string DeviceName; /// /// 0:设备不在线 /// 1:设备在线 /// public int IsOnline; /// /// 当前运行程序版本信息。 最大64字节 /// public int ImgVersion; /// /// 硬件版本 /// public int HwVersion; /// /// 当前镜像类型id /// public int ImgTypeId; /// /// 驱动代码。为0时,表示zigbee协调器设备。其他值表示为虚拟驱动设备 /// public int DriveCode; /// /// 厂商名称 /// public string ManufacturerName = string.Empty; /// /// 模块ID /// public string ModelIdentifier = string.Empty; /// /// 好像是序列号 /// public string ProductCode = string.Empty; /// /// 设备功能类型(空气开关和继电器专用) /// public int FunctionType = -1; /// /// 输入簇列表 /// public List InClusterList = new List(); /// /// 输出簇列表 /// public List OutClusterList = new List(); /// /// 用于记录设备最新上报的属性状态信息。最大支持记录16个属性状态,且只记录属性值长度不大于4字节的数据。 /// public List AttributeStatus = new List(); } #endregion #region 错误结果定义 /// /// 网关信息错误反馈共通 /// [System.Serializable] public class ErrorResponCommon { /// /// 错误信息 /// public string errorMessageBase; /// /// 网关信息错误反馈 /// 当网关接收到客户端信息后,出现以下异常情况将反馈错误。 /// public ErrorResponData errorResponData; } /// /// 网关信息错误反馈 /// 当网关接收到客户端信息后,出现以下异常情况将反馈错误。 /// [System.Serializable] public class ErrorResponData { /// /// Error参数含义 ///1:网关无法解析命令数据。 ///2:协调器正在升级或备份/恢复数据 ///3:操作设备/组/场景不存在 ///4:其他错误 ///5:数据传输错误(在某次客户端向网关发送数据的过程中,网关在合理时间范围内接收客户端数据不完整导致该错误发生。如客户端向网关一次发送100个字节的数据,但网关等待接收了一秒只接收了80个字节。发生该错误,网关将主动关闭客户端连接) /// public int Error; } /// /// 网关错误信息具体内容 /// public static string ErrorMess(int err) { string message = ""; switch (err) { case 1: message = " 网关无法解析命令数据。"; break; case 2: message = " 协调器正在升级或备份 / 恢复数据。"; break; case 3: message = "操作设备 / 组 / 场景不存在"; break; case 4: message = " 其他错误"; break; case 5: message = " 数据传输错误(在某次客户端向网关发送数据的过程中,网关在合理时间范围内接收客户端数据不完整导致该错误发生。如客户端向网关一次发送100个字节的数据,但网关等待接收了一秒只接收了 个字节。发生该错误,网关将主动关闭客户端连接)"; break; default: break; } return message; } #endregion #region 修改设备端口名称 /// /// 重命名设备,网关反馈具体信息 /// [System.Serializable] public class DeviceRenameAllData { /// /// 错误信息 /// public string errorMessageBase; /// /// 网关信息错误反馈 /// 当网关接收到客户端信息后,出现以下异常情况将反馈错误。 /// public ErrorResponData errorResponData; /// /// 设备名称修改 /// public DeviceRenameResponseData deviceRenameData; } /// /// 设备名称修改 /// [System.Serializable] public class DeviceRenameResponseData { /// /// 0:修改成功 /// 1:修改失败 /// public int Result; /// /// 修改后的设备名称 /// public string DeviceName; } #endregion #region 修改设备mac名称 /// /// 修改设备mac名称数据,网关反馈具体信息 /// [System.Serializable] public class RenameDeviceMacNameAllData : ErrorResponCommon { /// /// 修改设备mac名称数据 /// public RenameDeviceMacNameData renameDeviceMacNameData; } /// /// 修改设备mac名称数据 /// [System.Serializable] public class RenameDeviceMacNameData { /// /// 0:修改成功 /// 1:修改失败,mac不存在 /// public int Result; /// /// 修改后的设备名称 /// public string MacName; } #endregion #region 一键更新四寸屏按键属性 /// /// 同步设备功能 /// /// public async System.Threading.Tasks.Task SyncMsgToBindSource(string deviceAddr, int deviceEpoint) { if (Gateway == null) { return null; } return await System.Threading.Tasks.Task.Run(async () => { SynchronizationDeviceResponseAllData resContent = null; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { resContent = new SynchronizationDeviceResponseAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { resContent = new SynchronizationDeviceResponseAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "Bind/SyncMsgToBindSourceRespon") { var res = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"]["Result"].ToString()); if (res == null) { resContent = new SynchronizationDeviceResponseAllData { errorMessageBase = "网关返回的数据为空" }; } else { resContent = new SynchronizationDeviceResponseAllData { result = res }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; Gateway.Actions = action; DebugPrintLog("Bind/SyncMsgToBindSourceRespon_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", deviceAddr }, { "Epoint", deviceEpoint }, { "Cluster_ID", 0 }, { "Command", 5010 } }; Gateway.Send("Bind/SyncMsgToBindSource", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (resContent != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { resContent = new SynchronizationDeviceResponseAllData { errorMessageBase = " 回复超时,请重新操作" }; } Gateway.Actions -= action; DebugPrintLog("Bind/SyncMsgToBindSource_Actions 退出" + System.DateTime.Now.ToString()); return resContent; }); } /// /// 同步设备,网关反馈具体信息 /// [System.Serializable] public class SynchronizationDeviceResponseAllData { /// /// 错误信息 /// public string errorMessageBase; /// /// 网关信息错误反馈 /// 当网关接收到客户端信息后,出现以下异常情况将反馈错误。 /// public ErrorResponData errorResponData; /// /// 同步结果 /// 0:成功:网关内部自动写入设备目标名字、设备目标功能类型、场景目标名字、utc时间写入4寸屏 /// 1:失败 /// public int result; } #endregion #region 删除设备(使设备离网) /// /// 删除设备(使设备离网) /// /// The device async. /// Remove data. public async System.Threading.Tasks.Task DeleteDeviceAsync(ZigBee.Device.CommonDevice.RemoveDeviceData removeData) { if (Gateway == null || removeData == null) { return null; } return await System.Threading.Tasks.Task.Run(async () => { RemoveDeviceResponseAllData d = null; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new RemoveDeviceResponseAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new RemoveDeviceResponseAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "RemoveDeviceRespon") { var removeDeviceResponseData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (removeDeviceResponseData == null) { d = new RemoveDeviceResponseAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new RemoveDeviceResponseAllData { removeDeviceResponseData = removeDeviceResponseData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; Gateway.Actions += action; DebugPrintLog("RemoveDevice_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { if (removeData != null) { var jObject = new JObject { { "Cluster_ID", 0 }, { "Command", 99 } }; var deviceAddrList = new JArray { }; foreach (var a in removeData.DeviceAddrList) { var dd = new JObject { { "DeviceAddr", a.DeviceAddr } }; deviceAddrList.Add(dd); } var data = new JObject { { "CompelClear", removeData.CompelClear }, { "DeviceAddrList", deviceAddrList } }; jObject.Add("Data", data); Gateway.Send(("RemoveDevice"), jObject.ToString()); } } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new RemoveDeviceResponseAllData { errorMessageBase = " 回复超时,请重新操作" }; } Gateway.Actions -= action; DebugPrintLog("RemoveDevice_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 需要删除设备的数据 /// [System.Serializable] public class RemoveDeviceData { /// /// 0:不强制清除。需要节点设备反馈离网确认信息后才能删除设备信息。 ///1:强制清除。不需要节点设备反馈离网确认信息,直接删除设备信息。 ///说明:正常情况下让节点设备离网,需要节点设备在线,节点设备反馈离网确认信息后网关方可删除该设备的设备信息。但如果设备已经损坏,或已经通过外部功能离网,此时节点设备已经无法反馈离网确认信息,面对这种情况,要删除保存在网关上的该节点设备的设备信息,需要将该字段赋值为1,网关强制删除该设备信息,不需要节点设备确认。 /// public int CompelClear = 1; /// /// 出网设备列表 /// public List DeviceAddrList = new List(); } /// /// 场景信息 /// public class RemoveDeviceListInfo { /// /// 设备mac地址 /// public string DeviceAddr; } /// /// 移除设备,网关反馈具体信息 /// [System.Serializable] public class RemoveDeviceResponseAllData { /// /// 错误信息 /// public string errorMessageBase; /// /// 网关信息错误反馈 /// 当网关接收到客户端信息后,出现以下异常情况将反馈错误。 /// public ErrorResponData errorResponData; /// /// 设备名称修改 /// public RemoveDeviceResponseData removeDeviceResponseData; } /// /// 删除设备回复数据 /// 返回结果Resul=,删除成功 /// [System.Serializable] public class RemoveDeviceResponseData { /// /// 0:删除成功 /// 删除失败 /// public int Result = 2; /// /// 出网设备列表 /// public List DeviceList = new List(); } /// /// 场景信息 /// [System.Serializable] public class DeviceListInfo { /// /// 设备ID /// public int Device_ID; /// /// 设备mac地址 /// public string MacAddr; /// /// 设备端口号 /// public int Epoint; } #endregion #region 识别设备 /// /// 识别设备 /// cluster=3,具有Identify(识别)功能,属于ZCL库 /// time:设置设备闪烁时间(秒)范围:0-65535 /// public void IdentifyControl(string deviceAddr, int deviceEpoint, int time) { if (Gateway == null) { return; } Action action = (topic, message) => { }; Gateway.Actions += action; System.Console.WriteLine("Identify_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", deviceAddr }, { "Epoint", deviceEpoint }, { "Cluster_ID", 3 }, { "Command", 0 }, { "SendMode", 2 } }; var data = new JObject { { "Time", time } }; jObject.Add("Data", data); Gateway.Send(("Identify"), jObject.ToString()); } catch { } Gateway.Actions -= action; System.Console.WriteLine("Identify_Actions 退出" + System.DateTime.Now.ToString()); } #endregion #region 设备属性状态上报 /// /// 获取设备当前属性状态 /// /// Cluster identifier. /// Attri bute identifier. public async void ReadAttri(Cluster_ID clusterID, AttriButeId attriButeId) { if (Gateway == null) { return; } await System.Threading.Tasks.Task.Run(async () => { //Action action = (topic, message) => { }; // Gateway.Actions += action; System.Console.WriteLine("GetDeviceStatus_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var JObject = new JObject { { "DeviceAddr",DeviceAddr }, { "Epoint", DeviceEpoint }, { "Cluster_ID", (int)clusterID }, { "Command", 108 } }; var attriBute = new JArray{ new JObject { { "AttriButeId", (int)attriButeId} } }; var data = new JObject { { "AttriBute", attriBute } }; JObject.Add("Data", data); Gateway?.Send(("GetDeviceStatus"), JObject.ToString()); } catch { } // Gateway.Actions -= action; System.Console.WriteLine("GetDeviceStatus_Actions 退出" + System.DateTime.Now.ToString()); }); } /// /// 设备属性状态上报 /// [Newtonsoft.Json.JsonIgnore] public DeviceStatusReportData DeviceStatusReport = new DeviceStatusReportData(); /// /// 设备属性状态上报 /// [System.Serializable] public class DeviceStatusReportData { /// /// 属性所在CluterID /// /// 设备支持的输入功能 /// 0:Basic,设备支持“基础属性” /// 3:Identify,设备支持“识别功能” /// 4:Groups,设备支持“组功能” /// 5:Scenes,设备支持“场景功能” /// 6:on/off,设备支持“开关功能” /// 开关功能的设备如:调关灯/继电器/窗帘等。。。 /// 8:Level Control,设备支持“亮度调节功能” /// 亮度调节功能的设备如:调关灯。。。 /// 257:Door Lock,设备支持“门锁功能” /// 门锁功能的设备如:门锁。。。 /// 258:Window Covering,设备支持“窗帘控制功能” /// 窗帘控制功能的设备如:窗帘/开合帘/卷帘。。。 /// 513:Thermostat,设备支持“恒温器功能” /// 恒温器功能的设备如:空调。。。 /// 768:Color Control,设备支持“颜色调节功能” /// 颜色调节功能的设备如:调光灯。。。 /// 1026:Temperature Measurement,设备支持“温度测量功能” /// 温度测量功能的设备如:温度传感器。。。 /// 1029:Relative Humidity Measurement,设备支持“湿度测量功能” /// 湿度测量功能的设备如:湿度传感器。。。 /// /// public int CluterID; /// /// 属性列表 /// public List AttriBute = new List(); } #endregion #region 设置可写属性的值 /// /// 设置可写属性的值 /// /// The writable value async. /// Gateway. /// 要配置的属性所在的cluster. /// 设置可写属性的数据 public async System.Threading.Tasks.Task SetWritableValueAsync(ZigBee.Device.ZbGateway gateway, int clusterID, SetWritableValueData setWritableValue) { if (gateway == null || setWritableValue == null) { return null; } return await System.Threading.Tasks.Task.Run(async () => { SetWritableValueResponAllData d = null; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new SetWritableValueResponAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new SetWritableValueResponAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "SetWritableValue_Respon") { var tempData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (tempData == null) { d = new SetWritableValueResponAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new SetWritableValueResponAllData { setWritableValueResponData = tempData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("SetWritableValue_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", DeviceEpoint }, { "Cluster_ID", clusterID }, { "Command", 120 } }; var data = new JObject { { "Undivided", setWritableValue.Undivided }, { "AttributeId", setWritableValue.AttributeId }, { "AttributeDataType", setWritableValue.AttributeDataType }, { "AttributeData", setWritableValue.AttributeData } }; jObject.Add("Data", data); gateway.Send("SetWritableValue", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new SetWritableValueResponAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("SetWritableValue_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 网关版本信息,网关反馈信息 /// [System.Serializable] public class SetWritableValueResponAllData : ErrorResponCommon { /// /// 网关版本信息 /// public SetWritableValueResponData setWritableValueResponData; } /// /// 设置可写属性的值的数据 /// [System.Serializable] public class SetWritableValueResponData { /// /// 配置属性所在的cluster /// public int Cluster; /// /// 0:配置成功(若配置成功,下面的AttributeId字段不存在) ///134:不支持该属性 ///135:无效的属性值 ///141:无效的数据类型 /// public int Status; /// /// 配置的属性ID(当Status=0 时,该字段将不存在 ,也就是只有失败的结果才会返回该字段) /// public int AttributeId; } /// /// 设置可写属性的值的数据 /// [System.Serializable] public class SetWritableValueData { /// /// 是否强制写入属性 ///0:否 ///1:强制写属性值 ///可缺省,默认为0。 /// public int Undivided; /// /// 属性id /// public int AttributeId; /// /// 属性数据类型 /// public int AttributeDataType; /// /// 写入数值 /// public int AttributeData; } #endregion #region 开关 /// ///开关控制(仅用于cluster=6的设备) /// 设备支持cluster=6的设备才能调用该接口 /// command的值 ///0 : 关闭 ///1: 打开 ///2:取反 /// public void SwitchControl(int command) { try { var jobject = new JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", DeviceEpoint }, { "Cluster_ID", 6 }, { "Command", command }, { "SendMode", 2 } }; Gateway?.Send(("DeviceControl"), jobject.ToString()); System.Console.WriteLine("SwitchControl_发送数据" + "_" + jobject.ToString() + "_" + System.DateTime.Now.ToString()); } catch { } } #endregion #region ZCL库-发现属性 /// ///ZCL库-发现属性(如果返回为空,可能是设备不是标准设备,不支持这条命令) /// 获取设备的某个Cluster所支持的Attributes /// gateway:当前网关 /// clusterID:需要查询的cluster /// 读Panel的属性:clusterID=6 /// 读亮度的属性:clusterID=8 /// public async System.Threading.Tasks.Task ClusterOwnAttributesAsync(ZigBee.Device.ZbGateway gateway, int clusterID) { if (gateway == null) { return null; } return await System.Threading.Tasks.Task.Run(async () => { ClusterOwnAttributesResponAllData d = null; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new ClusterOwnAttributesResponAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new ClusterOwnAttributesResponAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "Cluster/OwnAttributes_Respon") { var clusterOwnAttributesResponData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); var tempAttributes = Newtonsoft.Json.Linq.JArray.Parse(jobject["Data"]["Attribute"].ToString()); for (int m = 0; tempAttributes != null && m < tempAttributes.Count; m++) { var tempAttribute = tempAttributes[m]; clusterOwnAttributesResponData.AttributeList.Add(Newtonsoft.Json.JsonConvert.DeserializeObject(tempAttribute.ToString())); } if (clusterOwnAttributesResponData == null) { d = new ClusterOwnAttributesResponAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new ClusterOwnAttributesResponAllData { clusterOwnAttributesResponData = clusterOwnAttributesResponData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("Cluster/OwnAttributes_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", DeviceEpoint }, { "Cluster_ID", clusterID }, { "Command", 301 } }; gateway.Send("Cluster/OwnAttributes", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new ClusterOwnAttributesResponAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("Cluster/OwnAttributes_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 发现属性,网关反馈信息 /// [System.Serializable] public class ClusterOwnAttributesResponAllData : ErrorResponCommon { /// /// 网关版本信息 /// public ClusterOwnAttributesResponData clusterOwnAttributesResponData; } [System.Serializable] public class ClusterOwnAttributesResponData { /// /// 查询的cluste /// public int Cluster; /// /// 设备属性列表 /// public List AttributeList = new List(); } #endregion #region ZCL库-支持的Command /// ///ZCL库-设备某cluster所支持的Command ;(如果返回为空,可能是设备不是标准设备,不支持这条命令) /// 获取设备某cluster所支持的Command /// gateway:当前网关 /// clusterID:需要查询的cluster /// public async System.Threading.Tasks.Task ClusterOwnCommandAsync(ZigBee.Device.ZbGateway gateway, int clusterID) { if (gateway == null) { return null; } return await System.Threading.Tasks.Task.Run(async () => { ClusterOwnCommandResponAllData d = null; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new ClusterOwnCommandResponAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new ClusterOwnCommandResponAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "Cluster/OwnCommand_Respon") { var clusterOwnCommandResponData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (clusterOwnCommandResponData == null) { d = new ClusterOwnCommandResponAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new ClusterOwnCommandResponAllData { clusterOwnCommandResponData = clusterOwnCommandResponData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("Cluster/OwnCommand_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", DeviceEpoint }, { "Cluster_ID", clusterID }, { "Command", 302 } }; gateway.Send("Cluster/OwnCommand", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new ClusterOwnCommandResponAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("Cluster/OwnCommand_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 设备某cluster所支持的Command数据,网关反馈信息 /// [System.Serializable] public class ClusterOwnCommandResponAllData : ErrorResponCommon { /// /// 网设备某cluster所支持的Command数据 /// public ClusterOwnCommandResponData clusterOwnCommandResponData; } /// /// 设备某cluster所支持的Command数据 /// [System.Serializable] public class ClusterOwnCommandResponData { /// /// 查询的cluste /// public int Cluster; /// /// 设备属性列表 /// public List Command = new List(); } #endregion #region 设定OTA升级固件.; /// /// 设定OTA升级固件 /// /// The NVA sync. /// Gateway. /// O TAI mage name:升级镜像名称 public async System.Threading.Tasks.Task UpgradeDeviceAsync(ZigBee.Device.ZbGateway gateway, string oTAImageName) { return await System.Threading.Tasks.Task.Run(async () => { OTASetImageResponseAllData d = null; ; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new OTASetImageResponseAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new OTASetImageResponseAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "OTA/SetImage_Respon") { var oTASetImageData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (oTASetImageData == null) { d = new OTASetImageResponseAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new OTASetImageResponseAllData { otaSetImageData = oTASetImageData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("OTA/SetImage_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "Cluster_ID", 25 }, { "Command", 30 } }; var data = new JObject { { "OTAImageName", oTAImageName }, { "OTAImagePath", "/tmp" } }; jObject.Add("Data", data); gateway.Send(("OTA/SetImage"), jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new OTASetImageResponseAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("OTA/SetImage_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 设备进行OTA升级,网关反馈具体信息 /// [System.Serializable] public class OTASetImageResponseAllData : ErrorResponCommon { /// /// 保存zigbee协调器组网信息 /// public OTASetImageData otaSetImageData; } [System.Serializable] public class OTASetImageData { /// /// 0:成功 ///1:没有找到文件或打开文件失败 ///2:当前有节点设备正在ota升级,原来的ota固件还在占用,不能重新设定固件。若要重新设定ota固件,则需要先用终止升级指令终止所有正在升级的节点设备。 /// public int Result; /// /// 该ota固件的制造商ID(Result = 0时存在) /// public int Manufacture; /// /// 该ota固件的固件类型id(Result = 0时存在) /// public int ImgTypeId; /// /// 该ota固件的版本(Result = 0时存在) /// public int FileVersion; /// /// 固件大小 /// public int FileSize; /// ///正在升级的ota节点设备列(Result=2时,该字段才存在) /// public List DeviceList = new List(); } /// /// 输入簇 /// [System.Serializable] public class OTADeviceList { /// /// MAC地址 /// public string MacAddr; /// /// 设备端口号,当升级设备,HDL的设备大多数的端点默认是200 /// public int Epoint = 200; } #endregion #region 启动升级; /// /// 设定OTA升级固件 /// /// The NVA sync. /// Gateway. /// O TAI mage name:升级镜像名称 public async System.Threading.Tasks.Task StartDeviceUpdateAsync(ZigBee.Device.ZbGateway gateway, StartUpdateData startUpdateData) { return await System.Threading.Tasks.Task.Run(async () => { StartDeviceUpdateResponseAllData d = null; ; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new StartDeviceUpdateResponseAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new StartDeviceUpdateResponseAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "OTA/StartUpdate_Respon") { var startUpdateDeviceData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (startUpdateDeviceData == null) { d = new StartDeviceUpdateResponseAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new StartDeviceUpdateResponseAllData { startUpdateDeviceData = startUpdateDeviceData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("OTA/StartUpdate_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { if (startUpdateData != null) { var jObject = new JObject { { "Cluster_ID", 25 }, { "Command", 0 } }; var deviceList = new JArray { }; foreach (var de in startUpdateData.DeviceList) { var dInfo = new JObject{ { "MacAddr",de.MacAddr}, { "Epoint", de.Epoint} }; deviceList.Add(dInfo); } var data = new JObject { { "DeviceList", deviceList } }; jObject.Add("Data", data); gateway.Send(("OTA/StartUpdate"), jObject.ToString()); } } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < 30 * 1000) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > 30 * 1000) { d = new StartDeviceUpdateResponseAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("OTA/StartUpdate_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 启动升级,网关反馈具体信息 /// [System.Serializable] public class StartDeviceUpdateResponseAllData { /// /// 错误信息 /// public string errorMessageBase; /// /// 网关信息错误反馈 /// 当网关接收到客户端信息后,出现以下异常情况将反馈错误。 /// public ErrorResponData errorResponData; /// /// 保存zigbee协调器组网信息 /// public StartDeviceUpdateData startUpdateDeviceData; } [System.Serializable] public class StartDeviceUpdateData { /// /// 0:正常 /// 1:启动失败,未设定升级固件 /// public int Result = 999; /// ///升级设备列表 /// public List DeviceList = new List(); } /// /// 输入簇 /// [System.Serializable] public class OTAStartUpdateList { /// /// MAC地址 /// public string MacAddr; /// /// 设备端口号,当升级设备,HDL的设备大多数的端点默认是200 /// public int Epoint = 200; /// /// 设备名称 /// public string DeviceName; } /// /// 启动升级 /// [Newtonsoft.Json.JsonIgnore] public OTAScheduleResponData oTAScheduleResponData; [System.Serializable] public class OTAScheduleResponData { /// /// 0:节点设备可进行OTA升级(如果设备在线,且支持OTA升级,则设备首先会反馈该状态,说明该设备OTA升级已启动) ///1:正在升级(设备处于下载OTA升级固件状态将反馈该状 ///2:升级完成(OTA升级完成,节点设备反馈该状态) ///3:升级失败,响应超时 ///150:无效的OTA升级固件(下载完成后,由节点设备判断固件是否有效) ///153:客户端仍需更多的OTA升级固件 ///149:升级终止 /// public int Status = 999; /// /// 升级百分比。(当Status=1时有效) /// public int Percent = 999; } [System.Serializable] public class StartUpdateData { /// ///升级设备列表 /// public List DeviceList = new List(); } #endregion #region 客户端向节点设备透传数据. /// /// 客户端向节点设备透传数据 /// passData:透传数据(这里的值是在各个设备对象中复制好的,传进来即可) /// 透传数据返回后,可以调用各个设备对象中获取相应的处理完成的数据 /// public async System.Threading.Tasks.Task ClientDataPassthroughAsync(ZigBee.Device.ZbGateway gateway, string passData) { return await System.Threading.Tasks.Task.Run(async () => { ClientDataPassthroughResponseAllData d = null; ; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new ClientDataPassthroughResponseAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new ClientDataPassthroughResponseAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "ZbDataPassthrough") { var clientDataPassthroughResponseData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (clientDataPassthroughResponseData == null) { d = new ClientDataPassthroughResponseAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new ClientDataPassthroughResponseAllData { clientDataPassthroughResponseData = clientDataPassthroughResponseData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("ClientDataPassthrough_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", 200 }, { "Cluster_ID", 64513 }, { "Command", 0 } }; var data = new JObject { { "PassData", passData } }; jObject.Add("Data", data); gateway.Send("ClientDataPassthrough", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new ClientDataPassthroughResponseAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("ClientDataPassthrough_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 客户端向节点设备透传数据,网关反馈具体信息 /// [System.Serializable] public class ClientDataPassthroughResponseAllData : ErrorResponCommon { /// /// 客户端向节点设备透传数据 /// public ClientDataPassthroughResponseData clientDataPassthroughResponseData; } /// /// 客户端向节点设备透传数据 /// [Newtonsoft.Json.JsonIgnore] public ClientDataPassthroughResponseData clientDataPassthroughResponseData = new ClientDataPassthroughResponseData(); [System.Serializable] public class ClientDataPassthroughResponseData { /// /// 透传的数据,最大256个字符,也就是透传128个字节 /// public string PassData; } /// /// 启用或关闭节点设备透传数据上传接口,网关反馈具体信息 /// [System.Serializable] public class OnZbDataPassthroughResponseAllData : ErrorResponCommon { /// /// 启用或关闭节点设备透传数据上传接口 /// public OnZbDataPassthroughData onZbDataPassthroughData; } [System.Serializable] public class OnZbDataPassthroughData { /// /// 已经转换成字符格式的16进制的透传数据 /// public string PassData; } #endregion #region 下载云端固件. /// /// 下载云端设备固件 /// /// The file async. /// Gateway:当前网关 /// Distributed mark:固件唯一标识 /// Image name:固件版本 public async System.Threading.Tasks.Task DownloadFileAsync(ZigBee.Device.ZbGateway gateway, string distributedMark, string imageName) { if (gateway == null) { return null; } return await System.Threading.Tasks.Task.Run(async () => { DownloadFileResponAllData d = null; ; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new DownloadFileResponAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new DownloadFileResponAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "DownloadFile_Respon") { var downloadFileResponData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (downloadFileResponData == null) { d = new DownloadFileResponAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new DownloadFileResponAllData { downloadFileResponData = downloadFileResponData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; try { var jObject = new JObject { { "Cluster_ID", 0 }, { "Command", 6000 } }; var data = new JObject { { "DistributeMark", distributedMark}, { "DownloadPath", "/tmp" }, { "FileName", imageName } }; jObject.Add("Data", data); gateway.Send("DownloadFile", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < 30 * 1000) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > 30 * 1000) { d = new DownloadFileResponAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("DownloadFile_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 网关系统升级,网关反馈具体信息 /// [System.Serializable] public class DownloadFileResponAllData : ErrorResponCommon { /// /// 下载云端固件 /// public DownloadFileResponData downloadFileResponData; } /// /// 下载云端固件 /// [System.Serializable] public class DownloadFileResponData { /// /// 下载固件的唯一标识 /// public string DistributeMark; /// /// 0:成功,开启启动下载。 ///1:失败,文件创建失败。 ///2:失败,云端没有找到该标识文件。 ///3:网关未能连接云端。 ///4:其他错误。 /// public int Result; } /// /// 下载进度 /// [Newtonsoft.Json.JsonIgnore] public DownloadFileProgressResponData downloadFileProgressResponData; /// /// 下载进度 /// [System.Serializable] public class DownloadFileProgressResponData { /// /// 下载固件的唯一标识 /// public string DistributeMark; /// ///0:下载成功 ///1:正在下载 ///2:下载失败 /// public int Status; /// ///文件总大小 /// public int TotalSize; /// ///当前已经下载文件大小 /// public int DownloadSize; /// ///下载进度,百分比。每百分之十反馈一次 /// public int DownloadPercent; } #endregion #region 终止设备升级; /// /// 终止设备升级 /// /// The NVA sync. /// Gateway. /// O TAI mage name:升级镜像名称 public async System.Threading.Tasks.Task KillUpdateAsync(ZigBee.Device.ZbGateway gateway, int deviceEpoint = 200) { return await System.Threading.Tasks.Task.Run(async () => { KillUpdateResponseAllData d = null; ; Action action = (topic, message) => { var gatewayID = topic.Split('/')[0]; var jobject = Newtonsoft.Json.Linq.JObject.Parse(message); if (topic == gatewayID + "/" + "Error_Respon") { var temp = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (temp == null) { d = new KillUpdateResponseAllData { errorMessageBase = "网关错误回复,且数据是空" }; } else { d = new KillUpdateResponseAllData { errorResponData = temp, errorMessageBase = ErrorMess(temp.Error) }; } } if (topic == gatewayID + "/" + "OTA/KillUpdate_Respon") { var killUpdateData = Newtonsoft.Json.JsonConvert.DeserializeObject(jobject["Data"].ToString()); if (killUpdateData == null) { d = new KillUpdateResponseAllData { errorMessageBase = "网关返回的数据为空" }; } else { d = new KillUpdateResponseAllData { killUpdateData = killUpdateData }; System.Console.WriteLine($"UI收到通知后的主题_{ topic}"); } } }; gateway.Actions += action; System.Console.WriteLine("OTA/KillUpdate_Actions 启动" + "_" + System.DateTime.Now.ToString()); try { var jObject = new JObject { { "DeviceAddr", DeviceAddr }, { "Epoint", deviceEpoint }, { "Cluster_ID", 25 }, { "Command", 5 } }; gateway.Send("OTA/KillUpdate", jObject.ToString()); } catch { } var dateTime = DateTime.Now; while ((DateTime.Now - dateTime).TotalMilliseconds < WaitReceiveDataTime) { await System.Threading.Tasks.Task.Delay(10); if (d != null) { break; } } if ((DateTime.Now - dateTime).TotalMilliseconds > WaitReceiveDataTime) { d = new KillUpdateResponseAllData { errorMessageBase = " 回复超时,请重新操作" }; } gateway.Actions -= action; System.Console.WriteLine("OTA/KillUpdate_Actions 退出" + System.DateTime.Now.ToString()); return d; }); } /// /// 终止设备升级,网关反馈具体信息 /// [System.Serializable] public class KillUpdateResponseAllData : ErrorResponCommon { /// /// 终止设备升级 /// public KillUpdateData killUpdateData; } [System.Serializable] public class KillUpdateData { /// ///0:终止成功 ///1:终止失败,设备并不处于OTA升级状态。 /// public int Result; } #endregion #region 私有协议网关和设备的默认回复 [System.Serializable] public class ResponseAllData : ErrorResponCommon { /// /// 按键指示灯颜色信息 /// public ResponseData responseData; } /// /// 私有协议网关和设备的默认回复 /// [System.Serializable] public class ResponseData { /// ///响应操作码(0-ffff) /// public string command; /// /// 状态值 /// 0--成功 1--失败 ff--无效 /// public int status = -1; } #endregion #region ■ 调试打印 /// /// 调试时打开打印信息,true:打印,false:不打印 /// /// Message. /// If set to true flage. public static void DebugPrintLog(string msg, bool flage = true) { #if DEBUG if (flage == true) { if (msg.Contains("DeviceStatusReport") == false) { System.Console.WriteLine(msg + " " + System.DateTime.Now.ToLongTimeString() + " " + System.DateTime.Now.Millisecond); } } #endif } #endregion } }