Parent repo: https://github.com/jfcarr/dotnet-iot-tui

Topics

  • Internet of Things
    • Raspberry Pi 4
    • Sense HAT
  • .NET
    • .NET 7 SDK
    • Web API
    • gRPC
    • Console application
    • Blazor server application
    • Console application + 3rd-party Nuget libraries
      • Terminal.GUI
      • Spectre.Console
  • Python/Flask

Environment and Tools

  • Linux
    • Ubuntu MATE
    • Raspberry Pi OS
  • Make files
  • SSH and SCP

What is IoT?

The term IoT, or Internet of Things, refers to the collective network of connected devices and the technology that facilitates communication between devices and the cloud, as well as between the devices themselves. Thanks to the advent of inexpensive computer chips and high bandwidth telecommunication, we now have billions of devices connected to the internet. This means everyday devices like toothbrushes, vacuums, cars, and machines can use sensors to collect data and respond intelligently to users.

The Internet of Things integrates everyday “things” with the internet. Computer Engineers have been adding sensors and processors to everyday objects since the 90s. However, progress was initially slow because the chips were big and bulky. Low power computer chips called RFID tags were first used to track expensive equipment. As computing devices shrank in size, these chips also became smaller, faster, and smarter over time.

Single-Board Computer vs Microcontroller

A single-board computer (SBC) is a complete computer built on a single circuit board. It has a microprocessor(s), memory, input/output (I/O) and other features required of a fully functional computer, and runs a full operating system. Examples: Raspberry Pi, Orange Pi, Hummingboard.

A microcontroller (or MCU, for microcontroller unit) is a small computer on a single VLSI integrated circuit (IC) chip. A microcontroller contains one or more CPUs (processor cores) along with memory and programmable input/output peripherals. Program memory in the form of ferroelectric RAM, NOR flash or OTP ROM is also often included on chip, as well as a small amount of RAM. Microcontrollers are designed for embedded applications, in contrast to the microprocessors used in personal computers or other general purpose applications consisting of various discrete chips. Examples: Arduino, ESP32.

Pros and Cons

Single-board computers are more powerful, but take longer to start up, and require an orderly shutdown. Microcontrollers are "instant-on" and have a smaller footprint, but are much more resource-constrained.

IoT in .NET

The .NET IoT libraries provide support for direct GPIO programming, and also device bindings for a comprehensive set of sensors, motor controllers, motion sensors, displays, and more.

The libraries require at least ARM v7, meaning they will not work on SBCs like the Raspberry Pi Zero. They support SBC hardware, not microcontrollers: If you are interested in microcontroller programming in .NET, check out .NET nanoFramework.

References

DescriptionLink
What is IoT (Internet of Things)? - Everything you need to know - AWShttps://aws.amazon.com/what-is/iot/
Microcontroller - Wikipediahttps://en.wikipedia.org/wiki/Microcontroller
.NET Internet of Things (IoT) applicationshttps://dotnet.microsoft.com/en-us/apps/iot

Configure the Raspberry Pi and Sense HAT

This is my working setup. Yours may be different, but this is the one that works for me.

Obtain a Raspberry Pi. I'm using a Raspberry Pi 4.

Install the 64-bit version of Raspberry Pi OS.

Using the raspi-config application, enable the following services:

  • SSH - Allows remote access to the Raspberry Pi via Secure Shell.
  • I2C - Enables the serial communication bus, allowing communication with attached devices and sensors.

Obtain a Sense HAT. The Raspberry Pi Sense HAT (Hardware Attached on Top) is an add-on board for Raspberry Pi. The Sense HAT is equipped with an 8×8 RGB LED matrix, a five-button joystick, and includes the following sensors:

  • Gyroscope
  • Accelerometer
  • Magnetometer
  • Temperature
  • Barometric pressure
  • Humidity

The Sense HAT can be installed directly on top of the Raspberry Pi. Keep in mind, however, that the ambient heat from the Raspberry Pi will influence the readings from the temperature sensor. If you want more accurate readings, you should use a compatible ribbon cable.

.NET SDK - Raspberry Pi

Download and install the .NET 7 SDK for 64-bit ARM devices, located here.

Image

Why are we using the 64-bit SDK?

.NET gRPC services are not supported in the 32-bit SDK.

.NET WebAPI Project (traditional REST)

Create the Service

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/SenseHatProvider

Steps:

  1. Create the project, using webapi as the project type.
  2. Add a project reference to SenseHatLib.csproj
  3. Add .NET IoT bindings.
  4. Configure the project for remote access (in launchsettings.json)
  5. Configure RESTful access to sensor data.

Service Startup

Open a terminal in the project directory and run:

dotnet run

If you want to start the service and leave it running in the background, add an ampersand to your command:

dotnet run &

Test with Swagger

Access the service Swagger page at http://<service ip>:<service port>/swagger.

.NET gRPC Project

Create the Service

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/SenseHatGrpcProvider

Steps:

  1. Create the project, using grpc as the project type.
  2. Add a project reference to SenseHatLib.csproj
  3. Add .NET IoT bindings.
  4. Configure the project for remote access (in launchsettings.json)
  5. Update the protocol buffer file with sensor-specific request and response messages.
  6. Implement the service messages.

Service Startup

Open a terminal in the project directory and run:

dotnet run

If you want to start the service and leave it running in the background, add an ampersand to your command:

dotnet run &

Testing

