This project describes how to build a custom thermostat to control a type of whole-house ventilation system made by Beutler called SmartVent. This would also make an excellent starting point for any thermostat project.
This uses a single relay to control an HVAC device (vent in this case), and it places the relay and the small amount of additional circuitry on the prototype area of the circuit board that comes with the case. This makes it a compact circuit and soldering project that shouldn't be too much of a challenge for most DIY-ers. All the software is provided, so no software development should be needed.
If you want to adapt this project to a more typical household thermostat, you would want to add two more relays, because you would want to control three devices: vent, furnace, and A/C. The prototype area is too small for three relays, so adding them requires building your own little prototype board and making it plug into the main circuit board, with a very low profile so the cover will fit. I've done it so it is doable, though somewhat challenging. The software provided here would give you a huge head-start in development of the software for such a typical thermostat. You would have to change the software for your needs.
You can also use this project as a starting point for a non-thermostat project that uses an LCD display with touchscreen. The code provides a way to create and organize screens and create buttons and text on them.
I am henceforth assuming that your goal is to make a SmartVent thermostat. If instead you are adapting this project for a different kind of thermostat or some other purpose, read through this anyway to get as much information as you can before modifying the design.
SmartVentThe motivation for this project was that I had a Beutler SmartVent for whole-house cooling, but had to disconnect it when I installed an EcoJay controller that supported standard thermostats, because that controller (and regular thermostats) know nothing about how to properly control the SmartVent.
The Beutler SmartVent is a great idea. It pulls in cool summer evening air and blows it out the registers throughout the house, exhausting the return air to the attic and hence outdoors. It lets you cool your house at night with outdoor air in the summer, using only the fan and not the more expensive A/C system.
However, the Beutler controller uses specialized digital thermostats that can't be replaced with a traditional thermostat (like a Nest or EcoBee). To remedy this problem (and a few others), I replaced my Beutler controller with an EcoJay controller that allowed me to use standard thermostats. See the hackster.io project titled Standard thermostats replace Beutler specialized ones!
For this SmartVent thermostat, it is important to know that you must use the EcoJay SmartZone-4X four-zone controller, which is able to use zone 4 to open and close the SmartVent damper with the on-demand fresh air mode of the EcoJay. The SmartZone-2X and -2L controllers do not support the on-demand fresh air mode.
Unfortunately, the EcoJay SmartZone-4X controller is not able to duplicate the Beutler SmartVent control. It can control the SmartVent damper, but it does not have the smarts to do so in the same way that the Beutler controller did. I had to abandon use of my SmartVent for a while, but ultimately I designed and built this custom thermostat that works alongside my standard thermostats to control SmartVent, using an algorithm like that of the Beutler controller. It talks to the EcoJay controller to tell it when to turn SmartVent on and off. In fact, it has improvements over the original control algorithm. You can set a maximum per-day run time, and you have control over all temperature differentials.
Case and MicrocomputerFor this project, I wanted a case that LOOKED LIKE a thermostat, and found one in the AZ-Touch MKR 2 Wall Mount Touchscreen Set, which contains a color LCD display with a touchscreen, and has sockets supporting Arduino microcomputers. Note that actually the display is a TFT=Thin Film Transistor display, but in this project I call it an LCD display.
The Arduino microcomputer I chose for the project is the Nano 33 IoT. I picked it because it is supported by the AZ-Touch MKR 2, even though it has features I don’t use in the thermostat, such as Bluetooth, WiFi, and accelero-meters. An Arduino microcomputer was a good choice because there is a great deal of hardware and software support available for low cost (or zero cost, for most software) and many tutorials to help the beginner learn how to use it.
You shouldn't need to do any programming for this project. However, knowing a bit about it can give you more confidence and improve the likelihood you will be successful. If you are unfamiliar with programming or with using Arduino microcomputers, you might choose to first purchase an Arduino starter kit (such as "ELEGOO UNO Project Super Starter Kit with Tutorial and UNO R3", available on Amazon) and work through some of the tutorials to gain a feeling for how Arduinos are programmed and used. This will also get you through the installation of the Arduino IDE software on your computer, and familiarize you with using it to compile a C++ program and load it into an Arduino microcomputer. That said, this project will also steer you through those initial steps and familiarization.
Con you do this project?How much technical savvy is needed to make this thermostat and install it? I hope I've done all the hard work and that you can simply copy what I've done. The soldering will be the main area of challenge.
My professional background made it possible for me to design and code this project, but the soldering was challenging and I’m not very good at it. Nevertheless, I got it working, which should give you confidence! If you are a handy DIY person and have worked a bit with soldering before, you can probably pull this off.
Reading through this project should give you a good feel for whether it is within your abilities or not. Here is a list of the tasks you will need to perform:
1. Install the EcoJay SmartZone-4X controller and configure it for fresh air operation on zone 4 (this is a project prerequisite, and the process is described fully in the hackster.io project Standard thermostats replace Beutler specialized ones!.
2. Order the parts for the thermostat.
3. Build and solder parts to the main board prototype area.
4. Install the Arduino IDE software, install my thermostat software and related libraries, compile my software with the Arduino IDE, and download it into the Nano 33 IoT microcomputer.
5. Run some tests on components of the thermostat to look for problems and ensure all hardware is working.
6. Run a 5-wire thermostat cable from the Beutler controller to the wall where the thermostat is to be placed, connect it to the Beutler controller, install a connector on the wall end of the cable, plug it in to the thermostat you’ve made, and finally, attach the thermostat to the wall.
6. Test that it works.
However, we all know that it never goes as easily as expected. Multiple things often go wrong, so some debugging work (mainly hardware, not software) will likely be required. If that happens and you can’t handle it yourself, you will need to find someone (perhaps in an online forum) that can help. I do try to step you through testing of each little bit of the hardware and point you in the direction to look if it doesn't work right.
If you have questions or problems with the project description, you can contact me through the normal hackster.io method or via email at ted@tedtoal.net.
Things used in this projectPrerequisites
- Beutler SmartVent system
- EcoJay SmartZone-4X controller that has replaced a Beutler controller
- A good work area for soldering
- A computer on which the Arduino IDE can be installed and used
Hardware components
- AZ-Touch MKR 2 Wall Mount Touchscreen Set (case, LCD touchscreen, circuit board with beeper)
- Arduino Nano 33 IoT microcomputer
- Various electronic components (see full parts list accompanying this project)
- 5-wire thermostat cable of sufficient length
Software components
- My SmartVent custom open-source thermostat C++ code (included)
- My custom open-source C++ libraries (included or available for free)
- Various open-source C++ libraries for Arduino (included or available for free)
Tools
- Soldering iron and related supplies such as solder and a solder-sucker tool
- Tools such as wire strippers, crimper, cutters, needle nose pliers (see full list that is part of this hacker.io project, noting that I've listed multiple possibilities for some tools)
This document is rather long, not because the project is difficult, but because I wanted to include complete detail to assist you as much as possible.
The rest of this document is divided into these sections and appendices. The appendices are mainly for reference and need not be read.
- Step 1: Project planning
- Step 2: Part sourcing
- Step 3: Familiarization
- Step 4: Theory of operation
- Step 5: Testing AZ-Touch MKR 2
- Step 6: Adding 5-wire cable connector
- Step 7: Connecting cable to EcoJay and outdoor thermistor
- Step 8: Soldering the circuitry
- Step 9: Testing the hardware
- Step 10: Installing the SmartVent thermostat code
- Step 11: Installing the thermostat
- Step 12: Testing the thermostat
- Step 13: Debugging a broken thermostat
- Appendix A: List of attached files
- Appendix B: Adapting new thermistors
- Appendix C: SAMD21 ADC Problems
- Appendix D: Software Description
- Appendix E: Adding 5-wire cable connector (older method)
You must have a Beutler SmartVent system, and you must first replace your Beutler controller and thermostats with an EcoJay controller and standard thermostats (unless you are using this project as a starting point for your own project). This is described in the hackster.io project Standard thermostats replace Beutler specialized ones! Begin by doing that, and return here when the system conversion is complete and running. Note that after doing that project, your SmartVent will be disabled and unusable until you also complete this project.
Read through this document thoroughly, then get all the parts and tools together, before starting to build your thermostat!
An important early consideration should be a check to see how easy it will be to run the 5-wire 20-gauge cable from the EcoJay controller through walls and attic space to the place where the SmartVent thermostat will be mounted. Remember that it will read the indoor temperature from where it is mounted. I put mine next to my upstairs thermostat that replaced my old Beutler thermostat. In the attic I found the cable going to it from the controller, and that allowed me to see that it would be pretty easy for me to route the cable. You might want to route the cable FIRST, because if that turns out to be too hard, that may kill the entire project.
I recommend you download the SmartVent thermostat code from my GitHub repository at this point, so you have document files available to refer to as needed. The repository is at this URL: https://github.com/tedtoal/SmartVent_Thermostat
To download it, click the red Code
button and download the zip file, then unzip it to obtain a folder containing a README.md
file and two subfolders, programs
and documents
. Peruse the files in the documents
folder so you have a feeling for what is there, and refer to these files as needed. The programs folder won't be used until Step 10: Installing the SmartVent thermostat code.
There are also files attached to this hackster.io project which you can download. All of those files are also in the documents
folder you just downloaded.
Read through the full list of hardware, software, and tools accompanying this project description.
The AZ-Touch MKR 2 supports two different Arduino microcomputers with two separate sockets. The code I’ve written is specific to the Nano 33 IoT (Internet of Things), which uses the Atmel SAMD21-18G microcontroller, which goes into one of the two MKR 2 sockets. It is possible that there is a microcomputer that will fit in the other socket that uses that same kind of microcontroller, so the code might work with it. However, I advise sticking with the Nano 33 IoT to avoid problems. This is the one I bought:
There might be different versions of the Nano 33 IoT using different microcontrollers. Be sure to get the one with the Atmel SAMD21 microcontroller. Atmel's data sheet refers to that device as a microcontroller that contains a 32-bit ARM® Cortex®-M0+ processor. The microcontroller is the microprocessor plus peripheral devices like timers, and the microcomputer is the microcontroller mounted on a little board with other components such as a power supply regulator.
Take note of the designation SAMD21
for the Nano 33 IoT microcontroller. It is a microcontroller architecture flavor from a family called SAMD
that differs from the architecture used by many other Arduino microcomputers. You will sometimes see references to SAMD
architecture within Arduino documentation, such as in reference to libraries, which sometimes will support only microcontrollers with SAMD
architecture. (If you intend to do any programming of the microcomputer to modify this project, you need to know that you will be working with SAMD
architecture and not the more typical Arduino architectures).
Don't buy a Nano microcomputer that has tall headers on it, as the space inside the MKR 2 case is very limited. I bought a microcomputer with short headers that I had to solder on myself. I recommend that one, as shown in the picture above.
I have a very small oscilloscope that I found invaluable for this project, though you won't need one, I've done the hard circuit debugging work for you! But if you are interested, there are some very inexpensive smaller oscilloscopes on the market these days.
Step 3: FamiliarizationThis section contains photographs to help familiarize you with the project's parts, schematics, and diagrams.
The AZ-Touch MKR 2 Wall Mount Touchscreen case looks like this:
The baseplate separates from the cover by squeezing and pulling. In the following photo look carefully to see how the internal circuit board snaps onto plastic wings to hold the board in place.
Here are the front and back sides of the internal printed circuit board (PCB).
When three screws are removed, the LCD display can be removed. This is necessary when wiring the prototype area.
The Arduino Nano 33 IoT microcomputer is only about an inch wide and two inches long.
The Nano can be inserted backwards if you aren't careful. I advise marking a "1" next to pin 1 on all three MKR 2 sockets on BOTH SIDES of the MKR 2 circuit board, see photographs above. Then, note that pin 1 of the Nano is next to the USB connector! The proper insertion is with the USB connector facing towards the middle of the board, NOT on the edge. Putting it in upside down might burn it out!
There is a connector labelled K2 on the MKR 2 board. I removed it for easier soldering to pins 1 and 2 to access GND and VIN on the MKR 2 board.
A close-up view of the wiring side of the prototype area follows, showing my soldering of wires to the prototype area to interconnect the thermostat components. I will discuss wiring in detail.
Schematic of MKR 2 printed circuit board
Following is the schematic of the MKR 2 PCB. This is also available in the project documents as file AZ-Touch_MKR_schematic_V02-02.pdf
. Look on the actual MKR 2 circuit board to find the circuit features described next .
At the top of the schematic are three rectangles representing the three sockets available for plugging things into the board: a socket for another different Arduino microcomputer (Arduino MKR socket), a socket for an Arduino shield board (Arduino MKR Shield socket), and the socket we use to plug in the Nano 33 IoT (Arduino Nano IoT socket).
At the right of the schematic is a rectangle representing the LCD screen with touch sensor.
At lower right is a buzzer on the board, which my Thermostat code uses to produce a beep when a screen press is detected.
At lower left is a rectangle and other components that are the 5V power supply for the board. Power input can come either from the USB connector or from connector K2. When programming the Nano, power comes in from the USB connector. When the thermostat is running normally, power comes in from K2, which is connected to the HVAC 24VAC hot and common power wires.
Finally, the custom circuitry that implements the thermostat, and that is placed on and wired into the MKR 2 prototype area, has a schematic, shown below and available in project file SmartVent Thermostat Schematic V4.pdf
. The schematic is also available in file SmartVent Thermostat Schematic V4.kicad_sch
, which is a file that can be read by the open-source KiCad PCB design program. You don't have to use that file or program unless you want to edit the schematic, perhaps to customize it for your own purposes. Below is the schematic.
The part of the schematic excluding the upper-right square is the main part of the MKR 2 circuit board, which is what was also shown in the schematic shown previously above. There are six yellow rectangles representing different elements of the board. Try to find each of these elements on the actual board. Going from lower-left upwards and then clockwise, the tiny rectangle with four pins is the K2 connector that can be used to supply power to the board (you can remove this connector as it isn't needed, and it can be in the way if you make your own large prototype board to plug into the MKR 2). To its left another rectangle represents the several circuit board components that convert the incoming power, which can be anywhere from 9V - 35V DC or AC, into the 5VDC required by the board. Above that is a rectangle labelled TFT that represents the connector into which the LCD (TFT) display is plugged. Above that is a rectangle labelled Arduino_Nano_33_IoT_Socket that is the socket into which the Nano 33 IoT microcomputer board is plugged. Moving clockwise to the right and down, the rectangle labelled Arduino MKR Shield Connector is a socket provided on the MKR 2 board in case you want to make a custom prototype board and plug it into the MKR 2 board, or perhaps you have bought such a board made to fit here. (In this project, that socket is not used, but if you are modifying this project for your own purposes, you might use it). Under that is the last rectangle, labelled AZ-Touch Arduino MKR Zero Connector, that is another socket for another microcontroller, an MKR Zero microcontroller. You can use the MKR 2 with either that or the Nano 33 IoT. We use the latter in this project, and so this socket is left empty.
The upper-right square on the schematic depicts the components you must add and wire up to the prototype area of the MKR 2 board. The large yellow rectangle is the Omron relay, which switches 24VAC to the EcoJay controller zone 4 vent input to signal that it should open the SmartVent damper and turn on the HVAC vent fan. The small 5-pin rectangle is the connector to which the wires from the EcoJay controller are connected. The other components are a fuse (F1), a power on/off switch (SW1), an indoor temperature thermistor (EPCOS), an LED (D4) and resistor (R4) to indicate that 5VDC power is on, another LED (D5) and resistor (R5) to indicate that the relay has been activated, two varistors for static electricity and transient protection (RV1 and RV2), three Schottky diodes for transient protection (D1, D2, D3), a transistor (Q1) and resistor (R6) to switch the relay on (it needs more current than a Nano output pin can provide), a resistor (R3) and capacitor (C3) for calibrating the Nano analog-to-digital converter (ADC), two capacitors across the indoor (C1) and outdoor (C2) thermistors for noise suppression, two resistors in series with the indoor (R1) and outdoor (R2) thermistors to create a voltage divider for generating a voltage that corresponds to temperature, capacitor C4 filters the 5VDC, and finally a diode to protect against relay coil transients (D6).
The Nano 33 IoT also has a schematic for its tiny little board, available in project file Arduino-Nano-33-IoT-Schematic.pdf
. I referred to it many times, in particular to track the changing names of pins as they went from one schematic to another. I also made an Excel spreadsheet that lists pin names and numbers and signal names at different places on different circuit boards and components, see file AZ-Touch_MKR_Nano_SAMD21G_pins.xlsx.
This is very helpful to sort through the profusion of changing signal names.
I also used Excel to make spreadsheets depicting the physical layout of components in the prototype area. That spreadsheet file is in the project documents as file SmartVentPrototypeArea.xlsx
. The sheet showing the component layout viewing from above down onto the components is shown below.
Another sheet in that file shows the other side of the prototype area and includes a wiring net list to use for soldering, shown below.
The connection of the five HVAC wires to the thermostat was a problem. I kept touching wires to things I shouldn't. I finally solved this by making a connector so I could easily connect and disconnect the thermostat from the cable (which I did innumerable times to program the device and then test it). I'll describe making that connector in detail.
This section describes the general operational theory of the MKR 2 and thermostat. Do not be intimidated by it. This is for information only, and is not necessary to build the project!
Cable from HVAC system
The 5-wire cable from the HVAC system carries these five signals:
- 24VAC hot: red wire, comes from 24VAC hot at the power input of the EcoJay SmartZone-4X controller.
- 24VAC common: blue wire, comes from 24VAC common at the power input of the EcoJay SmartZone-4X controller.
- VentFan: green wire, connected to the EcoJay SmartZone-4X zone 4 fan (G) connector.
- Sensor 1: yellow wire, tied to either of the two wires from the outdoor temperature thermistor used by the old Beutler controller.
- Sensor 2: white wire, tied to the other of the two wires from the outdoor temperature thermistor used by the old Beutler controller.
These wires enter the MKR 2 board through a female connector that attaches to 5 pads in the prototype area and corresponding male connector attached to the 5 cable wires as shown in a picture above.
There are several components that are meant to help protect the board from stray voltages appearing on the cable wires:
- A varistor connects across the 24VAC hot and common wires
- A varistor connects across the VentFan and 24VAC common wires
- Two Schottky diodes are across each Sensor wire and 24VAC common wire
A small DPST switch is used to switch the 24VAC hot and common wires into the circuitry, which was very useful for turning off power before connecting and disconnecting the thermostat, to help avoid power glitches that might burn something out. A 0.2A fuse lies in series with the 24VAC hot going to that switch. This provides protection were there to be a short on the board that caused it to draw excessive current. The switch is turned off to disconnect it, then the connectors are pulled apart. To reconnect, the connectors are pushed back together and then the switch is turned on. The combination of the fuse, switch, and connectors have saved me several times after having burned out several Nano IoT parts before implementing these protective measures.
Power Supply
The MKR 2 requires 5VDC to operate, and its circuitry includes a 5V regulator to provide that. The regulator Vin input must be fed an A/C or D/C voltage between 9 and 35 volts. In this case, the 24VAC from the HVAC system (red wire, R, 24VAC hot) is tied to Vin.
The 24VAC common from the HVAC system (blue wire, C, 24VAC common) is tied to the GROUND plane of the MKR 2. You do not have to worry about ground loops if you probe the circuit board with a device that is grounded to the house common, because the 24VAC transformer(s) serve to isolate the 24VAC common from the house common. (But if the 24VAC hot and common wires were incorrectly swapped somewhere, that will be a problem).
The Nano 33 IoT microcomputer's microcontroller requires 3.3VDC to operate, and its circuitry includes a 3.3V regulator to provide that. The MKR 2 provides 5V to the Nano, and that feeds the 3.3V regulator. An output pin on the Nano makes the 3.3VDC available on the MKR 2 circuit board, and it is used by the LCD display (but currently not by the thermostat circuitry).
The prototype area includes an LED that lights up when 5VDC is present, indicating the thermostat has power.
Beeper/Buzzer
The MKR 2 board has a beeper on it that the thermostat software uses to provide an audible beep when the user touches a button on the screen. This is done using the SAMD_PWM library.
LCD display and touchscreen
The MKR 2 LCD display is 240 pixels wide and 320 pixels tall. The controller is an ILI9341 IC. Using the Adafruit_ILI9341 library, the pixels are programmed to be 16 bits each, allowing for 64K+ colors. However, 19 color constants are defined in that library and I used those as they are sufficient.
The Adafruit_GFX library provides functions to write shapes and text to the LCD, and it includes several font files supporting four different font sizes, each with normal, bold, italic, and bold italic, and three font styles (mono, serif, sans serif) plus some tiny fonts. The thermostat makes use of a subset of the full set of fonts.
The LCD display is covered with a touch-sensitive screen, connected to an XPT2046 controller IC. I modified the Arduino XPT2046_Touchscreen library to add some needed features, and released the modified code as a new Arduino library named XPT2046_Touchscreen_TT. It is used by the software to initialize and communicate with the controller and register screen touches.
I wrote code for an extensive set of C++ classes that makes it easy to create buttons on the LCD display, and have released this code as a new Arduino library named Button_TT.
Microcontroller Arduino code shortcomings
The Nano 33 IoT microcomputer uses an Atmel SAM D21 G18 microcontroller. This is quite the beast, with lots of devices to make the programmer's job easy, including a wi-fi interface. The thermostat is using only a subset of those and does not currently use the wi-fi. The microcontroller data sheet is over 1000 pages, and is provided in project documents as file Atmel-42181-SAM-D21_Datasheet V2.pdf
. Much time was spent studying that data sheet to understand how to operate the microcontroller peripherals, and it should not be necessary for you to do so (unless you are modifying the code for your own purposes. The Arduino standard function library that is often used to control peripherals is very incomplete for this microcontroller, so if you want to write new code to use peripherals, you will probably need to study the data sheet because there won't be existing library functions to make it easy to use them.)
There were a number of issues that cropped up with writing code to use the microcontroller peripherals. For example, some of the Arduino hardware code for the microcontroller restricted the usage of some pins unnecessarily. Ultimately I had to rewrite some of that code, and I've made that available as a new Arduino library named wiring_analog_SAMD_TT. It is used by the thermostat code.
Nonvolatile Memory
It is necessary to store thermostat settings, such as the temperature setpoint, in some form of non-volatile memory that retains its value when the Nano is not powered. For this purpose, the software uses the Nano microcomputer's flash memory that stores the code run by the processor. The library FlashStorage_SAMD accesses a portion of the flash memory and uses it to store software settings, in this case the thermostat settings.
Other custom Arduino libraries
In addition to the above-mentioned 3rd-party libraries SAMD_PWM, Adafruit_ILI9341, and FlashStorage_SAMD, and my custom Arduino libraries Button_TT, XPT2046_Touchscreen_TT, and wiring_analog_SAMD_TT, I wrote and released three more smaller Arduino libraries used in this project. The monitor_printf library makes it easy to do printfs to the IDE monitor window, floatToString converts floating point values to decimal strings, and msToString converts millisecond timer counts to stopwatch-like strings. All nine libraries can be installed in the IDE by going to its Libraries tab and searching for the library name.
Indoor and Outdoor Temperature
Thermistors (resistors whose resistance varies with temperature) are used to measure indoor and outdoor temperature. For the outdoor thermistor, the Beutler SmartVent system used a thermistor mounted (in my case, anyway) in one corner of the outdoor A/C unit.
The wires that normally went from that thermistor to the Beutler controller are instead routed to the custom thermostat using two wires in the 5-wire cable.
A small thermistor is mounted in the MKR 2 prototype area to sense indoor temperature.
Thermistors are typically wired in series with another resistor, and a voltage is placed across the two components. The voltage at the junction between them changes as the temperature changes, and this voltage can be converted into a temperature.
Each different type of thermistor requires that certain coefficients be set in the software so it can properly compute temperature from the thermistor resistance. I provide some Python functions in project file thermistor.py
that can be used to compute the coefficients from temperature/resistance pairs given in the thermistor data sheet. There are several different sets of thermistor coefficients in the code, all commented out except for one indoor and one outdoor thermistor. If you use the same thermistors as I do, you won't need to touch the code, but if you use a different thermistor, you will need to comment out my thermistor coefficients and uncomment a line with your coefficients, or add a line if you have a thermistor with different coefficients. See Appendix B for further information.
The Nano microcomputer includes an analog-to-digital converter (ADC), which lets software read external voltages such as the one just described. I had a terrible time getting reliable temperature readings. Here are some of the things I went through to try to get good readings:
- Use 1% tolerance resistors in series with thermistors
- Use a more expensive thermistor for indoor temperature
- Add a capacitor to the Nano board and another to the MKR 2 board to reduce power supply noise
- Run an ADC calibration program to set the ADC calibration registers accurately
- Play around with the thermistor coefficients, assuming they might be wrong
- Try to manually measure thermistor coefficients by exposing the thermistor to hot water and ice water
- Compute a long-term moving average of temperatures
- Add a special hysteresis rounding algorithm when converting temperature to an integer
None of these things solved the problem, although some of them helped! The real problem turned out to be that the ADC had a truncated range that was not compensated for by its internal calibration registers and interfered with computing the correct calibration values. I solved the problem by including a series resistor and capacitor as part of the thermostat circuitry. A microcontroller pulse width modulation (PWM) device drives a PWM signal onto the resistor/capacitor, creating a very accurate known voltage, which I then measure with the ADC. With this technique I was able to do my own ADC calibration, and that finally solved the inaccurate temperature readings. I later discovered that newer versions of the Nano 33 IoT seem to have more reliable ADCs, perhaps because they use newer versions of the Atmel microcontroller that fix problems with the ADC device. See Appendix C for more details.
SmartVent Damper Control
The EcoJay SmartZone-4X controller can open and close the SmartVent damper when it is wired to zone 4 of the controller and the zone 4 thermostat type setting is "FA" (fresh air). The EcoJay automatic modes are not useful when you have a SmartVent, so they are not used and most zone 4 thermostat inputs are left unconnected, and additionally, the fresh air run time should be set to 0.
There is one EcoJay zone 4 thermostat input that is used, the Vent (green wire, G) input, which when activated causes the controller to open the SmartVent damper to outdoor air and turn on the furnace fan. This custom thermostat drives that Vent input with 24VAC to turn on SmartVent. It does so using a relay that connects 24VAC from the transformer to the Vent input on the EcoJay controller. A relay is used in order to isolate control signals from the other electronics in the MKR 2.
The relay is activated by software when it turns on a microcomputer digital output (3.3V output) that is connected to the base of NPN transistor Q1 (through a resistor). The transistor emitter is grounded and the collector is connected to one side of the relay coil, the other side being connected to 5VDC. When the digital output goes high, the transistor turns on, and that turns on the relay and closes its contact, thus connecting 24VAC to the EcoJay zone 4 Vent input and activating SmartVent venting.
An LED in the prototype area is connected to the transistor collector and it lights up when the relay is activated to turn SmartVent on. While lying in my bed at night looking at my SmartVent thermostat, this LED and the 5VDC power LED mentioned previously are visible to me, so I can tell if SmartVent is on. I had to tune the LED resistors to keep the brightness low enough that it didn't bother me.
Step 5: Test ing AZ-Touch MKR 2Before actually starting on the thermostat proper, it is a good idea to test your AZ-Touch MKR 2 to make sure that all of its different parts work properly. This also provides the benefit of giving you the hands-on experience of installing the Arduino IDE and using it to load code into the Nano 33 IoT microcomputer. In addition, it is always fun to see a display light up.
We'll test the Nano 33 IoT LED, MKR 2 beeper, touchscreen, and LCD display using code I've written just for this purpose. I will explain the code in some detail, which you can either skim, or skip, or read carefully if you are new to programming and want to learn.
Installing the Arduino IDE
If you don't already have the Arduino IDE software application installed on your computer, do so now. Visit https://www.arduino.cc/en/software to find the IDE software download. After downloading, follow usual procedures and/or given instructions for installation. Start the program running to ensure it starts up, then quit out of it.
Note: Arduino for some reason prefers to call programs
sketches
, but I prefer to call them programs
like everybody else. I'll use the word sketch occasionally if needed for clarity, but otherwise I'll use the word program.
Connecting Nano 33 IoT to the computer
You should have a Nano 33 IoT (hereafter just "Nano") microcomputer (see earlier photo) with two sets of header pins that may or may not already be soldered to the microcomputer board. You don't need them soldered on yet for the first few of these tests.
You must connect a USB cable from a USB port on your computer (that has the Arduino IDE installed on it) to the micro-USB port on the Nano. It is essential that the USB cable be a power+data cable and not a power-only cable. It is my experience that most USB cables with a micro-USB connector at one end are power-only cables. How do you tell if you have a power+data cable? Probably the simplest way is to test if the Arduino IDE can connect to the microcomputer over the cable.
Start by running the Arduino IDE on your computer. When it starts, it loads the last sketch (program ) you were working on and any others you had open, or if none, it starts with no open sketch. Strangely, if it has one open sketch and you close it, the IDE exits rather than staying open with no open sketch. If this happens, rerun it.
With the IDE running, choose "File", "New Sketch". This creates a window with an empty sketch (an empty program), which consists of two empty C++ functions named setup()
and loop().
Every Arduino program must be assigned to an Arduino "Board" (microcomputer), of which there are many many varieties. The one we are using here is the Nano 33 IoT. To choose that board for the empty sketch, choose "Tools", "Board", "Arduino SAMD Boards (32-bits ARM Cortex-M0+), Arduino Nano 33 IoT. If you don't have Arduino SAMD Boards, choose "Boards Manager" instead and search for and install the Arduino SAMD Boards, then try again.
Look at the Nano board and notice the tiny white pushbutton. Press it twice in a row, quickly. You should see the built-in LED on the Nano board, which is located between the micro-USB connector and pin 1 of the board, begin to pulsate on and off. This indicates that any program that might be running (or hung up in a non-running state) in the Nano has been shut down, and the Nano boot program is waiting for a connection to be made at the USB port. Normally it is not necessary to do this, but occasionally you might load a bad program into the Nano and find that you can't upload a replacement program. In that case, double-click the pushbutton and try the upload again! You probably should put the Nano in this "pulsating LED" mode while you are trying to connect to it with a USB cable. To do so, you will need to double-click the white button each time you connect a new USB cable.
At this point you are ready to begin testing USB cables. Connect a candidate USB cable from your computer to the micro-USB connector on your Nano board. Note that one side of the micro-USB connector has two small "fingers" facing upwards. Those two fingers should be UP to plug the connector into the Nano. Double-click the white button to get the pulsating LED, then test the cable for data capability by choosing "Tools", "Port", and see if a port whose name includes "usb" is listed. If so, choose that port. If no such port is listed, the cable is probably power-only, so disconnect it and get another one and repeat the process.
Once you are able to choose a port with "usb" in its name, that is probably the right port (unless there are more than one such ports). To confirm that it works, click the right-arrow in the upper left corner of the IDE window (just to the right of the checkmark icon). You should see an output pane appear at the bottom of the IDE window with messages in its lower-right corner that say "Compiling sketch", "Done compiling", "Uploading", "Done uploading". If so, the cable is good. If you get an error message that it couldn't upload, try again selecting the usb port under Tools, Port, and repeat the process, and if it still fails, try another cable until you find one that works.
I had 7 cables and only one was a power-data cable. If you can't find one, buy a cable that is specified to be power+data.
Writing an LED blink program
Now that the Nano is connected to the IDE, let's start with a simple little program to flash the LED on the Nano board. With the IDE still running with a new program opened, either replace that program with the following program by copying and pasting, or just type this new program directly into the new program in the IDE.
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(400);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
This is a simple C++ program that flashes the built-in LED on the Nano board, 400 milliseconds (0.4 seconds) on and 200 ms (0.2 s) off.
In C++ a function is a program piece with a name (the function name) followed by parentheses which sometimes contain function arguments inside them but are empty if there are no function arguments, followed by an open curly brace, followed by C++ code to be executed whenever the function is "called", followed by a final closing curly brace. The word "void" in the function definitions above means the function does not return a value to its caller. Other words can be used to indicate the function does return a value. For example, "int" would mean that the function would return an integer value.
A C++ function is called by using its name followed by a pair of parentheses, inside of which there will be values to use for the function arguments if the function has arguments. All C++ statements end with a semicolon (;)
. Calling a function causes its code to be executed, and when the end of the code is reached at the closing curly brace, the function is said to "return", meaning that execution continues at the code that follows the call to the function. When a function has a return value, it returns by using a return statement, which consists of the word "return" followed by a pair of parentheses inside of which there is the single return value.
All Arduino programs have the two functions shown here, setup()
and loop()
. When the Arduino microcomputer starts running, it runs some setup code behind the scenes to prepare the microprocessor to run your program, and then it calls the setup()
function once. You place your initialization code inside the setup()
function. Here we have a call to the built-in function pinMode
to set the microcomputer port pin that is connected to the built-in LED to be an output (it defaults to being an input).
After the setup()
function has returned, the loop()
function is called over and over forever. You put code that is to be executed repeatedly while the program runs inside loop()
. Here we call two built-in functions, digitalWrite()
and delay()
, twice each, writing a HIGH value to the built-in LED output port to turn the LED on, delaying 400 ms, writing a LOW value to turn the LED off, and then delaying 200 ms. The right curly brace at the end of the function is then reached, and the function returns. It is then immediately called again.
Compiling, downloading, and running the program
After a program is written, it must be translated into code that the microcomputer understands. This is done in a process called compiling, which also checks the program for some types of errors, such as mistyped words or other syntax errors. After compiling, the translated program must be loaded into the microcomputer, a process called uploading. Once a program is uploaded into a microcomputer, it starts running.
To compile and upload the program, click the right-arrow button on the IDE in the upper-left corner. If you have any syntax errors in the program, compiler errors will occur and will be shown in the output pane at the bottom of the IDE window. You must find and fix them and try again. Pay attention to the line (and column) numbers in the error messages to see where the error was detected. Usually the IDE will position the text cursor on the line where the error was first detected. I usually fix one error at a time and try again until there are no more errors. If you don't make mistakes typing in the programs I give here, you won't have any errors.
Once the program successfully compiles and uploads into the Nano, it automatically starts running, and you should see the built-in LED, located between the micro-USB connector and pin 1 of the Nano, begin to flash at the chosen rate.
You should save the program in case you want it later. Choose File, Save As, browse to the folder where you want to store programs (I usually save programs in my Documents/Arduino/programs folder), change the name to something like Flash_LED
, and save it. If you examine the folder with your file browser, you will see that the IDE made a new folder within the folder you browsed to, giving it the name you gave to the program, and inside that folder is a file with that same name and the suffix .ino
. That suffix indicates the file is an Arduino program file with setup()
and loop()
functions.
The IDE uploads programs into the EEPROM memory of the microprocessor on the Nano board, and that memory is non-volatile, so the program remains when the board is powered down. It will start running again when powered up, and it does not require the IDE to run. You can see this by quitting out of the IDE, disconnecting the USB cable, then reconnecting it. The Nano LED should start flashing again. You could even use a power-only USB cable because the only purpose of the cable now is to supply power.
You can also force the Nano microcomputer to reset and start running the program anew. Do this by pressing the tiny white reset button on the Nano one time only (not a double-click like before).
If this test was successful for you, congratulations, you have achieved a lot! You have installed the Arduino IDE on your computer, run it, created a new empty sketch (program), connected your Nano to the computer with a USB cable, used the IDE to enter a C++ program with initialization code in the setup() function and repetitive code in the loop() function, compiled the program and uploaded it into the Nano over the cable, watched the program run successfully, and saved the program. Then you ran it again without the IDE, reset the Nano with the white button and watched the program restart. That's the basic development cycle for programming an Arduino.
This has confirmed that the Nano 33 IoT is functional.
Plug Nano into MKR 2 and run LED program again
Next we will begin to confirm the functionality of the MKR 2 board. This is where you will need the header pins soldered onto your Nano. If they aren't already, solder them in place. Here are some recommendations for doing that:
- The header pins must be long enough to reach through the holes in the MKR 2 board and fit into the connector on the underside of the board. I found that I needed to push the pins slightly through the black plastic pin holder so that the short end of the pins didn't stick out quite so far and the long end stuck out slightly farther for a nice tight fit into the MKR 2 socket. One way to do this is to stick the short ends through the prototype area of the Nano board, flip it over, and push down on the pins to force them through the black plastic pin holder. That may push them a bit TOO FAR, though, so you might be able to devise a better way. Best seems to be when the pins stick up above the top surface of the Nano board by about 1 mm.
- Don't use a soldering iron that is too hot, it could damage the board. You want around 350°C to 375°C.
- Apply a tiny bit of solder to the soldering iron tip to help it conduct heat well into the pins and Nano board's pads.
- Skip around among the pins so you do don't apply too much heat at one time to a small area of the board.
- Some pins are connected to the ground or power planes, which act as strong heat sinks. These are much harder to get hot enough to solder, and you need to leave the iron on the pad quite a bit longer before the solder will melt.
Once you have the header pins soldered in place, orient the Nano board correctly and push it into the 30-pin Nano connector on the MKR 2. The connector is labelled "Arduino Nano IoT". Pin 1 is the pin closest to the center of the MKR 2 board. The Nano must be oriented so the micro-USB connector is towards the middle of the board and not towards the corner. Then pin 1 of the Nano is in pin 1 of the MKR 2. Refer to the earlier pictures. It is possible to insert the Nano backwards so its pin 1 is towards the corner of the MKR 2. DO NOT DO THIS, IT WILL PROBABLY BURN OUT THE NANO IF POWER IS APPLIED. You should mark a "1" next to pin 1 on the MKR 2 using a Sharpie, to help you avoid accidentally plugging the Nano in wrong. Maybe you can also put a mark on pin 1 on the Nano.
Now, connect the USB cable again, between your computer and the Nano. This should power up the Nano and the MKR 2 board, and the Nano should again start running its LED blink program and the LED should start blinking again. If not, unplug the Nano from the MKR 2 and see that the blink program works. If plugging the Nano into the MKR 2 causes it to stop blinking, and you are certain you have the correct Nano orientation, there must be some problem with the MKR 2 board.
If the LED blinks when the Nano is plugged into the MKR 2, congratulations, you now know how to properly plug the Nano into the MKR 2, and you have confirmed that the Nano still works when plugged in.
Testing the MKR 2 beeper
The MKR 2 board has three devices on it, and we want to test them. These are a beeper, a touchscreen, and an LCD display. Let's first test the beeper.
An easy way to start a new program is often to modify an existing one. We'll modify the LED blink program. Open it in the IDE ("File", "Open", unless you still have it open from before), then choose "File", "Save As", browse to the same program storage folder you browsed to before (it may already be positioned there), and then enter a NEW NAME such as Beeper_Test
and save it.
The IDE window containing the program should now show the new name you've given the program. Next, edit the program to contain the following code. You can simply cut and paste, or note that the two programs are very similar and you could edit it instead.
#define BEEPER_PIN A3
void setup() {
pinMode(BEEPER_PIN, OUTPUT);
}
void loop() {
digitalWrite(BEEPER_PIN, HIGH);
delay(4);
digitalWrite(BEEPER_PIN, LOW);
delay(2);
}
Like the Flash_LED
program, the Beeper_Test
program sets a digital port to be an output, and then drives that port alternately HIGH and LOW, repeatedly. The differences are that the pin being driven this time has been defined as pin A3, which is the Nano pin connected to the beeper device on the MKR 2 board, and the rate at which the pin is driven is 100 times faster, with 4 ms high and 2 ms low.
Save the program (File, Save), then compile and upload it with the right-arrow button. The beeper should immediately begin making an obnoxious sound. You'll probably want to halt it immediately, which you can do by disconnecting the USB cable, but eventually you'll want to connect it again, and immediately the noise will start. Instead, you could get rid of the four statements inside the loop()
function and compile and upload the result. The sound will stop. But, the IDE automatically saves a program when you compile it, so the modified program has overwritten the program you saved. To fix this problem, use Edit, Undo Typing to undo the deletion, then File, Save to save the program again with the four lines (but don't upload the program again or the beeping will start).
The advantage of saving programs is that you can reload them at any time (File, Open) if you want to run them again later.
We have now tested the beeper on the MKR 2 board.
Testing the MKR 2 touchscreen - Installing Libraries
Next we will test the touchscreen on the MKR 2. To do this, we'll use a library created for use with this touchscreen. This step will allow you to gain experience installing new libraries in the IDE if you haven't already.
The original library for the touchscreen was named XPT2046_Touchscreen,
written by Paul Stoffregen. You can install it and use it here and that should work. However, I modified this library to add some additional capability that I make use of in the thermostat code. This modified library is named XPT2046_Touchscreen_TT
, with the "_TT" suffix being my initials. We'll use the modified library.
We will also make use of another library of mine named monitor_printf
. It provides an easy way to print information to an IDE window called the monitor window.
Assuming you haven't installed these libraries yet, install them now. The procedure to install an Arduino library is:
- Start the IDE and click on the books icon at the left side of the main screen. This opens the Library Manager sidebar. (Another click closes it).
- In the Library Manager search window at the top, enter the library name. Let's start with
monitor_printf
. It should find the library and show it first, along with others that might have similar names. It will show the author of the library, in this case, my name, Ted Toal. - Click the Install button. The library should be installed. The place where it is installed (on my machine) is: Documents/Arduino/libraries/monitor_printf and if you browse there with your file browser, you can see the library files. One important file you may find is named
README.md
. It is often a detailed description of what the library does and how to use it. You may need to find a suitable program that can open a ".md" file in order to read it.. I recommend that you browse to the library directory and skim the filenames, then find an application that shows ".md" files, install it, and skim theREADME.md
file for this library.
Repeat the same process for the other library, XPT2046_Touchscreen_TT
.
Congratulations, you have searched for and installed two Arduino libraries, seen how they are stored in the libraries folder, installed a program to view ".md" files, and viewed the README.md
files for the libraries.
Testing the MKR 2 touchscreen - Writing the test program
Now create a new program (File, New Sketch) and replace the bare-bones program with the following program:
#include <Arduino.h>
#include <monitor_printf.h>
#include <XPT2046_Touchscreen_TT.h>
#define USE_MONITOR_PORT 1
#if USE_MONITOR_PORT
#define MONITOR_PORT &Serial
#else
#define MONITOR_PORT NULL
#endif
#define TOUCH_CS_PIN 10
#define TOUCH_IRQ_PIN A7
XPT2046_Touchscreen* ts;
void setup() {
monitor.begin(MONITOR_PORT, 115200);
monitor.printf("Hello world!\n");
ts = new XPT2046_Touchscreen(TOUCH_CS_PIN);
ts->begin();
ts->setRotation(1);
}
void loop() {
if (ts->touched()) {
TS_Point p = ts->getPoint();
monitor.printf("Pressure = %d (x,y)=(%d,%d)\n", p.z, p.x, p.y);
delay(500);
}
}
Before examining or running this program, compile it without uploading. This is done with the checkbox button at the upper left of the IDE. If any compile errors occur, double-check what you typed in, find the errors, and fix them.
There is a lot to unpack with this program. Let's work through it slowly.
The first line is #include <Arduino.h>,
which causes the file named Arduino.h
to be found (somewhere within the Arduino libraries and run-time code) and its contents inserted at that point in the program. Files whose names end in .h
are called "header files" and they contain code that provides definitions and declarations needed to use something. This particular file contains basic definitions that many Arduino programs might want to use, including declarations of basic functions we've already seen such as delay()
and digitalWrite()
. It is good practice to use this #include <Arduino.h>
statement at the start of every program you write. (I think that if you omit it, the file might be #included ANYWAY, but it is best to make it explicit.)
Sometimes you may want to look at the contents of a #include file such as Arduino.h
. This is easy to do, provided that you have compiled the program at least once already (which is why I had you do it already). Hover the mouse cursor anywhere over the #include <Arduino.h>
line and right-click to bring up the context menu, then left-click "Go to Definition". This opens a new tab in the IDE, containing the file Arduino.h
. This can be a very handy technique to find system files that otherwise may be hidden in some obscure directory.
The next lines are #include <monitor_printf.h>
and #include <XPT2046_Touchscreen_TT.h>.
These lines include the main header files for the two libraries we are using, which is what allows us to use those libraries in our program. It is typical for libraries to have a main header file that is often given the same name as the library with .h
appended.
The next line is #define USE_MONITOR_PORT 1,
which defines a compile-time constant named USE_MONITOR_PORT
and sets its value to the character string "1". Now any time we use this constant name later in the program, the string "1" is substituted for it by the compiler, before proceeding with the compile. It is a handy way to name constants to improve program readability. We used this statement because the README file for the monitor_printf
library recommended this.
The next 5 lines starting with #if USE_MONITOR_PORT
and ending with #endif
were also recommended by the monitor_printf README file. You can read the library README files to learn details about using the library, if you are interested.
The next two lines, #define TOUCH_CS_PIN 10
and #define TOUCH_IRQ_PIN A7,
define two more constant names. These are the two PIN numbers from the Nano that connect to the touchscreen XPT2046 controller on the MKR 2 board. They are used by the XPT2046_Touchscreen_TT
library to talk to the controller and read the touchscreen touch pressure and position.
The next line is XPT2046_Touchscreen* ts;
which is taken from the XPT2046_Touchscreen_TT
library's README file. It defines a variable named "ts" (for "touch screen") that points to a C++ object class named XPT2046_Touchscreen.
That object class contains the code necessary to talk to the XPT2046 controller.
Next we have five lines inside the setup()
function. The first is monitor.begin(MONITOR_PORT, 115200);
which is taken from the monitor_printf
library's README. It initializes an object named monitor
by calling its begin()
function. The monitor
object is able to print text via the USB cable to a pane in the IDE, and this is very handy for debugging programs. The statement here tells it which Nano serial port to use to talk to the IDE, and what speed to communicate at (115200).
The next line is monitor.printf("Hello world!\n");
which calls the printf()
function of the monitor
object. That function expects its first argument to be a text string, and it prints that string over the USB cable to the IDE monitor pane. We'll see that pane below. The \n
is a C++ construct meaning to start a new line.
The next line is ts = new XPT2046_Touchscreen(TOUCH_CS_PIN);
which uses the C++ new
function to allocate memory for a new object of class XPT2046_Touchscreen
and assigns a pointer to that object to the ts
variable we created earlier.
The next line is ts->begin();
which calls the begin()
function of the ts
object, and that function initializes the touchscreen XPT2046 controller.
The last line in setup()
is ts->setRotation(1);
which calls the setRotation()
function of the ts
object to specify which of the four orientations (0, 1, 2, 3) of the touchscreen we'll be using.
Finally, we see four statements in the loop()
function. Recall that these will be executed repeatedly as the program runs. The first is if (ts->touched()) {
which is an if
statement that calls the ts
object touched()
function and tests its return value to see if it is true, indicating that a touch of the touchscreen has been detected. If so, the statements inside the curly braces { }
are executed.
The first statement inside the curly braces
is TS_Point p = ts->getPoint();
which declares a new variable named p
of type TS_Point
which is a type defined in the XPT2046_Touchscreen_TT library and is described in its README file. It contains values (x, y, z) as if coordinates for a 3D point, but actually (x, y) is a 2D point on the touchscreen and z is the pressure of the touch. The variable p
is assigned a pointer to the TS_Point
object that is returned by the ts
object getPoint()
function. The TS_Point
object contains the current touchscreen touch position if any.
The next statement inside the curly braces
is monitor.printf("Pressure = %d (x,y)=(%d,%d)\n", p.z, p.x, p.y);
which is another monitor
object printf()
call. It is more complex than the earlier one. The first argument is still a text string, and as before it is printed verbatim to the IDE monitor pane, with the exception of any percent specifiers, which always start with a %
character and are usually followed by a lower case letter, d
in this case. Each %d
means that the next printf()
argument is expected to be an integer value to be printed in decimal at that point in the text string. There are three %d
specifiers and there are three integer arguments following the first text string argument to printf()
. You will see what the resulting text string looks like when you run the program and look at the output in the monitor pane.
The last statement inside the curly braces
is delay(500);
and its purpose is to delay half a second so that text strings don't spew out into the monitor pane too rapidly to read.
Testing the MKR 2 touchscreen - Opening the Monitor Pane
The IDE has a special window pane called the Serial Monitor or simply Monitor for viewing text sent over the USB cable by the microcomputer program that is running. It can also send text back to the microcomputer program. It is often used for program debugging. The monitor_printf
library makes it easy to print data to it using the printf()
function that we saw above.
To display the Serial Monitor pane, click the icon in the upper-right corner of the IDE that says "Serial Monitor" when you hover over it. A tab named "Serial Monitor" will appear at the bottom of the main IDE window. The size of the pane can be changed by dragging the boundary line between it and the code window above with the mouse.
The communication parameters must be set before using the Serial Monitor. In the upper-right corner of the pane the communication speed is shown in baud. We have set the program above to use 115200 baud, so choose that number in the drop-down speed box. Next to it, choose "Both NL and CR" so that when our code prints the special character '\n', the monitor will display a newline (NL) and will return the cursor to the start of that line (CR = carriage return).
Three icons above those settings are also important. A downwards arrow lets you turn on auto-scroll, which you usually want on, else new text scrolls off the bottom of the screen. The clock icon shows timestamps for each text string printed, and I usually turn that off. The little icon with bars in it clears the monitor pane of text.
Another pane usually also appears at the bottom of the IDE window, named Output. The Serial Monitor and Output panes have tabs, and you can only view one of the two at a time, by clicking on its tab. The Output pane shows compile and upload messages. When you do a compile or upload, the IDE will automatically switch to the Output tab if you are on the Serial Monitor tab. This is sometimes a nuisance, especially because sometimes you want to clear the text from the Monitor window, but when you go to click on the clear-text icon it disappears as the Output pane is displayed. If it automatically switches to the Output pane, it will usually automatically switch back after the upload is complete.
Testing the MKR 2 touchscreen - Running the Test Program
Now compile and upload the program entered above. When it finishes, look at the Serial Monitor tab. The program should print "Hello World!". Touch the touchscreen. It should print the (x, y) coordinates of the touch position and the touch pressure. Move your finger around, and every half second it should print an updated position and pressure. Notice that the lower-left corner of the screen is the corner that has the smallest coordinates.
You can restart the program by clearing the Monitor pane and then pressing the little white reset button.
If you've made it through this, congratulations again! You've successfully learned about the IDE's Serial Monitor pane and how to use it, you've written a touchscreen test program that prints coordinates of touches to the Monitor pane, and you've compiled, uploaded, and run that program.
This confirms that the touchscreen is working. It also installs the monitor_printf
and XPT2046_Touchscreen_TT
libraries, which are needed for the thermostat.
Testing the MKR 2 LCD display
Next we will test the LCD display on the MKR 2. The display uses an ILI9346 controller. We will use a library from Adafruit called Adafruit_ILI9341
, which talks to the controller to write to the display. It uses another Adafruit library, Adafruit GFX Library
, which provides functions for writing text and graphics to a display. The two of those use some other libraries. You only need to install the Adafruit_ILI9341
library, which you do using the same library installation procedure described above. When you do so, you will be prompted whether you want to install the additional dependent libraries. Respond Yes to that, to install all the required libraries.
We will use an example program that is part of the Adafruit_ILI9341
library to test the display. Most libraries come with one or more example programs, and these are a very handy source of simple code that uses the library. Often you can copy and paste from example programs to simplify programming work. The example programs are found in the library's subfolder, which is usually named the same as the library or very close to it, and its location is within the Arduino IDE libraries
folder. On my system that folder is at Documents/Arduino/libraries, and within that folder I find a subfolder named Adafruit_ILI9341,
and within that folder is an examples
folder. That's where the subfolders for the example programs are located.
The example program we will use is named mandelbrot.ino,
which draws a fractal curve on the display, and that file is located inside the mandelbrot
folder within the examples folder described above. Use the Arduino IDE to open it (File, Open).
Typically, example programs use hardware devices, and although you may have the same hardware devices, they might not be connected to the same digital I/O pins of your microcomputer as they were in the author's system. That is the case here. Look in mandelbrot.ino
and you will find two pairs of #defines of TFT_DC
and TFT_CS.
The pairs are located within a #ifdef/#else/#endif construct that is processed by the compiler preprocessor to select one or the other halves of the statement depending on whether ADAFRUIT_PYPORTAL
is defined. In our case it should not be defined, and we want the two #defines after the #else. Notice that there are also two other constants ending in _CS. They aren't used in the program and we ignore them. Edit the values to be correct for the Nano and MKR 2, and add a third #define statement to define the digital I/O pin that is connected to the display backlight LED, which must be turned on to see anything written to the display. Your changes should look like this:
#define TFT_CS 10
#define TFT_DC 2
#define TFT_BACKLIGHT_LED A2
One more change is needed, the backlight must be turned on in setup(). Scroll down and find the setup() function, and after the Serial.print("Mandelbrot drawer!"); statement, add these two lines to turn on the backlight:
pinMode(TFT_BACKLIGHT_LED, OUTPUT);
digitalWrite(TFT_BACKLIGHT_LED, LOW);
Note that a LOW output value turns the backlight on, while a HIGH output value turns it off.
You may be wondering about the Serial.print()
statement, which is different than the monitor.printf()
call we used earlier. Serial.print()
can also print text to the monitor window, but it doesn't have the sophisticated formatting capabilities of monitor.printf()
.
You are now ready to compile and upload the program and watch it run. Do that. If you display is working properly, you should see a couple of colorful fractal curves gradually appear on the display, at right angles to each other.
And, congratulations again! You've successfully learned to locate, open, modify, and run an example program that comes with an Arduino library.
This confirms that the LCD display is working. It also installs the Adafruit_ILI9341
and Adafruit_GFX_Library
libraries, which are needed for the thermostat.
Testing the Touchscreen, Display, and Beeper Together
Our final test will be to test the LCD display together with the touchscreen. For this we'll use another library I wrote, named Button_TT
. Use the IDE to search for the Button_TT library and install it. The library has many functions that support drawing buttons on the display, testing for taps of the buttons, and responding to those taps.
A second library is also needed, named SAMD_PWM
. It supports use of the pulse width modulator (PWM) within the Nano microcontroller to generate waveforms on the digital I/O pin that connects to the beeper. Search for the SAMD_PWM library and install it.
We will use an example program that comes with the Button_TT
library, named HelloWorld.ino
. Use the IDE to open that file (File, Open). We do not need to change any settings in this program, because I wrote it specifically for use with the Nano and MKR 2, so the digital I/O pins are already set properly. Compile and upload the program. When it runs, it draws a button (a rectangle) on the screen with the text "Hello World!" inside it. Tap the button with your finger or with the plastic stylus that comes with the MKR 2. The text changes to "Goodbye World!" and toggles back and forth each time you tap the button. While you are touching, the beeper will produce a sound.
This step has installed two more libraries needed by the thermostat, SAMD_PWM
and Button_TT
. We are ready to move on to the hardware-oriented tasks of creating the thermostat.
If you haven't already done so, route a 5-conductor 20-gauge solid copper insulated wire cable from your EcoJay controller to (and through) the wall where the thermostat will be mounted. (Sometimes 18-gauge is used, although with this thermostat you can probably get by with even a smaller gauge than 20). The cable should be sticking out of the wall, and you will want it to be able to slide in and out. I made a hole about 1/2" in diameter, then later sealed it with a soft rubbery tape that I had.
I added a 5-pin male plastic connector to the end of the 5-wire cable protruding from my wall, and added a corresponding 5-pin female connector to the prototype area of the MKR 2, making it easy to connect and disconnect the thermostat from the cable. This was particularly helpful because, prior to doing it, I found that as I connected the individual wires to the thermostat, I would sometimes touch them to one another or to some electronic device on the thermostat, shorting things out and in at least one case burning out some parts.
The connector pair (male and female) that I used had 8 pins, and I used only five. Both the male and female connector had pigtail wires coming out, which simplified things because it was not necessary to go through a pin-crimping process that can be problematic, and also because the solid copper wire in the cable is not easily crimpable, but the pigtail wires can easily be soldered to it. The exact connector style is not important as long as it will fit within the thermostat case and has at least 5 wires, so you can improvise with a different connector if you want.
First hold the two connectors in position within the baseplate in the orientation you want them to be in when connected. Think carefully about which side of each connector should face the wall (and hence face upwards when viewed looking down on the case with circuit board installed). Make sure there is room for the connectors and that they won't hit any bolts or components.
Prepare the male connector (which attaches to the cable wires) by tinning the 5 pigtail wires you will be using (white, yellow, green, blue, red) and cutting the unused wires just slightly short. Add a piece of heat shrink tubing to each of the 5 tinned wires.
Cut the cable end insulation back a bit to expose the 5 solid copper insulated wires, spread them in color order (WYGBR), strip and tin their ends, and add a large piece of heat shrink tubing over all the wires and slip it down the cable a ways.
Solder the male connector wires to the 5 cable wires.
Move the small heat shrink tubes into place and heat them to shrink them.
Slide the large heat shrink tube into place and heat it to shrink it. I left the unused wires in place and covered them also with the large heat shrink tubing.
The remaining work involves the female connector, and this is described as part of the upcoming section on soldering the circuitry.
Step 7: Connecting cable to EcoJay and outdoor thermistorWith the 5-pin male connector installed on the end of the cable that attaches to the thermostat, you can wire up the EcoJay end of the cable. Here I will assume that your cable colors are as follows. Make appropriate changes if you have different colors.
- Red: 24VAC hot
- Blue: 24VAC common
- Green: EcoJay Zone 4 thermostat vent input (G connector on zone 4)
- Yellow: outdoor thermistor connection 1
- White: outdoor thermistor connection 2
Strip about 3/8" of insulation off each wire.
Yellow and White: outdoor thermistor
The outdoor thermistor was connected to your old Beutler controller but is not connected to the EcoJay controller. You should have marked the wires (S1 and S2 on Beutler controller), which should come from the outdoor A/C compressor unit if yours is mounted the same way mine was. Identify those two wires and connect them to the yellow and white wires of the 5-wire cable. The wires connect to the outdoor thermistor and it is not a polarized component, so it doesn't matter which wire connects to yellow and which to white. I used small wire nuts to secure the wires that I twisted together.
Green: EcoJay Zone 4 vent input (G connector on zone 4 thermostat)
You should have configured your EcoJay controller for fresh air operation. If not, do so now. Refer to the earlier section discussing this. Locate the Zone 4 thermostat connections on the EcoJay and connect the green wire of the 5-wire cable to the "G" connector within Zone 4. You don't really need to turn off HVAC power to do this.
Red and Blue: 24VAC hot and common
For this step it is best if you turn off HVAC power so you take no chances shorting the 24VAC hot and common wires.
If you installed a 24VAC transformer, you have identified its two output wires as hot and common and connected them to the EcoJay POWER connector 24V and 24C connectors, respectively. If you did not install a transformer, you have presumably used your furnace transformer to power the EcoJay, and have connected its hot and common to the EcoJay 24V and 24C connectors.
If there are already two small wire nuts, one on the hot wire and one on the common wire going to 24V and 24C, remove those wire nuts. Otherwise, cut both the hot and common wires not far from the EcoJay, strip some insulation from them, twist the pairs back together, and have a wire nut available to put over each twisted pair to hold them securely, but don't put the wire nuts on yet.
Twist the stripped end of the red wire from the 5-wire cable together with the two 24VAC hot wires that are twisted together, then put on a wire nut to hold them. Repeat the same process for the blue wire from the 5-wire cable together with the two 24VAC common wires.
You should now be able to turn the HVAC power back on and the system should start up and run as usual. The other end of the 5-wire cable is still unconnected, having only a 5-pin male connector on the end of it.
Step 8: Soldering the circuitryBegin the process of soldering the circuitry and wiring to the prototype area of the MKR 2 circuit board by removing the LCD display from the MKR 2 and removing the K2 connector, which isn't needed and can get in the way. Then place all of the components shone in the parts list onto the MKR 2 prototype area in their correct positions, as shown by the Excel spreadsheet file named SmartVentPrototypeArea.xlsx
, in the sheet named Component Side
. You can bend the pins to hold the parts in place. They can be cut shorter too, although you may want to hold off on cutting them real short, until soldering is finished.
You will probably want to have a copy of the SmartVent circuit schematic in front of you also, to help identify components and how they interconnect. The schematic is in file SmartVent Thermostat Schematic V4.pdf
.
For the "5-pin header for HVAC connection", this is where the female connector's 5 pigtail wires connect. That connector plugs into the male connector added in an earlier step to the end of the 5-conductor cable coming out of the wall. You can either solder the pigtail wires directly in the holes on the circuit board, or you can cut 5 pins off a header strip that may have lying around, solder those into the circuit board holes, and solder the pigtail wires to those header pins. I did the latter but the former method is easier and recommended.
Some parts have a positive and negative side. Diodes (D prefix on the spreadsheet) have their negative side marked by a band around that end of the diode. LEDs have a longer pin that is positive and shorter one that is negative. The PN2222 NPN transistor has three pins named emitter (E), base (B), and collector (C), which are identified by holding the transistor with pins downwards and flat face of transistor towards you. Then, the pins, left-to-right, are E-B-C (see PN2222.pdf datasheet). The Omron relay has a dip on its top surface that marks the position of pin 10 (not pin 1 as would be expected). The small slide switch has "ON" printed above pin 4. All other parts can be oriented in either direction.
Make sure everything fits. Put the LCD display back on and check that the board will still fit within the case, with baseplate snapped on too. Space is tight. Look for screws hitting components. Consider where thermostat wall mounting screws will be placed. Consider where the male-plugged-into-female connector will lie within the case, and where the wires from those connectors will run to reach the circuit board "5-pin header for HVAC connection" and the hole in the wall behind the baseplate, and make sure there is space for it all. The fuse holder clips may be too tall, in which case you can bend over the tops of them or cut the tops off to fit. Check whether LEDs will be visible though thermostat "vents". Check whether indoor thermistor will be able to be positioned near a vent to get room air to it. (I was worried that heat inside the case might interfere, so I actually drilled a hole in the bottom of my case and pushed the thermistor through, so it sticks out the bottom. You may want to do this too.)
At this point I make two suggestions of possible changes to consider, but it is up to you whether or not to try it. First, the fuse holder is not in the best location, because it is up near the edge of the case, and when the cover is snapped on, it can catch on the fuse holder and bend it. This happened once to me and it caused the fuse to move and touch one side of C1, which blew out my Nano (because the fuse has 24VAC hot on it). You may want to try to rearrange components to move the fuse holder to a safer place. Or, perhaps you can find a smaller fuse, maybe one that can be soldered in place.
Second, I tried to arrange components to minimize the number of wires I had to add to connect everything, but I didn't do an ideal job. You may be able to move some components around and get better positioning with fewer wires needed.
If you make either of these changes, be sure to document what you do by editing the Excel sheet (make a copy and change it to match your new layout), and update the net list on the spreadsheet also.
Once you are sure everything fits and is in the right place, remove the LCD display again, then solder the components in place and trim off the excess leads using flush-cut wire cutters. This is the easy part of the soldering.
While soldering, be sure not to make your soldering iron too hot. Temperature should be no more than about 750° F (400° C). If too hot, it will cause the metal pads on the prototype area to melt off. This happened to me until I learned to be more careful.
You will also see that when soldering to a component that conducts a lot of heat away (e.g. fuse holders, components with thick wire leads), you will need to heat the component wire or terminal for a longer period before the solder will start to melt. I actually used two soldering irons, a small and a large, depending on what I was soldering.
Also, try to use an appropriate size of solder. I originally had solder that was too big in diameter, then overcorrected and went too small. A size of 0.028" diameter is often recommended for soldering prototype boards.
Once the components are soldered in place, it's time to begin soldering wires. Print out the Excel spreadsheet named "Wiring Side". If you haven't already done so, be sure to mark pin 1 of the 30-pin Nano socket on both sides of the MKR 2 board with a Sharpie. Starting at pin 1, the pins are numbered 1 to 30 going in a counter-clockwise direction as viewed from above, with the second row starting at pin 16. Get familiar with the pin numbering and counting from pin 1 or 16 to find a desired pin.
Notice how the prototype area is a grid of pads, and I've given letters and numbers to the columns and rows of this grid, the letters going from A to Q and the numbers from 1 to 10. This is how the net list refers to a pad to which a wire is to be soldered. All the pads in a given net list need to be soldered together into one common electrical connection. The first net list is "A1, A2", so A1 and A2 need to be wired together.
Start at the top of the wiring net list and work down, from simple connections to more complex ones. Many of the 2-node connections are side-by-side and can be soldered by using the technique of applying enough solder that a solder bridge is formed. Alternatively, just solder on a small piece of wire such as from a snipped component lead.
For all longer connections, I used Kynar-insulated 30-gauge wire-wrap wire. I had earlier used various other types of insulated wire, but all them experienced melting of the insulation that made a mess of things. Kynar insulation can withstand quite a bit of heat before it starts to melt. It made the job a lot cleaner.
Make sure you have wire strippers that do a nice easy job of stripping small amounts of insulation from the Kynar wire.
Soldering the wires in place was fairly difficult. I had to deal with hot fingers, wires that wouldn't stay put, solder that over-oxidized or seeped through the hole to the component side of the board, and other things. You will have to have patience and be willing to redo wires that go on poorly. You will need the solder sucker tool occasionally to remove excess solder to start over.
Once you get to nets with three or more nodes (pads), sometimes there will be two or three nodes right next to each other that can easily be soldered together by stripping more insulation from one end of the wire and just running the bare wire from node to node.
When it becomes necessary to wire up three or more nodes that are widely separated, it gets more difficult. I tried to carefully strip insulation from the middle portion of wire-wrap wires, and this was very difficult. I wouldn't recommend it. Instead, I would recommend always using point-to-point wires, and solder two wires to the same node as needed.
When soldering wires in place, be very careful not to make inadvertant solder bridges or bridges caused by wire-wrap wire that was stripped too long. You can use a utility knife to carefully cut off the ends of wires that stick out from the solder.
Some wires go to the Nano 33 IoT microcomputer. Make sure you count to the correct pin number for each such connection.
The last four nets are particularly difficult because there are so many nodes. Take your time, get them right. Note that GND and 24VAC hot are connected at connector K2 (pin 1 for 24VAC, pin 2 for GND). You could also connect GND at the GND pin at position K10.
A final thought on wiring. You may want to add a stiff short wire or post connected to GND, sticking up somewhere (not too high!) to make a handy place to connect a multimeter to ground if needed.
My finished wiring is shown in the photo below. Since doing it I changed the net list a bit to improve layout, so follow the net list in the spreadsheet, don't follow the photo below! (It is about the same though).
When finished, you need to check all the connections using a continuity tester. Usually you can set a multimeter to a continuity setting that will buzz or beep when the two probes are in electrical contact. Start by working your way through the net list and testing that the first node in each net connects to the other nodes in that net.
After checking each net individually, check for shorts between nets. In particular, make sure there is no short between +5V and GND, or between 24VAC and GND. I had one that I had to track down and fix. You should start with the first net and buzz to each other net to make sure it doesn't connect to any other one. Then, move to the second net and buzz to the third through last net, looking for a short. Then the third net, and so on, until you checked for lack of continuity between every pair of nets.
When convinced the wiring is correct, reattach the LCD display to the MKR 2, then plug the Nano 33 IoT into the correct MKR 2 socket, making sure its orientation is correct. Pop the soldered board into the case to make sure it fits.
The final part of soldering the circuitry is to solder the female connector to the "5-pin header for HVAC connection", for connection to the male connector attached to the cable coming out of the wall.
Hold the female connector in proper position in the case, making sure it isn't upside down, and determine the necessary wire length, then cut the pigtails to that length and cut off the unused wires near the connector.
Strip and tin the five female connector wires. The length to strip depends on whether you will be soldering them directly to the five holes in the circuit board (recommended) or to the 5 header pins that were already soldered into those holes (the method shown in the photos, a result of the method of connection being changed to a better one described here).
Cut the unused wires off close to the connector.
If header pins were used (not recommended but the way I did it and shown in the photo), tin the header pins on the circuit board.
Finally, solder the pigtail wires from the female connector directly to the circuit board (or to the header pins on the board). I recommend that you write the letters WYGBR at the 5 holes or pins labelled on the schematic as "5-pin header for HVAC connection", to help with double-checking that the wires are connected properly between the cable and the circuit board.
That completes the solder work on the circuitry.
Step 9: Testing the hardwareBefore trying to run the actual thermostat code, we will test several components that were added to the prototype area. We do these tests with the Nano plugged into its socket on the MKR 2 board. You will want to keep nearby printed copies of the schematic in file SmartVent Thermostat Schematic V4.pdf
and the Component Side
and Wiring Side
spreadsheets from file SmartVentPrototypeArea.xlsx
.
D4 LED,R4, and +5VDC
Unplug your USB cable from your computer, then plug the micro-USB connector into the Nano, and then, while watching the D4 LED, plug the other end of the cable into your computer's USB port and immediately pull it back out again. You should see the LED light up and go back off when you do that. If you don't, something isn't right, so go back and check wiring for D4, R4, and the +5VDC net. If it comes on, there is likely no power supply short, and you can plug it back in and the light should remain on, and nothing should start smoking. :-) The Nano and MKR board should also be powered up now, and the Nano should again start running its LED blink program and the LED on the Nano board should start blinking again.
You may find that the D4 LED is too bright or too dim (but don't forget that it will look a lot brighter in a dark bedroom at night). If so, change R4 (smaller ohms to make the LED brighter, larger ohms to make LED dimmer), doubling or halving it (or more) until you find the right brightness. You will probably need to use a solder sucker to remove the resistor.
This confirms that 5VDC makes it to the D4 LED and that the Nano still powers up and runs with the new circuitry in place.
Relay, R6,Q1, D5 LED, R5, C4,D3, Fuse, DPST switch, pins 1 and 3
For this test we need to write another short program. In the IDE, create a new program (File, New Sketch) and change it to the following:
#define SMARTVENT_RELAY 5
void setup() {
pinMode(SMARTVENT_RELAY, OUTPUT);
digitalWrite(SMARTVENT_RELAY, LOW);
}
void loop() {
delay(2000);
digitalWrite(SMARTVENT_RELAY, HIGH);
delay(2000);
digitalWrite(SMARTVENT_RELAY, LOW);
}
Compile and upload the program to the Nano. When it runs, it turns the Omron relay on for 2 seconds, then off for 2 seconds, repeating indefinitely. As this happens, you should hear a slight click each time the relay turns on or off, and the D5 LED should turn on when the relay is on, off when it is off.
Next, with the program still running, use a multimeter set to a continuity testing setting to test continuity between pins 1 (24VAC) and 3 (Vent Fan) of the 5-pin male connector that connects to the cable from the wall. There should be no continuity when the relay is off. When it is on, there should be continuity only if the fuse is in place and the small switch has been turned ON. Turning the switch OFF or removing the fuse should break continuity.
As with the other LED, you may find the D5 LED is too bright or too dim, and if so, you should change R5 to a value that gives a nice brightness.
This confirms that the transistor and relay circuitry, D5 and R5, and the fuse and switch are working along with the Nano.
You can use the DC volts setting of a multimeter to check whether or not the relay control output, which is the D5 I/O pin on the Nano, is actually going between 0 volts and 3.3 volts (logical 1 is 3.3 volts on the Nano) while the program is running. You may want to increase the on and off time to something much larger than 2 seconds, say 10 seconds (10000 milliseconds), to give your multimeter time to respond.
In all these tests, if the expected results aren't obtained, you need to methodically check the parts of the circuit being tested. Check the circuit wiring using the continuity test setting on a multimeter (with the circuit powered down, USB cable disconnected).
R3 and C3
For this test we need another short program. In the IDE, create a new program and copy and paste the following to it:
#define PIN_ADC 7
#define PIN_PWM 4
void setup() {
pinMode(PIN_ADC, INPUT);
pinMode(PIN_PWM, OUTPUT);
digitalWrite(PIN_PWM, LOW);
delay(1000);
}
// Turn PIN_PWM ON for ON_ms then OFF for OFF_ms, for MS total time.
void PIN_PWM_on_off(uint32_t ON_ms, uint32_t OFF_ms, uint32_t MS) {
uint32_t T = millis();
while (millis() - T < MS) {
if (ON_ms > 0) {
digitalWrite(PIN_PWM, HIGH);
delay(ON_ms);
}
if (OFF_ms > 0) {
digitalWrite(PIN_PWM, LOW);
delay(OFF_ms);
}
}
}
void loop() {
for (int i = 0; i <= 4; i++)
PIN_PWM_on_off(i, 4-i, 5000);
}
This program puts a rectangular wave on the Nano D4 output, changing its duty cycle every five seconds from 0% to 25% to 50% to 75% to 100% and back to 0%. This has the effect, via R3, of charging up capacitor C3 to one of those percentages of the full supply voltage of 3.3VDC, and this can be observed on the Nano D7 pin.
Compile and upload the program to the Nano. When it runs, use a multimeter set to its Volts DC setting to measure the voltage between ground (e.g. pin 14 of the Nano, or a ground strap you added to the prototype area) and Nano pin 25 (D7). You should see the voltage change every 5 seconds, in the sequence 0V, 0.825V, 1.65V, 2.475V, 3.3V or maybe a bit less such as 0, 0.8, 1.6, 2.4, 3.2.
This confirms that the voltage divider for ADC calibration is working.
R3, C3, R1, C1, indoor thermistor
For this test two more of my custom libraries are required. Use the usual library manager functionality of the IDE to search for and install the libraries named wiring_analog_SAMD_TT
and floatToString
. The former provides duplicate functionality to an Arduino run-time system file named wiring_analog.cpp
, but with the changes to overcome problems I had, while floatToString
provides a function to convert a floating point value to a decimal number string. Refer to the README.md
files for the libraries if you want more information.
For this test also, use the IDE to create a new program and then copy and paste the following to it:
#include <Arduino.h>
#include <wiring_private.h>
#include <wiring_analog_SAMD_TT.h>
#include <calibSAMD_ADC_withPWM.h>
#include <monitor_printf.h>
#include <floatToString.h>
#define PIN_ADC 7
#define PIN_PWM 4
#define PIN_AREF_OUT 6
#define PIN_INDOOR_THERM A1
#define CFG_ADC_SAMP_AVG 6
void setup() {
monitor.begin(&Serial);
pinMode(PIN_ADC, INPUT);
pinMode(PIN_PWM, OUTPUT);
pinMode(PIN_AREF_OUT, OUTPUT);
pinMode(PIN_INDOOR_THERM, INPUT);
digitalWrite(PIN_PWM, LOW);
digitalWrite(PIN_AREF_OUT, HIGH);
calibSAMD_ADC_withPWM(PIN_ADC, PIN_PWM, PIN_AREF_OUT, CFG_ADC_SAMP_AVG);
delay(100);
}
void loop() {
float Vo = 3.3 * (float) analogRead_SAMD_TT(PIN_INDOOR_THERM) / ADC_MAX;
char VoS[10];
floatToString(Vo, VoS, sizeof(VoS), 2);
monitor.printf("Voltage between indoor thermistor and R1: %s V.\n", VoS);
delay(4000);
}
This program calibrates the ADC, then reads the voltage at the junction between R1 and the indoor thermistor using the ADC and prints it to the IDE monitor pane. A thermistor is nothing more than a resistor that varies its resistance with temperature, so when in series with R1 a voltage divider is created that divides the 3.3V supply voltage.
Compile and upload the program to the Nano. Open the IDE monitor pane and set it to 115200 baud, both NL and CR. Every 4 seconds a message should appear announcing the voltage at the thermistor/R1 junction. Use a multimeter set to its Volts DC setting to measure the voltage between ground and the junction between R1 and thermistor, which on the net list is at the pad located at position L5, right next to the switch and fairly easy to get to. The voltage you measure should pretty closely match the voltage printed on the monitor pane. If the thermistor is touched to raise its temperature, its resistance should fall, causing the voltage to rise.
This confirms that ADC calibration works and the indoor thermistor and R1 are functioning correctly.
That completes testing of most of the prototype area circuitry. The outdoor thermistor can only be tested once the 5-wire cable is connected to the board using the male and female connectors, of course.
Step 10: Installing the SmartVent thermostat codeWe are now ready to compile and upload the SmartVent thermostat code into the Nano.
Installing Libraries
The code uses nine Arduino libraries (actually more, because others are automatically installed when these nine are installed). If you followed all of the above procedures, six of them have already been installed:
- monitor_printf
- floatToString
- Button_TT
- XPT2046_Touchscreen_TT
- wiring_analog_SAMD_TT
- Adafruit_ILI9341
In particular note that installation of the last one, Adafruit_ILI9341, causes another important library, Adafruit_GFX_Library, to also be installed.
Three more required libraries have not yet been installed:
- FlashStorage_SAMD
- wdt_samd21
- msToString
Use the Library Manager function of the Arduino IDE to install the above libraries now. If any of the first six have not yet been installed, do so now, so that all nine libraries are installed.
The first six libraries above have already been briefly described. Let's look at the other three. FlashStorage_SAMD
is a library that its author wrote specifically for SAMD
microcontrollers, of which the Nano is one. It provides the ability to read and write the Nano's EEPROM memory, which is non-volatile, persisting across power-downs. The SmartVent thermostat code uses it to store user settings that need to be persistent, such as the SmartVent temperature setpoint and the current mode selection of OFF/ON/AUTO.
The wdt_samd21
library was also written specifically for SAMD21
microcontrollers (a sub-flavor of SAMD
), of which the Nano is one. It provides services to use the Nano's internal watchdog timer, which is an internal timer that forces a system reset if the software for some reason stops running and regularly resetting the timer. The SmartVent thermostat uses it with a timeout setting of 4 seconds, and the code periodically resets the timer (at least every four seconds) to avoid a watchdog system reset.
The msToString
library is another of my own libraries. It converts an integer value representing a number of milliseconds into a "time-like" string such as "02:21:34", used by the thermostat software to display SmartVent run time.
As mentioned before, most of the libraries have a file named README.md
in the library's folder, which often describes in detail how to use the library, and there is a usually an examples
subfolder containing subfolders of simple example programs that demonstrate use of the library.
If for some reason the library can't be found by the IDE's library manager, it is also possible to download the code for a library folder as a zip file, from its repository, then put the unzipped file into the Arduino libraries
folder (by libraries folder is located at Documents/Arduino/libraries
). That installs the library the same way as if it had been done by the IDE library manager. Most library repositories can be found on GitHub (https://github.com), and all six of my libraries can be found there, under my GitHub account (https://github.com/tedtoal). My library names and repository URLs are:
- monitor_printf: https://github.com/tedtoal/monitor_printf
- floatToString: https://github.com/tedtoal/floatToString
- msToString: https://github.com/tedtoal/msToString
- Button_TT: https://github.com/tedtoal/Button_TT
- XPT2046_Touchscreen_TT: https://github.com/tedtoal/XPT2046_Touchscreen_TT
- wiring_analog_SAMD_TT: https://github.com/tedtoal/wiring_analog_SAMD_TT
If you click the red Code
button on a library's GitHub repository page you will see a link to download the zip file.
Installing, Compiling, and Uploading the SmartVent code
The SmartVent thermostat code is also in one of my GitHub repositories, as described in the earlier section Step 1: Project Planning, and you should have already downloaded the zip file and unzipped it. Within the unzipped folder is a subfolder named programs
, and within that is a subfolder named SmartVentThermostat
. Copy the SmartVentThermostat
subfolder into your Arduino programs
folder (my programs folder is located at Documents/Arduino/programs). Browse the subfolder to see the following files, which are the C++ source code for the SmartVent thermostat. The first file below, SmartVentThermostat.ino
, is the main program, while the others are either .cpp
code files containing additional code for the thermostat, or .h
header files included by the .ino
and .cpp
files to declare constants, variables, and functions defined in one of the .cpp
files. The reason there are lots of files is that any program is more manageable when its software is split up into multiple smaller files, each containing the code for some specific portion of the application.
SmartVent Thermostat Code Files
- SmartVentThermostat.ino: the main program
- pinSettings.h: defines Nano I/O pins used to control the various devices
- pinSettings.cpp: I/O functions declared in
pinSettings.h
- fontsAndColors.h: color constants and font variables
- fontsAndColors.cpp: includes Adafruit font files and defines font variables
- nonvolatileSettings.h: defines the thermostat setting values kept in EEPROM
- nonvolatileSettings.cpp: functions to read and write settings to/from EEPROM
- temperature.h: temperature variables and functions, extensive comments
- temperature.cpp: functions to read and average indoor/outdoor temperatures
- buttonConstants.h: constants handy for defining screen buttons
- screens.h: includes, constants, variables, and functions used by screen files
- screens.cpp: initialization of key variables for lcd, touchscreen, and sound
- screenMain.h: declare functions to display/manage Main screen
- screenMain.cpp: functions to implement the Main screen
- screenSettings.h: declare functions to display/manage Settings screen
- screenSettings.cpp: functions to implement the Settings screen
- screenAdvanced.h: declare functions to display/manage Advanced screen
- screenAdvanced.cpp: functions to implement the Advanced screen
- screenCleaning.h: declare functions to display/manage Cleaning screen
- screenCleaning.cpp: functions to implement the Cleaning screen
- screenSpecial.h: declare functions to display/manage Special screen
- screenSpecial.cpp: functions to implement the Special screen
- screenCalibration.h:declare functions to display/manage Calibration screen
- screenCalibration.cpp: functions to implement the Calibration screen
- screenDebug.h: declare functions to display/manage Debug screen
- screenDebug.cpp: functions to implement the Debug screen
Compiling and Uploading SmartVent Code
Plug your Nano into the MKR 2 and connect it to the IDE using the micro-USB connector on the USB cable. Then open the SmartVentThermostat.ino
file (File, Open) in the folder you just copied to (your Arduino programs
folder, SmartVentThermostat
subfolder).
If the IDE's "board" drop-down at the top to the right of the compile icon doesn't say "Arduino Nano 33 IoT", select it by choosing Tools, Board, Arduino SAMD Boards (32-bits ARM Cortex-M0+, Arduino Nano 33 IoT.
Choose Tools, Port, and check to see if a port with "usb" in its name is selected, and if not, select that port. If not listed, double-check your USB cable connection to the Nano.
Since you have already installed all required libraries, you should be able to compile it successfully. Do that by clicking the IDE's compile checkmark icon in the upper-left corner. If errors occur, you need to resolve them. None are expected.
Next, click the compile and upload button in the IDE to upload the code to the Nano. The upload should be successful. The SmartVent thermostat code should now start running and everything should work, except the outdoor temperature will be incorrect since the outdoor thermistor is not connected (and of course the SmartVent relay won't turn on the SmartVent system).
You should see the main thermostat screen on your LCD display. You should be able to tap buttons to access other screens and to change values. After a while, the backlight timeout should occur and the display backlight will turn off, making the display black. Touching it will turn the backlight on again.
Now is a good time to read through the SmartVent Thermostat User's Manual if you haven't already, and try things out. The thermostat is now about ready to be installed in its destination location, but before doing that, I'll discuss some settings you may want to consider changing. First, though, I'll talk about things that can help the DIYer who is modifying the thermostat code in some way. Skim through this section in case you have unexpected problems that you need to debug.
Debugging the Code
There are a few debug statements in the code that write text to the IDE's serial monitor pane. These can help when the system isn't working. If you've modified the code, you may need to turn on these debug statements to find the problem. The print statements show when each initialization step is complete, so you can see if the program hangs during some part of initialization. To turn on this debug output, in the IDE select the tab for the file screens.h
and scroll down to find the #define USE_MONITOR_PORT
statement. Change it so that it defines the value as 1, not 0, and then recompile and upload the code. Open the monitor pane window and set it to 115,200 baud. Every couple of seconds a print statement should show the latest reading of the indoor and outdoor temperatures in the monitor pane. Push the tiny white reset button on the Nano to start the program again to see the initialization messages.
You can also add monitor.printf()
statements to the code to print text and values to debug problems if you have any. (For example, if you are modifying the code in some way and the changes don't work). Sometimes you may also need to #include <monitor_printf.h>
in the file in which you add a monitor.printf()
call. All monitor.printf()
statements are turned on and off by setting the #define USE_MONITOR_PORT
statement in screens.h
as described above.
When you are making changes to the code yourself, something to be wary of is the possibility of timeout of the watchdog timer. When USE_MONITOR_PORT
has been defined as 1 to enable monitor pane output, the watchdog timer is disabled, because print statements can take a long time to execute. But when USE_MONITOR_PORT
is defined as 0 to disable monitor pane output (as it must be when running the system in its final location without the IDE), the watchdog timer is enabled. If something has been added to the code that takes a long time (say a lengthy initialization or anything else), the watchdog timer might reset the system, and you will observe that it simply stops working. If this happens, you can either increase the watchdog timer timeout time or reset the watchdog timer within that initialization code by calling wdt_reset()
.
Three constants defined in file temperature.h
can be useful during debugging, especially in order to provide an outdoor temperature value when the system is not connected to the outdoor thermistor. Comments in that file explain what these are:
- FORCE_INDOOR_TEMP
- FORCE_OUTDOOR_TEMP
- DEBUG_TEMP_OFFSET
During testing and debugging of the software, it was often desirable to force a given screen to appear at startup. The TEST_MODE
constant defined in file SmartVentThermostat.ino
can be set to a value other than 0 to select specific screens or debug information to be displayed at startup.
Currently the debug screen shows indoor and outdoor temperature information every couple seconds. You could alter the screen contents to show other information of interest. The screen is implemented in file screenDebug.cpp
.
Customizing Defaults and Fixed Settings
There are several thermostat settings the user can change that are stored in EEPROM memory so they persist across power-downs of the thermostat. These are:
- Indoor temperature setpoint in °F for SmartVent to turn on.
- Amount indoor temperature must exceed outdoor to turn on SmartVent.
- Hysteresis band to turn SmartVent on and off to avoid frequent cycling.
- Run time limit in hours.
- Amount outdoor temperature must exceed indoor to clear run timer.
- Amount added to measured indoor temperature in °F to get displayed value.
- Amount added to measured outdoor temperature in °F to get displayed value.
All of these settings can be changed in one of the settings menus. The settings initially take certain default values. While the user can always set them to whatever he wants and they will "stick" (persist), if you re-upload the code to the MKR 2, that wipes out the persisted user values and returns the settings to the defaults. You may find that you want to change the defaults to values you prefer so it isn't necessary to keep setting them each time you upload code again. (You may not upload code much; I did do it a lot during thermostat code development.)
To change any of the default settings, open file nonvolatileSettings.cpp
in the IDE and scroll down to the definition of the settingDefaults
variable. Change its initialization values to change the default settings.
There are a few other settings that are hard-coded values that can't be changed by the user. If you want to change them, you can edit the values in the file where they are defined:
- LCD_BACKLIGHT_AUTO_OFF_MS (
pinSettings.h
) - amount of time after no touchpad activity that backlight goes off. - USER_ACTIVITY_DELAY_MS (
SmartVentThermostat.ino
) - amount of time after no touchpad activity before any changes the user has made to settings actually take effect. - TS_TONE_FREQ (
screens.cpp
) - Tone frequency when screen is touched. - TS_TONE_DUTY (
screens.cpp
) - Tone duty cycle when screen is touched.
Preparing for Disconnection from IDE
Before disconnecting the MKR 2 for installation elsewhere, you MUST make certain that the code that writes text to the IDE serial monitor pane is turned off. To do this, in the IDE select the tab for the file screens.h
and scroll down to find the #define USE_MONITOR_PORT
statement. If not already so, change it to define the value as 0 (that is, zero) and compile and upload again. If the constant is left set to 1, when the code starts running without an IDE, it will try to write text to the monitor pane, and since it doesn't exist, the code will hang and you will observe that the thermostat doesn't work. In that case, take it back, change the value to 0 and compile and upload again.
Now when you disconnect the USB cable from the Nano, your thermostat is programmed with code and ready to go.
Step 11: Installing the thermostatYou haven't yet connected the MKR 2 to the 5-pin male connector on the cable coming out of your wall, the other end of which is connected to your EcoJay controller and outdoor thermistor. It is time to do that, but the first time this is done, we want to do it cautiously in case there is a wiring problem that creates a short on the 24VAC wires or otherwise causes a problem on the wiring of the 5-wire cable.
The value of having the 5-pin connector will now be obvious. If instead you have some other means of attaching the wires, such as screw terminals, you'll soon realize how messy that method is.
Turn off the small power switch you added to the MKR 2 prototype area.
Remove the Nano from its socket. We will initially check to see that the 24VAC from the cable correctly provides power to the MKR 2 board and allows it to generate 5VDC. If something is wrong, it is best to have the Nano removed to avoid it possibly being burned out, for example by having 24VAC applied to one of its pins.
Snap the circuit board into the case. Look carefully for problems that interfere with getting the case closed, and deal with them. I made the thermistor and LEDs jut out from my case, which involved making U-shaped channels that aligned with one another in both the case and baseplate. I had to carefully position things before snapping the circuit board into the case.
Before proceeding, make sure your HVAC power is on so that power is coming from the 24VAC transformer to the 5-wire cable.
Next, put the case up to the baseplate and get the orientation correct.
Make sure the small power switch on the circuit board is in the off position, then push together the connectors, male on the cable and female on the circuit board. You expect that nothing will smoke or blow or anything. Power should be making it through the connector to the fuse and to the power switch, but no further.
Work the wires into the baseplate and close the case over it, taking note of the fuse position and avoiding bending the fuse connectors. I had to cut and reshape the ends of the fuse clips because they stuck out too far and kept getting bent when I snapped the case on. In fact, once they bent and shorted something and burned out the Nano, so be careful! Make sure you have clean functional fuse clips.
You've successfully mounted the thermostat to the wall! Now, pop the case back off the baseplate, then pop the circuit board out of the case. We will work with only the circuit board connected to and hanging from the cable on the wall.
Flip the small power switch on. The fuse should not blow and the 5VDC LED should have lit up.
If not, something is wrong, most likely with the power supply that generates 5VDC from the 24VAC. When the 5-pin connector is connected instead of the USB cable, the 24VAC hot and common feed into the MKR 2 power supply regulator circuitry to produce 5VDC. With the device still connected to the cable and with the switch still on, measure voltages with a multimeter, being extremely careful not to short things together with the multimeter probe tips. When set to measure Volts AC, there should be about 24 volts between the 24VAC hot and common wires of the cable (red and blue). When set to measure Volts DC, there should be +5 volts between ground and the +5VDC net. The MKR 2 schematic can be used to trace these voltages in the power supply regulator circuit to look for problems. (I burned out a capacitor in that circuit by shorting something, and fortunately was able to replace the capacitor to get it working, rather than buying a new MKR 2). This is where you may need help, if you are unfamiliar with electronic circuits. Troubleshoot until you are able to make the 5VDC LED turn on.
Once the 5VDC LED lights up, it is time to install the Nano and try again. Turn off the switch, unplug the cable, insert the Nano in the correct orientation, plug on the cable again, and then flip the switch on again. The 5VDC LED should again light. Check to see if the SmartVent software begins to run and the LCD display shows the main screen of the thermostat. You expect that it will.
If not, recheck the 5VDC voltage with a multimeter, and recheck that the thermostat software runs okay when you disconnect it from the cable and bring it to your computer and connect via the USB cable. If you don't spot the problem, you will need to enlist help. When the thermostat starts up okay, you can snap the circuit board back into the case and then snap the case onto the baseplate.
Step 12: Testing the thermostatLet's run through a series of steps involving looking at different screens of the thermostat, and setting some values.
The D4 power LED should be lit to indicate that the thermostat is receiving 24VAC power.
Ensure that when you touch the screen when it is dark, it lights up. Leave it untouched and it goes dark again after LCD_BACKLIGHT_AUTO_OFF_MS.
Tap Advanced, Special, Calibrate, to advance through those screens to the Calibrate screen, then carefully tap the two "+" signs using the plastic stylus. Then tap the screen again several times to see that a "+" sign appears exactly where you tapped the screen. Then tap Save and exit back to the Main screen.
Tap the screen to light it up, and check the indoor and outdoor temperatures. Are they correct? (I've had a problem with incorrect temperatures showing for up to about 60 seconds after first connecting the thermostat to the 5-wire cable, and have not yet been able to track down the cause of this problem, but after that they are correct.) If not, you need to go back over thermistor coefficient settings, and also ensure that there is continuity from the thermostat circuit board all the way to the outdoor thermistor.
Tap the mode button until ON is shown. After USER_ACTIVITY_DELAY_MS SmartVent should turn on. You should hear the HVAC fan turn on, and you will hear a small click of the relay inside the MKR 2 case. The LED indicating active SmartVent should now be on. The SmartVent damper should slowly open. Look at it through the vent opening in your ceiling, opening up the vent cover for a clear view. The run timer should count up the run time.
Tap the mode button until OFF is shown. After USER_ACTIVITY_DELAY_MS SmartVent should turn off. The SmartVent LED should go off. The HVAC fan should turn off and the SmartVent damper should now slowly close.
If the mode ON and OFF tests don't work, find a way to check for continuity from the relay output (pad F5, or just from the G pin on the Dupont connector) to the EcoJay Zone 4 Fan (green) input.
To test AUTO mode for SmartVent, it needs to be at least a few degrees colder outdoors than indoors. We make the assumption that this is the case, for this test. Take note of the indoor and outdoor temperatures, then tap Settings. Change the Indoor setting to a few degrees cooler than the current indoor temperature. If necessary, decrease the Outdoor lower by setting to ensure that Indoor minus Outdoor lower by is greater than the current outdoor temperature. If necessary, reduce the Overshoot width so that Indoor plus Overshoot width is no greater than current indoor temperature, and so that Indoor minus Outdoor lower by minus Overshoot width is no less than the current outdoor temperature. Tap Save. (Try to pick values such that the conditions are met, but just by a couple of degrees, so that after just a little bit of cooling, one or the other condition will not be met and SmartVent will be turned off.) Tap the mode button until AUTO is shown. After USER_ACTIVITY_DELAY_MS SmartVent should turn on. As it runs, the run timer should show run time. When the indoor temperature cools enough that the conditions are no longer met, SmartVent should turn off.
You could also test the run timer, although this requires setting the maximum run time to a non-zero number of hours, one hour at a minimum, and so you will need to wait an hour to see if it turns off at that time.
Tap Advanced, Cleaning, then clean the display screen and wait LCD_BACKLIGHT_AUTO_OFF_MS for the screen to go dark. Tap it again and you should be back to the Main screen.
Tap Advanced, Special, Debug, and then watch the debug screen for a line every 2 seconds that gives indoor and outdoor thermistor info. The first number on each line is a count that increases. This is followed by three values, A, R, and T, for the indoor temperature and three more for the outdoor temperature. A is the analog value read from the ADC, a 12-bit value between 0 and 4095 representing what fraction of the supply voltage of 3.3 volts is present at the junction between the thermistor and 10K resistor voltage divider, e.g. a value of 1050 means 1050/4095 is the fraction of 3.3 volts. R is the thermistor resistance computed from that voltage, and T is the Fahrenheit temperature computed using that resistance for that thermistor type. While the temperatures shown on the Main screen are the average of 30 values measured over 60 seconds, the values shown on the Debug screen are not averages but are the instantaneous measurements made every two seconds.
Step 13: Debugging a broken thermostatWhat do you do when your thermostat stops working? Here is some guidance:
- If the thermostat is completely dead, check these: does power come to the thermostat? House power is good, circuit breaker is not tripped, HVAC system runs, 24VAC transformer is good (measures 24VAC at or close to the transformer), continuity of wires from transformer to thermostat, connector at thermostat isn't broken or loose and makes a good connection, thermostat fuse is good, thermostat on/off switch is on. Then, carefully probe the MKR 2 circuit board with a voltmeter to see if 24VAC is present in the prototype area across RV1. If not, disconnect the thermostat and carefully check for broken wires in the prototype area. If that is okay, check that 24VAC is present at the MKR 2 K2 connector pins 1 and 2. If so, the MKR 2 voltage regulator output should be 5VDC at pad L10 (the place where 5VDC comes into the prototype area from the main MKR 2 board) and the 5VDC indicator LED should be on. If not, disconnect the wire going to pad L10 (powering off while disconnecting it and then powering back on, of course) then check for 5VDC at L10. If not present, you will need someone with knowledge to troubleshoot that regulator. If it is present at L10, something in the prototype area is killing 5VDC. Remove the Nano from its socket, power on again and re-check. If 5VDC is now present, suspect a burned-out Nano. If not present, suspect C4, R4, R5, D3, D4, D5, D6, or the Omron relay coil. If you don't know how to test these devices, find someone who can help you do that.
- If the display is blank or the touchscreen doesn't work, return to Step 5: Testing AZ-Touch MKR 2, and try to rerun those tests to narrow down the problem.
- For any remaining problems, the first thing to suspect is a broken wire at a solder connection. You should turn off the thermostat and remove it, remove the display, and very carefully check each solder connection, using a continuity meter if possible. Try to rerun the tests in the section Step 9: Testing the hardware to find the problem.
- Assuming no broken-off wire was found and the tests succeed, if the indoor and outdoor temperatures are both incorrect, suspect a problem with C1, C2, C3, R3, or D1. If you don't know how to test these devices, find someone who can help you do that.
- If only the indoor temperature is incorrect, suspect a problem with the indoor thermistor or R1 or C1.
- If only the outdoor temperature is incorrect, the first thing to suspect is a problem with continuity to the thermistor. Measure the resistance between pins 4 and 5 of the 5-pin connector to which the thermostat cable attaches to the thermostat. The resistance should be around 10K ohms plus or minus maybe 20% depending on the temperature. An infinite resistance indicates an open connection. If this seems okay, suspect a problem with R2, C2, or D2. If all seems right with the circuitry but he temperature is still wrong, check that the Debug menu shows about the same resistance that you measured. You can use the Python thermistors.py program to check to see what temperature corresponds to the resistance you measured. If that temperature is about the same as the displayed temperature on the thermostat, then either the thermistor is bad or it is not the same type that you programmed into the OutdoorThermistor variable initialization in file temperature.cpp. If the temperature is NOT the same as what was displayed, you want to make sure that the PWM circuitry is working correctly and the ADC is being properly calibrated. Double-check R3, C3, and the connections to Nano pins D4, D6, and D7. If all seems good, and if you were able to rerun the tests in Step 9 successfully, that suggests a software problem, so please try to contact me if that is the case.
- If SmartVent doesn't come on in AUTO mode but does come on in manual ON mode, suspect a problem with setting parameters. Carefully review each one. Also make sure the indicated temperatures are such that the SmartVent should definitely come on.
- If SmartVent doesn't come on, even in manual ON mode, first check that it isn't a problem at the EcoJay controller or the SmartVent damper, by manually connecting a wire between the Zone 4 Vent Fan wire (green wire, pin 3 of 5-pin connector that thermostat cable connects to) and 24VAC HOT (pin 1 of that connector). This should immediately cause the EcoJay to turn on the HVAC fan and begin to open the SmartVent damper. If that doesn't happen, check connections at the EcoJay and the damper. If it does work, then suspect a problem with R6, Q1, or the Omron relay.
The GitHub repository for this thermostat includes a documents
folder containing the following files:
Custom SmartVent Thermostat User Manual.pdf:
the User Manual for this thermostat.Custom SmartVent Thermostat User Manual.odt:
Google Docs open document format file for the User Manual for this thermostat (from which the .pdf was made).AZ-Touch_MKR_Rev_B.pdf:
description that came with my AZ-Touch MKR 2.AZ-Touch_MKR_rev_B_Assembly_Instruction.pdf:
assembly instructions provided with my AZ-Touch MKR 2.AZ-Touch_MKR_schematic_V02-02.pdf:
circuit schematic diagram of AZ-Touch MKR 2 circuit board.Arduino-Nano-33-IoT-Schematic.pdf:
circuit schematic diagram of Nano 33 IoT microcomputer.SmartVent Thermostat Schematic V4.pdf:
PDF file of the thermostat schematic diagram (printed from KiCad schematic file).SmartVentPrototypeArea.xlsx:
Excel spreadsheet showing layout of thermostat components within the AZ-Touch MKR 2 circuit board prototype area, including wiring details in the form of a list of prototype area soldering pads to be connected together by wires.AZ-Touch_MKR_Nano_SAMD21G_pins.xlsx:
Excel spreadsheet that shows how names of pins change going from the microcontroller chip to the microcomputer board to the AZ-Touch MKR 2 circuit board to the thermostat schematic.Arduino-Nano-33-IoT-datasheet.pdf:
datasheet for Nano 33 IoT microcomputer.Atmel-42181-SAM-D21_Datasheet V2.pdf:
datasheet for Atmel SAM-D21 microcontroller chip, 1000+ pages but invaluable for the programmer at times.LCD_Controller_ILI9341_v1.11.pdf:
datasheet for ILI9341 display controller chip, 200+ pages.TouchController_xpt2046-datasheet.pdf:
datasheet for XPT2046 touchscreen controller chip.OMRON G5V-1 relay.pdf:
datasheet for OMRON relay used to switch SmartVent on/off.PN2222.pdf:
datasheet for PN2222 transistor.1N4001-D.pdf:
datasheet for 1N4001 diode.1N4734A.pdf:
datasheet for 1N4734A zener diode.Panasonic_Varistors.pdf:
datasheet for varistor that I used.GrayhillSeries78Switches.pdf:
datasheet for small on/off switch that I used.Thermistors:
subfolder containing files relating to thermistors:thermistors.py:
Python code file containing functions for working with thermistor coefficients..pdf files:
datasheet files for different types of thermistors, giving coefficients.SmartVent Thermostat Schematic V4:
subfolder containing KiCad files for the thermostat, currently only the schematic file is used:SmartVent Thermostat Schematic V4.kicad_sch:
KiCad schematic file from which was madeSmartVent Thermostat Schematic V4.pdf
.
The files temperature.cpp/.h
manage reading the thermistor voltages and computing temperatures, and averaging them over time. To compute temperature from thermistor voltage, the thermistor coefficients A, B, and C for the Steinhart–Hart equation are required. That equation is described in Wikipedia (Steinhart–Hart equation). Thermistor data sheets often give the coefficient values, but not always. Sometimes they give an alternative expression using a B number with two temperatures, usually 25°C and some other temperature:
B(t0/t1) = ln(R0/R1)*t0*t1/(t1-t0)
The thermostat code works with the A, B, C coefficients of the Steinhart-Hart equation, and I've avoided dealing with the B-number method. So, you need to be able to determine the Steinhart-Hart A, B, and C coefficients for your thermistor. In the header comments in file temperature.h
I list the coefficients for several thermistors I worked with. You can also determine the coefficients yourself by measuring the resistance of your thermistor at several temperatures, but I don't recommend that, it's too difficult to get accurate numbers. It's best to get a thermistor with known coefficients.
The coefficients are used by plugging them into the code in file temperature.cpp
, in the two lines starting with:
const thermistor IndoorThermistor = ....
const thermistor OutdoorThermistor = ....
These two lines also include the Arduino analog input "pin" number connected to the thermistor-10K-resistor junction, and the value of the resistor (10K is used at 1% or better precision).
In the thermostat GitHub repository subfolder named documents
there is a subfolder named Thermistors
that contains a number of thermistor datasheet PDF files that usually have A, B, C values for the thermistors. The subfolder also contains file thermistors.py
, which contains Python code that prints out some A, B, C values given the thermistor resistance at three different temperatures. You can run it from the command line like this on many systems (e.g. MacOS command line):
cd (repository directory)/documents/Thermistors
python thermistors.py
You can edit the thermistors.py
file to change the print statements at the bottom of the file to print out values for other thermistor resistances. You can also make use of the functions in the file for your own purposes. The file is well-commented, each function has a comment describing what it does, and even if you don't know Python, you should be able to figure out how to change the code at the bottom of the file that prints out different values, to discover the A, B, C coefficients of your thermistors or to otherwise experiment with your thermistors.
I spent a great deal of time trying to get accurate temperature readings using the Nano 33 IoT analog-to-digital converter (ADC) to read the voltage levels at the junction between a thermistor and a 10K resistor. The other side of the resistor is grounded, while the other side of the thermistor is tied to a digital output which is driven high (3.3v) while reading the junction voltage. The thermistors are negative temperature coefficient, meaning they simply act as a resistor whose resistance decreases as the temperature increases. Thus, the thermistor and resistor form a simple voltage divider. By measuring the junction voltage, the thermistor resistance can easily be calculated. Then, the A, B, C thermistor Steinhart-Hart coefficients, which quantify the exact relationship between resistance and temperature, are used to convert that resistance value into a temperature. The ADC uses the same digital output of 3.3v as its reference voltage, and it produces a 12-bit output, so that an output of 0 means 0 volts and an output of 4095 means 3.3 volts, IF the ADC is completely linear.
Despite the straightforward nature of the operation, my temperatures were always way off. I switched to 1% tolerance 10K resistors but that didn't help, nor did switching to a more expensive thermistor. Forums said that the Atmel SAM D21 microcontroller ADC has poor performance with lots of noise. I tried adding a capacitor to the Nano board as suggested by some forums, which didn't help. I added my own capacitors on the power supplies and across the thermistors themselves, still to no avail. I tried calibrating the ADC using code obtained online, and that didn't help. Eventually, careful measurements showed that the ADC had non-linearity problems at the high and low ends of its voltage range. I found that some Nano devices performed well, others did not.
I developed a way to measure the ADC performance to obtain better calibration values, and these are loaded into the ADC calibration registers. This involved using the microcontroller's pulse width modulation (PWM) capability to drive a rectangular wave onto a resistor and capacitor in series to ground. The capacitor then charged to a voltage that was a function of the PWM duty cycle, so it was possible to create highly accurate reference voltages, which I then measured with the ADC to see what value it gave for that particular voltage. I wrapped this code into a function named calibSAMD_ADC_withPWM()
defined in my files calibSAMD_ADC_withPWM.cpp/.h
that I included with my library named wiring_analog_SAMD_TT
, which also includes a pair of files wiring_analog_SAMD_TT.cpp/.h
to replace a file wiring_analog.c
in the SAMD Arduino runtime code. That latter file pair was needed because of several problems with the runtime code, as outlined in comments in wiring_analog_SAMD_TT.h.
One of the problems was that it wasn't possible to use the microcontroller timers for PWM in the way I needed to use them, which is why the ADC calibration code is included with this library.
I incorporated the PWM circuitry (resistor and capacitor with a digital output and an analog input) into the thermostat circuitry, and incorporated the ADC calibration code into the thermostat software. When the ADC is calibrated this way, the temperature values were much more accurate. However, they STILL had a lot of noise in them. I did four more things to deal with this noise. First, I put capacitors across the thermistors to smooth out noise. Second, I enabled internal automatic ADC conversion and averaging, so that each time a thermistor voltage is read, it is actually read 64 times in a row, and those 64 readings are averaged. Third, I added my own averaging on top of that. The thermostat reads both the indoor and outdoor temperature once every two seconds, and averages the last 30 values read over the last minute to obtain the displayed value. Fourth, I added a special hysteresis rounding algorithm for converting temperature to an integer, to obtain the final displayed temperature value. That displayed temperature also goes into the algorithm for determining when to turn SmartVent on and off in AUTO mode.
There are extensive header comments in wiring_analog_SAMD_TT.h,
calibSAMD_ADC_withPWM.h,
and temperature.h
that further explain the issues and resolutions.
The libraries used by the thermostat code provide an important foundation. If you want to delve into the thermostat code, start by making sure you've gone through the README.md
files for the libraries. Pay particular attention to the Button_TT
library README file.
I try to do extensive commenting in all my code, both my library code and the thermostat code. You will generally find file header comments in the .h
file of each .h/.cpp
file pair. Functions and variables always have usually-succinct comments describing them. Important code sections have succinct descriptive comments.
The thermostat code files were listed earlier along with a one-line description. Start by reading through the small files to become familiar with what they contain and what they do:
- pinSettings.h: defines Nano I/O pins used to control the various devices
- pinSettings.cpp: I/O functions declared in
pinSettings.h
- fontsAndColors.h: color constants and font variables
- fontsAndColors.cpp: includes Adafruit font files and defines font variables
- buttonConstants.h: constants handy for defining screen buttons
Next, look at the file pair nonvolatileSettings.cpp/h
,
which define the thermostat setting values kept in EEPROM and are quite straightforward. Pay attention to the difference between the activeSettings
and userSettings
variables and the way they relate to the USER_ACTIVITY_DELAY_MS constant.
Spend some time going through the file pair temperature.cpp/.h,
which handle reading the temperatures and averaging them. Pay attention to the temperature
struct and the curIndoorTemperature
and curOutdoorTemperature
variables that are used by the code to obtain the temperatures that are displayed and that control SmartVent on/off in AUTO mode.
Each different screen in the thermostat has its own .cpp/.h
file pair, named using the pattern screen<ScreenName>
. Each of these file pairs is organized in a similar manner, so once you've understood one of them, the remainder are straightforward. Before looking at them, read through the screens.cpp/.h
file pair, which provide the basic stuff used by the screen files. Every screen file #includes screens.h
. Note how this file pair defines the key objects used by the screen files:
- lcd: the display screen object
- touch: the touchscreen object
- ts_display: the display-touchscreen interface object for mapping coordinates between touchscreen and display and for generating touch events on the screen
- screenButtons: the object that records the buttons on the current screen and checks the coordinates of screen taps to see if they lie within one of those buttons, and if so, calls the button tap handler function.
Then go through the files that implement each screen. I recommend starting with the file pair having the smallest .cpp
file size and working up to the largest, in this order:
- screenCleaning
- screenSpecial
- screenDebug
- screenCalibration
- screenAdvanced
- screenSettings
- screenMain
That leaves the main program file named SmartVentThermostat.ino
. Since the bulk of the work is done by the screen files, it implements only a few key functions:
- processTouchesAndReleases() to test for button press events and use the screenButtons object to handle them, along with handling touch timeout and making the screen go dark, then lighting it back up at the next touch.
- updateCurrentTemperatures() reads the current temperatures every two seconds.
- updateSmartVentRunTimer() monitors for timeout of the SmartVent run timer.
- updateSmartVentOnOff() monitors indoor and outdoor temperatures for when to turn SmartVent on and off.
- updateArmState() monitors and acts upon changes to the arm state.
- updateActiveSettings() monitors for USER_ACTIVITY_DELAY_MS timer timeout after the user changes some settings, and makes the changed settings be the new active settings.
- setup() to do initialization
- loop() to handle the main runtime loop, which calls the several processing and update functions listed above and then calls the loop function for the currently displayed screen to handle updates to that screen
One customization that might be desired is to add a new screen. The design pattern of using a .cpp/.h
file pair for each screen makes this fairly straightforward to do. Be sure to read the Buttons_TT
library README file so you are prepared to fully understand the button initializations. Sizing and positioning the buttons and text on a new screen are the hardest part of making a new screen. The TEST_MODE #define in SmartVentThermostat.ino
lets you activate a new screen immediately on startup to assist with that.
Originally I used a different method of providing a 5-wire connector to connect the thermostat to the 5-conductor cable coming from the EcoJay controller. That connector turned out to easily wear out and slip off easily. An earlier step above details the new and better connector I have switched to. I didn't want to lose the instructions for the old method, as they contain useful detail on how to crimp Dupont connectors, so I moved the earlier description to this appendix. You can ignore this unless you want to learn something about crimping Dupont connectors.
I will give very detailed instructions here, trying to help you across the difficulties I experienced learning to crimp pins onto wires.
To add the connector, you need a crimping tool, a 5-pin Dupont connector, five female pins, and 5 male pins (which are found on male header strips). Here is a picture of one kit that looks very similar to the one I used, with everything needed.
At first, I didn't even know in which orientation to hold the crimper tool. Hold it as follows.
The jaw of the crimper tool has two metal dies screwed in place that mate with one another when the tool is squeezed. There are multiple aspects of the jaw to understand. Here's a close-up look.
Not obvious from the previous picture is that both the upper and lower tooth sections are divided into two pieces, one on the left side of the crimper tool and one on the right side. When holding the tool in the orientation shown, the teeth sections on the right side are slightly smaller than the ones on the left. This is critical, as is the resulting "step up" when moving from the left to the right side of the bottom of the "female tooth". This photo shows another close-up.
I had trouble determining which of the three "tooth" sizes to use. Experimentation showed that the smallest one, 0.25, at the jaw tip, worked best.
The female pin to be crimped has its own characteristics to understand. The next photo shows a close-up of one.
At the right side of the above photo, the tall wings (just one is clearly visible) are crimped around the wire insulation. Just to their left are two stubby wings, looking almost too small to be of use, and they get crimped around the wire itself to make a solid electrical connection. Look closely on the left side along the top, and you can see two small metal plates, one going under the other. Those serve to put force on the male pin being inserted into this female pin, to make a good connection with it.
Here's another view.
Here is a view of the underside of the pin.
I didn't know which way to insert the pin into the crimp tool, or which side faces left and which faces right. The following photo shows the proper orientation.
To insert the pin into the crimper tool, you need to align it precisely within the tooth, in-and-out. The large wings will be on the larger half of the tooth. Align the crack between the two halves of the tooth jaw dies with the center of the dip between the long and stubby wings of the pin, as shown in the next picture.
The alignment can tolerate a little bit of shift, but the consequences of shifting it are that you reduce the margin of error for getting the wire inserted just right, so try to keep it as close as possible. I've found that if I put a tiny bit more than half of the "dip" between teeth TO THE RIGHT SIDE of the dividing line between die halves (upwards in the above photo), it works a little better. (Holding the crimper tool in the right hand as shown in a preceding photo and calling the sides left and right). If you tend to crimp with the insulation too close to the stubby wings, that's the way to shift the pin in the crimper. On the other hand, if you tend to not have the insulation fully surrounded by the big wings, you might try shifting the pin just a hair the other direction (downwards in the above photo).
To get the pin to stay in the crimper tooth, you need to crimp down three clicks to press it in just slightly, all the while maintaining the previous left-right alignment. After you do this, the pin stays in the crimper as shown in the next two photos. Note that the crimper tool will have a little lever you can push on to release it without having to crimp down all the way, if you need to extract the pin and try again.
Stripping insulation from the wires to be crimped to the pins is also a precise operation. The amount to be stripped is 2.5mm. This is indicated by a slot in the metal strip to which the female pins are attached.
Cut yourself a couple dozen short pieces of the same 20-gauge wire used in the thermostat cable and PRACTICE WIRE STRIPPING until you get it just about perfect. Eyeball it, strip it, compare it to the strip gauge, and try again until you've mastered it. Wire stripper quality is important here too.
Before we move on to the final instructions for crimping the pins to the actual 5-wire cable, the technique of crimping must be perfected. This involves precise positioning of the female pin in the crimper (already discussed) and precise positioning of the stripped wire into the female pin, followed by crimping.
Do you recall the "step up" when moving across the base of the female crimper tooth from left side to right side, at the center where the two die halves meet? That "step up" is crucial to properly aligning the stripped wire. The height of the step up is about the same as the thickness of the wire insulation. Insert the stripped end of the wire into the left side of the crimper, along the bottom edge of the female tooth, and carefully move it until the start of the insulation butts up against the "step up". This requires careful movement and exquisite sensitivity, feeling for the insulation to abut but not slip past the "step up". It is made more difficult because the bottom of the tooth has the "pointy mountain" on it, and you actually want to be on top of that mountain even though the natural tendency of the wire is to slide to one side of it. Actually, I don't think that matters because I believe that during the actual crimping the wire will be forced onto the peak of the mountain. You will practice crimping and you will find out how it works. The next several photos show the wire properly positioned, but with the jaws open and the pin not inserted. You will actually insert the wire after inserting the pin and clicking down three clicks.
The next two photos show the wire as it should be positioned within the pin. The problem is, you can't see this, you are inserting the wire blind into the crimper tooth holding the pin.
The crimping is then done by inserting the wire as shown and crimping down firmly and without shaking, not too slow, not too fast, good and hard down. The final crimp should look as shown in the following photos, and when you pull and wiggle it, it should feel like a very firm connection.
In the above photo, notice how the "mountain peak" on the base of the crimper tooth not only helped the wings to bend around the insulation and the wire, but also it indented the wire itself. This is helpful for the plastic tab that keeps the pin from pulling out of the connector, because it has a little "bump" that juts out and nests against the wire.
If the wire is stripped too far, it will extend past the stubby wings into the "well", which could be a problem. However, if the wire is not stripped far enough, it may not extend the full length of the stubby wings.
The crimped pins don't always fit into the Dupont connector. Usually it is necessary to squeeze the large wings together slightly with pliers to reduce the size enough that it will fit. Insert it in the orientation such that the plastic tab on the connector will face the crimped wire and the "well" just after it.
The Dupont connector has small plastic tabs, one per pin, that bend upwards as the pin is inserted, and then when the "well" reaches the bump on the bottom of the tab, the tab drops back down again. If you try to pull the pin out, the metal top of the pin just after the well butts against the tab, preventing it from coming out.
Now that you have a good understanding of the crimping process, it is time once again for practice. Do some more stripping, then crimp each stripped wire, repeating until you've perfected the process. It would be extremely annoying and inconvenient to crimp four of the five wires and then mess up on the fifth and have to cut them off and start over. Somehow I managed to do a decent job on all five the first time. Practice sure helps!
After you've nailed the crimping process, it is time to prepare the five wires on the cable coming out of your wall. Do this:
- If you haven't already, mount the baseplate of the MKR 2 to your wall with the 5-wire cable coming out through a cut-out hole in its center.
- Arrange the five wires side by side, straightened out with minimal bends, in the same order that the will go into the connector and attach to the thermostat. See photo below. Take time to make sure you don't have it reversed left-to-right, which is easy to do. When connecting the thermostat to the connector, you will have the thermostat turned around backwards with its upper surface facing the floor and its display facing the wall.
- Trim the ends of the wires flush with one another.
- Cut off about three inches of cable insulation.
- Bend the cable 90° to the right, so it is oriented as shown in the second picture below.
- Arrange wires in order shown in second photo below, white wire on top, red wire on bottom. Order is WYGBR.
- Hold a 5-pin female Dupont connector up to the wires in the orientation it will need in order to insert the pins into it. The connector has a small triangle next to pin 1 (for the Red 24VAC hot wire), located at the end that the MALE pin will insert into. That triangle should be facing down and on the right in the wire orientation shown in the second photo below.
- Prepare a pin in the crimper and hold it up to the wires and Dupont connector, and carefully consider whether, after crimping, the wire and pin will be in the correct orientation to insert directly into the connector, in the proper order, without having to try to bend wires or switch their position or rotate them about their axis.
Once you are certain you have the orientation correct, you are ready to start crimping. Good luck! Once you have five good crimps and have squeezed the insulation end with pliers to achieve a good fit, push all the pins in place and check that they don't pull back out. Success!
Comments
Please log in or sign up to comment.