This is a little tree of about 11,5 cm height with 36 (37) colored lights on it. They blink in all colors in a funny way. But they do it more or less always in the same way. This gave me the idea to bring some order into the chaos by adding some additional parts. The result is a controller with an ESP32 and various sensors, which put the illumination of the LEDs in the service of various measurement tasks, or simply provide for amazement. A part of what would be possible altogether, I present you individually in the following chapters. All applications are programmed in MicroPython. My colleague Andreas Wolter has additionally ported the programs for the Arduino IDE to C++ for you. So welcome to the
Stories around a small Christmas tree
Image 1: The tree stories
- The components list
- The software
- We build the trees and wire it
- Targeted illumination
- The OLED display for plain text information
- Steamed lights
- The enchanted trees
- Who makes such a noise?
- On the trail of tree theft
- A pleasant stay wish ESP32 and DHT22 / DHT11
- The somewhat different Christmas raffle
- The Christmas tree app
(*) The use of the vibrating contacts or GY-51 module requires a different programming required.
2. The software
For flashing and programming the ESP32:
pacetender To test ESP32 / ESP8266 as the UDP server
Browser: Opera or Chrome
The micropython programs for the project:
Project files Micropython:
Project files Arduino IDE:
The version of the Arduino IDE used here is 1.8.16
To use the ESP32 Core you have to enter this link in the preferences as additional board manager URL:
Then search for ESP32 via the menu Tools -> Board -> Board manager and install it.
The used libraries like LittleFS were integrated late into the core. Therefore it is important to update it if necessary.
optional noisy_ticker_h.ino (with Ticker.h Bibliothek)
Micropython - language - modules and programs
Once the firmware is flashed, you can casually talk to your controller one-on-one, test individual commands and see the response immediately, without having to compile and transfer an entire program first. In fact, that's what bothers me about the Arduino IDE. You simply save an enormous amount of time if you can do simple tests of the syntax and the hardware up to trying out and refining functions and whole program parts via the command line in advance before you knit a program out of it. For this purpose I also like to create small test programs from time to time. As a kind of macro they summarize recurring commands. From such program fragments sometimes whole applications are developed.
If the program is to start autonomously when the controller is switched on, copy the program text into a newly created blank file. Save this file as boot.py in the workspace and upload it to the ESP chip. The program will start automatically at the next reset or power-on.
Manually, programs are started from the current editor window in the Thonny IDE via the F5 key. This is faster than clicking on the Start button or via the Run menu. Only the modules used in the program must be located in the Flash of the ESP32.
In between again Arduino-IDE?
If you want to use the controller together with the Arduino IDE again later, just flash the program in the usual way. However, the ESP32/ESP8266 has then forgotten that it ever spoke MicroPython. Conversely, any Espressif chip that contains a compiled program from the Arduino IDE or the AT firmware or LUA or ... can easily be flashed with the MicroPython firmware. The process is always as described here.
3. We build the trees and wire it
There is one for the assembly of the tree Video.
Of course, after assembling the little tree, you can sit back and relax, admiring his work. Additional fun can be had if we modify the assembly process in a few places. At three points in the video we have to proceed differently for our project. The 4.7kΩ resistors mentioned there are those with 10kΩ in the parts package. And these three resistors per board A and B are soldered only at the places on the board, as it is shown in the figures Fig.2 and Fig.3, the other end of these resistors remains free for the time being. Later we solder thin wires (for example flat ribbon) to these free ends for the connection to the ESP32. This applies to both boards, A and B. The electrolytic capacitors remain completely away.
Figure 2: Part A
Image 3: Part B
The rest of the assembly can be done exactly according to the video template. When the base plate is also attached, we solder the little cables to the free ends of the 10kΩ resistors. The length should be between 25 and 30 cm. At the other end of the cable we solder a piece of pin header to make it pluggable.
Image 4: The Tree Connection
The assignment of the connectors on the tree to the GPIOs of the ESP32 can be seen in Table 1. The index refers to the list of pin objects. This list with the name layer is used to address the LED layers by loops, as we will see. The pins are distributed in such a way that an even-numbered index is always followed by the LED layer on board B with the same layer. Of course, any rearrangements are possible at any time.
Table 1: Connections between trees and ESP32
Image 5: Base wiring
Image 6: Basic resistors on Part B - Detail, free ends are above
Image 7: Wired of Part A
4. Targeted illumination
The wiring is finished? Then we want to ignite the LEDs on the little tree already. We supply the little tree either via the batteries or via the supplied cable from a USB port. After switching it on, it remains dark. Sure, because the base connections of the transistors are exposed, so no base current can flow and because then also no collector current flows, the LEDs stay dark.
Image 8: one of 6 transistor levels
This changes when the GPIOs are programmed as outputs and the level of GND potential is raised to 3.3V. We achieve this by assigning a 1 as value. In Thonny's terminal, we enter the following lines.
If wired correctly, the LEDs of level A1 now start to light up and go out after the input of.
In contrast to the previous version of the little tree kit, the new version is equipped with flicker LEDs. Previously they were simple colored LEDs. This has a certain disadvantage, because dimming the "Flashing LEDs" is no longer possible. Nevertheless it is fun to experiment with it. Via the six transistors we are now able to start or turn off all 6 levels exactly according to our wishes. With this we also influence the overall brightness.
The arrangement of the lights is shown in Fig. 9. It applies to both part A and part B.
Image 9: Distribution of the LEDs is rank
The arrangement of the LEDs, the wiring for and the connections on the ESP32, are provided for all further attempts than given. They therefore no longer immerse explicitly in the descriptions and circuit breakers of the partial circuits.
5. The OLED display
The OLED display can provide us with plain text information, but it can also display graphics in black and white. Programming is easy if we use the associated MicroPython software modules. The SH1106 hardware driver is directly responsible for the 1.3'' display and can only be used for it. The module framebuf integrated in the MicroPython core provides simple graphics and text commands and the module oled.py gives us comfortable commands for text output.
The display is controlled only via the two lines of the I2C bus. We create an I2C object and pass it to the constructor of the class OLED. The hardware device address of the display is fixed and anchored as a constant in OLED. Nevertheless, we first check what is available on the bus. Then we delete the display and output a few lines.
The graphic in Fig. 10 and the following program demonstrate the handling. The program we enter in the Thonny Editor, save it and then start it with the function key F5.
Image10: The OLED on the ESP32
This is the constructor of OLED Class
The device address of the display is decimal 60 or 0x3c hexadecimal. The constructor of the OLED class also knows that the display has 128 x 64 pixels. After the output of the four lines, "Christmas" is replaced by "chist" later. Previously, we must delete this line of course. Quietly try the individual commands individually via REPL, the Terminal Console from Thonny.
For Arduino IDE:
For the display, the library becomes U2G8 Used that you can install via library management.
6. Steamed lights
Image 11: Level1
Image 12: Level2
Since we can control the individual levels of the LEDs on the tree separately, let's take advantage of this to go from the lowest level - OFF - up to the maximum brightness and back down again. We don't need to change anything on the circuit. The display informs us about the currently active level.
We define the order of the layers in the layerPin list. According to this pattern the pin objects are created in the following for loop. The functions switch(), stop() and all() help us to make the program clearer. Furthermore we will use them several times in the following chapters.
In the main program we clear the screen and draw a frame. 4 and 16 are the pixel coordinates of the upper left corner, 123 and 40 are the width and height in pixels and 1 is the color white, there are no more colors. The outer for-loop counts the total passes. The first inner for loop counts up i in intervals of 3 seconds and turns on the layers. The second loop counts down and clears the LEDs again.
The last edition is removed, and the STOP () function reliably deletes all LEDs and says goodbye with a friendly "good bye".
About the interval length and the number of runs we can specify the behavior of the LEDs itself.
For Arduino IDE
7. The enchanted trees
Anyone could come along and want to switch on our little tree. But no way, that's only possible with our magic hands. Of course, we don't say that we have a small neodymium magnet rod hidden in each hand. What do we need it for? For "magic". Because we have modified our circuit in the meantime. A reed contact is now connected to ground at GPIO pin 13. Inside the glass tube there is a switching contact which closes when a magnet approaches.
Image 13: Muggles have no magnet, the tree remains dark
Image 14: In the yellow marker: Contact and Magnet
The glass is very brittle and the wires are very stiff. Do not bend them, otherwise the glass will shatter and you can bury the component.
Image 15: Reed contact helps magic
There is something else we must not forget, namely that OLED and Trees remain connected as described above.
The reed contact must be placed in such a way that we can easily get close to it with our magnet when we place Bäumchen or Breadboard on the palm of our hand. A thin black glove helps us to keep the magnet invisible. Probably everyone around you are muggles.
The program is very simple. We already know everything up to the main program. The while loop runs endlessly until the power is turned off. If the contact in the neighborhood of the solenoid is closed, then GPIO13 is at GND potential and all lights go on. Otherwise, the resistor built into the module pulls GPIO13 to Vcc=3.3V and the lights go off.
To make the magic work better, the little tree with breadboard should be powered by the battery. The positive terminal of the battery must be connected to the pin Vin / 5V of the ESP32. Furthermore the program must be uploaded as boot.py on the ESP32, so that the controller starts autonomously after power on. How to do this is described in detail in chapter 2 - Autostart.
For Arduino IDE
8. Advent and Christmas, the "staade" time
Translated into the common German language, "Staad" means something like "calm", "contemplative". But everyday life teaches us that even in the run-up to Christmas, things can get pretty heated. When things get too turbulent, the little tree reminds us to turn down the volume a few decibels. How does it do that? Well, there is a sound module that picks up sound and delivers the digitized signal to the ESP32.
Image 16: Volume OK
Image 17: too loud
Image18: Sound Machine on ESP32
Sound is transmitted by rapid pressure fluctuations in the air. A sound signal propagates at approx. 340 m/s. In a room, practically without any perceptible delay. The microphone in the sound module converts the pressure fluctuations into an electrical signal. Unlike the reed contact, however, these oscillations can no longer be detected by polling the GPIO port; this method is too slow. Therefore we use another technique here, the interrupt programming. An interrupt is the interruption of a program by a specific event. We will use two different interrupt sources. One triggers an interrupt when the level on a GPIO pin changes, from 0 to 1 or vice versa. The other IRQ source is a hardware timer of the ESP32. It triggers the IRQ when the alarm clock rings.
Both now play the ball to each other alternately. The GPIO17 waits for a signal from the sound module. If a falling edge arrives, the function soundDetected() starts and checks first if it is meant because of the passed parameter pin. If n is True, then a cycle is already running and there is nothing further to do. On the other hand, if n is False, then it is a fresh job. The pin change IRQ is turned off, and n is set to True to suppress immediately following pulses at GPIO17. Then the timer is started, which specifies the runtime of the tree lighting. The lighting is switched on by calling all().
If the timer has expired, the associated interrupt is triggered, which the function Sounddone() starts. n will be on False Set, the lights go out and the PIN-CHANGE-IRQ is turned on again.When the timer expires, the corresponding interrupt is triggered, which starts the soundDone() function. n is set to False, the lights go out, and the pin change IRQ is armed again.
The main program consists of just two lines. When the timer expires, the corresponding interrupt is triggered, which starts the soundDone() function. n is set to False, the lights go out, and the pin change IRQ is armed again.
The main program consists of just two lines. n is set to False so that the pin change IRQ that is activated afterwards can be triggered.
The interesting thing is that the IRQs are still active even if the main program is already finished. To switch this off the ESP32 must be reset with the STOP/RESTART button.is set to False so that the pin change IRQ that is activated afterwards can be triggered.
The interesting thing is that the IRQs are still active even if the main program is already finished. To switch this off the ESP32 must be reset with the STOP/RESTART button.
For Arduino IDE
Two variants were used here to implement the timer interrupts. In the noisy.ino only binary variables are switched in the two interrupt service routines. The change is then detected in the normal main loop. As an alternative you can include the Ticker.h library. Its settings are a bit easier to make. It is included in the ESP32 core. You don't have to install it. If it is not found during compilation, you may have to update the ESP32 core.
9. On the trail of tree theftThere are supposed to be people who steal their Christmas tree - from the forest. Well, dear foresters, why don't you do like we do and install a guard in your little trees like the one we are about to describe.
OK, admittedly, this will certainly be as difficult as monitoring other bans if the staff is lacking. What's the point of banning something if you can't control it? Be that as it may.
Our little tree gets a supervisor - namely itself! A sensor, which comes from a completely different corner, helps it to do this. The used GY-521 module with the MPU6050 is an accelerometer with gyroscope. It can be used to measure accelerations, forces and rotations. Yes, and if you want to take something away, you have to lift it and set it in motion. In both cases you accelerate the object, even when tilting.
Image19: Light tilting is enough to trigger the alarm
Even very slight changes in location produce forces and thus our sensor to respond. The rest is easy, the triggering is followed by the illumination of the tree and hopefully the potential thief will run away. By the way, a timer interrupt is again responsible for the duration of the alarm.
Image 20: Antiklau unit
Again there are good acquaintances in the program. But new is the initialization of the GY521. For the block we have to upload another module to the ESP32, gy521rc.py. The class contained in it is called the same as the module.Like the OLED display, the GY521 is also operated via the I2C bus. We pass the same I2C object to the constructor, set the threshold for triggering the alarm and its duration in milliseconds.
The threshold is the absolute amount of deviation of the measured value from the average value of the acceleration measurement in x-direction. The sensor is aligned so that the positive x-axis points vertically upwards. The measured value is around 16000 counts and corresponds in this case to the acceleration due to gravity g=9.81m/s².
The function hasMoved() represents the main loop here. At the entry the average value is determined by 100 measurements. It is clear that the sensor must not move.
Then it goes into the main loop. The current acceleration is measured and the deviations to the average values are calculated. If the difference exceeds the predefined limit, an alarm is triggered and the timer is activated. Alarm means, the tree goes to full brightness.
The service routine of the timer IRQs extinguished the lights. The solution on the IRQ ensures that immediately after alarm is triggered, the circuit is sharp again. If the alarm duration set by a sleep command in the main loop, then the circuit for that period would be dead.
The Rüttelkontakte mentioned in the parts list would be connected like the reed contact at ESP32, but do not allow adjustment of sensitivity.
For Arduino IDE
The GY521 library is included here for the gyroscope sensor. You can also install this via the library management. In addition, the Ticker.h library is also used here. In contrast to the MicroPython template, all axes of the sensor are considered here.
If you are not sure which I2C address the sensor uses, you can load the program I2C_Scanner.ino on the ESP. There should then be two addresses shown in the serial monitor in this case (for the display and the sensor). At the sensor itself you have the possibility to choose between the addresses 0x68 and 0x69. You have to connect pin A0 either to GND or to 3.3V of the ESP.
10. A pleasant stay wish ESP32 and DHT22 / DHT11
A pleasant room climate is part of the festive mood. Now, the ESP32 cannot change the room climate in this simple application, but it can report on it. The exact values for temperature and humidity are shown on the OLED display, the rough values are told by the little tree. In 2-degree increments, it reports the values of the room temperature through different numbers of switched-on LED levels.
Image 21: Medium temperature - half lighting
Image 22: Temperature and humidity measurement in a module
There are 2 variants of DHT22, alias AM2302. The module in the left picture already contains the necessary pullup resistor for the One-Wire-Bus, which by the way must not be confused with the system of the Dallas- device DS18B20. The Dallas bus has a completely different timing. For the naked version in the right figure a 4.7kΩ to 10kΩ resistor against Vcc must be installed.
The operation in the program is easy. The three necessary orders is already integrated in Micro Python module dht to disposal.
Besides the usual suspects, the program offers only the import of the module dht, the instantiation of the object dht22 and the main loop with the measurement job dht22.measure() and the reading of temperature and humidity value. We already know the output on the display and the tree display. Interesting and inconspicuous is perhaps the conversion of the temperature from °C to the index of the illumination level. by the term int(((t-15)//2)%6). From the quotient value of the integer division of the deviation of the temperature from 15 °C upwards and 2, the 6-division remainder is determined and represented as an integer to be on the safe side. Once again very slowly.
for 28°C the result would be: 28-15=13; 13//2=6; 6%6 = 0; The last step is necessary because there is no step with the number 6.
For Arduino IDE
For this sensor please install the DHT sensor library and the Adafruit Unified Sensor Library via the library management. In contrast to Python you have to pay close attention to data types in C/C++. The measured values of the sensor are returned of type float. Accordingly you have to set up the formatted output and also the calculation for the control of the LEDs can be faulty if you leave out the data type.
11. The (somewhat different) Christmas raffleI still know this from my school days. Everyone brought a package during Advent and the week before the vacations the raffle was started - every ticket wins.
I chose neutral RFID cards as recyclable raffle tickets. The draw is done by the ESP32 together with the RFID kit. Only the prizes have to be taken care of by yourself. Of course the little tree is also included. By its luminosity it announces its profit to the respective player. So that no doubts arise in the interpretation, the display unambiguously states the location of each draw: Freiburg, Berlin, Hamburg ... Six lot cards and one master card are needed.
Image 23: The height of the hit number determines the light intensity
Image 23: The height of the hit number determines the luminosity
Image 24: Lottery
Image 25: RFID cards reader
Due to the SPI bus the wiring is a bit more complex than with the I2C bus with its two lines. SPI bus devices do not have a hardware device address, but they have a chip select connector that must be set to LOW if the device is to be addressed. Also the data transfer runs a little bit different, it is always send and receive at the same time. It is not necessary to clarify the procedure here, because the class MFRC522 does it for us. We only tell the constructor the pin assignments and the transfer speed. The transfer works with fast 3.2MHz. For comparison, I2C works on 400kHz.
The function Readuid() Reads the unique identifier of the card and returns them as a hexadecimal value and as a decimal number. The cards are requested via the OLED display. So that the function does not block the entire process, a timeout ensures an ordered retreat. In this case, the value None is returned instead of the card ID.
Figure 26: RFID cards and chip
So that the lot cards come into the game, we need a master card. To do this, we take any card or a chip from the stack, read the ID and thus prove the variable with the decimal value at the beginning of the program:
Masterid = 4217116188.
The first start determines the ESP32 that there is no file with the lot card data and requires the master card. After it has been detected, a lot card is requested. After reading the ID, this is written to the file and again requires the master card. Reading will continue until the last lot card. If no loose card is offered after the master card requirement for 10 seconds, the system restarts itself. Prerequisite is that the program rfid.py as boat.py was sent to the ESP32. Chapter 2 - Autostart explains exactly how that works. To start completely from the front, we can get the file slavecards.txt Delete with the lot card IDs via the Thonny Console. After a reset, the lot cards can be read again.
For a game cycle, 6 wins are determined, the 6 cards are shuffled and dealt, and the new round is started by pressing the PROG button on the ESP32.
For Arduino IDE
Note: in this case the connections to the pins of the ESP32 must be changed. The reason for this is that the hardware SPI interface is used. Its pins are not changeable.
MOSI = 23
MISO = 19
SCK = 18
SDA = 5
RST = 17
For the RFID scanner, please install the MFRC522 library.
For a direct comparison with MicroPython, you can change this line so that you don't have to change the pins every time:
To store the text file with the IDs, a file system is set up in the flash memory of the ESP using the LittleFS library (the successor to SPIFS). Files can then be stored there. The library is now part of the ESP32 core. You do not have to install it separately either. The program is written so that you do not have to edit the text file on the PC.
If you still want to do this, you can install the ESP32 Upload Plugin. However, the data exchange then also works (as the name suggests) only in one direction.
The program structure has been changed a little here. But the behavior of the program should be the same. Some more functions have been added. You can read the master card at program start. It is also possible to delete the text file from the flash. For this you can connect a cable or a push button to GND at the given pin (see source code). Keep it pressed and restart the ESP. Then the file will be deleted if it exists. Then disconnect it and re-read the winning cards. The maximum number of winning cards corresponds to the LED levels of the Christmas tree. If you want to use fewer cards, you can wait for the timeout during the reading process.
12. The little tree in the LAN/WLAN
Let's do the dozen full, and we bring the trees to the net. Because, if an ESP32 is already used for controlling, then LAN or WLAN access must also be controlled. I decided to realize a web server on the ESP32 because the levels of the trees can then be controlled with almost any browser. Alternatively, an UDP server would have been in question on the controller and a mobile app. But that would have blasted the framework of this blog and therefore I have spaced from it. For those interested, such a kind of control, I have already described in other posts, for example here and here.
For the circuit, the construction of Chapter 5 is used, which we extend around an RGB LED and three 1.0 kΩ resistors.
Image 27: Web structure
After importing the necessary modules, we define the pins for the RGB LED, which reveals us the network status visible to a long distance. This is followed by the selection of the network mode, WLAN or ESP32 own accessspoint. Wi-Fi is preset by default. To access the WLAN router, the access data must then be specified here. The layer definition is extended by three lists, plain text for on / off, background color for the table in the web page and the switching states of the levels.
In the functions, the blocking ends were removed, swell(), swell(), wave() and tree(). New hexmac(), blink(), LEDsOFF() and web_page(). hexmac Specifies the MAC address of the ESP32 in station mode, blink() Signals the network and server states. With LEDsOFF() When the RGB LED is turned off and web_page() Captured requests from the browser, executes the orders and returns a response as a web guide text.
The request of the browser goes to the server as a query string. The string has the shape ?, ? P or ? E = X & V = Y. Therein X for the level number and Y for switching state, 0 or 1.
web_page() Converts the request to capital letters, first checks "A" and "P". If the request contains more than 2 characters, attempts to determine the level and switching state. If there is a mistake, no action is triggered and the naked home page is called. This also happens when no QueryString has been specified. Thereafter, the structure of the website takes place as a string and its return to the main loop.
Following the function definitions, the construction of the network connection follows, either as its own access point or as a connection to the WLAN router. This is controlled by the two variables Ownap and Wirisconnect. In both cases, a fixed IP address (10.0.1.181) will be assigned because it is a server. Dynamic addresses from the WLAN router are unsuitable because they can switch from time to time. The connection to the router is marked by the blinking of the blue LED. The display informs us that the connection is and the connection socket S is ready to answer inquiries.
In the main loop, the reception loop is waiting for the method Accept() On a request. Does not matter to the timeout, throws Accept() An exception that we intercept with the foregoing try.
If a request is available, then supplies Accept() a communications seat C and the address of the requesting machine back. C Used processing the data exchange between the client and server, while S is released again to accept additional incoming requests. The method C.Recv() Returns the text of the request from which only the first few characters are interested. In the development phase you can test the parser web_page() Enter requests from hand. Ownap and Wirisconnect then both have to False be set.
The byte object requester of the received text is now in a string r decoded, which are easier to handle leaves. We are looking for a "GET /" far right at the beginning of the string and follows the position where the "http". If both found, then we isolate the text after the "/" of "GET" until the space of "HTML" and send it as a query string to the parser web_page(). Its response we received in the variable response. Then we send the HTML header and the text of the HTML page with the included reply to the caller. The following two else and the except are used to catch and handle of possible errors. Important is the final c.close(), Which the communication socket C Closes.
After a key interrogation program termination shows us the green LED on by their brief flash as a heartbeat that the system is still alive.
Image 28: Live from the browserThis is how the website looks in reality on Google Chrome. Opera offers a similar picture after entering the URL 10.0.1.181:9002. Firefox makes a fuss, because the creators got it into their heads that they had to bully the users by having their browser only accept https addresses. But there are alternatives. If things get really bad, you could even write your own frontend for the PC using CPython.
Well, I think now you have enough to do with the tree projects until Christmas. Surely there is one or the other for everyone. The important thing is that you enjoy the implementation and that I could arouse your interest. In any case, I wish you a wonderful Advent season.
For Arduino IDE
Download webcontrol.inoThe interface in the browser looks slightly different here. The function is the same.
Depending on whether you want to use your own access point or the local WLAN, you must comment out the respective unused option in the source code at the beginning in the #defines.
// #define WLANconnect true
#define ownAP true
Do not forget to enter your access data when you select the WLAN option.
The IP address of the access point is here:
You can find the password in the source code.
At this point we wish you a happy 1st Advent! 🕯