rui


Installing Thingino on a Vanhua FJZ camera  

Two months ago my brother asked me: Which security IP camera should I buy? It seemed a simple question, but I needed some time to find a good solution.

I used a Yi Camera for several years, but their mobile app is overloaded with ads constantly pushing their cloud video storage services. I cannot recommend Yi or any other vendor whose business model relies on selling inexpensive cameras just to lock you into their cloud services. I also played with ESP-CAM (and a ESP32-S3-CAM), but the video quality is not enough (MJPEG, low framerate, no night vision…).

For devices as senstitive as cameras, I cannot trust closed firmware or Wi-Fi. Both are explotable security holes. I also can’t trust any camera vendor’s cloud service.

So my requirements were:

  • Open source firmware.
  • Ethernet only, no Wi-Fi.
  • Ceiling mount.
  • Power over Ethernet (PoE) to simplify the setup in the ceiling.
  • Night vision.
  • No vendor cloud service.
  • RTSP streams for self-hosted recording services (I use Frigate).
  • H.265 support to save storage, but I ended up using H.264 because Telegram doesn’t support H.265.
  • On camera motion detection.

It is quite hard to find cameras that clearly show their chipset in the listing. Finally I bought an inexpensive Vanhua FJZ OEM camera from Aliexpress.

After opening the camera, the board didn’t match the images of the Aliexpress listing, so I thought it was a scam, but the camera is OK, the listing is outdated.

Camera specs

  • Chipset: Ingenic T31X (should be enough for H.265 and basic motion detection)
  • Sensor: GC4653 5 MP (with the resolution for 5 MP the image is distorted, I willl use QHD 2560×1440, 3.6 MP)
  • Flash: 16 MB
  • Connectivity: Ethernet only
  • Power: PoE, 48 V
  • Storage: No SD card
  • Metal housing

Why switch firmware?

