diff --git a/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 b/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 index 88c7ab1..0c2df2f 100644 Binary files a/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 and b/.vs/IoTGateway/DesignTimeBuild/.dtbcache.v2 differ diff --git a/.vs/IoTGateway/v17/.futdcache.v1 b/.vs/IoTGateway/v17/.futdcache.v1 index b05816c..e1f9d41 100644 Binary files a/.vs/IoTGateway/v17/.futdcache.v1 and b/.vs/IoTGateway/v17/.futdcache.v1 differ diff --git a/.vs/IoTGateway/v17/.suo b/.vs/IoTGateway/v17/.suo index 5661591..0dd8683 100644 Binary files a/.vs/IoTGateway/v17/.suo and b/.vs/IoTGateway/v17/.suo differ diff --git a/.vs/IoTGateway/v17/fileList.bin b/.vs/IoTGateway/v17/fileList.bin index 37febe1..07e7be0 100644 Binary files a/.vs/IoTGateway/v17/fileList.bin and b/.vs/IoTGateway/v17/fileList.bin differ diff --git a/IoTGateway.Model/SystemConfig.cs b/IoTGateway.Model/SystemConfig.cs index 536a40d..4748b37 100644 --- a/IoTGateway.Model/SystemConfig.cs +++ b/IoTGateway.Model/SystemConfig.cs @@ -31,7 +31,8 @@ namespace IoTGateway.Model [Display(Name = "百度物联网通信")] BaiduIoTCore =4, [Display(Name = "中移OneNet")] - OneNET =5 - + OneNET = 5, + [Display(Name = "ThingsCloud")] + ThingsCloud = 6 } } \ No newline at end of file diff --git a/IoTGateway/Areas/Config/Views/SystemConfig/Index.cshtml b/IoTGateway/Areas/Config/Views/SystemConfig/Index.cshtml index 527b61c..33eef27 100644 --- a/IoTGateway/Areas/Config/Views/SystemConfig/Index.cshtml +++ b/IoTGateway/Areas/Config/Views/SystemConfig/Index.cshtml @@ -5,5 +5,5 @@ -注意:目前实现了iotsharp和tb的遥测、属性上传以及RPC功能 +注意:目前实现了iotsharp、thingsboard、thingscloud的遥测、属性上传以及RPC功能 diff --git a/IoTGateway/iotgateway.db b/IoTGateway/iotgateway.db index 1610250..38a5c24 100644 Binary files a/IoTGateway/iotgateway.db and b/IoTGateway/iotgateway.db differ diff --git a/Plugins/Plugin/DeviceThread.cs b/Plugins/Plugin/DeviceThread.cs index b88a804..e6c9de8 100644 --- a/Plugins/Plugin/DeviceThread.cs +++ b/Plugins/Plugin/DeviceThread.cs @@ -258,8 +258,8 @@ namespace Plugin if (task != null) { _myMqttClient.OnExcRpc -= MyMqttClient_OnExcRpc; - _driver.Close(); tokenSource.Cancel(); + _driver.Close(); } } diff --git a/Plugins/Plugin/MyMqttClient.cs b/Plugins/Plugin/MyMqttClient.cs index 3f202bd..b83e747 100644 --- a/Plugins/Plugin/MyMqttClient.cs +++ b/Plugins/Plugin/MyMqttClient.cs @@ -120,6 +120,13 @@ namespace Plugin //Message: {"device": "Device A", "data": {"attribute1": "value1", "attribute2": 42}} Client.SubscribeAsync("devices/+/attributes/response/+", MqttQualityOfServiceLevel.ExactlyOnce); break; + case IoTPlatformType.ThingsCloud: + Client.SubscribeAsync("gateway/attributes/response", MqttQualityOfServiceLevel.ExactlyOnce); + Client.SubscribeAsync("gateway/attributes/get/response", MqttQualityOfServiceLevel.ExactlyOnce); + Client.SubscribeAsync("gateway/attributes/push", MqttQualityOfServiceLevel.ExactlyOnce); + Client.SubscribeAsync("gateway/event/response", MqttQualityOfServiceLevel.ExactlyOnce); + Client.SubscribeAsync("gateway/command/send", MqttQualityOfServiceLevel.ExactlyOnce); + break; case IoTPlatformType.AliCloudIoT: break; case IoTPlatformType.TencentIoTHub: @@ -149,6 +156,9 @@ namespace Plugin else if (e.ApplicationMessage.Topic.StartsWith($"devices/") && e.ApplicationMessage.Topic.Contains("/rpc/request/")) { ReceiveIsRpc(e); + }else if(e.ApplicationMessage.Topic== "gateway/command/send") + { + ReceiveTcRpc(e); } } catch (Exception ex) @@ -158,6 +168,10 @@ namespace Plugin return Task.CompletedTask; } + /// + /// thingsboard rpc + /// + /// private void ReceiveTbRpc(MqttApplicationMessageReceivedEventArgs e) { TBRpcRequest tBRpcRequest; @@ -179,6 +193,30 @@ namespace Plugin } + /// + /// thingscloud rpc + /// + /// + private void ReceiveTcRpc(MqttApplicationMessageReceivedEventArgs e) + { + TCRpcRequest tCRpcRequest; + try + { + tCRpcRequest = JsonConvert.DeserializeObject(e.ApplicationMessage.ConvertPayloadToString()); + OnExcRpc?.Invoke(Client, new RpcRequest() + { + Method = tCRpcRequest.RequestData.Method, + DeviceName = tCRpcRequest.DeviceName, + RequestId = tCRpcRequest.RequestData.RequestId, + Params = tCRpcRequest.RequestData.Params + }); + } + catch (Exception ex) + { + _logger.LogError($"ReceiveTbRpc:Topic:{e.ApplicationMessage.Topic},Payload:{e.ApplicationMessage.ConvertPayloadToString()}", ex); + } + + } private void ReceiveIsRpc(MqttApplicationMessageReceivedEventArgs e) { try @@ -217,6 +255,15 @@ namespace Plugin .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce).Build()); } + private Task ResponseTCRpc(TCRpcRequest tCRpcResponse) + { + string topic = $"command/reply/{tCRpcResponse.RequestData.RequestId}"; + return Client.PublishAsync(new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(JsonConvert.SerializeObject(tCRpcResponse)) + .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce).Build()); + } + private Task ResponseISRpc(ISRpcResponse rpcResult) { ///IoTSharp/Clients/RpcClient.cs#L65 var responseTopic = $"/devices/{deviceid}/rpc/response/{methodName}/{rpcid}"; @@ -269,11 +316,16 @@ namespace Plugin } - public Task UploadTelemetryDataAsync(string _devicename, object obj) + public Task UploadISTelemetryDataAsync(string _devicename, object obj) { return Client.PublishAsync(new MqttApplicationMessageBuilder().WithTopic($"devices/{_devicename}/telemetry").WithPayload(Newtonsoft.Json.JsonConvert.SerializeObject(obj)).Build()); } + public Task UploadTCTelemetryDataAsync(string _devicename, object obj) + { + var toSend = new Dictionary { { _devicename, obj } }; + return Client.PublishAsync("gateway/attributes", JsonConvert.SerializeObject(toSend)); + } public void ResponseRpc(RpcResponse rpcResponse) { try @@ -298,6 +350,9 @@ namespace Plugin Data = JsonConvert.SerializeObject(new Dictionary { { "success", rpcResponse.IsSuccess }, { "description", rpcResponse.Description } }) }); break; + case IoTPlatformType.ThingsCloud: + //官网API不需要回复的 + break; case IoTPlatformType.AliCloudIoT: break; case IoTPlatformType.TencentIoTHub: @@ -372,7 +427,13 @@ namespace Plugin case IoTPlatformType.IoTSharp: foreach (var payload in SendModel[device.DeviceName]) { - UploadTelemetryDataAsync(device.DeviceName, payload.Values); + UploadISTelemetryDataAsync(device.DeviceName, payload.Values); + } + break; + case IoTPlatformType.ThingsCloud: + foreach (var payload in SendModel[device.DeviceName]) + { + UploadTCTelemetryDataAsync(device.DeviceName, payload.Values); } break; case IoTPlatformType.AliCloudIoT: @@ -418,6 +479,9 @@ namespace Plugin break; case IoTPlatformType.OneNET: break; + case IoTPlatformType.ThingsCloud: + await Client.PublishAsync("gateway/connect", JsonConvert.SerializeObject(new Dictionary { { "device", DeviceName } })); + break; default: break; } @@ -446,6 +510,9 @@ namespace Plugin break; case IoTPlatformType.OneNET: break; + case IoTPlatformType.ThingsCloud: + await Client.PublishAsync("gateway/disconnect", JsonConvert.SerializeObject(new Dictionary { { "device", DeviceName } })); + break; default: break; } diff --git a/Plugins/PluginInterface/ThingsCloud/TCRpcRequest.cs b/Plugins/PluginInterface/ThingsCloud/TCRpcRequest.cs new file mode 100644 index 0000000..e4627ea --- /dev/null +++ b/Plugins/PluginInterface/ThingsCloud/TCRpcRequest.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PluginInterface.ThingsBoard +{ + public class TCRpcRequest + { + [JsonProperty(PropertyName = "device")] + public string DeviceName { get; set; } + [JsonProperty(PropertyName = "command")] + public TBRpcData RequestData { get; set; } + } + public class TCRpcData + { + [JsonProperty(PropertyName = "id")] + public string RequestId { get; set; } + [JsonProperty(PropertyName = "method")] + public string Method { get; set; } + [JsonProperty(PropertyName = "params")] + public Dictionary Params { get; set; } + } +} diff --git a/iotgateway.db b/iotgateway.db index 1610250..38a5c24 100644 Binary files a/iotgateway.db and b/iotgateway.db differ