获得.NET 核心 SDK 和 ASP.NET Core 3.0 以处理我的树莓派和 Windows 10 物联网核心后,我想看看是否可以直接从我的 Web 应用程序与一些电子产品进行通信。这是可能的;这里是如何做到这一点。

此处显示并讨论的代码示例解决方案可在 GitHub 存储库gpeipman/AspNetCore3LedOnOff上找到。它有更多的代码,LED可以从Web应用程序主页控制。

LED 闪烁入门

我开始与相同的默认Web应用程序,我在我的博客文章ASP.NET核心3.0在树莓皮和Windows 10物联网核心。为了与GPIO通信,我们需要.NET核心物联网库。它在阿尔法,所以它是实验性的,但它工作得很好,至少对我来说是这样。

我添加了我的树莓派磁盘作为一个网络驱动器,然后打开我的网络应用程序从可视化工作室,并添加了NuGet引用系统.Device.Gpio包。不要忘记选中”包括预发布”复选框,因为此程序包尚未具有稳定版本。

接下来,我从.NET Core IoT 库示例存储库中取走了和 LED 闪烁示例,并确保示例在我的板上工作。以下是我如何将事物连接在一起。

rpi-led_bb

我的示例项目中的所有闪烁工作都Program.cs文件的 Main() 方法中完成。

public static void Main(string[] args)
{
    var pin = 17;
    var lightTimeInMilliseconds = 1000;
    var dimTimeInMilliseconds = 200;

    using (GpioController controller = new GpioController())
    {
        controller.OpenPin(pin, PinMode.Output);
        Console.WriteLine($"GPIO pin enabled for use: {pin}");
        Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs eventArgs) =>
        {
            controller.Dispose();
        };

        while (true)
        {
            Console.WriteLine($"Light for {lightTimeInMilliseconds}ms");
            controller.Write(pin, PinValue.High);
            Thread.Sleep(lightTimeInMilliseconds);
            Console.WriteLine($"Dim for {dimTimeInMilliseconds}ms");
            controller.Write(pin, PinValue.Low);
            Thread.Sleep(dimTimeInMilliseconds);
        }
    }
}

快速提示。我向 Main() Web 应用程序的方法添加了上述方法的内容, Main() 并注释了对 CreateHostBuilder() 该方法的调用。不管它是不是 Web 应用程序 ,它仍然是 .NET 核心应用程序。

如果一切工作,并引导开始闪烁,那么我们准备移动到ASP.NET核心3.0。

迁移到 ASP

有时候,我喜欢像我的学生一样做一个无主,这些是我的控制器操作在第一次运行。

public IActionResult LedOn()
{
    using (GpioController controller = new GpioController())
    {
        controller.OpenPin(Pin, PinMode.Output);
        controller.Write(Pin, PinValue.High);
        Thread.Sleep(2000);
    }

    return Content("Led on");
}

public IActionResult LedOff()
{
    using (GpioController controller = new GpioController())
    {
        controller.OpenPin(Pin, PinMode.Output);
        controller.Write(Pin, PinValue.Low);
    }

    return Content("Led off");
}

猜猜怎么着?它不工作。好吧,它的工作原理,因为没有错误,但LED不执行任何操作。原因很简单 – 控制器操作可释放 GPIO 控制器类实例,并自动关闭所有引脚。

我们需要一个GPIO控制器的实例,我们不能在控制器操作中释放它。为了使控制器操作正常工作,我将这两行添加到程序类。

public const int LedPin = 17;
public static GpioController Controller = new GpioController();

我们现在有一个 GPIO 控制器的静态实例,以及 LED 正在等待的引脚的常量。

当应用程序启动时,我们需要打开 LED 引脚并确保 LED 已关闭。当应用程序关闭时,我们必须释放 GPIO 控制器。这是我 Configure() Startup() 这些更改后的类方法。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime)
{
    Program.Controller.OpenPin(Program.LedPin, PinMode.Output);
    Program.Controller.Write(Program.LedPin, PinValue.Low);

    applicationLifetime.ApplicationStopped.Register(() =>
    {
        Program.Controller.ClosePin(Program.LedPin);
        Program.Controller.Dispose();
    });

    // Default code follows
}

可在此处找到使用 GPIO 控制器静态实例的控制器操作。

public IActionResult LedOn()
{
    Program.Controller.Write(Program.LedPin, PinValue.High);

    return Content("Led on");
}