The camera shipped with an unreliable Chinese firmware. For example, viewing video through a browser required a plugin that didn’t work on Linux or Mac. So I decided to install Thingino (https://thingino.com/).

OpenIPC was another option, but Thingino seemed better maintained and feature-rich. However, Thingino isn’t perfect: There are bugs, and updates are frequent. Fixing bugs requires SSH access and manual edits.

Installing the firmware

Installing Thingino isn’t straightforward. You need to disassemble the camera and follow the steps in the Thingino wiki.

Some notes from my experience:

  • I had to make a pogo-pin connector for the serial port.
  • The camera has two serial ports. I lost a lot of time because I was trying to connect to the wrong one.
  • The bootloader is locked. There is a clever trick to access it, triggering an error by shorting two pins of the flash chip during the boot sequence, so it fails to read the kernel .
  • Firmware is uploaded via the serial port using ymodem (it is very slow, it reminded me of the BBS days).

The correct serial port and the pins to short during boot:

Accessing the camera

By default, the camera obtains an IP via DHCP.

  • Web interface: http://<camera_ip>
  • SSH: ssh root@<camera_ip> (default password: root, you’ll be prompted to change it on first login)

Configuring streams

In the web interface under Settings → Streamer/OSD, you can configure two streams:

  • Main: I’m using 2560×1440 30 FPS H.264 15000 kbps
  • Substream: For previews or motion detection. I set it to 640×360 10 FPS H.264 1000 kbps

Stream settings are saved in /etc/prudynt.json.

RTSP URLs:

  • Main: rtsp://thingino:thingino@<camera_ip>:554/ch0
  • Substream: rtsp://thingino:thingino@<camera_ip>:554/ch1

These streams can be used from recording apps like Frigate or tested from Linux using ffplay <stream_url>.

Motion detection

Motion detection is enabled from the web interface by clicking the person icon or from Services → Motion Guard. It was not working with the default settings because there were no secondary stream.

Thingino supports simple motion detection with rectangular zones defined in JSON. I think that the original chinese firmware had better detection options. But I will use Frigate for advanced detection options.

On motion detection Thingino has a lot of notification options:

  • Email
  • FTP
  • MQTT
  • Telegram
  • Webhooks
  • Ntfy.sh

Telegram is particularly useful as it sends notifications to the phone and can store video clips (for free!).

Some configuration quirks:

  • The file /etc/prudynt.json stores motion detection settings under a “motion” object.
  • The Send to Telegram option sometimes fails to save from the web UI. I needed to manually set "send2telegram": true.
  • Motion triggers the script /sbin/motion, which has a bug: it starts a video recording and calls /sbin/send2telegram, which tries to start another recording and fails. I needed to comment out the redundant recording call in /sbin/motion.

Publishing to Telegram

To enable Telegram notifications:

  1. Create a bot with @BotFather.
  2. Create a channel and make the bot an administrator.
  3. Enter the bot token and channel ID in the Thingino web interface: Tools → Send to Telegram.

By default, /sbin/motion tries to send a photo and video to Telegram. This did not work in this camera, and I needed to change the call to /sbin/send2telegram clip to send only the video.

Another drawback is that the Telegram app does not support playing H.265 videos, the main stream needs to be set to H.264.

Telegram bot

The bot can also respond to commands from authorized users to send live snapshots or video clips. Enable it in the web interface under Services → Telegram bot, and modify the wrong default actions to run binaries in /sbin/ instead of /usr/bin/.

Final thoughts

Installing Thingino on this camera is a rewarding but technical process. You gain better control and privacy, but it requires patience and careful troubleshooting. I will need another post to explain the Frigate setup.


2024

It has been a year full of decisions—some very difficult, others quite simple.

I continue to learn what it means to be a father, and it’s proving to be as complicated as I had imagined.

I’m not active on social media, and after the collapse of Twitter, I’ve been trying to revive my activity here on the blog.

On the professional front, I made the decision to leave Netcentric, where I worked for the past five years. I had a great time there, and it was a tough decision, but an exciting new opportunity came my way. I left the AEM consultancy world to join Alén Space, a company focused on building satellites. I now work on their Mission Control System software. So, while I’m still pursuing my career as a Java developer, I’m also taking on a more managerial role, leading a developer team.

In another change, after seven years of working with a Mac, I’m back on Linux—and I’m very happy about it. I also replaced my old home lab Dell T3500 workhorse with a sleeker Minisforum UM890 Pro, and it’s been amazing. For my home office setup, I’ve also switched back to OpenWRT with a Xiaomi AX3000T (with WiFi 6). I had forgotten how easy it is to configure OpenWRT.

This has also been a great year for my home automation journey. I started the year by moving Home Assistant to a small and efficient Orange Pi 3B. I’m extremely happy with the combination of Home Assistant and ESPHome. Home Assistant has become an essential part of our daily routine, mainly for climate control and air quality monitoring.

On a personal note, we moved from an apartment in the city back to our country house. This means more commuting, but it also means more comfort and a better school for our little one. I was disappointed by Santiago de Compostela—it’s turning into a theme park focused solely on tourism.

Finally, I replaced my 20-year-old diesel car with an electric one. I would have switched sooner if I had known just how great and affordable electric cars are. I chose a Tesla primarily for its price-to-technology ratio. I’m not a fan of the brand or their CEO, but the car has made living in the country much cheaper.

Happy 2025!


Abusing Apple’s Find My network

Some months ago Apple was running a commercial on Spanish TV about the iPhone’s privacy, mocking users with Android devices.

Probably, iPhone users do not know that it is really easy to physically track them.

Apple’s “Find My” network was launched in 2019 and the AirTag in 2021. The AirTag emits BLE beacons with a public key that, when received by another Apple device, are sent along with the location of the device that received them to Apple servers, encrypted with the AirTag public key. The information on the Apple servers needs to be decrypted with the AirTag’s private key.

However, when the AirTag location is updated, the owner of the AirTag also knows that there is an Apple device nearby.

In theory it’s required to have an iPhone/iPad/iPod to activate an AirTag, but it’s very easy to build an AirTag clone with ESP32.

The Macless Haystack project, based on the original OpenHaystack, provides:

  • The python utility to generate AirTag key pairs
  • The firmware to flash an ESP32-WROOM-32 and convert it to an AirTag clone
  • An Android app to check the location of your fake AirTags
  • Two Docker containers needed to retrieve the info from the Apple servers, they need to be accesible by the Android app

And, of course, I built my own one:

These ESP clones are much bigger than AirTags but they are ok to track cars, suitcases or bags. There is a PR to the Macless Haystack repo alowing to use an ESP32-C3 Supermini, that makes a smaller device with a better battery duration.

Google launched the “Find My Device” network in April 2024, and the tags supporting it (i.e. the Chippolo Point or the Pebblebee) are slowly reaching the market. But the default security option only shares the location information if there are other Android devices nearby. That is much better for the privacy of Android device owners, but much worse for the owners of the tags.

So, if you own an Android device, it is still better to use AirTag clones, abusing the lack of privacy of the Apple devices.


Back to OpenWrt

Some years ago, my network provider (O2 – Spain) installed a router for me (Mitrastar HGU GPT-2541GNAC) with much better specs than my old OpenWrt router (TP-Link TL-WDR4300). So, I ditched OpenWrt and started using the company’s router.

But the Mitrastar needed to be factory reset every 6 months because it had some problems with the DHCP in my network. Recently, I offloaded the DHCP to an OrangePi 3B, but now my home network was relying too much on the availability of this device. Also, the Mitrastar is starting to show its age without features like WiFi 6…

A couple of weeks ago I found on Aliexpress a new Xiaomi AX3000T router. It has an amazing set of specs:

  • 2 ARMv8 cores @ 1.3GHz (MediaTek MT7981B)
  • 128 MB ROM
  • 256 MB RAM
  • WiFi 6 (AX) in the 2.4 GHz and 5 GHz bands

And it’s compatible with the lastest snapshot of OpenWrt:

https://openwrt.org/inbox/toh/xiaomi/ax3000t

I was able to get it during the AliExpress ChoiceDay (this happens the first days of each month) for 26 EUR (including a 4 EUR coupon).

When it arrived, I found it a bit smaller than what I expected, and I liked its minimalist look. It has only one button for WPS (+ the reset pinhole), and one LED in the front panel (i.e. it does not have LEDs on the ethernet ports).

Everything was in Chinese, but it’s easy to read it using the Google Translate camera, only for the steps necessary to set up OpenWrt. I did a simple installation without the U-Boot boot loader.

So, I put again an OpenWrt router back in my home network moving the DHCP and WireGuard services to the router. I had forgotten the beauty and simplicity of OpenWrt.

I also tested adblock-lean and it works quite well on the router with big lists like https://oisd.nl/: It’s able to manage the 660K domains of both oisd big and osid nsfw lists. But at the moment I’ll continue using the Pi-hole on the OrangePi. I still need the OrangePi to run Home Assistant and the NAS.


CO2 sensor with LCD and ESP32-C3 Supermini

I wanted to add an LCD screen to my CO2 sensor, so I bought a white LCD 1602 with an I2C controller. The I2C controller needs to be soldered to the LCD, but my basic soldering skills were sufficient for the task.

I also wanted to place it in a box, so I purchased this plastic enclosure but I cannot recommend it. It required a lot of glue from a glue gun to install the LCD and the ESP. I also had to use the soldering iron to create space for the ESP and a hole for the USB connector. I installed the plastic buttons but they are only decorative.

I made room for the sensors inside the box, but finally left them outside because they are more precise that way.

The ESP32-WROOM-32 was too large for the enclosure, so I used a ESP32-C3 Supermini with an expansion board. This is a really amazing board with a 32-bit RISC-V 160MHz microcontroller, WiFi, Bluetooh, I2C and UART. It’s not as powerful as the ESP32-WROOM-32 with a dual core 32-bit Xtensa 240Mhz, but it’s more than capable to control the sensors and the LCD.

This is the ESPHome configuration, which includes a switch to control the LCD backlight and a clock synchronizing the time with Home Assistant:

esphome:
  name: co2sensor
  friendly_name: CO2 Sensor

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

logger:
  level: ERROR

api:
  password: ""

ota:
  platform: esphome
  password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 90s
  ap:
    ssid: ${friendly_name} Hotspot
    password: !secret wifi_password

captive_portal:

web_server:
  port: 80

debug:

time:
  - platform: homeassistant
    id: homeassistant_time
    timezone: "Europe/Madrid"

uart:
  rx_pin: GPIO20
  tx_pin: GPIO21
  baud_rate: 9600

i2c:
  sda: GPIO8
  scl: GPIO9

sensor:
  - platform: uptime
    name: Uptime
    filters:
      - lambda: return x / 60.0;
    unit_of_measurement: minutes

  - platform: wifi_signal
    name: "WiFi signal sensor"
    update_interval: 60s

  - platform: dht
    model: AM2302
    pin: GPIO10
    temperature:
      id: "dht22_temperature"
      name: "DHT22 Temperature"
    humidity:
      id: "dht22_humidity"
      name: "DHT22 Humidity"
    update_interval: 50s

  - platform: mhz19
    co2:
      id: "mhz19_co2"
      name: "MH-Z19 CO2"
    temperature:
      id: "mhz19_temperature"
      name: "MH-Z19 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false

display:
  - platform: lcd_pcf8574
    dimensions: 16x2
    address: 0x27
    update_interval: 1s
    lambda: |-
        auto time =  id(homeassistant_time).now();
        it.printf(11, 0, "%02d:%02d", time.hour, time.minute);
        it.printf(11, 1, "%02d/%02d", time.day_of_month, time.month);
        auto co2 = id(mhz19_co2).state;
        if (!isnan(co2)) {
          it.printf(0, 0, "%.0fppm", co2);
        }
        it.printf(0, 1, "%.1fC", id(dht22_temperature).state);
        it.printf(6, 1, "%.0f%%", id(dht22_humidity).state);

switch:
  - platform: gpio
    pin: GPIO7
    name: "LED Backlight"
    id: led_backlight
    restore_mode: ALWAYS_OFF

And the full BOM:


MH-Z19B CO2 sensor

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 DHT22 sensor. I bought this DHT22 sensor but it is not an original one, and the measures do not seem very correct, so I ordered again an original AM2302 (=DHT22). 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 ESP32-WROOM-32 on the expansion board connected to the MH-Z19B (gold) and to the DHT22 (red)
  • 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

esphome:
  name: ${devicename}
  friendly_name: ${friendly_name}
  platform: ESP32
  board: nodemcu-32s

logger:

api:
  password: ""

ota:
  password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  reboot_timeout: 90s
  ap:
    ssid: ${friendly_name} Hotspot
    password: !secret wifi_password

captive_portal:

web_server:
  port: 80

debug:

time:
  - platform: homeassistant
    id: homeassistant_time

uart:
  rx_pin: GPIO3
  tx_pin: GPIO1
  baud_rate: 9600

sensor:
  - platform: uptime
    name: Uptime
    filters:
      - lambda: return x / 60.0;
    unit_of_measurement: minutes

  - platform: wifi_signal
    name: "WiFi signal sensor"
    update_interval: 60s

  - platform: dht
    model: DHT22
    pin: GPIO16
    temperature:
      id: "dht22_temperature"
      name: "DHT22 Temperature"
    humidity:
      id: "dht22_humidity"
      name: "DHT22 Humidity"
    update_interval: 60s

  - platform: mhz19
    co2:
      id: "mhz19_co2"
      name: "MH-Z19 CO2"
    temperature:
      id: "mhz19_temperature"
      name: "MH-Z19 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false

And It’s working nicely, this is the ESPHome web interface:

Keeping the CO2 levels under control is helping me create a healthier workplace environment and improve performance.


Improving WiFi reception with an ESP32-WROOM-32U

I’m using a ESP32 with ESPHome connected to my heating system for climate control, as expained in a previous post.

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):

