This blog post summarises the Cool Wave firmware. My focus for the project was to make it as accessible and extensible as possible, and this extends to the firmware. This affected my choice of language and the style of the code.
The firmware is written in MicroPython. I did give serious consideration to using C in the Arduino IDE, an environment that I personally am more comfortable with, but my focus is that it should be extendable by others. With Python being slightly more accessible and often in the top two languages on most lists (feel free to disagree), Python it is.
I could have used MicroPython or CircuitPython. My choice of MicroPython is because it is closest to the base Python language and most are familiar with. The truth be told there is little difference and I could have gone with either.
The Basic Firmware
I have taken the “build and enhance” approach to this project by building (as in prototyping and then combining and refactoring), and then enhancing. In this post I will summarise how the basic code works and it is enough to make the device work. After this I have included a more advanced firmware that is a little more complex but has more features. If this is way below your capabilities then please feel free to skip this basic section.
To get going I recommend using the Thonny IDE to develop it and if you are starting out in development I recommend it. I have already documented setting up the microcontroller in the earlier blog post. So on to the code…
At the top we import all the libraries we need and create all the objects we need to talk to the hardware. I hope it is fairly self-evident what is happening here, and even if it is not it does not matter.
import time from machine import Pin, I2C, Timer from dht12 import DHT12 from dht20 import DHT20 i2c = I2C(0, scl=Pin(9), sda=Pin(8)) dht12 = DHT12(i2c, 0x5c) dht20 = DHT20(0x38, i2c) led = Pin(18, Pin.OUT) relay = Pin(10, Pin.OUT)
We also need to download the DHT12 and DHT20 libraries and save them to the Seeeduino XIAO. More details on this are on my previous blog posts here and here.
Next I have created some simple functions to read the inside and outside temperatures. This creates a standard way to interface all the temperature sensors to both make the code more understandable, and to enable different types of sensor to be easily swapped in and out with next to no re-coding.
def readDHT12(): dht12.measure() temperature = dht12.temperature() humidity = dht12.humidity() return temperature, humidity def readDHT20(): measurements = dht20.measurements temperature = measurements["t"] humidity = measurements["rh"] return temperature, humidity
In the same vein we also need a simple way to turn on and off the fan. It is ridiculously basic but allows us to quickly change the firmware to use a different control system in the future without needing to deep dive into the rest of the code. It also makes the code more readable.
def setFan(active): relay.value(active)
Now we have all the functions to read the values and control the output, we need a main “loop” where all the business logic will be.
def minuteLoop(minuteTimer): outsideTemperature, outsideHumidity = readDHT12() insideTemperature, insideHumidity = readDHT20() setFan( insideTemperature > outsideTemperature )
Again it is so simple, but unapologetically so. It simply reads the Temperature and Humidity from the outside, then reads the Temperature and Humidity from the inside, and finally tells the fan to switch on or off. If it is warmer inside then it will switch on, otherwise it will switch off.
We will be wise to allow the sensor values to be calibrated, and to code in an offset so if a sensor is not accurate we do not end up pumping hotter air in than we want, but that is where the enhancement comes in and I have addressed this in the advanced code below.
Now we have the loop we need to make it run. The following two lines will create a timer and get it to call the loop code every minute.
minuteTimer = Timer(-1) minuteTimer.init(period=60000, mode=Timer.PERIODIC, callback=minuteLoop)
Finally for this basic code we need to make it run automatically when the hardware is powered on. Assuming we have saved this code as coolwave.py we need to create a file called main.py and add the following one line to it.
import coolwave
This file is executed when we power on the hardware, and will then run our code. If we want to run some different code we simply change the name of the file we import, and if we want to disable it we can simply comment out the line.
The Advanced Firmware
We can do better than this basic setup though, and I have already added more features. It is work in progress but at this point in time, but I have already built in the ability to calibrate the sensors, and there is an optional temperature window to prevent the fan switching on and off every few minutes. It will also identify when we are in a heat wave and only start cooling a home when it is actually needed.
This code can be found on Git Hub and will likely be updated before the next Northern hemisphere summer. Please feel free to contribute.
My next task is to add more conditions as to when the fan is turned on and off. This will include when the inside is overly damp to help dehumidify the house without needing to power an inefficient dehumidifier. This is the definition of scope creep so I will not implement it now, but it is an extra feature that will make my life better so why not.
If you have any other feature suggestions then please share them below.