As mentioned I’ve contributed a bit to Mobile Blazor Bindings in my spare time. As it’s relatively unknown I thought it would be fun to do a project with it. To know what MBB is, you first need to know what Blazor is. Blazor is the opportunity to write web applications in C# instead of JavaScript, inside the browser, using familiar HTML and CSS. It’s the brainchild of Steven Sanderson which uniquely qualifies him to tell you all about it. When you embed Blazor inside a web browser that you embed again in an application you are able to run Blazor as an app. And indeed that has been done with Electron in the past. But you still need a web server inside or run on a WebAssembly version of the .NET runtime. Mobile Blazor Bindings takes this a step further by both running on top of the normal dotnet framework (eliminating the web server) and allowing you to mix HTML UI elements with Xamarin Forms elements (as Blazor components) in a single application. I recommend watching Eilon Lipton talking about it for .NET Conf this year. If all of this is total abracadabra to you, just remember the greatest benefit of MBB for C# developers:

Mobile Blazor Bindings allows you to write applications in HTML, CSS and C# that run inside a web browser, on iOS, macOS, Android, Windows with a single code base.

This was something we did not have in .NET until MBB came along, so I’m very grateful to Steve and Eilon for this. Based on MBB, Bootstrap and Blazorise I was able to quickly whip up this mock-up that is already componentized. It will serve as the basis for the UI of the machine and is pretty close to the sketches I drew earlier:

Another pet peeve of mine is that I like functional and reactive programming and have to bring it up in every programming conversation. This won’t be any different. It’s so powerful to leave the imperative world and think in composing higher order functions or data streams. For this project I’ll be building the app with ReactiveUI (by Anaïs Bets) as there is a lot of real-time data that flows from the machine and needs to be displayed in a pretty way. ReactiveUI can transparently signal Blazor witch parts of the UI need to redraw, which ideally should save me some headache there.

ReactiveUI works best with an MVVM tiering which is what I will be using for the app too. Using ViewModels and Interfaces I’ll also be much more able to write unit tests for the application and create a simulation in C# of the electronics before I actually start working on them.

So to sum up the challenge:

  • Use Mobile Blazor Bindings
  • Use Bootstrap / Font Awesome (yes, uninspiring, but it will suffice).
  • Use ReactiveUI
  • Use ReactiveX (reactive programming library for i.a. C#)
  • Use MVVM pattern
  • Unit test everything.
  • Create a simulation of the electronics in C#.

Doesn’t sound too difficult right?

The Service interfaces

I’ve decided on representing the different parts of the espresso machine in .NET even though technically the app just talks against an MQTT broker and a web server. This allows me to functionally group and control parts of the machine that belong together. The parts of the espresso machine (and grinder) that I want to control are:

  • The power circuit that will turn on/off the machine and allows me to get the power usage and energy consumption.
  • The boiler circuit that will allow me to control boiler temperature and pressure. I might add heat exchanger temperature as a sensor to this.
  • The grinder circuit that will be responsible for turning the grinder on and off and allows me to get power usage and energy consumption again.
  • The maintenance circuit that will control blind flushes and group head flushes.
  • The scale circuit that will control the electronic scale that will be integrated into the drip tray.
  • The espresso circuit that will control the group head temperature, preinfusion time, monitor water pressure, take you through the cooling flush and finally make an espresso based on the provided parameters.

In addition to the machine it self we also need a place to store and interact with the recipes. The recipe and photo services will take care of this. This leads to the following class diagram.

I’ll discuss each interface and code below:

IPowerService

The IPowerService will provide observables for the power state (on/off) and power usage (in watts). It will also provide the methods to turn the machine on or off. The cancellation tokens will appear frequently in all method calls. All methods are asynchronous because of the multiple boundaries a method call will cross. The methods only return when confirmation is received of retrieval of the command by the hardware. If for any reason this communication hangs (i.e. no confirmation received), the cancellation token provides a way out by cancelling the command after three seconds.

IBoilerService

The IBoilerService provides observables for boiler pressure, target pressure, boiler temperature, protection and heating state (and a few offsets for calibration). The Nuova Simonelli Mac is an heat exchanger machine. This means that there is a single boiler that provides steam for cappuccino. To heat the water for espresso, fresh water is transported through pipes inside the boiler that will flash-heat it to the 93-ish °C. The group head will provide the final heat up / cool down to the right temperature to achieve temperature stability. This means that you only have indirect control of the brew temperature by either adjusting the boiler temperature (typically 124°C) or cooling down the group head by flushing water through it (called a cooling flush). And since measuring temperature accurately inside a boiler is no easy feat (at least it wasn’t 20 years ago when this machine was designed), the designers of my machine (and many others) used a bit of physics to control another variable that is related to temperature: pressure. I’ll devote some more time to the relation between water temperature and steam pressure in a future post about the electronics simulation. For now it is enough to know that inside the boiler a temperature directly corresponds to a pressure. My machine uses a pressure switch to control pressure, which in turn controls boiler temperature, which indirectly controls brew temperature. 1.2barG (I’ll get to barG in a subsequent post as well) is the default pressure for espresso machines. The disadvantage of the mechanical pressure switch and especially my aging switch is a considerable dead band (between 1.0 and 1.5 actually, used to be 1.1 and 1.3). This would correspond to temperature changes between 120 and 128 °C. These boiler temperature fluctuations are dampened a bit by the large group head, but by no means is an 8° difference ideal. This is why I want to use a PID algorithm to control the steam pressure. I might end up controlling the boiler water temperature directly in the future, in which case I’d have to change the TargetPressure property and SetTargetPressure method to TargetTemperature and SetTargetTemperature respectively.

The arduino will limit the pressure to 1.99 barG and 133 °C (whichever comes first) during normal operation. You’d probably never want to reach these temperatures because it will probably burn the coffee. The electronics circuit will trigger a soft protection once the boiler water reaches 135°C. This soft protection can be reset by calling ResetProtection on this interface. Hopefully the large copper surface of the boiler and tubing will prevent the thermal circuit breaker on the outside of the boiler (rated at 135°C) from triggering before the software protection inside the Ardiuno triggers.

Stay tuned for part 2 of this post.

Leave a Reply

Your email address will not be published.