CoffeePID: the software

After I had decided on all the hardware (see here), I was really motivated to get the software part running quickly. I love these kind of projects, as I always learn a lot of new stuff.

But first we need to know how the components are wired together and how they talk to each other. The PT1000 (2-wire) is simply connected via the terminal block to the MAX31865-board, which itself is connected to the ESP8266 using SPI. The SSR can then be controlled by almost any remaining free IO-pin on the ESP. Two little anecdotes regarding this:

  • Somebody taking a look at my final pinout may think: “Why didn’t he just use the SlaveSelect port of the WEMOS D1 mini pro as the ChipSelect port for SPI? This way you can’t use hardware SPI and the wiring is a bit odd.” - I would reply: “Thanks for the hint, but I already tried that. And while SS was connected to CS of the MAX31865, the ESP8266 couldn’t be programmed anymore. This may be related to the fact that the flash of the WEMOS D1 mini pro is itself connected to the ESP8266 via SPI. The funny part is, that this only effected programming, the code was actually running fine using hardware SPI. To fix the programming issue, I simply switched the CS port to another free IO-pin, as I don’t really care for hardware SPI anyway.”

  • Don’t use the port “D4” of the WEMOS to switch the relay. DON’T. Believe me. RealIy really! I actually initially chose that port randomly, but experienced some strange issues during uploading, when the SSR was connected to the ESP. This is simply because D4 is connected to the on-board led, which is switched on multiple times during programming. This meant the SSR was switched multiple times pretty quickly while uploading the firmware, what apparently can lead to problems. I also simply changed to another free port and finally everything is working as intended.

So the setup I ended up with for developing the software looked like this. I’ll redo the wiring later, when I know where and how I want to place the components inside the machine.

Components of CoffeePID (PT1000 bottom left, MAX31865 top left, WEMOS D1 mini pro top right and the Solid-State-Relay bottom right)

Components of CoffeePID (PT1000 bottom left, MAX31865 top left, WEMOS D1 mini pro top right and the Solid-State-Relay bottom right)

But now to the software, really really

First we have to decide on the platform we want to use. I usually use the Arduino environment in most of my ESP8266-projects, as it offers a great ecosystem regarding programming and libraries and has pretty good ESP-support. So there were also libraries for every needed component in this project, like web server, pid, MAX31865, mdns and persistent storage. This will make the coding of those components very lightweight and simple, as you will see later on. Any finally it’s very easy to program the WEMOS D1 using the Arduino IDE.

Before writing any code you need to setup the Arduino environment including all esp8266 stuff (see here). Then you should be able to select your board via the tools menu. And here (in the tools menu) is another quality I like about the ESP8266: You can easily overclock it. It runs on a base clock of 80 MHz, but you can set it to 160 MHz via Tools > CPU Frequency. I run all my ESPs overclocked, for years now, and I never ran into any thermal or power issues. So from my perspective it is totally safe to permanently run these chips on 160 MHz which greatly improves performance.

As it would go beyond the scope of this post, I will not explain every detail of the final code here, but I commented the code quite thoroughly to make it easier to understand what’s happening. The full source code is available at the Github repository, feel free to use and modify it, as you like. Also if you have any issues or questions regarding the code, just create an issue in the repository.

Using the PT1000

Let’s start with the code right at the core functionality: measuring the temperature. As I use a breakout board similar to the Adafruit MAX31865, I can simply use the Adafruit library. And that is quite nice, as Adafruit has always great examples and tutorials (here), so the implementation was a breeze. I just had to install the “Adafruit_MAX31865“ library via the Arduino IDE and the integration of the breakout and measuring the temperature were reduced to just these few lines of code:

Be aware, that there are two different “versions” of the MAX31865 breakout board. The PT100 and the PT1000 version, which only differ in the on-board reference resistor (PT100 -> 430 Ohm, PT1000 -> 4,3 kOhm). I actually had to switch this resistor on my board, which was a bit tricky, as it is a pretty small SMD component.

Integrating the Solid-State-Relay

Next up is switching the relay. As we use a relay that can be triggered with 3,3V TTL-level we just define an output pin and initialize it with “LOW” (meaning the heating being switched off). Then later, depending on the temperature reading, we can switch it on and off as we like.

I actually don’t know yet how I should implement this for best temperature stability / accuracy. Of course it is quite simple to implement a real software PID, but as our controlled variable (switching the SSR) is digital and not analog, I doubt that this will give us an ideal result. It is also a lot of work finding optimal PID parameters preventing a temperature overshoot and reducing the (damped) oscillation around the target value. At this point the firmware simply works as a binary switch, heating below the target temperature and switching off, when it’s reached. I’ll come back to this later, when I can test different heating strategies in real live.

WiFi

Let’s continue with the next part: make it connect to the wifi and start a web server. It was important to me, that the wifi credentials are not hardcoded in any way, so you can change your wifi password without recompiling the software. There is a great project called “WifiManager” (Github repository) that solves the problem for you by implementing a captive portal to enter the wifi credentials. But as the frontend is not very appealing and we want to optimize the process as much as possible, I created my own somehow similar implementation. This is the setup process I came up with:

  1. Check for saved credentials, if there are credentials stored, the ESP will try to connect to the network.

    • On success: the CoffeePID is now reachable in your wifi network.

    • On fail: If no credentials are found or a connect is not possible for more than 20 seconds, the controller starts in access point mode and you can connect to its network.

  2. Now the chip is reachable via any device connected to its network.

The code to connect to a wifi network or create an access point is also pretty straight forward:

The microcontroller is now reachable in the network, but I didn’t want to type the IP address into the browser, so addressing it by name would be great. This can simply be achieved by using mDNS responder (aka: Apple Bonjour) which makes devices announce their name on the network and are therefore discoverable by all other network clients. And again, there is a library for that (named “esp8266_mdns”), reducing the code to:

Great, we now can reach the web server of the ESP8266 at the address “http://coffeepid“ (Depending on the network it may be necessary to append “.local” to the url).

Webserver

As I will go into the details in a later post, let me just show you the basic integration. I used the library “ESP8266WebServer“ (installed via the library manager) to host the website on the microcontroller.

LittleFS

So finally we need to have some kind of internal logic which manages the wifi credentials, being able to persistently store and retrieve them from some kind of memory. The easiest way to store data permanently on a ESP8266 is to use its integrated file system. You can choose between two different filesystems, SPIFFS is the “classic” implementation and generally very lightweight, LittleFS is a pretty new implementation and focused on real directory support and performance. I did a performance comparison and in this scenario LittleFS was much faster for serving the files. And again, using the according Arduino library you can access files with very few code. But how do you write files to the LittleFS area using the Arduino IDE, because we want to write all files needed for the website in this area. There is a plugin for the Arduino IDE which allows you to write all files from a folder named “data” in the project directory (GitHub repository). For security reasons I separated the paths for the configuration file and the web server content, so the web server has no access to the configuration file.

Now we can check for a valid wifi configuration and switch the network mode correspondingly. The controller starts in wifi client mode if there are saved wifi credentials or in access point mode if not. So it’s up to the enduser if you want to use the coffeePID inside your existing wifi network, or if you want it to create its own.

RECAP

So, the ESP8266 is now connecting to the network (or creates its own), can handle local configuration files, measure the temperature and switch the relay. We now “just” need the functionality to set and show the temperature to the user. And as already mentioned, this will be done using a web frontend. But that is definitely a completely different story / post. I will report on my journey of creating and optimizing the frontend soon, so stay tuned…

Other parts of this series: