[Azure]_Azure Service Bus Event Hubs應用於IoT:適用於任何裝置的傳輸使用(包含.NET以及JS的範例)
本文翻譯&整理&擴充專案做法原文來自:http://fabriccontroller.net/blog/posts/iot-with-azure-service-bus-event-hubs-authenticating-and-sending-from-any-type-of-device-net-and-js-samples/
前天發了一篇翻譯整理自Sandrino Di Mattia的文章,在:https://www.ntex.tw/wordpress/1983.html
如果你還沒看過上一篇,請先看上一篇,了解大概內容後再看本篇會比較清楚在幹嘛
下文有些步驟就直接省略了,只截圖重要的地方
本篇示範會利用多種方式,新版的.NET(HttpClient), 舊版的.NET(HttpWebRequest), JS, 這三種方式透過HTTPS認證傳輸
以及一種新版的.NET透過SERVICE BUS SDK 的AMQP傳輸,前面提到四個方式分別實作模擬成真實環境的四個不同的sensor,會隨機產生溫度資料回傳Event Hub
還有一個負責接收的Processor.
原文作者的SAMPLE放在:https://github.com/sandrinodimattia/AzureServiceBus.EventHubs.Samples
▼ 建立一個名為”temperature”的event hub, 且具有兩個SAP,名稱分別是SenderDevice、TemperatureProcessor,而權限分別是Send、Listen
接著,需要為每個Device依照不同的Publisher名稱跟傳輸模式產生出回傳至EventHub的驗證key,原文作者寫了一個非常實用的產生器,位置在:
https://github.com/sandrinodimattia/RedDog/releases/tag/0.2.0.1
source code上面也有,原文作者也只有提到主要串接字串的部分,其他產稱token都是由api來處理。
這裡就不詳述其中運作的原理,但筆記一下如何使用
▼ 本圖我解釋一下
左邊Hub的區塊,
- Namespace填入你EventHubs所屬的Service Bus Name
- HubName則是剛剛建立出來的EventHubs Name
- Publisher代表識別拿等下產生出的key去傳送資料的裝置名稱(在這個sample case有livingroom, garage, bathroom, phone)
- Mode則為要使用Https或者AMQP,若為後者必須要使用MICROSOFOT SERVICE BUS SDK才OK。
右邊的Credentials區塊,
- Sender Key Name就是前面在Azure設定SAP的Rule Name
- Sender Key就是對應著前面Sender Key Name的Key
- Token TTL代表這個Key可以活多久,設定為0代表永久有效
按下產生就會有一長串的key出現在下方,因為是透過SHA處理,每按一次都不一樣。
那這些Key產生出來要怎麼塞回作者提供的code裡面?,以下針對四個專案的Programe需要修改的地方後面有中文註解提示(SAS KEY可能要捲動一下SYNTAX PLUG-IN的水平卷軸):
EventHubs.IoT.AuthAndSend.HttpClientSender/Programe.cs
static void Main(string[] args)
{
// Generate a SAS key with the Signature Generator.: https://github.com/sandrinodimattia/RedDog/releases
var sas = "SharedAccessSignature sr=https%3a%2f%2fdxrdaa01.servicebus.windows.net%2ftemperature%2fpublishers%2flivingroom%2fmessages&sig=ynYwdHRupw0SBWE07lOc3UGV%2biUPslMxSyZgOw6Rcfc%3d&se=1420016997&skn=SenderDevice"; //這裡要換掉key
// Namespace info.
var serviceNamespace = "dxrdaa01"; //改成Service bus name
var hubName = "temperature";
var deviceName = "livingroom"; //記得對應著上面的產生器所設的命名來產生對應的key
// Create client.
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(String.Format("https://{0}.servicebus.windows.net/", serviceNamespace));
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", sas);
Console.WriteLine("Starting device: {0}", deviceName);
// Keep sending.
while (true)
{
var eventData = new
{
Temperature = new Random().Next(20, 50)
};
var postResult = httpClient.PostAsJsonAsync(String.Format("{0}/publishers/{1}/messages", hubName, deviceName), eventData).Result;
Console.WriteLine("Sent temperature using HttpClient: {0}", eventData.Temperature);
Console.WriteLine(" > Response: {0}", postResult.StatusCode);
Console.WriteLine(" > Response Content: {0}", postResult.Content.ReadAsStringAsync().Result);
Thread.Sleep(new Random().Next(1000, 5000));
}
}
EventHubs.IoT.AuthAndSend.Sender\Programe.cs
static void Main(string[] args)
{
// Generate a SAS key with the Signature Generator.: https://github.com/sandrinodimattia/RedDog/releases
var sas = "SharedAccessSignature sr=https%3a%2f%2fdxrdaa01.servicebus.windows.net%2ftemperature%2fpublishers%2fbathroom%2fmessages&sig=ZDXAFS3Rcr51a7gGbSU1lw6ifBCcJ3LHAo%2br7ul5bao%3d&se=1420016981&skn=SenderDevice"; //這裡要換key
// Namespace info.
var serviceNamespace = "dxrdaa01"; //改成Service bus name
var hubName = "temperature";
var deviceName = "bathroom"; //記得對應著上面的產生器所設的命名來產生對應的key
Console.WriteLine("Starting device: {0}", deviceName);
var uri = new Uri(String.Format("https://{0}.servicebus.windows.net/{1}/publishers/{2}/messages", serviceNamespace, hubName, deviceName));
// Keep sending.
while (true)
{
var eventData = new
{
Temperature = new Random().Next(20, 50)
};
var req = WebRequest.CreateHttp(uri);
req.Method = "POST";
req.Headers.Add("Authorization", sas);
req.ContentType = "application/atom+xml;type=entry;charset=utf-8";
using (var writer = new StreamWriter(req.GetRequestStream()))
{
writer.Write("{ Temperature: " + eventData.Temperature + "}");
}
using (var response = req.GetResponse() as HttpWebResponse)
{
Console.WriteLine("Sent temperature using legacy HttpWebRequest: {0}", eventData.Temperature);
Console.WriteLine(" > Response: {0}", response.StatusCode);
}
Thread.Sleep(new Random().Next(1000, 5000));
}
}
EventHubs.IoT.AuthAndSend.WinJsSender\default.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>EventHubs.IoT.AuthAndSend.WinJsSender</title>
<!-- WinJS references -->
<!-- At runtime, ui-themed.css resolves to ui-themed.light.css or ui-themed.dark.css
based on the user’s theme setting. This is part of the MRT resource loading functionality. -->
<link href="/css/ui-themed.css" rel="stylesheet" />
<script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
<script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>
<!-- EventHubs.IoT.AuthAndSend.WinJsSender references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
</head>
<body class="phone">
<input type="text" value="0" id="temp" />
<input type="button" value="Send Temperature" onclick="sendTemperature()" />
<label id="status"></label>
<script type="text/javascript">
function sendTemperature() {
// Generate a SAS key with the Signature Generator.: https://github.com/sandrinodimattia/RedDog/releases
// Could be provided by a Web API.
var sas = "SharedAccessSignature sr=https%3a%2f%2fdxrdaa01.servicebus.windows.net%2ftemperature%2fpublishers%2fphone%2fmessages&sig=Vn82Im04c8RisIZS8zNj1LfQH6aJvfWeOO7BCK62C2A%3d&se=1420016964&skn=SenderDevice" //這裡要換key;
var serviceNamespace = "dxrdaa01"; //改成Service bus name
var hubName = "temperature";
var deviceName = "phone"; //記得對應著上面的產生器所設的命名來產生對應的key
var xmlHttpRequest = new XMLHttpRequest();
xmlHttpRequest.open("POST", "https://" +
serviceNamespace + ".servicebus.windows.net/" + hubName + "/publishers/" + deviceName + "/messages", true);
xmlHttpRequest.setRequestHeader('Content-Type',
"application/atom+xml;type=entry;charset=utf-8");
xmlHttpRequest.setRequestHeader("Authorization", sas);
xmlHttpRequest.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 201) {
document.getElementById('status').innerText =
'Sent: ' + document.getElementById('temp').value;
} else {
document.getElementById('status').innerText =
this.status;
}
}
};
xmlHttpRequest.send("{ Temperature: " + document.getElementById('temp').value + " }");
}
</script>
</body>
</html>
EventHubs.IoT.AuthAndSent.ClientSender\Program.cs
static void Main(string[] args)
{
// Generate a SAS key with the Signature Generator.: https://github.com/sandrinodimattia/RedDog/releases
// Be sure to choose the AMQP option.
var sas = "SharedAccessSignature sr=sb%3a%2f%2fdxrdaa01.servicebus.windows.net%2ftemperature%2fpublishers%2fgarage&sig=nRzLDYPRBAb%2f0Us26BLCTS%2b%2bxcDA%2bjY4C4dJxWVsqgs%3d&se=1420016929&skn=SenderDevice"; //這裡要換key
// Namespace info.
var serviceNamespace = "dxrdaa01"; //改成Service bus name
var hubName = "temperature";
var deviceName = "garage"; //記得對應著上面的產生器所設的命名來產生對應的key
Console.WriteLine("Starting device: {0}", deviceName);
// Keep sending.
while (true)
{
var eventData = new
{
Temperature = new Random().Next(20, 50)
};
var factory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, ""), new MessagingFactorySettings
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(sas),
TransportType = TransportType.Amqp
});
var client = factory.CreateEventHubClient(String.Format("{0}/publishers/{1}", hubName, deviceName));
var data = new EventData(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(eventData)));
data.PartitionKey = deviceName;
client.Send(data);
Console.WriteLine("Sent temperature using EventHubClient: {0}", eventData.Temperature);
Thread.Sleep(new Random().Next(1000, 5000));
}
}
這樣ok之後前面四個Sender的對應資訊就set好了,而reciver的部分相對單純些,把SAP設定成Listener的那條Rule,在這就是TemperatureProcessor,而key再使用對應的那組就可以:
EventHubs.IoT.AuthAndSend.Receiver/Program.cs
static void Main(string[] args)
{
var partitionCount = 8;
var serviceNamespace = "dxrdaa01";
var hubName = "temperature";
var receiverKeyName = "TemperatureProcessor";
var receiverKey = "WkkWm3yJ57oMaFEASrFChuvheJRr404rdLDalnsQ+vU="; //這裡要換key
Console.WriteLine("Starting temperature processor with {0} partitions.", partitionCount);
CancellationTokenSource cts = new CancellationTokenSource();
for (int i = 0; i <= partitionCount - 1; i++)
{
Task.Factory.StartNew((state) =>
{
Console.WriteLine("Starting worker to process partition: {0}", state);
var factory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, ""), new MessagingFactorySettings()
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(receiverKeyName, receiverKey),
TransportType = TransportType.Amqp
});
var receiver = factory.CreateEventHubClient(hubName)
.GetDefaultConsumerGroup()
.CreateReceiver(state.ToString(), DateTime.UtcNow);
while (true)
{
// Receive could fail, I would need a retry policy etc...
var messages = receiver.Receive(10);
foreach (var message in messages)
{
var eventBody = Newtonsoft.Json.JsonConvert.DeserializeObject<TemperatureEvent>(Encoding.Default.GetString(message.GetBytes()));
Console.WriteLine("{0} [{1}] Temperature: {2}", DateTime.Now, message.PartitionKey, eventBody.Temperature);
}
if (cts.IsCancellationRequested)
{
Console.WriteLine("Stopping: {0}", state);
receiver.Close();
}
}
}, i);
}
Console.ReadLine();
cts.Cancel();
Console.WriteLine("Wait for all receivers to close and then press ENTER.");
Console.ReadLine();
}
▼ 到這個步驟,方案按下右鍵,選Set as StartUp Project,然後把五個專案全部選擇同時start。
▼ 如果你都有設定ok,會發現有三個sender開始傳送資料到event hubs, 而一台由js寫的windows phone也會跟著起來運作,可以手動傳值,再來可以看到圖片中右下角的視窗為Processor,也會跟著開始接收訊息。
依照SAMPLE可以發現EVENT HUBS在SENDER的支援度非常高,支援HTTPS的裝置就可以運用結合各種字串來傳送資料,但要注意一次的POST不能超過256KB
以上。


Leave a comment
很抱歉,必須登入網站才能發佈留言。