You can find it on GitHub
This Thermostat gives you the possibility to drive multiple devices in order to control temperature. In my case, I have installed two fans in my attic in order to cool it down in summer. There are no windows, so I had to force airflow. The first fan starts when the temperature reaches 35 degrees, and the second over 45.
You can control any reasonable amount of units, it's all configurable. You have also had access to basic statistics for the past two weeks:
Runtime of whole system |
ON time for each relay |
Statistics for 14 days |
Statistics for 7th day |
Configuration
The whole configuration is stored in Config.h. You can change PINs controlling relays, buttons, and input for reading temperature, thresholds, or timings.Hardware
Buttons
Two buttons are dedicated for menu navigation and the third one resets statistics. They are stored in EEPROM (Storage.cpp) once a day. Pins assigned to buttons can be found in Config.h
Configuring Relays
Let's assume that we would like to have 3 relays:
You have to edit Config.h and configure PINs, thresholds and amount of relays. Obviously, some properties already exist, so you have to just edit them.
const static uint8_t DIG_PIN_RELAY_0 = 1; const static uint8_t DIG_PIN_RELAY_1 = 10; const static uint8_t DIG_PIN_RELAY_2 = 11; const static uint8_t RELAYS_AMOUNT = 3; const static int16_t RELAY_TEMP_SET_POINT_0 = 20; const static int16_t RELAY_TEMP_SET_POINT_1 = 30; const static int16_t RELAY_TEMP_SET_POINT_2 = 40;
Now we have to set up relays and controller, this happens in RelayDriver.cpp
initRelayHysteresisController(0, DIG_PIN_RELAY_0, RELAY_TEMP_SET_POINT_0); initRelayHysteresisController(1, DIG_PIN_RELAY_1, RELAY_TEMP_SET_POINT_1); initRelayHysteresisController(2, DIG_PIN_RELAY_2, RELAY_TEMP_SET_POINT_2);
Choosing Controller
Hysteresis Controller
It's the one chosen in the example above, it has few additional configurations:
const static uint32_t RELAY_DELAY_AFTER_SWITCH_MS = 300000; // 5 minutes const static uint32_t RHC_RELAY_MIN_SWITCH_MS = 3600000;
RELAY_DELAY_AFTER_SWITCH_MS gives a wait time for switching to the next relay. Imagine that configuration from our example would start working in 40 degrees environment. This would result in enabling all three relays at the same time. This could eventually lead to high power consumption - depending on what you are controlling, an electric engine, for example, consumes more power during the start. In our case, switching relays have the following flow: the first relay goes, waits 5 minutes, the second goes on, waits 5 minutes, third goes on.
RHC_RELAY_MIN_SWITCH_MS defines hysteresis, it's the minimum frequency for a particular relay to change its state. Once it's on, it will remain on for at least this period of time, ignoring temperature changes. This is quite useful if you control electric motors since each switch negatively impacts live time.
PID Controller
This is an advanced topic. Implementing such a controller is a simple task, finding the right amplitude settings is a different story.
To use the PID controller, you must change initRelayHysteresisController(.....) to initRelayPiDController(....) and find the right settings for it. You will find them in Config.h
I've implemented a simple simulator in Java so that it's possible to visualize the results. It can be found in the folder: pidsimulator.
Below you can see simulations for two controllers PID, and P. PID is not perfectly stable because I did not apply any sophisticated algorithm to find the right values.
Software Design
Message Bus
Different software modules have to communicate with each other, hopefully not both ways ;)
For example:
- statistics module has to know when the particular relay goes on and off,
- pressing a button has to change display content, and it also has to suspend services that would consume many CPU cycles, for example, temperature reading from the sensor,
- after some time temperature reading has to be renewed,
- and so on...
Every module is connected to Message Bus and can register for particular events and can produce any events.
For example, pressing Next button results in the following flow:
Some components have some tasks that need to be executed periodically. We could call their corresponding methods from the main loop since we have Message Bus it's only necessary to propagate the right event:
LIBS
The following libs are required to compile Thermostat:
- https://github.com/maciejmiklas/Thermostat
- https://github.com/milesburton/Arduino-Temperature-Control-Library
- https://github.com/maciejmiklas/ArdLog.git