We won't implement a tester as part of this discussion, but if you want to explore this further on your own, here are some options for implementing a gRPC test runner:

.NET Console

The simplest CLI. No bells and whistles, but it gets the job done!

We'll build two versions: One will retrieve sensor data using our REST service, and the other will call the gRPC service.

Console Project for REST

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/ConsoleClient

Steps:

  1. Create the project, using console as the project type.
  2. Add a project reference to SenseHatLib.csproj
  3. App settings:
    1. Copy the appsettings.default.json file to appsettings.json, and update the setting values.
    2. Add appsettings content entry to the .csproj file.
  4. Implement details in Program.cs

Console Project for gRPC

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/SenseHatGrpcClient

Steps:

  1. Create the project, using console as the project type.
  2. Add package references to support gRPC: Google.Protobuf, Grpc.Net.Client, and Grpc.Tools.
  3. Add a project reference to SenseHatLib.csproj
  4. App settings:
    1. Copy the appsettings.default.json file to appsettings.json, and update the setting values.
    2. Add appsettings content entry to the .csproj file.
  5. Protocol buffer:
    1. Copy the protocol buffer file from the gRPC service project, and update the namespace.
    2. Add a Protobuf entry to the project file.
  6. Implement details in Program.cs

Blazor

A web application, for displaying the sensor data in a browser. .NET supports two Blazor project types: Blazor Server (runs on the server) and Blazor WebAssembly (runs in the browser). We'll be using the Server type.

Create the Project

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/BlazorClient

Steps:

  1. Create the project, using blazorserver as the project type.
  2. Add a project reference to SenseHatLib.csproj
  3. App settings:
    1. Copy the appsettings.default.json file to appsettings.json, and update the setting values.
    2. Add appsettings content entry to the .csproj file.
  4. Sensor page:
    1. Add a new Sensor.razor page.
    2. Add a code-behind file for the page: Sensor.razor.cs.
    3. Implement code details.
    4. Update NavMenu.razor to include the new Sensor page.

Terminal.GUI

From the Terminal.Gui repo:

Terminal.Gui: A toolkit for building rich console apps for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix.

What's a TUI?

In computing, text-based user interfaces (TUI) (alternately terminal user interfaces, to reflect a dependence upon the properties of computer terminals and not just text), is a retronym describing a type of user interface (UI) common as an early form of human–computer interaction, before the advent of modern conventional graphical user interfaces (GUIs). Like GUIs, they may use the entire screen area and accept mouse and other inputs. They may also use color and often structure the display using special graphical characters such as ┌ and ╣, referred to in Unicode as the "box drawing" set. The modern context of use is usually a terminal emulator.

https://en.wikipedia.org/wiki/Text-based_user_interface

What are the benefits?

  • Performance
  • Runnable on headless systems
  • Standalone
  • Nice balance between the simplicity of a CLI and the enhanced presentation/controls/widgets of a GUI.

Create the Project

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/TerminalGuiClient

  1. Create the project, using console as the project type.
  2. Add a package reference to Terminal.Gui.
  3. Add a project reference to SenseHatLib.csproj
  4. App settings:
    1. Copy the appsettings.default.json file to appsettings.json, and update the setting values.
    2. Add appsettings content entry to the .csproj file.
  5. Implement details in Program.cs

Spectre.Console

From the Spectre.Console repo:

A .NET library that makes it easier to create beautiful, cross platform, console applications. It is heavily inspired by the excellent Rich library for Python. For detailed usage instructions, please refer to the documentation at https://spectreconsole.net/.

Spectre.Console vs Terminal.GUI

Using Terminal.Gui, you can create applications that look more like traditional desktop apps than you can with Spectre.Console. But, Terminal.Gui has a critical dependency that introduces a limitation: It requires a graphical stack for rendering. Usually, this is fine: You'll be running your Terminal.Gui applications from a command prompt in Windows, or in a terminal from your Linux desktop. But, for something like a Linux server that boots to a CLI, your Terminal.Gui applications will not run because there's no graphical stack.

Spectre.Console applications do not follow the "desktop application" paradigm. They are closer to console applications, but with enhanced colors, and rendering of other things like tables, but in a scrolling view. Most importantly, though, Spectre.Console applications do not require a graphical environment. So, for a purely text-based environment, Spectre.Console fills this need.

Create the Project

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/SpectreClient

  1. Create the project, using console as the project type.
  2. Add package references:
    1. Spectre.Console.Cli (adds nice command line argument handling)
    2. Spectre.Console
  3. Add a project reference to SenseHatLib.csproj
  4. App settings:
    1. Copy the appsettings.default.json file to appsettings.json, and update the setting values.
    2. Add appsettings content entry to the .csproj file.
  5. Implement details in Program.cs

Python / Flask Project

Using a standard like REST to capture information from a device and make it available means we can swap out the internal details of the service implementation. This can be as simple as refactoring of an existing implementation, or as drastic as completely replacing the dev stack.

This is an example of recreating our .NET implementation with Python/Flask.

Create the Project

https://github.com/jfcarr/dotnet-iot-tui/tree/main/src/SenseHatFlaskProvider

  1. Install Python (you probably already have it).
  2. Install libraries for Flask and the Sense HAT:
    1. pip install flask
    2. pip install sense-hat
  3. Create service.py file. Add endpoints and supporting code.

Start the Service

flask --app service run --host=0.0.0.0 --port 5191