To keep a healthy environment at home or at the workplace, one of the important things to control is the carbon dioxide (CO2) level.
It’s measured in ppm (parts per million), indicating how many parts of CO2 there are in one million parts of air. As a reference:
Less than 1000 ppm are healthy levels
Between 1000 ppm and 2000 ppm, we need to reduce the CO2 levels
Levels greater than 2000 ppm are associated with headaches, sleepiness, poor concentration, loss of attention…
To reduce the CO2 level, we need to ventilate the room. It can be manually done (opening the windows) or it can be automated with a ventilation system.
To measure it we need a proper CO2 sensor, and one of the most reliables sensors is the MH-Z19B. It is not cheap for the Aliexpress standards (it costs around 20 EUR), but other cheap sensors announced as “air quality” sensors or “eCO2” sensors are not really measuring the CO2 level (i.e. the MQ135).
I bought this MH-Z19B from Aliexpress and hooked it to an ESP32-WROOM-32 board. This board is going to be also purposed as a temperature and humidity sensor, so I also attached a much cheaper DHT22 sensor. The MH-Z19B includes a temperature sensor, but it’s mainly used for calibration and it lacks precision, as it does not report decimals. I’m also using an expansion board to simplify the connections.
The jumper in the expansion board needs to be set to 5V (because both of these sensors need 5V).
Connected VCC and GND of both sensors to the expansion board
Connected the RX and TX of the MH-Z19B to the TX and RX (GPIO1 and GPIO3) of the ESP
Connected GPIO16 to the DAT of the DHT22
Finally, I installed ESPHome to the board with this configuration:
substitutions: devicename: co2sensor friendly_name: CO2 sensor
The heating system is in a different builng than the router and I was experiencing some WiFi coverage issues (the WiFi signal needs to cross two metallic window blinds…).
To diagnose the WiFi coverage is very useful the wifi_signal sensor in ESPHome:
sensor:
- platform: wifi_signal
name: Wifi Signal
update_interval: 60s
It was showing a WiFi signal of -95 dBm in the board: This is very low, and it was experiencing some disconnections.
Usually the ESP32 boards have an antenna integrated in the board, but the ESP32-WROOM-32U has an IPEX connector for an external antenna:
So, I spent less than 10 EUR in Aliexpress buying (affiliate links):
I bought from a popular chinese store a generic Tuya smart plug with power monitoring. It was extrememly cheap, costing less than 4 EUR. And of course I bought it to play trying to flash ESPHome.
The first challenge was to open it without breaking it. I was able to open it by wrapping it in cardboard and gently tapping it with a hammer around the body.
You never know what chip you are going to find. In the past ESP8266 was very common but now they switched mainly to Beken chips. This smart switch has a T102_V1.1 board with a Realtek RTL8710BX chip:
Luckily the support for this chip was developed in the LibreTiny project:
After the flashing, if I try to power it from USB the WiFi module did not start and it causes a boot loop, but It worked perfectly plugging it into the mains power. A new device appeared in the router and I can connect to the ESPHome web dashboard.
Adding power metering
The plug includes a power metering chip: the BL0936, that is supported by ESPHome:
However, after configuring and uploading the firmware with the power meter enabled to the board, the device enters a boot loop, displaying the following error:
[D][switch:016]: 'Smart Plug 1' Turning OFF.
[D][binary_sensor:034]: 'Button': Sending initial state OFF
[C][hlw8012:014]: Setting up HLW8012...
W [ 0.109] CHANGE interrupts not supported
Luckily, after 10 reboots, the firmware enters in the “OTA safe mode”, disabling all the modules and connecting to the WiFi without the web dashboard but opening a port to allow remote flashing.
It can be fixed with the workaround of SuperXL2023 modifying the .esphome/platformio/platforms/libretiny/cores/realtek-amb/arduino/src/wiring_irq.c file and adding the lines 64 and 65:
In the ESPHome config I’m specifying the version of the framework to avoid losing this fix in an automatic update. It works perfectly after rebuilding the image with this fix and uploading it to the device.
This is the complete ESPHome configuration with power metering:
It needs to calibrate the sensor to obtain the proper values of voltage_divider, current_resistor and current_multiply. It can be done with a multimeter and entering the values in the hlw8012 page.
I’m using it to remotely access private services in my home server. I setup a star topology, where all the VPN clients connect to the home server and they can only see the server.
So I need a dynamic DNS and an open port in the router, I already have them for Home Assistant.
Eloy Coto recommended Tailscale, it is an amazing mesh VPN based in WireGuard. It’s much simpler to set up, and you do not need to open public ports, but it’s commercial and a bit overkill for my needs.
Generating the WireGuard configurations
The most tedious part of WireGuard is to generate the configurations, but there are some nice tools to ease that, like:
The tool generates the configuration for the server and for the requested number of clients. It does everything in the frontend, so it is not leaking the VPN keys.
As I’m only acessing the server, I have removed the IP forwarding options in the Post-Up and Post-Down rules.
Installing and configuring the WireGuard server
WireGuard is in the official Ubuntu repos, so to install it in the server it’s enough to do:
sudo apt install wireguard
Then I needed to put the config in the /etc/wireguard/wg0.conf file and do:
To setup the client in the phones, the WireGuard Config web tool generates QR codes. In other devices you’ll need to create a file with it or paste the config contents.
Using Pi-hole from the VPN clients
To use the Pi-hole hosted in the same VPN server from the VPN clients, you can specify a DNS property in the client config, i.e. if the server is 100.100.1.1 and the client is 100.100.1.2:
Every time that you connect the VPN, the DNS server in the client changes to 100.100.1.1 and it is reverted to the previous DNS server when the VPN is disconnected.
Additionally, Pi-hole needs to be listening in the wg0 interface, I explained how to make Pi-hole listen on multiple interfaces in the Pi-hole post.
ChatGPT was launched in November 2022, and it changed our world as we knew it. Since then, Large Language Models (LLMs) have integrated into our daily workflows enhancing our productivity and the quality of our work.
Another interesting milestone happened in February 2023, when Meta released the Llama LLM under a noncommercial license:
This sparked the enthusiasm among numerous developers dedicated to advancing LLMs, leading to a increase in collaborative efforts and innovation within the field. A good example is the Hugging Face Model Hub where new models are constantly published:
Mistral 7B was released in October 2023, achieving better performance than larger Llama models and demonstrating the effectiveness of LLMs in compressing knowledge.:
And now it’s easier than ever to locally execute LLMs, especially since November 2023, with the Llamafile project that packs Llama.cpp and a full LLM into a multi-OS single executable file:
And about using LLMs for code generation (Github’s Copilot has been available since 2021), there are IntelliJ plugins like CodeGPT (with its first release in February 2023) that now allows you to run the code generation against a local LLM (running under llama.cpp):
Google is a bit late to the party. In December 2023 they announced Gemini. In February 2024, they launched the Gemma open models, based on the same technology than Gemini:
And finally, if you are lost among so many LLM models, an interesting resource is the Chatbot Arena, released in August 2023. It allows humans to compare the results from different LLMs, keeping a leaderboard with chess-like ELO ratings:
But something that seems trivial, like publicly accessing services in your home server, has some complications, and you usually need to worry about dynamic IPs and security.
What do we need:
An ISP not using CG-NAT
Redirect ports in the router
A dynamic DNS provider and a client to update the IP (or a static IP)
An SSL certificate to securely access the HTTP services
ISP providers with CG-NAT
Some ISPs use CG-NAT (Carrier-Grade NAT), sharing the same IPv4 among multiple customers. In that case the only way to expose your services is using reverse proxy services such as ngrok.
Ngrok allows you to generate one static domain and it also automatically generates a SSL certificate, so most steps in this post do not apply.
My ISP (O2 Spain) assigns me a dynamic IP, and I prefer to not rely on these reverse proxy services, so I remotely access my home server redirecting ports in the router.
Dynamic DNS provider
Usually, and unless you have a static IP service (not very common, and not available in my ISP), you need to setup a dynamic DNS service.
I have been using the free Now-DNS service for years:
And to update the IP in my home server, I setup ddclient with this /etc/ddclient.conf file:
ssl=yes
protocol=dyndns2
daemon=60
mail=root # mail all msgs to root
mail-failure=root # mail failed update msgs to root
pid=/var/run/ddclient.pid # record PID in file.
use=web, web=now-dns.com/ip # get ip from server.
server=now-dns.com # default server
login=<your-login>
password=<your-password>
server=now-dns.com,<your-dynamic-domain>
Some of these dynamic DNS domains are blocked in the Pi-hole blocking lists, so, if you are using Pi-hole or other DNS blocking service, you’ll probably need to whitelist your domain.
SSL certificate
With the amazing Certbot you can obtain free SSL certificates:
But in order to make that work, you need a domain name (available from the dynamic DNS provider in the previous section).
HTTP Server
And to verify that the domain points to your server, Certbot is going to do an HTTP request to that domain, so you also need to have an HTTP server in the port 80 and open the port 80 in the router. This is also needed for the certificate renewals.
You may encounter numerous attacks on this port, so it is crucial to have a reliable web server that is consistently updated and properly configured. I personally use nginx as my HTTP server, and it has never failed me so far.
Home Assistant
To use the SSL certificate from the HA container, we need to share the folder where certificates are stored passing a “-v /etc/letsencrypt:/etc/letsencrypt” to the docker command and setting in the HA configuration.yaml:
I’ve never been a fan of the Raspberry Pi. In my opinion, it occupies an intermediate position where it is too underpowered for desktop use and too overpowered for IoT projects:
To use them as a desktop, there are great X86 alternatives available at about the same price than a RPi 5 but much more powerful, such as the Intel N100.
And for IoT projects, the ESP32 is the king, with amazing boards with Wifi, Bluetooth, etc., all at a price of less than 5 euros.
So it’s place may be TV boxes (where I prefer a Chromecast with Android) or small servers where the power consumtion is important because they are always on.
I bought an Orange Pi 3B: 4 cores, 4GB RAM, 64GB eMMC (~50 euros in Aliexpress) to replace my old X86 home server (Intel N450: 2 cores, 2 GB RAM, 64GB SSD):
The Orange Pi 3B shares the form factor with the Raspberry Pi 3B but it is almost as powerful as the Raspberry Pi 4. Notably, the Orange Pi 3B comes with several advantages over the RPi 4:
Support for eMMC (much faster and reliable than SD cards)
A power button
A full-size HDMI port
External antenna
And it’s cheaper
I installed the Ubuntu Jammy server image in the eMMC following the OPi manual. It needs to use a USB-A male to USB-A male cable and the RKDevTool (it’s in Chinese) that runs only in Windows.
And, as this machine is going to be exposed to internet, I hardened a bit the security:
Changed the APT repositories to ports.ubuntu.com
Regenerated SSH server keys
Removed SSH root access
Changed passwords
Renamed the orangepi user
Removed the local autologin
To remove the local autologin we need to edit:
/lib/systemd/system/getty@.service.d/override.conf: For the display console autologin
/lib/systemd/system/serial-getty@.service.d/override.conf: For the serial console autologin
I encountered numerous issues with my network provider’s router DHCP. Since I haven’t yet decided to acquire another router, I opted to offload the DHCP server to another machine, which is currently running my Home Assistant and NAS.
I was in search of a DHCP server with a web UI. During my exploration, I came across Pi-hole, a DNS server specifically designed to block DNS queries to domains that serve ads and do tracking. Interestingly, Pi-hole also incorporates an integrated DHCP server (dnsmasqd) that can be configured through its admin UI.
I presume the integration of the DHCP server aimed to simplify the setup of clients’ DNS servers, yet it proves highly convenient for home networks. And forget about the “Pi” in the name, it can be run in any linux server, not necessarily in a Raspberry Pi.
I’m still an addict to running everything in Docker containers. So I set up the Docker Pi-hole container (https://github.com/pi-hole/docker-pi-hole) using this script localed at /usr/local/pihole/docker.sh:
And of course, you need to disable also the DHCP server on the router, it’s a very bad idea to have two DHCP servers working in the same network…
It is now functioning smoothly, and the included ad-blocking feature is a definite plus. Although it doesn’t currently block ads on YouTube and Twitch, its still great.
I’m also using it in my phone with a Wireguard VPN (it maybe a topic for another post). To make it listen in multiple interfaces like in the local and the VPN interfaces, I needed to create a /usr/local/pihole/etc-dnsmasq.d/99-interfaces.conf adding there:
interface=lo
interface=wg0
Another similar alternative worth exploring is AdGuard Home, but I haven’t had the time to test it yet:
Two years ago I started to need controlling my home heating system while I’m not at home. I could go the easy way and buy a couple Nest thermostats, but I preferred the DIY way.
ESP32 board with ESPHome
I connected the boiler to a ESP-WROOM-32 board via a relay module. The box and the cables were more expensive than the board (~10 EUR) and the relay module (~5 EUR).
The ESP32 board is running ESPHome: https://esphome.io/. I think it is a very nice project and very easy to setup. All the configuration is done via YAML files. The board is connected to the home WiFi and it has a fallback hotspot.
My home heating system has two radiating floor zones with two independent pumps. I also decided to automate the boiler’s “Winter mode”, in this mode the boiler heats the water for the heating, and I wanted to disable it when the heating is not working.
In my case I needed to activate the winter mode when any pump is working and keep it working for a period of time after the pump is off.
To measure the temperature in the rooms, I used two Xiaomi Mi Home Bluetooth Thermometer 2 (~6 EUR each). They transmit the temperature via BLE (Bluetooth Low Energy) beacons.
Their LCD display is very convenient and, as they are battery powered, you can place them in the better part of the room. I flashed them with this custom firmware:
The control, reading the thermometers and activating the pumps, is done via a Home Assistant (HA) running in an old X86 tablet with Ubuntu (this is usually run in a Raspberry Pi or similar…).
I installed HA in a Docker container, this is my script to update and start the container:
Home assistant reads the thermometers via the Passive BLE monitor integration: https://github.com/custom-components/ble_monitor that can be easily installed via HACS (the Home Assistant Community Store). I needed a Bluetooth 5 USB adapter.
Then, I needed to setup two thermostats in HA via the config/configuration.yaml file:
After the initial hype (with Apple showing some nice fake videos…), it seems that now things are much more quiet about the Vision Pro. I’m sure they are going to fail, like all the previous attemps on VR “failed”, or at least they failed as a mass consumer product.
People do not want immersive experiences, or they do not want these experiences all the time. Books like “Neuromancer” or “Ready Player One” portray a society were all the computers use VR interfaces, but I think that is still not possible with the technology we have in 2024. Even if it becomes possible someday, people may not embrace it.
3D interfaces in computers are not comfortable, and all attempts to develop these kinds of interfaces have failed. Humans have been using paper, a “2D” medium, for thousands of years; that is why it’s so easy for us to interact with 2D screens on mobile phones or tablets.
We observed the evolution of past interface design trends, such as skeuomorphism, transforming into clean visual languages characterized by simplified interfaces, as exemplified by material design. The natural environment of these interfaces is 2D.
And additionally, there are other factors like the weight or the low resolution of the screens and the cameras (yes, it’s one of the biggest in the market, but it still cannot replace a real monitor, and it’s going to guarantee you dizziness when you try to read text).
There are still some niches where VR is a success, mainly those gaming related (and of course porn), but Apple is not good at any of those.
I remember some VR/AR memorable failures, the Vision Pro will soon join the list: