And here we are again – back to temperature monitoring! I wrote extensively about this three months ago in Building a Raspberry Pi-based temperature monitoring solution.
I have a small cabinet in my home office, under my table that houses my Synology NAS, the Philips Hue controller, the Unifi network gear, and similar essential equipment I rely on every day. Now that the summer is (finally) fast approaching in Finland also, I’m a little bit worried about the airflow, and especially the temperature within this cabinet. You can read more about the cabinet and the setup here.
While that solution is pretty great and awesome, it had one problem – the huge LEGO-case for the Raspberry Pi and the LED matrix display weren’t too pretty.
So I set out to replace the LED matrix with something more.. digital. In essence, I repurposed my previous solution to something more flexible.
As a brief background from my previous build, I use a Ruuvitag Bluetooth beacon with its built-in sensor to capture temperature and humidity within the cabinet. I also built a simple LEGO case for that. A Raspberry Pi 4 is used to capture this data from the Ruuvitag, and to store that in a database in Azure. And a LED matrix display is mounted on the Raspberry Pi to show me the temperature data. Since I had built the LED matrix to display the temperature within the cabinet every 30 minutes, I felt it was better to build something that I could use on my main Windows 10 desktop.
In essence, the process is this:
- Raspberry Pi 4 pings the Ruuvitag Bluetooth beacon every 30 minutes
- Upon receiving those values (temp, humidity etc.) a Python script on the Raspberry Pi calls Azure IoT Hub and passes on the values
- Azure IoT Hub subsequently calls an Azure Function, that cleans and sanitizes the data and stores it in Azure SQL
This way, I have both most recent and historical data in the Azure SQL database:
In my previous attempt I also built a Logic App that gets me the latest temperature reading. I use this to query for the current temperature:
Now, I want to replace the LED matrix, and query for the value from the Logic App with something that I can run from Windows 10.
Back when I was young, we built TSRs or Terminate-and-Stay-Resident programs. They would usually be small .EXE files, that upon launching would stay in the background usually providing something useful. In Windows, the System Tray usually houses icons that provide access and visuals for background processes in a somewhat modern way.
The essential information I need is the temperature of the hardware cabinet. If it’s over 30 °C, I guess I have problem.
Building the app
I discarded the idea of building an old-school Windows NT Service from the beginning. They are very much still around and support, but I wanted to build something that embraces modern Windows 10 techniques. For me, these small projects are a way to learn new things, not just to re-do something over and over again that I already know how to do. Thus, I also discarded a custom PowerShell script that would be easy to whip together and schedule for Windows 10.
I have an endpoint in Azure from the Logic App, and by calling that simple API I can retrieve the current temperature. I then started looking at UWP, or Universal Windows Platform. It’s a bit sad that the second search result in Google is “is UWP dead?“. Over the years I’ve built a few apps with UWP, but I never got to around to actually learn it, when C# and now especially .NET Core is so flexible and adaptable for my needs.
When you build UWP-based apps you can target Windows 10, Xbox One, HoloLens, and Windows 10 Mobile (ahem). Just now, WinUI 3.0 Preview 1 was also released, which aims to unify all Windows app – from Win32 to UWP and align their user experience.
I spent about 15 minutes creatively googling and browsing the Docs site for UWP apps. I was hoping to find a decent explanation of how to build UWP-apps that are actually SysTray apps. I found one project on GitHub but it hadn’t been updated in 3 years, so I chose not to spend time on it. I also found this User Voice to bring support for UWP apps to minimize to SysTray. It became evident that UWP + SysTray is not going to work.
I then realized that even if my Windows 10 Start Menu is quite barren and empty, there are tiles for apps. And these tiles can show data!
So I got to figure out how to build a UWP app with a tile, that updates. I guess these are now called Adaptive Tiles. I’d just installed Visual Studio 2019 with WinGet, so I created a new UWP app with the default template. I pressed F5 to generate the skeleton app, and I was then able to pin my app in the Start Menu. Now, all I needed to do was to update the tile with the temperature readings!
I found this quickstart to aid me, and by following the guidance I was able to figure out I need to create a local notification. The link to this other quickstart provided me with the missing logic – how to perform periodic updates to my tile.
Thus, my super simple UWP app only consists of the following few lines within the MainPage() class:
this.InitializeComponent(); var recurrence = Windows.UI.Notifications.PeriodicUpdateRecurrence.HalfHour; var url = new System.Uri(URI); TileUpdateManager.CreateTileUpdaterForApplication().StartPeriodicUpdate(url, recurrence);
I want to update the tile every 30 minutes, thus the PeriodicUpdateRecurrence is set to .HalfHour. That is the fastest update recurrence you can set. Then, in order for the tile to update it requires content. And this content lives in an XML file named Tile.xml which I’ll need to fetch. The structure of the XML block must be:
<tile> <visual version="2"> <binding template="TileSquare150x150Text04" fallback="TileSquareText04"> <text id="1">Temperature goes here</text> </binding> </visual> </tile>
The template this binds to, is the 150 x 150 pixel tile of my app. I wasn’t sure if this was going to work, but what I simply did was I set the Logic App to
- Retrieve the temperature data from my Azure SQL database
- Print out the XML block, with the temperature injected as the text
And much to my surprise, this worked on the first try. The Logic App is the same as I’ve shown above, but now the result is printed as follows:
I tried calling the Logic App directly from a command prompt – the endpoint address is generated upon saving the Logic App:
25.43 °C, so all good! I configured the Logic App URL as the URI for my UWP app, re-built the app and ran it.
And there it is! A simple UWP app, that retrieves local temperature data from Azure Logic Apps and displays it neatly in the Windows 10 Start Menu! Also, the UWP app does not need to be running – it’s enough if it’s pinned in the Start Menu. It also automatically refreshes every 30 minutes.
I was initially very hesitant to go this route, as my limited understanding of UWP might force me to face the facts. But I also wanted to not use a traditional scheduled script, and I was certain this approach would prove to be useful at a later date, also. In the end, I was surprised how easy it was to build the app, even if I know someone reading this might go “pff… you forgot to do X, Y and Z!” and that’s fine. Perhaps polishing the app warrants another blog post sometime in the future!