未验证 提交 b352f374 编写于 作者: I Ibrahim KIVANC 提交者: GitHub

Add sample for .NET Core IoT with BMP280 Sensor, Azure SDK and Certificates (#1665)

上级 78a7365d
......@@ -45,4 +45,4 @@
<Sha>bfc49945c0bedeffe01bb5d6f3c217dad207d0d8</Sha>
</Dependency>
</ProductDependencies>
</Dependencies>
</Dependencies>
\ No newline at end of file
......@@ -18,4 +18,4 @@
<MicrosoftExtensionsLoggingPackageVersion>5.0.0</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>5.0.0</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
</PropertyGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -15,4 +15,4 @@
"Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21511.1",
"Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.21511.1"
}
}
}
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Platforms>AnyCPU;ARM32</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Iot.Device.Bindings" Version="1.5.0-prerelease.21212.1" />
<PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.38.0" />
<PackageReference Include="System.Device.Gpio" Version="1.5.0-prerelease.21212.1" />
</ItemGroup>
<ItemGroup>
<None Update="raspberry-pi.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Device.I2c;
using System.Threading;
using Iot.Device.Bmxx80;
using Iot.Device.Common;
using UnitsNet;
using System.Device.Gpio;
using Microsoft.Azure.Devices.Client;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace DNSensorAzureIoTHub
{
public class Program
{
// set up IoT Hub message
private const string DeviceID = "<replace-with-your-device-id>";
private const string IotBrokerAddress = "<replace-with-your-iot-hub-name>.azure-devices.net";
// LED constraints
private const int Pin = 18;
private const int LightTime = 1000;
private const int DimTime = 2000;
// busId number for I2C pins
private const int BusId = 1;
public static void Main()
{
Console.WriteLine($".Net IoT with BMP280 Sensor!");
// set up for LED and pin
using GpioController led = new();
led.OpenPin(Pin, PinMode.Output);
// setup for BMP280
I2cConnectionSettings i2cSettings = new(BusId, Bmp280.DefaultI2cAddress);
I2cDevice i2cDevice = I2cDevice.Create(i2cSettings);
using var i2CBmp280 = new Bmp280(i2cDevice);
// Create an X.509 certificate object.
var cert = new X509Certificate2($"{DeviceID}.pfx", "1234");
var auth = new DeviceAuthenticationWithX509Certificate(DeviceID, cert);
DeviceClient? azureIoTClient = DeviceClient.Create(IotBrokerAddress, auth, TransportType.Mqtt);
if (azureIoTClient == null)
{
Console.WriteLine("Failed to create DeviceClient!");
}
else
{
Console.WriteLine("Successfully created DeviceClient!");
Console.WriteLine("Press CTRL+D to stop application");
}
while (true) // while(!Console.KeyAvailable) if you're using the app via external console
{
try
{
// set higher sampling and perform a synchronous measurement
i2CBmp280.TemperatureSampling = Sampling.LowPower;
i2CBmp280.PressureSampling = Sampling.UltraHighResolution;
var readResult = i2CBmp280.Read();
// led on
led.Write(Pin, PinValue.High);
Thread.Sleep(LightTime);
// print out the measured data
string? temperature = readResult.Temperature?.DegreesCelsius.ToString("F");
string? pressure = readResult.Pressure?.Hectopascals.ToString("F");
Console.WriteLine("-----------------------------------------");
Console.WriteLine($"Temperature: {temperature}\u00B0C");
Console.WriteLine($"Pressure: {pressure}hPa");
// send to Iot Hub
string message = $"{{\"Temperature\":{temperature},\"Pressure\":{pressure},\"DeviceID\":\"{DeviceID}\"}}";
Message eventMessage = new Message(Encoding.UTF8.GetBytes(message));
azureIoTClient?.SendEventAsync(eventMessage).Wait();
Console.WriteLine($"Data is pushed to Iot Hub: {message}");
// blink led after reading value
led.Write(Pin, PinValue.Low);
Thread.Sleep(75);
led.Write(Pin, PinValue.High);
Thread.Sleep(75);
led.Write(Pin, PinValue.Low);
Thread.Sleep(75);
led.Write(Pin, PinValue.High);
Thread.Sleep(75);
led.Write(Pin, PinValue.Low);
Thread.Sleep(DimTime);
}
catch (Exception ex)
{
Console.WriteLine($"An error occured: {ex.Message}");
}
}
}
}
}
\ No newline at end of file
# Raspberry Pi with .NET Core IoT
Raspberry Pi is one of the most popular boards and now .NET IoT can be used on top of Raspberry Pi OS to enable the writing of managed code applications.
In this sample Raspberry Pi 2 will be used, you can use above Raspberry Pi 2. This sample application includes a scenario: Every 3 seconds application reads temperature value from BMP280 sensor and turns on LED after reading the value. Then this temperature value is pushed to IoT Hub with device name and after every successful push LED will turn off. Data will be handled by IoT Hub message routing and will be pushed to blob storage to store.
![Raspberry Pi with nanoFramework to Azure Iot Hub](images/RP-Azure-flow.png)
## Getting Started with nanoFramework
* [Getting Started Guide for .NET Core IoT](https://docs.microsoft.com/en-us/dotnet/iot/)
* [IoT with .NET Core Video Series](https://channel9.msdn.com/Series/IoT-101)
* [List of suported devices/sensors by .NET Core IoT](https://github.com/dotnet/iot/blob/main/Documentation/README.md)
* [.NET Core IoT Samples](https://github.com/dotnet/iot/blob/main/samples/README.md)
* [Install .NET Core on Raspberry Pi](https://www.petecodes.co.uk/explorations-in-dot-net-core-3-0-for-raspberry-pi)
## Prerequisites
* Raspberry Pi (2 or greater) with [Raspberry Pi OS installed](https://www.raspberrypi.org/documentation/computers/getting-started.html)
* BMP280 Pressure/Temperature sensor breakout
* Jumper wires
* 5 mm LED
* 330 Ω resistor
* Breadboard (optional)
* [.NET SDK](https://dotnet.microsoft.com/download) version 5.0.100 RC2 or later
* A device certificate following [create test certificate using OpenSSL](create-certificate.md) documentation
## Prerequisite Packages
* dotnet add package Iot.Device.Bindings --source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json
* dotnet add package System.Device.Gpio --source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json
* dotnet add package Microsoft.Azure.Devices.Client --version 1.38.0
## Prepare the hardware
Use the hardware components to build the circuit as depicted in the following diagram:
![Raspberry Pi 2 with .NET Iot](images/RP-BMP280_bb.png)
## Pins
The following are the connections from the Raspberry Pi to the BME280 breakout:
* 3.3V to VIN OR 3V3 (shown in red)
* Ground to GND (grey)
* SDA (GPIO 2) to SDI (blue)
* SCL (GPIO 3) to SCK (yellow)
* GPIO 18 to LED anode (longer, positive lead)
* LED cathode (shorter, negative lead) to 330 Ω resistor (either end)
* 330 Ω resistor (other end) to ground
## Run the Solution
Use your Azure Subscription for following steps:
1. Make sure your [Pins](#-Pins) are correctly connected.
2. Create an IoT Hub using your Azure Subscription and leave the authentication options to default (Symmetric Key, autogenerated). You'll need IoT Hub name in the next steps in your code. You can use free tier of IoT Hub as well.
3. Create a `pfx` certificate using OpenSLL following [Create test certificate using OpenSSL](create-certificate.md) documentation.
4. Add your certificate into root folder of the solution like `raspberry-pi.pfx` for demo purposes verified certificate in this sample is removed from repo.
5. Provide your device id and IoT Hub device connection detail into `Program.cs`. Open your solution with Microsoft Visual Studio 2019.
```csharp
const string DeviceID = "<replace-with-your-device-id>";
const string IotBrokerAddress = "<replace-with-your-iot-hub-name>.azure-devices.net";
```
### Building the sample
1. Starting in the folder where you unzipped the samples, go to the subfolder for this specific sample. Double-click the Visual Studio Solution (.sln) file.
2. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
3. Make sure to click on device explorer and select your device.
The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it.
### Deploying the sample
* Select Build > Deploy Solution.
### Deploying and running the sample
* To debug the sample and then run it, press F5 or select Debug > Start Debugging.
## Remote Debugging
If you're using [VS Code](http://code.visualstudio.com) to enable remote debugging on Raspberry Pi make sure following below steps.
* [Remote debugging with VS Code on Windows to a Raspberry Pi using .NET Core on ARM](https://www.hanselman.com/blog/remote-debugging-with-vs-code-on-windows-to-a-raspberry-pi-using-net-core-on-arm)
* [How to use Windows 10's built-in OpenSSH to automatically SSH into a remote Linux machine](https://www.hanselman.com/blog/how-to-use-windows-10s-builtin-openssh-to-automatically-ssh-into-a-remote-linux-machine)
After the setup we have [launch.json](../.vscode/launch.json) file to enable build and publish steps. Also we have [tasks.json](../.vscode/tasks.json) . file to enable remote debugging feature helps us to debug our application on Raspberry Pi on Raspberry Pi OS with .NET Core IoT.
First we need to ssh to Raspberry Pi and create folder for deployment check [IoT Series Video 6](https://channel9.msdn.com/Series/IoT-101/Hello-World-in-IoT-ie-Blinky-headless-mode-tutorial-6-of-9)
```bash
mkdir DNSensorAzureIoTHub
sudo chmod 775 ./DNSensorAzureIoTHub
```
You can deploy and debug your solution or just deploy your solution without debugging.
1. For deploy and enable debugging: add `publish.bat` file with following commands to the root folder to publish and push compiled code to IoT device, make sure you provide your password and ip address of your Raspberry Pi. This file will be used by `.vscode/tasks.json` during remote debugging.
```bash
dotnet publish -r linux-arm /p:ShowLinkerSizeComparison=true
pushd .\bin\Debug\net5.0\linux-arm\publish
pscp -pw 1234 -v -r .\* pi@192.168.1.147:DNSensorAzureIoTHub
popd
```
2. If you would like to publish manually and deploy the code manually, you can run below commands
On windows on your project root run below commands
```bash
dotnet publish -r linux-arm
cd .\bin\Debug\net5.0\linux-arm\
scp publish\* pi@192.168.1.109:BlinkTutorial
```
Then run below commands on your Raspberry Pi using ssh
```bash
cd DNSensorAzureIoTHub
./DNSensorAzureIoTHub
```
If you are using [Visual Studio 2019](https://visualstudio.microsoft.com/vs/) you can follow [Debug .NET apps on Raspberry Pi](https://docs.microsoft.com/en-us/dotnet/iot/debugging?tabs=self-contained&pivots=visualstudio) documentation
## Result
![Result Raspberry Pi circuit](images/RP-BMP280_integration.png)
If you enable Message routing with Custom endpoint, you can save all inputs into an Azure Blob Storage
* First Create a route
![Iot Hub Message Routing](images/iot-hub-message-routing-1.png)
* Create a custom endpoint to connect to your blob storage data will be save in below format:
`{iothub}/{partition}/{YYYY}/{MM}/{DD}/{HH}/{mm}` Once connection is succesfull you can see the status as healty
![Iot Hub Message Routing](images/iot-hub-message-routing-2.png)
* Blob storage contains all data from IoT Hub in a container
![Iot Hub Message Routing](images/iot-hub-message-routing-3.png)
and single JSON file structure looks like below:
```json
{
"EnqueuedTimeUtc": "2021-09-10T12:31:25.1720000Z",
"Properties": {},
"SystemProperties": {
"connectionDeviceId": "raspberry-pi",
"connectionAuthMethod": "{\"scope\":\"device\",\"type\":\"sas\",\"issuer\":\"iothub\",\"acceptingIpFilterRule\":null}",
"connectionDeviceGenerationId": "637668692473913123",
"enqueuedTime": "2021-09-10T12:31:25.1720000Z"
},
"Body": "eyJUZW1wZXJhdHVyZSI6MjYuOTk3LCJQcmVzc3VyZSI6MTAwNy4yNzcsIkRldmljZUlEIjoicmFzcGJlcnJ5LXBpIn0="
}
```
Body message is encoded with Base64 format, if you decode the value, you'll retrieve the message we sent to Azure IoT Hub:
```json
{
"Temperature": 26.997,
"Pressure": 1007.277,
"DeviceID": "raspberry-pi"
}
```
## References
* [Blink an LED](https://docs.microsoft.com/en-us/dotnet/iot/tutorials/blink-led)
* [Read environmental conditions from a sensor](https://docs.microsoft.com/en-us/dotnet/iot/tutorials/temp-sensor)
* [Azure SDK - Microsoft.Azure.Devices.Client](https://www.nuget.org/packages/Microsoft.Azure.Devices.Client)
# Create test certificate using OpenSSL and Azure IoT Hub
This documentation is created following [Tutorial: Using OpenSSL to create test certificates](https://docs.microsoft.com/en-us/azure/iot-hub/tutorial-x509-openssl) document.
> NOTE: This example was created using [Cygwin64 for Windows](https://cygwin.com/install.html). Cygwin is an open source tool collection that allows Unix or Linux applications to be run on Windows from within a Linux-like interface. CygWin64 is bundled with OpenSSL. If you are using Linux, you probably already have OpenSSL installed.
Although you can purchase X.509 certificates from a trusted certification authority, creating your own test certificate hierarchy or using self-signed certificates is adequate for testing IoT hub device authentication. The following example uses [OpenSSL](https://www.openssl.org/) and the [OpenSSL Cookbook](https://www.feistyduck.com/library/openssl-cookbook/online/ch-openssl.html) to create a certification authority (CA) and a device certificate. The example then signs the CA and the device certificate into a certificate hierarchy. This is presented for example purposes only.
## Step 1 - Create the root CA directory structure
In Cygwin specify the folder you'll be creating your certificates, for accessing easily to certificates you can select Documents folder with following command:
```bash
cd /cygdrive/c/Users/{your-username}/Documents
```
Create a directory structure for the certification authority.
* The **certs** directory stores new certificates.
* The **db** directory is used for the certificate database.
* The **private** directory stores the CA private key.
```bash
mkdir rootca
cd rootca
mkdir certs db private
touch db/index
openssl rand -hex 16 > db/serial
echo 1001 > db/crlnumber
```
## Step 2 - Create a root CA configuration file
Before creating a CA, create a configuration file and save it as `rootca.conf` in the rootca directory.
```xml
[default]
name = rootca
domain_suffix = example.com
aia_url = http://$name.$domain_suffix/$name.crt
crl_url = http://$name.$domain_suffix/$name.crl
default_ca = ca_default
name_opt = utf8,esc_ctrl,multiline,lname,align
[ca_dn]
commonName = "Test Root CA"
[ca_default]
home = ../rootca
database = $home/db/index
serial = $home/db/serial
crlnumber = $home/db/crlnumber
certificate = $home/$name.crt
private_key = $home/private/$name.key
RANDFILE = $home/private/random
new_certs_dir = $home/certs
unique_subject = no
copy_extensions = none
default_days = 3650
default_crl_days = 365
default_md = sha256
policy = policy_c_o_match
[policy_c_o_match]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[req]
default_bits = 2048
encrypt_key = yes
default_md = sha256
utf8 = yes
string_mask = utf8only
prompt = no
distinguished_name = ca_dn
req_extensions = ca_ext
[ca_ext]
basicConstraints = critical,CA:true
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
[sub_ca_ext]
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:true,pathlen:0
extendedKeyUsage = clientAuth,serverAuth
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
[client_ext]
authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
extendedKeyUsage = clientAuth
keyUsage = critical,digitalSignature
subjectKeyIdentifier = hash
```
## Step 3 - Create a root CA
First, generate the key and the certificate signing request (CSR) in the rootca directory. This step will ask you PEM pass phrase, enter the value twice
```bash
openssl req -new -config rootca.conf -out rootca.csr -keyout private/rootca.key
```
Next, create a self-signed CA certificate. Self-signing is suitable for testing purposes. Specify the ca_ext configuration file extensions on the command line. These indicate that the certificate is for a root CA and can be used to sign certificates and certificate revocation lists (CRLs). Sign the certificate, and commit it to the database.
```bash
openssl ca -selfsign -config rootca.conf -in rootca.csr -out rootca.crt -extensions ca_ext
```
## Step 4 - Demonstrate proof of possession
You now have a root CA certificate. You can use it to sign device certificates. This certifate must be uploaded to your IoT Hub. To upload and register your CA certificate to your IoT Hub:
1. In the Azure portal, navigate to your IoTHub and select **Settings > Certificates**.
2. Select **Add** to add your new CA certificate.
3. Enter a display name in the **Certificate Name** field, and select the PEM certificate file you created previously.
> NOTE: The .crt certificates created above are the same as .pem certificates. You can simply change the extension when uploading a certificate to prove possession, or you can use the following OpenSSL command:
```bash
openssl x509 -in rootca.crt -out rootca.pem -outform PEM
```
4. Select **Save**. Your certificate is shown in the certificate list with a status of **Unverified**. The verification process will prove that you own the certificate.
5. Select the certificate to view the **Certificate Details** dialog.
6. Select **Generate Verification Code**. For more information, see [Prove Possession of a CA certificate](https://docs.microsoft.com/en-us/azure/iot-hub/tutorial-x509-prove-possession).
![Certificate Azure IoT Hub CA](images/certificate-iot-hub-ca.png)
7. Copy the verification code to the clipboard. You must set the verification code as the certificate subject. For example, if the verification code is BB0C656E69AF75E3FB3C8D922C1760C58C1DA5B05AAA9D0A, add that as the subject of your certificate as shown in step 9.
8. Generate a private key.
```bash
openssl genpkey -out pop.key -algorithm RSA -pkeyopt rsa_keygen_bits:2048
```
9. Generate a certificate signing request (CSR) from the private key. Add the verification code as the subject of your certificate.
```bash
openssl req -new -key pop.key -out pop.csr
-----
Country Name (2 letter code) [XX]:.
State or Province Name (full name) []:.
Locality Name (eg, city) [Default City]:.
Organization Name (eg, company) [Default Company Ltd]:.
Organizational Unit Name (eg, section) []:.
Common Name (eg, your name or your server hostname) []:BB0C656E69AF75E3FB3C8D922C1760C58C1DA5B05AAA9D0A
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```
![Certificate Azure IoT Hub CA](images/certificate-iot-hub-ca-csr.png)
10. Create a certificate using the root CA configuration file and the CSR for the proof of possession certificate.
```bash
openssl ca -config rootca.conf -in pop.csr -out pop.crt -extensions client_ext
```
11. Select the new certificate in the **Certificate Details** view. To find the PEM file, navigate to the certs folder.
12. After the certificate uploads, select **Verify**. The CA certificate status should change to **Verified**.
## Step 8 - Create a device in your IoT Hub
Navigate to your IoT Hub in the Azure portal and create a new IoT device identity with the following values:
1. Provide the **Device ID** that matches the subject name of your device certificates. In the following sample we'll use **"raspberry-pi"** as device id.
1. Select the **X.509 CA Signed** authentication type.
1. Select **Save**.
![Certificate Azure IoT Hub CA](images/create-a-device-ca-certificate.png)
## Step 9 - Create a client device certificate
To generate a client certificate, you must first generate a private key. The following command shows how to use OpenSSL to create a private key. Create the key in the subca directory.
```bash
openssl genpkey -out device.key -algorithm RSA -pkeyopt rsa_keygen_bits:2048
```
Create a certificate signing request (CSR) for the key. You do not need to enter a challenge password or an optional company name. You must, however, enter the device ID in the common name field. In our case we picked **"raspberry-pi"** as device ID, we'll use this id in the common name field.
```bash
openssl req -new -key device.key -out device.csr
-----
Country Name (2 letter code) [XX]:.
State or Province Name (full name) []:.
Locality Name (eg, city) [Default City]:.
Organization Name (eg, company) [Default Company Ltd]:.
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server hostname) []: raspberry-pi
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
```
![Certificate Azure IoT Hub CA](images/certificate-iot-hub-csr.png)
Check that the CSR is what you expect.
```bash
openssl req -text -in device.csr -noout
```
Send the CSR to the CA for signing. Specify `client_ext` in the `-extensions` switch. Notice that the `Basic Constraints` in the issued certificate indicate that this certificate is not for a CA. If you are signing multiple certificates, be sure to update the serial number before generating each certificate by using the openssl `rand -hex 16 > db/serial` command.
```bash
openssl ca -config rootca.conf -in device.csr -out device.crt -extensions client_ext
```
## Step 10 - Create `pfx` certificate for device
After creating certificates and keys using `openssl`, now it is time to create PFX certificate files for devices using PEM and Key files. When you run these commands, you're prompted to create a password. Make a note of the password, you need it in the next step.
Use key and the latest pem file in certs folder.
```bash
openssl pkcs12 -export -out raspberry-pi.pfx -inkey device.key -in certs/***.pem
```
## Step 11 - Test `pfx` device certificate
Go to [Testing Certificate Authentication](https://docs.microsoft.com/en-us/azure/iot-hub/tutorial-x509-test-certificate) to determine if your certificate can authenticate your device to your IoT Hub.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册