And replaced the previous ESP32-WROOM-32 module with an ESP32-WROOM-32U, installing the external antenna. This is how it looks now:

ESP32-WROOM-32U mounted on an expasion board connected to the 4 relay module

The WiFi signal shown in ESPHome increased from -95 dBm to –75 dBm and it’s no longer experiencing any interruptions.


ESPHome in a RTL8710BX smart plug

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:

https://github.com/libretiny-eu/libretiny

And now it’s integrated into ESPHome:

https://esphome.io/components/libretiny

This is the board:

https://fcc.report/FCC-ID/2AU7O-T102V11/4540736.pdf

And after investigating the outputs, I reached this conclusion about them:

IndexRTL8710BXConnection
1VDDConnected
3GNDConnected
5GPIO_A18/UART0_RXDConnected to the button
7GPIO_A23/UART0_TXDNot connected
9GPIO_A14/PWM0 Power Monitor SEL pin
11GPIO_A15/PWM1Connected to the relay
2 GPIO_A12/PWM3Power monitor CF1 pin
4GPIO_A0/PWM2Power monitor CF pin
6GPIO_A5/PWM4Status LED inverted (there is another LED connected to the relay)
8GPIO_A30/DEBUG_LOG_TXNot connected, I soldered a cable to the flasher RX
10GPIO_A29/DEBUG_LOG_RXNot connected, I soldered a cable to the flasher TX

