I Made the Perfect Gadget for My Room Using ESP32 - Unihiker K10
by alaminashik in Circuits > Gadgets
157 Views, 1 Favorites, 0 Comments
I Made the Perfect Gadget for My Room Using ESP32 - Unihiker K10
I have always wanted to automate my room using voice commands. Also, something that easily fits with my existing switchboard, has a beautiful interface, touch controls, and can be connected to my phone.
In this project, I will describe in detail all the processes of making such a device.
The device features:
- Voice commands to perform various tasks. (with dual mic)
- Appliance control using TRIAC (1 Fan with dimmer, and 1 Light)
- Appliance control using Infra-Red (1 AC by cloning the remote signal)
- Wifi synced NTP Clock.
- Alarm clock.
- Four touch-sensitive buttons.
- A 2.8-inch color LCD screen.
- Temperature, Humidity, and Light Intensity Measurement.
- Auditory feedback.
- Mobile phone/webpage control (future implementation)
These features may seem like a lot of work, but luckily, I used the Unihiker k10, which has most of the components on board already. Made my life 10 times easier!
The processor is an ESP32-S3 with 16MB flash and 512kB SRAM. Even with all these features, it currently consumes only 30% of flash storage! The code utilizes FreeRTOS and dual-core use for a better real-world experience.
Additionally, I over-engineered the hardware parts to increase their lifespan. I will share all the details, so let's get started!
Supplies
Items needed for this project, but are not limited to:
Features and Functionalities
I wanted to make a very practical project. With that in mind, I added multiple features. They are:
There are mainly two Pages:
- Home page
- Alarm Page
Home page
- shows time, WiFi, appliance status, light intensity, humidity, temperature, and alarm status.
- Responds to the four buttons:
- Alarm button:
- Short press: Switches between fan speeds (0 to 4) and stops the alarm if ringing.
- long press: toggles between home and alarm pages.
- AC button:
- Short press: Toggles AC ON and OFF with a single press.
- Fan button:
- Short press: Toggles Fan ON and OFF with a single press.
- Light button:
- Short press: Toggles Light ON and OFF with a single press.
- Responds to voice commands:
- Voice command "Show Alarm": switches to the alarm page.
- Voice command "Hide Alarm": switches to the main page.
- Voice command "Fan": Toggles fan ON and OFF.
- Voice command "Lights": Toggles light ON and OFF.
- Voice command "AC": Toggles AC ON and OFF.
- Voice command "Fan Full speed": sets fan speed to max speed.
- Voice command "Fan low speed": set the fan speed to the lowest speed.
Alarm page (24-hour format)
- shows time, WiFi, alarm logo, alarm time, alarm status, and button functions.
- Responds to the four buttons:
- Alarm button:
- Short press: stops the alarm if ringing.
- long press: switches to the Home page.
- AC button:
- Short press: Toggles alarm on and OFF.
- Fan button:
- Short press: increments the minute hand.
- Light button:
- Short press: increments the hour hand.
- Responds to voice commands: Same as Home page.
Taking Measurements
Like every other project, the most important aspect of a project is making the enclosure. The project will be mounted on a regular wall socket.
I found the dimensions of my socket as 85 x 85 x 60mm (LxWxD)
Additionally, the precise dimensions and 3d model of the dev board (Unihiker K10) are available online. The maximum length of the unihiker is 83mm, which is a perfect fit for my 85mm socket.
3D Modelling & Printing
There are two parts to this device. One at the front that holds the Display, sensors, and dev board. The other is on the back side that holds the high-voltage appliance control circuitry and wiring.
I have used orange filament to create a good contrast, so the lights can pass through the enclosure. DfRobot openly published their STL files, so it was quite easy to accurately construct the structure.
The enclosure contains grooves to hold sensors and an IR LED. I had kept enough space for the appliance control circuitry.
This was printed using ABS plastic with 70% infill. Printed on Ender-3 V3-KE. Two M3 screws are used to attach the front cover to the back. It also has the Type-C port exposed, which makes it super easy to upload code via wire.
I have attached the Fusion 360 files.
STL files are uploaded to my drive: https://drive.google.com/drive/folders/1VTTiMSqH7U_fU79PbRRuitZcICIyWLob?usp=sharing
Schematic
The schematic is divided into several sections for better understanding.
- The top left section shows the connection of the touch sensors. The VCC is connected to 3.3V, GND is connected to GND, and the outputs (TouchA, TouchB, etc.) are connected to the corresponding ESP32 GPIO pins.
- The section below is the IR LED control section. An infrared LED can consume a large current during operation. So, it is driven by an A03400 N-channel MOSFET. A series 20R resistor is connected as a current-limiting resistor. The GPIO_IR net drives the MOSFET gate.
- The section below is the 220V mains power input section. The input power has a 0.1uF 275V Myler capacitor for filtering.
- The Top right section is the TRIAC circuitry. I found that BT134-600 is enough to control a household light and fan. Note that a microcontroller cannot directly run a TRIAC, so a TRIAC driver, MOC3041, is used in this case. It is like an optocoupler. It is important to add protection circuitry since the fan and lights can easily damage the TRIAC. A snubber circuit using a 220R 1W resistor and 104j 630 capacitor is used in parallel to the TRIAC's cathode and anode. Additionally, I added a 471k Varistor (MOV) across the fan terminal to protect the circuit from any surge voltage.
- Finally, the bottom right section shows all the connections of the edge connector of the Unihiker K10. Note that for infrared and LCD backlight functions, I was not able to utilize the edge connector. So the GPIO_IR and LCD_BLK are connected directly on the ESP32 pins at P0 and P1. Details of this modification are given in the following steps.
Adding the Touch Sensors
I used the very common TTP223B touch sensors. These are easy to connect and can work from a distance. However, the default sensitivity causes the sensor to trigger when my hand is 2-3cm away from the sensor pad.
So to reduce the sensitivity, a 15pF capacitor is used as shown in the image. I realized that this value is close to human capacitance and thus reduces sensitivity to a few mm.
Adjusting the Unihiker K10 to Fit
I had to modify the main board to fit in the enclosure. At first, I removed the camera to make room for the 5V adapter (discussed in the later part).
The edge connector had a flaw! The pins that are facing the display are connected to the main board. The edge connector of the Unihiker has a connection only on the front side, which I cannot access.
The pins of the edge connector at the back are not connected to anything. Since I won't be able to access the front pins, I had to solder the front pins to their corresponding pins at the back. This way, I can access the useful pins even when the Unihiker k10 is screwed to the enclosure. See the first two images for better understanding.
Building the IR Circuitry
As discussed earlier, an infrared LED can consume a large current during operation. So, it is driven by an A03400 N-channel MOSFET. A series 20R resistor is connected as a current-limiting resistor. The GPIO_IR net drives the MOSFET gate. This net is directly connected to the GPIO pin of the ESP32 (See the third image)
The whole IR circuit came out to be very small and cute.
Connecting the Adapter
Luckily, the unihiker board has a screw mount on the back where I could place the charger. Even though I had to carefully drill a hole in the adapter PCB to fit a screw.
The GPIO pins are used to take input from touch sensors and output to the TRIAC circuit, IR LED driver, and LCD back light.
Front Panel Complete
Finally, it was pretty simple to place all the components and glue them together. The unihiker did not require any glue since it fits properly, and the Type C housing holds it in place.
Building Power Circuitry
The TRIAC circuit contains two 4-ampere TRIACs to control the lights and fan. I could've used relays, but it would take too much space, and the fan would no longer have speed control.
As discussed in step 4, for protection, I added a snubber circuit using a 104J 630V capacitor in series with 220ohm resistors for both lights and the fan. For the EMI filter from the fan, a 14mH toroidal inductor is used in series. Additionally, a 471k MOV is used to reduce spikes that may induce from the fan.
Note: You can also use the MOC3021 TRIAC driver instead of MOC3041, but in that case, you need an external ZCD circuit, because without it, the fan will behave unexpectedly at lower speeds.
Protection
Keep in mind that we are working with mains voltage, which can be dangerous. I used electrical tape to insulate the adapter and double-sided tape for the TRIAC circuitry.
This is not only dangerous but also can damage other components permanently. Always take precautions.
Connecting LCD Backlight to ESP32 GPIO
I wanted the LCD backlight to auto-adjust its brightness based on ambient light intensity. But the backlight is connected via the IO expander, and I was unable to control it via the LEDC library. (I am not that great of a coder :)) So, I removed the on-board tiny 2k resistor that drives the backlight transistor. Later, I connected that transistor base to the P1 pin via a 2.2k resistor. (look at 2nd and 3rd image)
The P1 pin is a direct GPIO of the ESP32 and supports LEDC PWM. Thus, I was able to control the brightness of the backlight based on light intensity using code. PWM is basically turning the backlight on and off very frequently.
This was important for me since the display can get quite bright, especially at night.
Connecting the Back Panel With the Front Panel
This is a very important step. The connections are pretty simple. There is a 3-pin JST connector and one 2-pin power connector connecting the front panel to the back panel. The front and back panel connections are:
Front Panel -------- Back panel
GND -------- GND
ep9 -------- MOC3041 (Light)
ep10 -------- MOC3041 (Fan)
Live (adapter) -------- Live (outlet)
Neutral (adapter) -------- Neutral (outlet)
Follow the main schematic from step 4 to verify the connections.
Replacing Old Switch Board
Finally, the device is complete. I simply removed the old switchboard and used its screws to mount the device.
4 wires are coming out of our device. They are live, neutral, triac-1, and triac 2. These 4 wires are connected to the outlet according to the following connections:
Back panel -------- Outlet
TRIAC-1 (MT2) -------- Light (~40W)
TRIAC-2 (MT2) -------- Fan (~150W)
Live --------Live
Neutral --------Neutral
Note that one end of the light/fan is connected to our device, and the other end is connected to neutral. When turned on, it completes the circuit.
Be careful, while working with high voltage, there is a risk of getting shocked!
Designing the Interface
Now it's time to power the device and code!
Like every other project, planning is very important before coding. I wanted the UI to look modern and feature-rich. So, I created a canvas with 240x320 pixels in Illustrator. The dimension matches the actual display. It helps to get the coordinates of the individual icon to be placed on the screen.
To convert an icon into C code, I used a free resource: https://notisrac.github.io/FileToCArray/. Upload the image, set the code format to Decimal, palette mod to 2byte/pixel (for color), and uint8_t data type.
The background is a solid blue rectangle, and the icons also have a blue background. I could not get a transparent background using C code. Let me know if there are better ways for this!
Code Part 1 - Void Setup()
The whole code is divided into several sections, and the most important is the Void setup() part.
The code under setup() :
- Initialize the libraries.
- Create the semaphores for FreeRTOS.
- Connects to wifi and gets time from pool.ntp.org
- Add the voice commands.
- Set the input and output pins.
- Create several tasks to perform various functions.
Code Part 1
To keep the code understandable for everyone, I kept the whole code in a single file: "Main.cpp". Additionally, many comments are added to clearly explain what each line/code means.
I will describe the major portion of the code in detail:
The functions necessary for codes:
- Function to toggle the light state. A simple code to toggle the light state from high to low or vice versa.
- Function to toggle the state of the fan; this is similar to the toggleLight function.
- Function to switch between difference speed of the fan but turning on/off the optocoupler.
- Function to toggle the AC on or off. Additionally, this function generates the infrared signal by suspending all the tasks on this core; without this, the correct infrared signal will not be generated.
- Function to generate a PWM signal for adjusting the brightness of baclkight led of the display. The lowest brightness is 0, but the minimum brightness is 50. Maximum brightness is 255.
- Function to draw intensity level using graphical vertical lines based on light intensity, temperature, and humidity.
- A function to enter the wifi configuration portal to change the WiFi credentials.
The entire code is divided into different tasks. I utilized FreeRTOS to divide these functions into various tasks. These functions are called under various tasks. The tasks are mentioned in step-16.
To read more about FreeRTOS, you can check the article: https://www.freertos.org/Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/00-Overview
Uploading the Code
The code utilizes FreeRTOS and the dual-core processor is used for a seamless user interface. If you don't know about FreeRTOS, think of it as having multiple "void loop ()" running in synchrony.
The code mainly has the following parts:
- Some pre-defined functions that can perform simple tasks (toggle appliance, IR data send, draw graphics, etc)
- 4 tasks to handle:
- button interfacing
- Voice detection
- Alarm task
- UI task
- Three semaphores to transfer data between the tasks.
The code is written in a single script in arduino framework. Some header files such as icons, are also used. You can find those from my github: https://github.com/AlAminAshik/Multipurpose-Home-Automation-Socket-Using-Unihiker-K10
Troubleshooting
I have been using the days regularly for last few days, and I must admit, it is very useful to me. The freedom to modify code that suits my needs really is a game-changer.
The button feels very real-time, thanks to the use of RTOS. I am constantly updating the code to fix bugs and add more features. I am currently working to add webpage connectivity. Keep an eye on my GitHub profile for the updates. Cheers!