The E-files - Part 3 - It's all about the environment
In this case I'm talking about the development environment. There are a lot of different ways that you can make .NET core stuff run on a Raspberry Pi. In this part of the series I'll show you a couple of ways to do this and how I set up an environment that works the way I like it. I definitely did not come up with all the steps described here. I just gathered info from a lot of different sources in one location and made them all work togheter.
Getting .NET on the Raspberry Pi
I already touched upon this in the first part of the series but wanted to elaborate on it a bit. Feel free to skip this if you already have this set up. You can get .NET running on a Raspberry Pi for a while now. Support was a bit limited in the beginning but since around begining 2019 Linux ARM32 is a supported distro. It is not like the situation on Windows where you just run an .exe and be done with it. There is still a fair bit of manual labor involved and you need to know where to find the right steps.
You can get the bits needed by browsing to https://dotnet.microsoft.com/download and then select the Linux tab. Then you click on the big 'Install .NET Core' button. This leads you to a page in the documentation (https://docs.microsoft.com/en-us/dotnet/core/install/linux). Now, lots of Linux distro's are supported, but in case of a standard configured Raspbian running Pi you want to go to the Debian section (Raspbian Buster is a Debian 10 derivative).
As we can see, at the time of writing, .NET Core 3.1 and 5.0 Preview are available and supported configurations. Also, .NET Core 2.1 is also still supported but I don't see a reason at this time to move forward with that version. You can click in the table on the Debian version or use the menu on the right of the page to go to the more detailed installation instructions.
Just as you start reading that page, you stumble on the following text: Package manager installs are only supported on the x64 architecture. Other architectures, such as ARM, must manually install the .NET Core SDK or .NET Core Runtime. For more information, see the manually install section below.
Bummer! Click the link to get you to the right section and then click on the link for the version you want to download. You need to decide if you just want to run .NET programs (install runtime) or that you want to be able to actually build (and debug) apps on the Pi (install SDK). I went with the ARM32 SDK option (for Raspberry Pi 3B and higher, you could choose the ARM64 as an lternative). Obviously, it is easiest to download this directly on the Pi and then do the installation there as well.
Next step on the Pi is to open up a terminal and execute the following steps to extract and install:
mkdir -p "$HOME/.dotnet" && tar zxf dotnet-sdk-3.1.301-linux-arm.tar.gz -C "$HOME/.dotnet"
export DOTNET_ROOT=$HOME/.dotnet
export PATH=$PATH:$HOME/.dotnet
I choose to change the folder to '.dotnet' instead of just the plain 'dotnet' mentioned in the docs. Also you need to make sure the name of the downloaded archive coresponds with the name in the script above. As mentioned in the docs, make sure you add the 2 export lines to your profile to have the dotnet tools always available. Again, in the case of the a standard configured Raspbian running Pi the file to add the lines to is the '.bashrc' file in the home folder (which in you case will most probably be the '/home/pi/' folder). After these steps, open up a new terminal and type dotnet --info
. This should give you something like this:
To IDE or not to IDE
For a long time already, it has been possible to have Visual Studio Code running on the Pi itself (see Scott Hanselmann's post for example). This process has been simplified a lot because a pre-built version is made available on http://code.headmelted.com/. Now, on a Pi 4 this probably works pretty good. On a Pi 3 (which I am using) I found the experience a bit meh. A better way of doing this in my opinion is to make use of some of the remoting capabilities of Visual Studio Code and the Visual Studio Debugger. There are a couple of pre-requisites:
- You need to be ale to ssh into the Pi (without the need to supply a password)
- You need to install the VS Remote Debugger on the Pi
SSH into the Pi
To communicate with the Pi and send files over, I use SSH. This is available on Windows for a while now and it takes just a few steps to get it to run in a way so you do not need to supply a password to login. So, fire up a PowerShell terminal and type/copy the following:
cat ~/.ssh/id_rsa.pub | ssh pi@raspberrypi 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
What this does is it copies over your public key to an authorized_keys
file on the Pi in the right directory (and creates it if it does not exist). This takes care of the Windows part. I assumed you already have an ssh public key set up on your machine. If not, first execute the ssh-keygen
command to generate the id_rsa.pub
file
When running/debugging code, I need to copy over files from the source folder to a folder on the Pi. To do this as efficiently as possible, I would like to only copy the changed files instead of the whole folder every time. I don't know of such a tool on Windows, but I do know one one Linux: rsync
. So, why not use Linux on the Windows machine (= WSL) to do this? Setting WSL up is described in the docs (I installed Ubuntu 20.04 LTS). If you are already on Windows 2004, make sure to update your distro to WSL 2. Then execute the folowing commands (where you replace the {username} with your username) from a bash prompt:
ssh-keygen -f "/home/{username}/.ssh/known_hosts" -R "raspberrypi"
sudo cat ~/.ssh/id_rsa.pub | ssh pi@raspberrypi 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
If both scripts ran successfully, you should be able to ssh into your Raspberry Pi without supplying a password from Windows AND you WSL distro!
Install VS Remote Debugger
A couple of steps need to be executed on the Pi to get the Visual Studio Remote Debugger installed:
- Install the VS remote debugger on your Pi by running this command:
curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -l ~/vsdbg
- To debug you will need to run the program as root, so we'll need to be able to remote launch the program as root as well. For this, we need to first set a password for the root user in your pi, which you can do by running:
sudo passwd root
- Then we need to enable ssh connections using root, by running :
sudo nano /etc/ssh/sshd_config
and adding a line that reads:PermitRootLogin yes
- reboot the pi:
sudo reboot
(Steps taken from Scott Hanselman's blog)
Visual Studio Code setup
I set up my VS Code with a workspace wherein the source files are on my computer, so not on the Pi. As you can see in the screenshot, there is also a .vs folder. More on that later...
It consists of two projects and the usual Git, editor and VS Code support files. The crux to get this working in a way that works for me can be found in the launch.json
and task.json
files. With the task.json
file, we tell VS Code to compile the code and copy the artifacts to the Pi (by using rsync
). Compilation is done with the dotnet
tool but instead of the build
command, we use the publish
command. This gives us a folder that contains all the necessary files to run the application (so you basically do not need to have dotnet installed on the Pi). The complete file lookes like this:
{
"version": "2.0.0",
"tasks": [
{
"label": "RaspberryPublish",
"command": "pwsh",
"type": "shell",
"problemMatcher": "$msCompile",
"args": [
"-c",
"dotnet publish -r linux-arm",
"${workspaceFolder}\\${workspaceFolderBasename}\\${workspaceFolderBasename}.csproj",
"&&",
"bash",
"-c",
"rsync -az --update --verbose $(wslpath '${workspaceFolder}')/${workspaceFolderBasename}/bin/Debug/netcoreapp3.1/linux-arm/publish/ pi@raspberrypi:/home/pi/Desktop/${workspaceFolderBasename}"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
This runs a PowerShell terminal from the VS Code command prompt with the dotnet publish -r linux-arm
command for the specified folder and then run bash
in that same terminal (so start WSL) with the rsync
command to copy the differences to a folder on the Desktop on the Pi. Took me some time to get this right, but I have to say this works really well.
So running the 'RaspberryPublish' task gets everything built and deployed. If you don't want to debug your program, running this is enough to get you going. You just need to start the program manually on the Pi. If you do want to debug the program while it is running on the PI, you can use the below launch.json
:
{
"version": "0.2.0",
"configurations": [
{
"name": "Pi=>Publish, Launch and Attach Debugger",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "RaspberryPublish",
"program": "~/.dotnet/dotnet",
"args": ["/home/pi/Desktop/${workspaceFolderBasename}/${workspaceFolderBasename}.dll"],
"cwd": "/home/pi/Desktop/${workspaceFolderBasename}",
"stopAtEntry": false,
"console": "internalConsole",
"pipeTransport":
{
"pipeCwd": "${workspaceFolder}",
"pipeProgram": "ssh",
"pipeArgs": [
"pi@raspberrypi"
],
"debuggerPath": "~/.vsdbg/vsdbg"
},
"env": {
"DOTNET_ENVIRONMENT" : "Development"
}
}
]
}
Starting a debug session calls the task described above, runs dotnet with the compiled dll and attaches the debugger through ssh. Breakpoints, watches, stepping, skipping, it all just works! I actually copied the whole configuration in the file again, but left out the preLaunchTask. This way I can just attach the debugger to the version of the program that is already on the Pi.
One more thing
I really like Visual Studio Code, but I have a very longstanding relation with Visual Studio. There is a lot of muscle memory there and overall I like the interface a bit more. Visual Studio however does not have something like the task and launch functionality and has no native capability to connect a to a remote debugger over SSH. You would say that using VS in the same way as VS Code is not possible. Fortunately an extension has been built by Radu Tomuleasa (source) to bring remote SSH debugging to Visual Studio as well. I couldn't get it to work at first, but by examining the source, I found out it had to do with the paths to the debugger and the .NET SDK on the Pi. One could be changed in the settings for the extension, the other not. I created a PR for this and Radu has released an updated version (1.3) with these changes. The extension also allows for a flow of just building and publishing the code to the Pi but not yet in an optimal way. This will probably come in a later version.
I hope this helps in getting your own environment set up in a way that works for you. If you have tips on making this better, let me know in the comments below! In the next part I'll be diving deeper into the code that reads the data from the electricity meter. Hope to see you there.
Comments
Comments are closed