ESPHome

I created one device this config in the ESPHome dashboard (without power monitoring, read below if you want to enable it):

substitutions:
  devicename: smartplug1
  friendly_name: Smart Plug 1

esphome:
  name: ${devicename}
  friendly_name: ${friendly_name}

rtl87xx:
  board: wr2
  framework:
    version: 1.5.1

logger:

api:
  password: ""

ota:
  password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: ${friendly_name} Fallback Hotspot
    password: !secret wifi_password

captive_portal:

web_server:
  port: 80

status_led:
  pin:
    number: PA5
    inverted: true

text_sensor:
  - platform: libretiny
    version:
      name: LibreTiny Version

sensor:
  - platform: uptime
    name: Uptime
    filters:
      - lambda: return x / 60.0;
    unit_of_measurement: minutes

  - platform: wifi_signal
    name: Wifi Signal
    update_interval: 60s

binary_sensor:
  - platform: gpio
    device_class: power
    name: Button
    pin:
      number: PA18
      mode: INPUT_PULLUP
      inverted: true
    on_press:
      - switch.toggle: relay

switch:
  - platform: gpio
    id: relay
    name: ${friendly_name}
    pin: PA15
    restore_mode: RESTORE_DEFAULT_OFF

There is currently an open bug in LibreTiny and with the board t102-v1.1 the PA15 output does not work, so I needed to use the board wr2 on line 10.

