田牌魔术 | .NET Core 3.0 + Azure 远程点亮树莓派上的一盏灯
點(diǎn)擊上方藍(lán)字關(guān)注“汪宇杰博客”
導(dǎo)語
3年前,我寫過一篇《Windows 10 IoT Core + Azure 遠(yuǎn)程控制LED》,實(shí)現(xiàn)了《生活大爆炸》中的注孤生實(shí)驗(yàn),讓信號(hào)從家里出發(fā),繞地球轉(zhuǎn)一圈,經(jīng)過微軟美國數(shù)據(jù)中心,返回家里點(diǎn)亮樹莓派上連接的一個(gè) LED 燈泡。然而3年后的現(xiàn)在,Windows 10 IoT Core 以及UWP 已經(jīng)冰冰涼透心涼,甚至微軟至今也沒有支持樹莓派4的 Windows 版本。我只能茍且偷生,委曲求全,開葷 Linux,使用 .NET Core 重現(xiàn)了這個(gè)實(shí)驗(yàn)。微軟和社區(qū)對(duì)于 .NET Core IoT 非常積極,提供了比 UWP 好用不少的 IoT 基礎(chǔ)庫,讓我這個(gè)項(xiàng)目遷移非常方便。
.NET Core IoT 全家桶:https://github.com/dotnet/iot
在開始之前,如果你還沒有在樹莓派上配置.NET Core環(huán)境,可以參考我之前寫的:
在樹莓派4上安裝 .NET Core 3.0 運(yùn)行時(shí)及 SDK
“自啟動(dòng)”樹莓派上的 .NET Core 3.0 環(huán)境
基本原理
我們要從自己電腦上發(fā)送信號(hào)到 Azure IoT Hub,樹莓派上的.NET Core程序會(huì)監(jiān)聽消息,并控制LED開關(guān)。
創(chuàng)建 Azure IoT Hub
請(qǐng)根據(jù)微軟文檔創(chuàng)建 IoT Hub。最后記下你的連接字符串,看起來就像這樣:
HostName=<Your Hub Name>.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=<Your Key>
微軟文檔:https://docs.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-dotnet?WT.mc_id=AZ-MVP-5002809
下載并安裝?Azure Device Explorer (https://aka.ms/aziotdevexp)
把連接字符串粘貼到 Configuration / Connection? Information里,點(diǎn)擊 Update 按鈕。
切換到?Management?選項(xiàng)卡,點(diǎn)擊?Create?,輸入你的設(shè)備名稱,勾選?Auto Generate Keys?
樹莓派物理連接
將一個(gè)LED連接到樹莓派:
長腳連接到 GPIO 17
短腳連接到接地(GROUND)
附:樹莓派4 GPIO 全家桶圖(來自網(wǎng)絡(luò))
復(fù)制粘貼
創(chuàng)建一個(gè) .NET Core 3.0 控制臺(tái)程序。添加?Microsoft.Azure.Devices.Client 以及?System.Device.Gpio NuGet 包。前者用于和Azure IoT Hub通訊,后者用于控制 GPIO 來開關(guān)LED燈泡。
<Project Sdk="Microsoft.NET.Sdk">
? <PropertyGroup>
? ? <OutputType>Exe</OutputType>
? ? <TargetFramework>netcoreapp3.0</TargetFramework>
? </PropertyGroup>
? <ItemGroup>
? ? <PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.21.1" />
? ? <PackageReference Include="System.Device.Gpio" Version="1.0.0" />
? </ItemGroup>
</Project>
Program.cs 最終代碼如下。記得把里面的字符串常量換成你自己的 Azure IoT Hub 信息。
using System;
using System.Device.Gpio;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Client.Exceptions;
namespace AzureLightControl
{
? ? class Program
? ? {
? ? ? ? private const string IotHubUri = "<Your Hub Name>.azure-devices.net";
? ? ? ? private const string DeviceKey = "<Your Key>";
? ? ? ? private const string DeviceId = "<Your Device ID>";
? ? ? ? private const int Pin = 17;
? ? ? ? private static CancellationToken _ct;
? ? ? ? static async Task Main(string[] args)
? ? ? ? {
? ? ? ? ? ? Console.WriteLine("------------------------------");
? ? ? ? ? ? Console.WriteLine(" Azure IoT Hub Light Control");
? ? ? ? ? ? Console.WriteLine("------------------------------");
? ? ? ? ? ? var cts = new CancellationTokenSource();
? ? ? ? ? ? _ct = cts.Token;
? ? ? ? ? ? Console.CancelKeyPress += (sender, eventArgs) =>
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Cancelling...");
? ? ? ? ? ? ? ? cts.Cancel();
? ? ? ? ? ? ? ? eventArgs.Cancel = true;
? ? ? ? ? ? };
? ? ? ? ? ??
? ? ? ? ? ? try
? ? ? ? ? ? {
? ? ? ? ? ? ? ? var t = Task.Run(Run, cts.Token);
? ? ? ? ? ? ? ? await t;
? ? ? ? ? ? }
? ? ? ? ? ? catch (IotHubCommunicationException)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Operation has been canceled.");
? ? ? ? ? ? }
? ? ? ? ? ? catch (OperationCanceledException)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Operation has been canceled.");
? ? ? ? ? ? }
? ? ? ? ? ? finally
? ? ? ? ? ? {
? ? ? ? ? ? ? ? cts.Dispose();
? ? ? ? ? ? }
? ? ? ? ? ? Console.ReadKey();
? ? ? ? }
? ? ? ? private static async Task Run()
? ? ? ? {
? ? ? ? ? ? using var deviceClient = DeviceClient.Create(IotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey(DeviceId, DeviceKey));
? ? ? ? ? ? using var controller = new GpioController();
? ? ? ? ? ? controller.OpenPin(Pin, PinMode.Output);
? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Connected to the best cloud on the planet.");
? ? ? ? ? ? Console.WriteLine($"Azure IoT Hub: {IotHubUri}");
? ? ? ? ? ? Console.WriteLine($"Device ID: {DeviceId}");
? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > GPIO pin enabled for use: {Pin}");
? ? ? ? ? ? while (!_ct.IsCancellationRequested)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Waiting new message from Azure...");
? ? ? ? ? ? ? ? var receivedMessage = await deviceClient.ReceiveAsync(_ct);
? ? ? ? ? ? ? ? if (receivedMessage == null) continue;
? ? ? ? ? ? ? ? var msg = Encoding.ASCII.GetString(receivedMessage.GetBytes());
? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Received message: {msg}");
? ? ? ? ? ? ? ? switch (msg)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? case "on":
? ? ? ? ? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Turn on the light.");
? ? ? ? ? ? ? ? ? ? ? ? controller.Write(Pin, PinValue.High);
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? case "off":
? ? ? ? ? ? ? ? ? ? ? ? Console.WriteLine($"{DateTime.Now} > Turn off the light.");
? ? ? ? ? ? ? ? ? ? ? ? controller.Write(Pin, PinValue.Low);
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? ? ? Console.WriteLine($"Unknown command: {msg}");
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? await deviceClient.CompleteAsync(receivedMessage, _ct);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
這里面,deviceClient.ReceiveAsync() 負(fù)責(zé)監(jiān)聽 Azure IoT Hub 有沒有發(fā)來新消息,并處理收到的消息,完事后調(diào)用?CompleteAsync() 告訴 Azure 這個(gè)消息已經(jīng)處理好了,這樣的話設(shè)備再次連接到 Azure 就不會(huì)重復(fù)處理這條消息。
處理消息十分直接,讀取消息內(nèi)容為字符串,如果寫著"on",就向GPIO 17輸出高電位,即點(diǎn)亮燈泡。如果是"off",就輸出低電位關(guān)閉燈泡。
能跑就行
將源代碼或者發(fā)布后的dll全家桶復(fù)制到樹莓派。然后在樹莓派上用 .NET CLI 啟動(dòng)程序。在 PC 上,通過 Device Explorer 向設(shè)備發(fā)送 on 或 off 消息。
現(xiàn)在你學(xué)會(huì)了通過互聯(lián)網(wǎng)控制家里燈泡開關(guān)的魔術(shù):
總結(jié)
以上是生活随笔為你收集整理的田牌魔术 | .NET Core 3.0 + Azure 远程点亮树莓派上的一盏灯的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入Dapper.NET源码
- 下一篇: 在 ASP.NET Core 项目中使用