public IActionResult LedOff()
{
    Program.Controller.Write(Program.LedPin, PinValue.Low);

    return Content("Led off");
}

想要查看 Web 应用程序是否可以打开和关闭 LED 的用户可以使用以下 URL:

  • / 首页/Ledon
  • 关闭= /首页/LedOff

现在它的工作原理,但它不够ASP.NET核心。

介绍 LedClient 类

我们可能都知道,如果从应用程序的其他层使用原始静态实例,将会有多大的糟糕混乱和代码气味。更不用说公开给应用程序其他部分的所有内部详细信息了。

由于我们现在可以打开和关闭控制器操作的 LED,因此是时候清理我们的代码并遵循我们行业的最佳实践了。

  • 静态实例— 我们不必使用 .NET Core 上类的静态实例,因为我们具有依赖项注入。我们可以将某些类型注册为静态,然后将这些类型注入控制器。顺便说一下,.NET 核心依赖项注入也支持处置。
  • GPIO 逻辑是可见的– 我们可以以特定方式将 MVC 控制器操作作为客户端代码使用 GPIO 控制器。目前,MVC 知道有关 GPIO 控制器世界的肮脏机密,这意味着硬件和 Web 层紧密地绑定在一起。这就像为麻烦而尖叫。

我知道这是更多的代码,但我希望GPIO和MVC世界有尽可能少的接触

因此,我编写 LedClient 了环绕 GPIO 控制器相关代码的类。

public class LedClient : IDisposable
{
    private const int LedPin = 17;

    private GpioController _controller = new GpioController();
    private bool disposedValue = false;

    public LedClient()
    {
        _controller.OpenPin(LedPin, PinMode.Output);
        _controller.Write(LedPin, PinValue.Low);
    }

    public void LedOn()
    {
        _controller.Write(LedPin, PinValue.High);
    }

    public void LedOff()
    {
        _controller.Write(LedPin, PinValue.Low);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                _controller.Dispose();
            }

            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

当我们通过 .NET Core 依赖项注入使用某些内容时,我们需要注册它。下面是 ConfigureServices() 我的启动类的方法。

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();

    services.AddSingleton<LedClient>();
}

现在,我们可以使用构造函数注入与 HomeController 来注入 LedClient 的实例。这里是我的家庭控制器与LedClient类。

public class HomeController : Controller
{
    private readonly LedClient _ledClient;

    public HomeController(LedClient ledClient)
    {
        _ledClient = ledClient;
    }

    public IActionResult Index()
    {
        return View();
    }

    public IActionResult LedOn()
    {
        _ledClient.LedOn();

        return Content("Led on");
    }

    public IActionResult LedOff()
    {
        _ledClient.LedOff();

        return Content("Led off");
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel
        {
            RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier
        });
    }
}

就是这样。我们现在ASP.NET核心3.0网络应用程序,运行在树莓派,并能够与LED使用GPIO通信。

支持多个用户

我们的 LedClient 类适合一人方案,直到这个人在浏览器窗口中按 F5 的速度不是太快,其中一些控制器操作处于打开状态,控制 LED。 LedClientame时间。

我们必须保证不同的请求不能同时访问 LED。最简单的方法是在请求即将更改 LED 状态时使用 lock 语句将请求保留在行上。

public class LedClient : IDisposable
{
    private const int LedPin = 17;

    private GpioController _controller = new GpioController();
    private bool disposedValue = false;
    private object _locker = new object();

    public LedClient()
    {
        _controller.OpenPin(LedPin, PinMode.Output);
        _controller.Write(LedPin, PinValue.Low);
    }

    public void LedOn()
    {
        lock (_locker)
        {
            _controller.Write(LedPin, PinValue.High);
        }
    }

    public void LedOff()
    {
        lock (_locker)
        {
            _controller.Write(LedPin, PinValue.Low);
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                _controller.Dispose();
            }

            disposedValue = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

不确定此解决方案有多完美,但它工作正常,并行请求不能再同时写入引脚树莓派和 Windows 10 IoT 上的 NET Core 3.0 是受支持的方案,使用 .NET Core IoT 库的预发布版本还使我们能够编写与 GPIO 连接的设备通信的 Web 应用程序。对于 Web 应用程序,我们必须考虑多用户方案,并确保并行请求不能同时使用硬件。在这里,我们进行了简单的锁定,但实际的锁定策略取决于应用程序提供的设备和用例。

Comments are closed.