I built it from the ESPHome dashboard and downloaded a .uf2 file.

Connecting an USB UART to the chip

I soldered four dupont cables to VDD, GND, GPIO_A29 and GPIO_A30 connecting them to an FTDI232 USB UART:

While connected to the FTDI232, the log from the chip can be viewed, i.e. with minicom (but remember to disable hardware flow control):

minicom -D /dev/ttyUSB0 -b 115200

Flashing

The official flashing guide does not recomment to power the chip with the USB flasher, but it worked for me:

https://docs.libretiny.eu/docs/platform/realtek-ambz/#flashing

You need the ltchiptool tool, I installed it in a Python virtualenv:

python3 -m venv .
source bin/activate
pip install ltchiptool zeroconf

The ltchiptool GUI caused some segmentation fault, so I used it from the commmand line.

To put the chip in flash mode, we need to power it with the TX pin connected to GND.

In flash mode, I created a backup of the previous firmware:

ltchiptool flash read realtek-ambz flash-backup.bin

And to write the ESPHome firmware:

ltchiptool flash write smartplug1.uf2


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:

https://esphome.io/components/sensor/hlw8012.html

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.

https://esphome.io/components/ota.html

It is a problem in the combination of the RTL8710 chip and the BL0936 module, there is an open issue about this:

