[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
很抱歉,必須登入網站才能發佈留言。