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