https://github.com/libretiny-eu/libretiny/issues/155

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:

62: #if LT_RTL8720C
63:                        event = IRQ_FALL_RISE;
64: #elif LT_RTL8710B
65:                        event = IRQ_RISE;
66: #else
67:                        LT_W("CHANGE interrupts not supported !!!!!!");

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:

substitutions:
  devicename: smartplug1
  friendly_name: Smart Plug 1

  voltage_divider: "1400"
  current_resistor: "0.001"
  current_multiply: "1.0"

esphome:
  name: ${devicename}
  friendly_name: ${friendly_name}

rtl87xx:
  board: wr2
  framework:
    version: 1.5.1

logger:

api:
  password: ""

ota:
  password: ""

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: ${friendly_name} Fallback Hotspot
    password: !secret wifi_password

captive_portal:

web_server:
  port: 80

status_led:
  pin:
    number: PA5
    inverted: true

text_sensor:
  - platform: libretiny
    version:
      name: LibreTiny Version

sensor:
  - platform: uptime
    name: Uptime
    filters:
      - lambda: return x / 60.0;
    unit_of_measurement: minutes

  - platform: wifi_signal
    name: Wifi Signal
    update_interval: 60s

  - platform: hlw8012
    model: BL0937
    sel_pin:
      number: PA14
      inverted: true
    cf_pin:
      number: PA0
    cf1_pin:
      number: PA12

    current:
      name: Current
      filters:
        - multiply: ${current_multiply}
    voltage:
      name: Voltage
    power:
      name: Power
    energy:
      name: Energy

    update_interval: 30s
    current_resistor: ${current_resistor}
    voltage_divider: ${voltage_divider}

binary_sensor:
  - platform: gpio
    device_class: power
    name: Button
    pin:
      number: PA18
      mode: INPUT_PULLUP
      inverted: true
    on_press:
      - switch.toggle: relay

switch:
  - platform: gpio
    id: relay
    name: ${friendly_name}
    pin: PA15
    restore_mode: RESTORE_DEFAULT_OFF

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.


WireGuard

I always used OpenVPN in my servers, but now WireGuard is a better option:

https://www.wireguard.com/

  • It’s simpler
  • It’s more efficient
  • It’s faster
  • It uses modern cryptography algorithms

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:

https://www.wireguardconfig.com/

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:

sudo systemctl enable wg-quick@wg0.service
sudo systemctl start wg-quick@wg0.service

Installing and configuring the clients

WireGuard has clients for almost any OS:

https://www.wireguard.com/install/

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:

[Interface]
PrivateKey = <client-private-key>
Address = 100.100.1.2/32
DNS = 100.100.1.1

[Peer]
PublicKey = <server-public-key>
PresharedKey = <preshared-key>
Endpoint = <my-home-server>:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

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.


The LLM revolution

I took this photo of three Llamas in Machu Picchu some years ago…

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:

https://llama.meta.com

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:

https://huggingface.co/models

Developers started creating improved models and optimizing performance for local execution of LLMs on consumer-grade hardware.

Llama.cpp is a port of Llama to C++, started in March 2023 with a strong emphasis on performance and portability. It includes a web server and an API:

https://github.com/ggerganov/llama.cpp

Mistral 7B was released in October 2023, achieving better performance than larger Llama models and demonstrating the effectiveness of LLMs in compressing knowledge.:

https://huggingface.co/papers/2310.06825

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:

https://github.com/Mozilla-Ocho/llamafile

The llama.cpp web interface running Mistral 7B Instruct in local via a llamafile

It’s even possible to run LLMs in a Raspberry Pi 4, like the TinyLlama-1.1B used from a llamafile in this project:

https://github.com/nickbild/local_llm_assistant

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):

https://github.com/carlrobertoh/CodeGPT

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:

https://blog.google/technology/developers/gemma-open-models

They also released a gemma.cpp inference engine:

https://github.com/google/gemma.cpp

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:

https://chat.lmsys.org

And according to this leaderboard, at the moment GPT-4 is still the king.