PiNAP – converting my QNAP TS-41x to run Open Media Vault on a Raspberry Pi 5

I have several QNAP storage arrays at home. I store my Photos, Videos, MP3 collection and DVDs, etc, on them. I usually have two running at any one time and they usually mirror each other, so I have two copies of all my data at home at any time. I also backup to cloud storage and try and follow the “3-2-1 backup policy” – 3 total copies of your data, stored on 2 different types of media, with 1 copy kept off-site – to provide good resilience in the event of a major incident or failure.

However, recently I’ve been using them for other things, specifically storing my security camera footage, and other less important things, and the two live units I currently have are nearing capacity.

While rummaging through the loft a few weeks ago, I noticed that my old, retired QNAPs are still in the loft, powered down and collecting dust. I have three old 4-bay units (2 x TS-412 & 1 x TS-410), which are long since out of support, and no longer get updates or patches. The TS-412 was released in 2009, and served me well, I probably got 15+ years of life out of them. They finally went End Of Life on 31 December 2020, and I replaced them with two TS-431KX. I’ve had these for a few years now too, and even they are classed as “legacy”, so I expect them to go EOL soon.

The motherboards in the TS-410 & TS-412 look identical. The specification on the QNAP Site (TS-410 & TS-412) suggest the only difference is a slightly faster SoC in the TS-412. 1.2 GHz in the TS-412 verses 800Mhz in the TS-410. I suspect the same motherboard is used in other models, but I dont have access to any. Feel free to contact me if you find other QNAP models that use the same motherboard, that this conversation will also work with.

PiNAP – QNAP TS-412
PiNAP – TS-412 Motherboard

So, I had the brilliant idea to upcycle my old TS-412 devices to see if I could migrate them to use open-source software so I could squeeze more life out of them, than the manufacturer wants to support. It seems wasteful to replace them every 5 or 10 years, just because the software is no longer supported. The form factor is perfect. They are small and quiet and hold four full sized hard disks. I even have the old 3TB Seagate drives in them, so if I manage to upcycle them I could resurrect 18-24TB of storage!

Initially, I planned to try and get Linux to run natively on the existing hardware. I took one apart to get all the hardware specs and investigate the internals. The motherboard is based around a Marvell 6281 1.2GHz Arm CPU, with 256MB DDR2 RAM, 2 x Gigabit ethernet ports, and 4 x USB 2.0 ports. I could probably get Linux to run on this hardware, but its not particularly performant and shows the age of the 15 year old hardware. 256MB of RAM will be a challenge, even for Linux, and it does not have a standard bootloader.

However, I noticed that the SATA backplane connects to the old motherboard with what looks like a PCI connector. Once I had the backplane card out completely, I traced the pins and pads and compared it to the PCIe standard, and it looked similar, in fact I was confident it was a valid PCIe connection. The SATA Controller IC on the backplane is a Marvell 88SX7042 PCIe 4ch SATA-II bridge.

PiNAP - SATA Backplane
PiNAP – SATA Backplane

This got me thinking. The new Raspberry Pi 5 has a PCIe connector on it. I could potentially plug this backplane directly in to the Raspberry Pi 5 and run free open-source NAS software, rejuvenating my QNAPs to run up to date software, on modern hardware, economically, and undo their EOL status. I could continue to upgrade them in the future with new Raspberry Pi hardware, new software, giving them potentially decades more life. Very environmentally friendly, reducing e-waste and giving me handy additional storage, and a cool hardware project to tinker with at the weekends.

I called the project PiNAP, a portmanteau of “Pi” and “QNAP” 😊

PCIe Adapters

I searched for PCIe card slot adapters for the Raspberry Pi 5 and found a popular version on the PiHut website. I bought a SupTronics X1010 PCIe adapter. I also checked the Debian releases to see if they included the Marvell 88SX7042 drivers in the main kernel. I didn’t really want to have to compile a custom kernel. Lucky they are supported natively. So, this should be a simple plug and play project. (ominous foreshadowing)

When the adapter arrived, I was excited to try it out. I first tried it with no external power, booted the Pi5 and ran “lspci” and was disappointed to see no Marvel SATA adapter listed in the output. Thus began three weeks of tinkering and tearing my hair out trying to work out why the Pi5 wouldn’t recognise the PCIe SATA adapter. I will condense three weeks into two lines, but I tried every combination of dtparam in the boot.conf file, every variation of power to the card and drives, every variation of disks, with HDD and SSD and lots of Googling.

During this time, I was venting with my geeky friends on our WhatsApp group. My long time friend and Jedi level tinkerer Oli, also had a TS-412, and thought he’d try it our too. Within a single day his was working :-O. It would seem not all PCIe adapters are born equally. He bought a PCIe adapter made by 52PI (The Pi Hut – PCIe Slot for Raspberry Pi 5 (P02)) and it basically worked out of the box, with no disks or external power.

So, I bought one too, and behold, I had a working prototype (Thanks Oli)

$ lspci
0001:00:00.0 PCI bridge: Broadcom Inc. and subsidiaries BCM2712 PCIe Bridge (rev 21)
--> 0001:01:00.0 SCSI storage controller: Marvell Technology Group Ltd. 88SX7042 PCIe 4-port SATA-II controller (rev 02)
0002:00:00.0 PCI bridge: Broadcom Inc. and subsidiaries BCM2712 PCIe Bridge (rev 21)
0002:01:00.0 Ethernet controller: Raspberry Pi Ltd RP1 PCIe 2.0 South Bridge

I was slightly disappointed that I could not fit the Pi5 and PCIe adapter directly on to the backplane in place of the old motherboard. This would have been perfect. But the PCIe adapter is round the wrong way to fit on the card, without hitting the case. I briefly considered designing my own motherboard that took a Raspberry Pi 5 compute module and had a PCIe connector in the right place, so the new board would fit directly on to the old mounting holes, but although I’ve designed and built many PCBs in my time, I’ve never made one with PCIe traces. That requires controlled impedance and more complex routing. Maybe if there is demand I’ll consider that in phase two.

The QNAP case has a lot of spare room inside and there is ample space at the top to mount the Pi5 and adapter card, and I can run a PCI extension cable down to the backplane card. I also needed a high current 5v supply to power the hard disks and the Pi. The original QNAP power adapter is 120W 12v/10A which is enough to power everything, and I can reuse the existing power supply. I just need to add a reasonably large step-down converter to provide the 5v at 6-8A from the 12v supply to power the hard disks.

A typical 3.5” disk needs less than 1A for both 12v and 5v supplies. So, all four disks shouldn’t consumer more than 5v/4A and 12v/4A peak load.

The cooling fan is a PWM fan 4-pin fan, so the speed can be controlled with a PWM signal. I also added a temperature sensor in my design so I can speed up the fan if the interior of the case gets hot and slow it down as it cools to reduce noise.

Front Panel LED control

It would also be nice to get the original power switch and LEDs working on the front panel too, so the entire unit is more user friendly and functional. I traced the IO ribbon cable to reverse engineer the LED and switch board.

PiNAP - Front Panel LED Board
PiNAP – Front Panel LED Board

This LED Board has a very peculiar circuit and seems to mix 5v and 3.3v logic to power the LEDs. I’m sure this has something to do with reusing it on other QNAP models and in fact the motherboard has various ICs and regions unpopulated. I guess most of the hardware gets reused in lots of different models with a slightly different configuration, to reduce hardware designed time and variations.

PiNAP - Front Panel LED Board Schematic
Front Panel LED Board Schematic

The Green hard disk LEDs are powered via 5v and the Red hard disk LEDs is powered by 3.3v, both are controlled by a single MOSFET, operated by the same GPIO signal, but they have different power sources.

The LAN and eSATA LEDs are powered from 3.3v and the Status and USB LEDs are powered by 5v. They are each controller via a MOSFET using the Pi5 GPIO.

Seeing as I needed an external power circuit, fan connector and complex GPIO control of the LEDs, I designed a custom PCB mounting board to hold the Pi, PCIe connector board and provide the logic circuits and power connector. This would allow me to mount everything in one place, with tidy cable management and reuse of most of the internal cables and front panel. I added a piezo buzzer and amplifier, so the device could beep like the old QNAP on startup and shutdown and if there are errors. I managed to find all the right connectors on Digikey so I can reuse the original hard disk power cable, the front panel ribbon cable, and the power supply. I had these manufactured by JLCPCB and they arrive quickly.

PiNAP Conversion Card PCB
PiNAP - PCB Schematic v1.3
PiNAP Conversion PCB Schematic

LED Triggers

Connecting everything was relatively straight forward and the LEDs seem to work with the right combination of GPIOs enabled.

I can control the LEDs using a kernel Device Tree Overlay. However, only certain activities are supported in the stock Raspberry Pi kernel to trigger the LEDs.

You can list the available trigger modules by catting the trigger file:

$ sudo cat /sys/class/leds/disk1\:activity/trigger
[none] default rc-feedback kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock timer oneshot heartbeat backlight cpu cpu0 cpu1 cpu2 cpu3 default-on input panic actpwr mmc1 mmc0 netdev rfkill-any rfkill-none rfkill0 rfkill1

I used the stock “heartbeat” trigger to flash the Status LED and the “netdev” trigger to flash the LAN LED to show ethernet activity.

However, there is no “sda”, “sdb”, etc, triggers in the stock kernel, so it’s not possible to automatically trigger the hard disk LEDs on disk activity. I wrote a small python daemon to monitor each hard disks activity and flash the hard disk LEDs accordingly, rather than compiling a custom kernel. This has a tiny overhead (less than 1% CPU) so even though it’s not ideal, it won’t impact performance.

The python daemon also monitors for USB button presses, and monitors the temperature sensor and adjusts the PWM fan speed accordingly.

Hardware Requirements

To convert your QNAP TS-412 to Raspberry Pi and Open Media Vault you will need the following hardware:

  • Raspberry Pi 5 (I am using the version with 8GB RAM, but 2GB or 4GB will probably work perfectly well too)
  • PCIe Slot for Raspberry Pi 5 (P02)
  • PCIe extension cable
    • PCIe 4.0 X1 90 Degree Extension Cable (30CM)
    • Not all cables work correctly. This one specifically has the right angles in the correct orientation, however you will need to sand off 5 mm of the edge of the PCB to get it to fit. This doesn’t affect its functionality as long as the modification is clean.
  • A PiNAP conversion kit (available from Tindie)
    • This includes;
    • the fully populated conversion PCB with 5v buck convertor.
    • the power socket and bolts
    • nylon PCB standoffs
  • You will reuse your QNAP case, power supply and internal cables.
  • You will need appropriate 3.5″ or 2.5″ hard disks.
  • You will also need a Dremel to cut out a hole in the back of the case and drill and 2mm drill bit to mount the power socket.
  • A soldering iron and steady hand to modify and solder a tiny wire on the SATA backplane to enable the SAT3 & SATA4 power.

PCIe extension cable

The PCIe backplane connector is very close to the bottom of the case. I struggled to find a PCIe extension cable that would fit, so I ended up modifying one. I sanded the edge of the PCB down to make it fit. Although this isn’t a recommended option, I couldn’t find an alternative, and double checked for short circuits before plugging it in.

PiNAP - PCIe Extension Modification Before
The PCIe Extension cable before modification hits the bottom of the case and doesn’t fit
PiNAP - PCIe Extension Modification
Modified PCIe cable. The edge is sanded down.
PiNAP - PCIe Extension Modification After
The modified PCIe cable now fits perfectly.
PiNAP - PCIe Extension Cable

Case Modification

The only big modification was to cut a hole in the back of the QNAP case to get access to the Pi5 network and USB ports. Maybe one day I’ll design a 3D printed panel, but for now, I just cut a large square hole with a Dremel!

I also drilled two small 2mm holes to mount the power connector in its original hole as there is no longer a motherboard behind it.

PiNAP - Modified Case
PiNAP – Modified Case

SATA Backplane Power

There is also another minor issue with the SATA backplane card. It uses two unused or reserved pins on the PCIe connector to control the power to the third and fourth hard disk connectors. I assume this is to limit the start up current and prevent all four hard drives spinning up at the same time. The custom motherboard uses these PCIe pins to stagger disks 3 and 4 to power up after a delay.

I couldn’t do this with the Pi5, without a custom motherboard. So, I opted to cut the traces on the backplane card that go to the PCIe connector and tie them permanently high to 3.3v. This would force all the drives to power up simultaneously, and generate large initial power draw, but we’ll see how it goes. In the future I could add a jumper wire, and perhaps route the power enable signals to a GPIO pin on the Pi5 if I do get issues with power surges, but if I use a big enough power supply it should be fine.

SATA3 power enable is on the outside pins of R492 & R495

PiNAP – SATA3 Power Enable

SATA4 power enable is on the outside pins of R493 & R494

PiNAP – SATA4 Power Enable

Both traces run down the PCB to the PCIe connector, where I cut them, soldered a small wire to them and tied them to a 3.3v. I found a 3.3v source at the bottom of the card on the positive pin of “EC9”

PiNAP – SATA Power Enable
PiNAP – SATA Power Enable
PiNAP – SATA Power Enable

Power Switch

The front panel power switch is terminated on the conversation board with a two pin header. This can be connected to the Pi5 power switch header, to enable the Pi5 to be controlled by the front panel power switch. You will need to solder a two pin header on to the Raspberry Pi 5, then connect the jumper wire.

PiNAP – Power Switch Connector
PiNAP – Power Switch Connector

USB socket and switch

Currently I don’t have a need for the front panel USB socket or switch. The socket can be connected to one of the spare USB ports on the Pi5 with an extension cable. The front panel USB switch is connected to a GPIO, but current doesn’t do anything other than flash the USB LED when pressed (just to show its working). This could be configured at a later stage to trigger a copy script on the Pi5 to copy the contents of the USB disks to a folder in OMV. You can buy a USB lead with a 4 pin JST-PH connector, and route the cable out of the back of the case though one of the holes and plug it into the Pi 5.

PiNAP – USB Cable

Software Installation

Raspberry Pi OS Installation

Create a USB flash disk with the latest Raspberry Pi OS 64 bit Lite image using the Raspberry Pi Imager software. Open Media Vault only works on the Lite version of the OS.

The Raspberry Pi 5 will not initially boot when installed in the PiNAP board because it cannot measure the power supply and refuses to boot from USB. You need to make a change to the /boot/firmware/config.txt. There are two options to achieve this:

Option 1 – Boot the Pi5 initially with USB-C Power

Before installing the Pi5 in the PiNAP board you can boot the Pi5 independently, install the Raspberry Pi OS and make some changes to the /boot/firmware/config.txt. Boot the Pi 5 from the USB flash disk with a compatible 5v USB-C supply and once it has booted, edit the /boot/firmware/config.txt file. Add the following lines to the end of the file:

usb_max_current_enable=1
dtparam=pciex1
dtoverlay=pwm,pin=12,func=4
dtoverlay=w1-gpio,gpiopin=14

Save and shutdown.

You can now install the Pi5 in the PiNAP convertor PCB and connect all the connectors in the case and continue the installation process.

Connect the Pi 5 to the network and ensure everything is up to date:

sudo apt update
sudo apt upgrade

Reboot the Pi 5

Option 2 – Edit the config.txt file on the USB flash disk before installing

When you have created the USB flash disk with the latest Raspberry Pi OS 64 bit Lite image using the Raspberry Pi Imager software, insert the flash disk into a suitable laptop or computer. In the “bootfs” partition you should find the file /config.txt. Add the following lines to the end of the file:

usb_max_current_enable=1
dtparam=pciex1
dtoverlay=pwm,pin=12,func=4
dtoverlay=w1-gpio,gpiopin=14

Save the file and eject the USB flash drive.

You can now install the Pi5 in the PiNAP convertor PCB and connect all the connectors in the case and continue the installation process.

Connect the Pi 5 to the network and ensure everything is up to date:

sudo apt update
sudo apt upgrade

Reboot the Pi 5

Verify PCIe SATA Backplane is recognised

$ lspci
0001:00:00.0 PCI bridge: Broadcom Inc. and subsidiaries BCM2712 PCIe Bridge (rev 21)
--> 0001:01:00.0 SCSI storage controller: Marvell Technology Group Ltd. 88SX7042 PCIe 4-port SATA-II controller (rev 02)
0002:00:00.0 PCI bridge: Broadcom Inc. and subsidiaries BCM2712 PCIe Bridge (rev 21)
0002:01:00.0 Ethernet controller: Raspberry Pi Ltd RP1 PCIe 2.0 South Bridge

Open Media Vault Installation

I installed Open Media Vault (OMV) first and get that running, then install the Device Tree Overlay and daemon. OMV configured the ethernet port as “end0” not the default “eth0” so the device tree needs to reflect that.

The Open Media Vault install was very straight forward. The instructions are easy to follow. Follow the instructions for Raspberry Pi: https://github.com/OpenMediaVault-Plugin-Developers/installScript

wget -O - https://github.com/OpenMediaVault-Plugin-Developers/installScript/raw/master/install | sudo bash

This should install Open Media Vault, you can then access the web interface using a browser.

Ensure everything is up to date:

sudo apt update
sudo apt upgrade

You can now setup Open Media Vault, install the various plugins you need, configure the disks and RAID Arrays and create a filing system and shares.

$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 1 28.7G 0 disk
├─sda1 8:1 1 512M 0 part /boot/firmware
└─sda2 8:2 1 28.2G 0 part /
sdb 8:16 0 2.7T 0 disk
└─md0 9:0 0 8.2T 0 raid5 /export/data
/srv/dev-disk-by-uuid-abcdef12-39fd-456a-abcd-123456789123
sdc 8:32 0 2.7T 0 disk
└─md0 9:0 0 8.2T 0 raid5 /export/data
/srv/dev-disk-by-uuid-abcdef12-39fd-456a-abcd-123456789123
sdd 8:48 0 2.7T 0 disk
└─md0 9:0 0 8.2T 0 raid5 /export/data
/srv/dev-disk-by-uuid-abcdef12-39fd-456a-abcd-123456789123
sde 8:64 0 2.7T 0 disk
└─md0 9:0 0 8.2T 0 raid5 /export/data
/srv/dev-disk-by-uuid-abcdef12-39fd-456a-abcd-123456789123

Reboot the Pi 5

PiNAP Software Installation

cd ~
git clone https://github.com/JonRussell00/PiNAP.git
cd PiNAP
sudo cp pinap-leds.dts /boot/firmware/overlays/pinap-leds.dts
sudo cp pinap-daemon.py /usr/local/bin/pinap-daemon.py
sudo cp pinap-daemon.service /etc/systemd/system/pinap-daemon.service
sudo cp pinap-lan-led-trigger.service /etc/systemd/system/pinap-lan-led-trigger.service
sudo chmod +x /usr/local/bin/pinap-daemon.py

Configure OneWire for the Temperature Sensor

lsmod | grep w1

You should see w1_gpio and w1_therm listed. If not, load them:

sudo modprobe w1_gpio
sudo modprobe w1_therm

Reboot the Pi 5

You should now be able to see the onboard OneWire temperature sensor:

$ sudo ls -la /sys/bus/w1/devices/
lrwxrwxrwx 1 root root 0 Jun 18 01:39 28-00000xxxxxxx -> ../../../devices/w1_bus_master1/28-00000xxxxxxx
lrwxrwxrwx 1 root root 0 Jun 18 17:12 w1_bus_master1 -> ../../../devices/w1_bus_master1

Make a note of the number of your temperature sensors unique number starting “28-“

Test the sensor reads the correct temperature substituting your unique ID in the following command:

$ sudo cat /sys/bus/w1/devices/28-000000000000/temperature | awk '{printf "%.2f\n", $1/1000}'
28.75

Edit the daemon Python file /usr/local/bin/pinap-daemon.py and add your unique ID. Edit the TEMP_SENSOR_ID variable here:

# ---------------------------------------------------------------------------
# Temperature sensor configuration (1-wire DS18B20 on GPIO 14)
# ---------------------------------------------------------------------------
# 1-wire device ID for the temperature sensor
# ## UPDATE FOR YOUR SENSOR ID ##
TEMP_SENSOR_ID = '28-000000000000'
# Path to the sensor's temperature attribute (value is in milli-degrees C)
TEMP_SENSOR_PATH = Path(f'/sys/bus/w1/devices/{TEMP_SENSOR_ID}/temperature')

Device Tree Overlay

Build the device tree overlay:

sudo dtc -@ -I dts -O dtb -o /boot/firmware/overlays/pinap-leds.dtbo /boot/firmware/overlays/pinap-leds.dts

Edit the /boot/firmware/config.txt file. Add the following lines to the end of the file:

dtoverlay=pinap-leds

Enable the netdev LED trigger

sudo modprobe ledtrig-netdev
echo "ledtrig-netdev" | sudo tee -a /etc/modules

Double check your ethernet port is labelled “end0”.

$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: end0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether d8:3a:dd:ff:ff:ff brd ff:ff:ff:ff:ff:ff
altname enxd83addffffff

if its still “eth0” you will need to change it to “end0” with:

sudo omv-firstaid

The LAN LED Trigger service assumes “end0”

Enable the Python Daemon

sudo systemctl daemon-reload
sudo systemctl enable pinap-daemon.service
sudo systemctl start pinap-daemon.service

Enable LAN LED Trigger Service

sudo systemctl daemon-reload
sudo systemctl enable pinap-lan-led-trigger.service
sudo systemctl start pinap-lan-led-trigger.service

Testing

At the end of the install process you should have the following lines at the end of your /boot/firmware/config.txt

usb_max_current_enable=1
dtparam=pciex1
dtoverlay=pinap-leds
dtoverlay=w1-gpio,gpiopin=14
dtoverlay=pwm,pin=12,func=4

Reboot the Pi 5

All the features should now be functional:

  • The Green Status LED on the front panel should make a heartbeat flashing pattern
  • The Amber LAN LED should flash in time with network activity
  • The four Green HDD LEDs should flash in time with disk activity
  • If you press the USB button on the front panel, the Blue USB LED should light and the PiNAP should beep. I currently don’t use the USB button, USB LED or eSATA LED for anything. They are there for future expansion and compatibility. There’s no reason why you can trigger a script when the USB button is pressed to copy files from the USB to the RAID Array if you need that functionality.
  • When you shutdown or startup the PiNAP should beep, in a similar fashion to the QNAP functionality.

⚠️ Important Safety Notes

  • Always disconnect power before working with hardware.
  • The SATA backplane modification requires precision soldering. Ensure you know what you are doing to avoid damaging the Raspberry Pi.
  • Test all connections before closing the case.

Troubleshooting

  • Pi won’t boot from PiNAP power: Ensure usb_max_current_enable=1 is set in config.txt
  • LAN LED not working: Verify ethernet interface is named “end0” using ip link show
  • Temperature sensor not detected: Check w1_gpio and w1_therm modules are loaded

Performance

I tested the disk performance using iperf3 on the PiNAP. I did a test from one PiNAP to the other, on a gigabit wired network, configuring the server end to store data on the raid array. I can swamp my gigabit network connection during the transfer, which is good enough for me.

pi@pinap01:~ $ iperf3 -s -F /srv/dev-disk-by-uuid-abcdef12-39fd-456a-abcd-123456789123/data/iperffile
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
Accepted connection from 10.1.0.182, port 38638
[ 5] local 10.1.0.181 port 5201 connected to 10.1.0.182 port 38650
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 111 MBytes 931 Mbits/sec
[ 5] 1.00-2.00 sec 111 MBytes 934 Mbits/sec
[ 5] 2.00-3.00 sec 111 MBytes 932 Mbits/sec
[ 5] 3.00-4.00 sec 111 MBytes 934 Mbits/sec
[ 5] 4.00-5.00 sec 109 MBytes 912 Mbits/sec
[ 5] 5.00-6.00 sec 110 MBytes 927 Mbits/sec
[ 5] 6.00-7.00 sec 111 MBytes 932 Mbits/sec
[ 5] 7.00-8.00 sec 111 MBytes 934 Mbits/sec
[ 5] 8.00-9.00 sec 111 MBytes 932 Mbits/sec
[ 5] 9.00-10.00 sec 109 MBytes 918 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
Sent 1.08 GByte / 1.08 GByte (100%) of /srv/dev-disk-by-uuid-abcdef12-39fd-456a-abcd-123456789123/data/iperffile
[ 5] 0.00-10.00 sec 1.08 GBytes 929 Mbits/sec receiver
pi@pinap02:~ $ iperf3 -c pinap01.woodside
Connecting to host pinap01.woodside, port 5201
[ 5] local 10.1.0.182 port 38650 connected to 10.1.0.181 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 115 MBytes 963 Mbits/sec 0 761 KBytes
[ 5] 1.00-2.00 sec 111 MBytes 929 Mbits/sec 0 1.04 MBytes
[ 5] 2.00-3.00 sec 111 MBytes 929 Mbits/sec 143 872 KBytes
[ 5] 3.00-4.00 sec 112 MBytes 941 Mbits/sec 143 727 KBytes
[ 5] 4.00-5.00 sec 108 MBytes 906 Mbits/sec 0 834 KBytes
[ 5] 5.00-6.00 sec 111 MBytes 934 Mbits/sec 0 836 KBytes
[ 5] 6.00-7.00 sec 111 MBytes 931 Mbits/sec 0 837 KBytes
[ 5] 7.00-8.00 sec 111 MBytes 929 Mbits/sec 0 898 KBytes
[ 5] 8.00-9.00 sec 111 MBytes 931 Mbits/sec 143 725 KBytes
[ 5] 9.00-10.00 sec 109 MBytes 917 Mbits/sec 0 834 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 1.08 GBytes 931 Mbits/sec 429 sender
[ 5] 0.00-10.00 sec 1.08 GBytes 929 Mbits/sec receiver
iperf Done.

Summary

I have had my PiNAP conversations running for over a month now, without any issues. One has 4 x 3TB disks, giving about 8 TB RAID5 filesystem, the second has 4 x 4TB disks, giving about 11TB RAID5 filesystem.

PiNAP – Populated PiNAP Board
PiNAP – Populated PiNAP Board
PiNAP – Fully Assembled
PiNAP – Fully Assembled
PiNAP Back
Open Media Vault Dashboard
Open Media Vault Dashboard

They are fast, quiet and run the latest open source software. This is a great way to squeeze some extra life out of my old QNAPs and provide reliable RAID Storage for years to come.

If there is demand for the conversion kits on Tindie, and I sell more than 20 or 30, it might motivate me to design and build a customer PCB that fits in the exact space the old QNAP motherboard did, removing the need for any major alterations, soldering, or dremelling of the QNAP.

I sell on Tindie

Message me if you would buy a drop in conversation PCB for your QNAP, running a Raspberry Pi 5 compute module. If there is enough demand, maybe I’ll run a Kick Starter.

Switching from Windows to Linux on my laptop

In October 2025, Microsoft will end support for Windows 10, forcing all Windows users to upgrade to Windows 11. Usually that just means installing the new software, which although a pain, is a necessary evil to remain secure. However, this time, Microsoft has made certain requirements on the hardware compulsory, including a list of supported CPUs and a Trusted Platform Module v2.0 (TPM) be present on the machine. Unfortunately, a lot of older machines don’t have a TPM device. Specifically, my old HP and Dell laptops, which were built around 2014.

According to Canalys, approximately 240 million PCs could become e-waste due to this incompatibility issue with Windows 11, including my trusty HP EliteBook and Dell Precision. Both of my machines are perfectly usable (with i5 CPU and 8GB RAM), upgradable with SSDs and extra RAM, however, in October 2025, I face a difficult decision. I either need to scrap them and buy a new laptop, which although sounds fun, seems very wasteful as there is nothing wrong with the existing hardware. Or I continue using Windows 10, without security updates, which is a disaster waiting to happen. I don’t recommend anyone runs any software without regular security patches. The internet is rife with nefarious people and bored hackers, desperate to get their hands on your personal data, and bank details.

So this Christmas, I embarked on a third option, to switch from Microsoft Windows to Linux on my laptops. Linux is a free, open source, operating system, which although somewhat uncommon on desktops, is completely dominant the server and mobile market. The majority of servers in the cloud run a flavour of Linux. Over 96 percent of the top 1 million web servers on the internet run Linux. There are billions of mobile phones that run Android, which is based on a version of Linux, and MacOS is also based on a version of Linux. In fact, Windows is the odd one out really.

I use Ubuntu at work for servers running Linux, so I decided to use Ubuntu Desktop for my laptops. 95% of everything I do on my laptop, is captures in three activities: Email, Web Browsing and Office documents. All these activities have mature, well support Linux equivalents. I decided to use ThunderBird for an email client, Libre Office is a free office suite for documents, spreadsheets, and presentations, and I use Chrome on all my other devices, so Chrome for Linux seems the obvious choice.

Even for the other activities I use my laptop for, there are Linux equivalents for all the software. Visual Studio Code and Arduino IDE run natively in Linux, as does Ansible, Python, Dropbox, FileZilla, SecureCRT and PasswordSafe. In fact, I haven’t found an application I desperately need, that doesn’t have a Linux version yet, except for BackBlaze, but I can live without that as long as I’m careful to keep everything important on DropBox.

The install was simple. I bought a new, bigger, SSD for the install, which means I could roll back to Windows 10 by putting the old hard disk back in, if anything went wrong. A 1TB SSD was £60 which is much cheaper than a new laptop!

Those wishing to follow along at home and do the same, download the Ubuntu Desktop ISO from here: https://ubuntu.com/download/desktop. Ubuntu 24.04 LTS will be supported for free until 2029 and has extended paid support until 2034, but even before then, you can just run an in-situ upgrade to v25, or v26 when they are released. Ubuntu is a stable, well supported, mature OS, dating back to 2004. The Debian kernel, it is based on, dates back to the early 1990’s which is also the base for other popular Linux distributions, including the Raspberry Pi.

I burnt the Ubuntu ISO image onto a USB drive, switched hard disks and booted my laptop. The install took about an hour and includes the Libre Office software and Thunderbird email client as standard. I installed Chrome, and within an hour or so, I had a new laptop running, that would support most of my needs. It ran quickly, all the peripherals worked out of the box, like network drivers, graphics drivers, sounds, touchpad, etc. Even the function buttons on my keyboard for mute and aeroplane mode, all worked out of the box. I couldn’t get the fingerprint reader working, but I’ll fix that eventually. More googling required. I installed Dropbox and let it sync overnight and by the morning I had all my documents, music and photos.

However, the fun doesn’t have to stop there. Seeing as I have a spare Windows license now, why don’t I see if I can get a Windows 11 virtual machine running on Ubuntu, for those rare occasions where I need windows, and there isn’t a Linux equivalent. I can’t think of many examples, but there is an old windows app I use about twice a year, that controls an LED badge I bought in Maplins 10 years ago. Without the app, the badge is e-waste too, so let’s see if I can get an emergency Windows 11 install working.

With a large helping of irony, the thing stopping me running Windows 11 natively on my laptop, e.g. the lack of a TPM device, is emulated in Ubuntu as part of the hypervisor. So, I can run a virtual Windows 11 machine on my laptop, with a virtual TPM device, even though I can’t run Windows 11 natively. How frustratingly ironic.

There are lots of options for virtual machines and hypervisors in Linux. I went for QEMU & KVM, as there are both open source and free. Once I found the right instructions online (Thanks Richard!) the install was also easy. Those following along at home can find the instructions here: https://www.liquidweb.com/blog/how-to-set-up-virtualization-host-using-kvm-ubuntu/.

I downloaded the Windows 11 24H2 ISO from here: https://www.microsoft.com/en-us/software-download/windows11. The windows install also took about an hour, and using the network hack to allow you to create a local account rather than insist on a Microsoft account, I had a Windows 11 virtual machine running the same afternoon. I shared the Dropbox directory on my Linux OS to Windows, through KVM, so it only needs to sync once, and I was up and running with all my documents in Windows 11.

Linux Laptop running Windows 11 Virtual Machine

So far, it’s been a very pleasant experience. I am writing this article on Libre Office, and I have already written some Arduino software and deployed it to a Raspberry Pi Pico all from Ubuntu. Everything seems to work fine, and the interface feel familiar and easy to use.

So, instead of keeping an unpatched version of Windows 10 on your old machine after October 2025, and becoming a target for hackers, why don’t you give Linux a try and play a part in reducing e-waste and giving your old laptop a new lease of life, and for free! 🙂

Designing an Automated Testing Jig for my IOT MOSFET Shield

When I first started selling my IOT MOSFET shields on Tindie, I honestly didn’t think I’d sell many. I thought I might sell the odd one or two, but instead I’ve sold hundreds, all over the world! Which is quite amazing. Thank you to everyone who bought one, I’m pleased it solved a problem for you.

MOSFET Shield for Wemos D1 mini Panel
MOSFET Shield for Wemos D1 mini Panel
I sell on Tindie

This of course created its own problems. I needed to create a more streamlined logistics and more automated testing to fulfil orders efficiently. Luckily 95% of the orders are less than five boards, so they all fit in a small A5 padded envelope, and after a little research I found self-adhesive laser printable labels that fit the UK Royal Mail labels exactly, so processing orders is very easy and efficient. I print the packing slip, buy the postage online and print out the address and customs declaration labels. Then insert the packing slip and products in to an envelope, seal it and stink on the labels. It literally takes a few seconds.

The only complex part is testing the boards. In theory, the boards are tested by the PCB manufacturer before being shipped to me. But they are built on panels. I need to separate them and there is a chance they could be damaged by the separation and handling process. It is also another excuse for an interesting project.

The two features of the boards I need to test are the LED indicators and the MOSFET operation. To test for potentially weak solder joints, I wanted to test at a relatively high current, rather than just continuity.

I designed a test that switches each of the MOSFETs on and off sequentially. There is a load connected to the MOSFETs, so I can test at a specific current. I measure the current for each MOSFET under test and check its within range. I use an INA260 Digital Current Monitor IC which can measure currents up to 15A, but during the test I only draw about 2A. However, I can adjust the load to set a higher current. I also added an Arduino microcontroller to execute the test, and a red, amber and green LED to provide feedback. Amber means the test is running, red and green mean pass or fail.

MOSFET Shield Test Jig Schematic
MOSFET Shield Test Jig Schematic

I built the variable load using some high power resistors bolted to a heat sink, which will be useful for other projects too. The resistors are 3 ohms @ 50 watts. I have them arranged in a 2S3P grid, with switches between each of the 3 parallel rows, so I can switch the load to be 6 ohms, 3 ohms or 2 ohms. At 12v this would generate 2A, 4A & 6A respectively, which is perfect for this project, but would also be useful for other projects too. I mounted an XT60 connector, so I could plug it in to other projects if required.

MOSFET Shield Test Jig Variable Load

The INA260 uses I2C to communicate with the microcontroller. There an existing library to interface with it, making the software is very easy.

An interesting problem was how to interface to the MOSFET shield under test to allow for quick testing. I had seen a few videos on YouTube using pogo pins and wanted to try them. Pogo pins are tiny spring mounted pins with various shaped heads on them to contact test points of pads on PCBs.

I decided to keep the pogo pin interface board on a separate PCB to the test circuit. This way if I change the MOSFET shield design or design a shield with a different layout I can use the same test jig, with different interface boards.

I prototyped the circuit on a breadboard before committing it to a custom PCB.

MOSFET Shield Test Jig Prototype
MOSFET Shield Test Jig - Pogo Pins 1
MOSFET Shield Test Jig – Pogo Pins
MOSFET Shield Test Jig - Pogo Pins 2
MOSFET Shield Test Jig – Pogo Pins
MOSFET Shield Test Jig - Motherboard
MOSFET Shield Test Jig – Motherboard

The software is very simple;

  • Measure the voltage with the INA260 to ensure the power is on.
  • Turn on the Amber LED to signal the test is underway.
  • Turn on each MOSFET in sequence and measures the current flowing through it. If the current does not exceed the acceptable threshold, mark the test as failed.
  • Once all MOSFETs are tested, turn off the Amber LED and turn on either the Red or Green LED, depending on if the test has passed or failed.
  • Pause for 5 seconds to allow the operator to put a new board on the test jig for testing.
  • Rinse and Repeat.
#include <Adafruit_INA260.h>

//A4 (SDA) and A5 (SCL)
#define CH1 6
#define CH2 7
#define CH3 8
#define CH4 9

#define LED_RED 3
#define LED_GREEN 5
#define LED_AMBER 4

#define V_THRESHOLD 6000  //6v
#define I_THRESHOLD  500  //500mA

float nV;
float nI;
int bPassed = true;

Adafruit_INA260 ina260 = Adafruit_INA260();

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(CH1, OUTPUT);
  pinMode(CH2, OUTPUT);
  pinMode(CH3, OUTPUT);
  pinMode(CH4, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_AMBER, OUTPUT);

  Serial.begin(115200);
  Serial.println("Setup...");
  if (!ina260.begin()) {
    Serial.println("Couldn't find INA260 chip");
    while (1);
  }
  Serial.println("Found INA260 chip...");

}

void loop() {
 runTest();
}

void runTest(){
  digitalWrite(CH1, LOW);         //MOSFET A OFF
  digitalWrite(CH2, LOW);         //MOSFET B OFF
  digitalWrite(CH3, LOW);         //MOSFET C OFF
  digitalWrite(CH4, LOW);         //MOSFET D OFF
  digitalWrite(LED_RED, LOW);     //RED OFF
  digitalWrite(LED_GREEN, LOW);   //GREEN OFF
  digitalWrite(LED_AMBER, LOW);   //AMBER OFF

  Serial.println("Begining Test...");
  delay(1000);
  bPassed = true;
  
  nV = ina260.readBusVoltage();
  Serial.print("Bus Voltage: ");
  Serial.print(nV/1000);
  Serial.println("V");

  if (nV > V_THRESHOLD) {
    //power is on
    digitalWrite(LED_AMBER, HIGH);   //AMBER ON - Running ...
    Serial.println("Testing...");
    Serial.println("Channel A:");
    testChannel(CH1);
    Serial.println("Channel B:");
    testChannel(CH2);
    Serial.println("Channel C:");
    testChannel(CH3);
    Serial.println("Channel D:");
    testChannel(CH4);
  } else {
    Serial.println("Power Off...");
    bPassed = false;
  }

  if (bPassed){
    digitalWrite(LED_RED, LOW);      //RED OFF
    digitalWrite(LED_GREEN, HIGH);   //GREEN ON - Pass!
    digitalWrite(LED_AMBER, LOW);    //AMBER OFF
    Serial.println("PASSED");
  } else {
    digitalWrite(LED_RED, HIGH);     //RED ON - Fail!
    digitalWrite(LED_GREEN, LOW);    //GREEN OFF
    digitalWrite(LED_AMBER, LOW);    //AMBER OFF
    Serial.println("FAILED");
  }

  Serial.println("All done.");
  delay(5000);  // Wait 5 seconds to load next board to test.
}

void testChannel(int nC){
  digitalWrite(nC, HIGH);
  delay(500);
  nI = ina260.readCurrent();
  Serial.print("Current: ");
  Serial.print(nI);
  Serial.println("mA");
  if (nI > I_THRESHOLD){
    Serial.println("Passed!");
  } else {
    Serial.println("Failed!");
    bPassed = false;
  }
  digitalWrite(nC, LOW);
  delay(500);
}

The test jig worked well, and once you get in to right rhythm of changing boards after the test, it takes about 10 seconds to test each board. You can efficiently test a whole batch within a few minutes.

MOSFET Shield Test Jig in Operation

And just to prove the tester really does fail a broken board, I cut the trace to the 3rd MOSFET on a test board and ran a test on it. You can see in the video, the third LED fails to light correctly, and the test jig reports a failure by lighting the red LED at the end of the test.

MOSFET Shield Test Jig in Operation – Fail

Having used the jig to test a few hundred boards, there are some improvements I could make for version 2. A 3D printed frame to help align the board on the pogo pins would be useful to help with changing the boards quickly. This could perhaps also include a mechanical switch, which would start the test when the board was pressed down, rather than relying on a timed sequence. In addition I should add a sounder to make a pass and fail noise, so I don’t have to stare at the LEDs. An audio confirmation would make it easier to use. Maybe I’ll make a version 2 at some point, but this version works perfectly and has significantly improved the speed I can test the boards. It also highlights the quality of the manufacturing process, as to this day, I’ve never had a board fail the test.

Home Automation – Immersion Heater Controller

Although automated sockets and temperature sensing is useful, I needed to solve a more complex problem with my home automation system. I have Economy 7 heating, which heats both my hot water and central heating system overnight on cheap electricity, so I can use it during the day. The controller for my hot water was old and mechanical (a ticking clock) which was in my daughters bedroom next to the hot water tank and the ticking kept her awake at night.

It has a boost function, which allows you to turn on a second heating element during the day for an hour, if you run out of hot water. Again, this button was in my daughters bedroom, and rather high up, making it difficult to reach during the night, if we needed extra hot water, without waking her.

Economy 7 Heating Clock

Economy 7 Heating Clock

You can buy digital controllers which would solve the ticking problem, but they would still have the boost button problem. A more automated solution would be better.

I wanted to use Tasmota and a Wemos D1 mini as I had found them to be very reliable and easy to configure and manage in other projects. The two elements (Main and Boost) are mains voltage and 3kW each (13A @ 230v) so I cant control them with a microcontroller pin ! 😊

I used two 25A mains rated relays with 12v coils. I can fit these, plus a couple of power supplies on a DIN rail in an IP rated enclosure.

However to switch the relays I needed to control them with a MOSFET. There wasn’t an existing MOSFET shield for the Wemos D1 mini, so I decided to build my own shield with a custom PCB.

The design is quite simple. The MOSFET needed to be logic level, turned on with 3.3v. The relays only draw about half an amp, but for future use, the shield supports more current.

There is a dedicated blog post about the process I went through to design and manufacture the MOSFET shield, and you can buy them on Tindie 😊

I sell on Tindie

4 Channel MOSFET Shields for Wemos D1 Mini

4 Channel MOSFET Shields for Wemos D1 Mini

The custom immersion heater controller needs two relays to control the two heating elements. The controller must prevent the possibility of ever having both immersion heaters on at the same time. This would draw too much current (26A!) and overload the mains wiring to the controller. The previous manual controller had the same interlock to prevent both elements being powered. If you select the boost function, it turns off the main heater. It’s not safe enough to just have one heater on one relay and the second heater on the second relay. Although I could configure the code to not turn on both relays at the same time, there was a risk that if the microcontroller crashed or hung, both relays could come on at the same time.

So, the solution is to use the first relay to provide power and the second relay to switch the power between the main and boost elements. When both relays are off, power is off. With the power relay on and the second relay off, the main element is powered. With the power relay on and the second relay on, the boost element is powered. At no point can both elements be powered at the same time. Safe!

Immersion Heater Controller Diagram

Immersion Heater Controller Diagram

The circuit was built in an IP rated box and tested, then installed in the hot water cylinder cupboard.

Immersion Heater Controller Installed

Immersion Heater Controller Installed

Node Red was configured to control it. There are two flows. The first turns the main element on between 00:30 and 06:30 to heat the tank overnight. This just needs to turn the first relay on, to apply power through the normally closed contact of the second relay to the main element.

The second flow is more complex, but essentially sends four messages; the first two messages send “On” commands to both relays, to the first relay supplies power and the second relay connects the boost element. After a delay of 60 minutes, two further messages send “Off” commands to turn both relays Off. A button is used on the Node Red Dashboard user interface to trigger the flow.

I also have two manual switches on the dashboard to control the individual relays, if required.

Immersion Heater NodeRed Flow

Immersion Heater NodeRed Flow

Immersion Heater NodeRed Dashboard

Immersion Heater NodeRed Dashboard

My Economy 7 hot water system is now fully automatic, silent, hidden, and fully controllable from any browser enabled device in the house!

Combine this with the hot water tank temperature monitoring I have already installed and I have complete visibility over how much hot water I have left and the ability to switch on the boost all from my mobile phone browser if I ever run low !

Home Automation – Automatic Garden Watering

An automatic garden watering system was my original goal for my home automation system, especially as this year we have had very sunny and dry conditions. I was out watering my plants nearly every night.

I have several different things I needed to water; raised beds with vegetables, a wall of strawberries, some fruit trees, and we tried our hand at potatoes this year as well.

Automatic Watering System - Beds

Automatic Watering System – Beds

Four zones fitted nicely with my four channel MOSFET board I had designed. There is a dedicated blog post about the process I went through to design and manufacture the MOSFET shields and you can buy them on Tindie for you own projects. 😊

I sell on Tindie

I designed a water manifold with four 12v solenoids which would give me four individually controlled watering zones and a pass-through connector so I could daisy chain additional controllers later as required.

I needed to split the watering zones up because my water pressure could not drive all the drippers and sprinklers at the some time, if they were all connected in series. You need a reasonable amount of pressure to get the mini sprinklers to work properly and you can’t drive more than 15-20 at once as the pressure drops too low.

I used Hoselock Easy Drip system to supply water to the plants and beds I needed to water. The system is simple to configure. You run a standard hose around the bed, and clip on sprinkler heads which pierce the hose and provide irrigation. There is also a micro drip system which uses smaller 4mm hose for pots. I used the Easy Drip for all the beds and Micro Drip for the strawberries.

Hozelock Easy Drip System

Hozelock Easy Drip System

Hozelock Micro Dripper

Hozelock Micro Dripper

Design

I built the manifold out of ¾” threaded pipe connectors and 12v solenoids. Next time, I might try making the manifold from soldered fittings, but the threaded fittings gave me the flexibility to change the design as I built it. I have also found some ready-made manifolds since building mine, so I might try those too next time.

Automatic Watering System Manifold

Automatic Watering System Manifold

I built a wooden box out of some old decking boards I had, so I could mount the manifold and controller on the fence.

Automatic Watering System Box

Automatic Watering System Box

The device would be in my garden, so I used a Wemos D1 Mini microcontroller with an external antenna to give me a bit of extra WiFi range. It will be powered by a 12v battery, so I mounted the Wemos and MOSFET shield in an IP60 weatherproof case, with a DC-DC step down convertor to give me 5v to power the Wemos and 12v from the battery for the solenoids.

The plan is to charge the battery from a small solar panel, so its completely wireless in the garden. The current draw is tiny. The solenoids only draw about 600mA each and they are only on for short amounts of time. Even without a solar panel to charge the battery, it would last maybe 2 weeks between charges.

Automatic Watering System Final Installation

Automatic Watering System Final Installation

The main water feed from the garden tap comes in on the right hand side via a manual valve so I can quickly turn off the water if I need to, without having to walk all the way back down the garden. I leave this on and connected all the time, so the watering system can water at any time of the day or night.

There are four watering zones, one on each solenoid. The four zones are;

  1. Potatoes
  2. Vegetables Beds
  3. Fruit trees
  4. Strawberry Wall

The last connection on the left is a pass through from the main feed, also via a manual valve, where I can either daisy chain another four zone controller, or attach a hose and hand held sprinkler for manual watering.

Testing

To test the controllers and manifold worked correctly before I installed it permanently, I wrote a simple script that turned on each channel sequentially, with an MQTT message, every 2 seconds.

I positioned the controller with its external antenna just on the edge of my house WiFi range, so it was as far up the garden as it could be, but still in range.

Automatic Watering System - Potatoes

Automatic Watering System – Potatoes

The automation is driven by NodeRed. I water each zone for 20 mins every morning at 6am. I can add more logic later if I need. There are all kinds of modules and sensors I could add to measure soil moisture or rain sensors and decide not to water if its been raining or the ground is already moist, but there’s no risk of over-watering anything at the moment, so it just waters every day for 20 mins.

In theory if the summer gets really hot, I could measure soil moisture and decide to add an extra watering cycle midday if the ground is really drying out in the sun. But that will be a phase two.

I also have a manual override using the NodeRed dashboard buttons, so I can manually turn zones on and off from my mobile phone.

Automatic Watering System NodeRed Flows

Automatic Watering System NodeRed Flows


Automatic Watering System NodeRed UI

Automatic Watering System NodeRed UI

The results have been amazing. The strawberries have really benefited for daily watering. We got a fantastic crop of potatoes too. Now the automatic watering system is in place we will increase the volume of plants next summer, now I’m confident they will all survive, and I don’t need to spend hours watering them every day! 😊

Lots of Strawberries

Lots of Strawberries

Design, Fabrication and Testing of a MOSFET Shield for a Wemos D1 mini ESP8266 Microcontroller

Design

I needed a MOSFET Shield for a Wemos D1 mini to drive solenoids and relays. I could not find anything suitable online, so I decided to design and build my own. The board size of a Wemos D1 mini is quite small (1″ x 1.3″) and part of that is the PCB antenna, so a shield should avoid covering the area over the antenna with copper or lots of components.

Wemos D1 Mini ESP8266 Development Board

Wemos D1 Mini ESP8266 Development Board

I wanted the shield to be the same size as the Wemos D1 mini. I need to be able to switch about 12v at about 2A. Most use cases I had were small relays and solenoids.

I found a very small dual channel MOSFET in a 2mm x 2mm package (FDMA1024NZ – Dual N-Channel MOSFET 20V / 5.0A). This MOSFET is so small I could fit two on the shield, giving a total of four channels.

Wemos D1 Mini MOSFET Shield 4ch v1.3 Schematic

Wemos D1 Mini MOSFET Shield 4ch v1.3 Schematic

Wemos D1 Mini MOSFET Shield 4ch v1.1 Board

Wemos D1 Mini MOSFET Shield 4ch v1.1 Board

Fabrication

I created the board design and ordered the PCBs and a solder stencil for the first prototype. The 2mm x 2mm package is very difficult, if not impossible, to hand solder, so the stencil would allow me to stencil the solder paste and hand place the components, before reflowing it in an oven.

MOSFET Shield for Wemos D1 mini before solder stencilling

Before solder stencilling

MOSFET Shield for Wemos D1 mini during solder stencilling

During solder stencilling

MOSFET Shield for Wemos D1 mini after solder stencilling

After solder stencilling

MOSFET Shield for Wemos D1 mini close up of solder stencilling and component placement

Close up of solder stencilling and component placement

MOSFET Shield for Wemos D1 mini v1.1

First prototype completed

The first version worked perfectly, but the 2mm x 2mm MOSFET was a little obscure and difficult to hand solder. In addition, JLC PCB had launched a pick and place PCB fabrication service which was very economical. I thought I’d try it for my MOSFET board, but the MOSFETs I was using were not supported. So I replaced the two obscure dual MOSFETs with four discrete MOSFETs which JLC support as a basic components.

Wemos D1 Mini MOSFET Shield 4ch v1.3 Board

Wemos D1 Mini MOSFET Shield 4ch v1.3 Board

The JLC PCB fabrication service built a batch which again all worked perfectly.

MOSFET Shields for Wemos D1 Mini v1.2

MOSFET Shields for Wemos D1 Mini v1.2

Testing

I needed to test the board design to ensure it could handle the current rating. The MOSFETs are rated at a maximum of 5A each. So, each individual channel should switch 5A. In addition all four channels can be connected together which would switch about 20A in total. I wanted to make sure the tiny PCB would handle this load. I designed the power traces on the PCB to be as wide as the physical dimensions of the board would allow.

I bought a 180W battery tester from BangGood to use as a variable load which could test up to 20A and 180W. This device has lots of useful features. You can configure it as a constant current load in 10mA increments. It measures voltage, current, power and even temperature using a plug in thermocouple, and displays all the readings in real time on a colour LCD. Its a very functional device for a very economical price.

To source 20A, I decided to use a lead acid battery. I don’t have a bench power supply that can easily provide 20A. I used thick 12AWG wire to connect the battery to the variable load and the shield under test.

MOSFET Shield for Wemos D1 mini Power Testing Setup

MOSFET Shield for Wemos D1 mini Power Testing Setup

The test setup consisted of;

  • A 12v lead acid battery
  • The variable load
  • The shield under test – with the MOSFET outputs shorted together

Power Testing Setup

Power Testing Setup

I planned to test each individual channel at 1A, 2A, 3A, 4A & 5A, while monitoring the temperature of the MOSFET, PCB traces and connectors. In addition, I want to connect all four channels together and test up to 20A.

The first few tests went well. Each channel can handle up to 5A. The MOSFETs get a little warm at 5A. If the board is used at maximum capacity for long periods, it would benefit from either forced air cooling or a small heat sink on the MOSFETs.

MOSFET Shield for Wemos D1 mini Power Testing Temperature

MOSFET Shield for Wemos D1 mini Power Testing Temperature

I struggled to test all channels to a total of 20A. The battery tester I had can only handle 180W, and the only convenient 20A source I had was a 12v lead acid battery. 12v @ 20A is 240W which is more than 180W, and the tester cuts out when it hits 180W.

I managed to test up to 16A with the lead acid battery setup, which was right on the limit of the 180W limit.

MOSFET Shield for Wemos D1 mini Power Testing 16A

MOSFET Shield for Wemos D1 mini Power Testing 16A

I had a small 2S LiPo at 7.2v and managed to complete a final test of 20A using this LiPo, but at 20A is the battery discharged very quickly and the voltage would drop to 6v very quickly and the tester cuts out at 6v to protect the battery from over discharge.

MOSFET Shield for Wemos D1 mini Power Testing 18A

MOSFET Shield for Wemos D1 mini Power Testing 18A

I’m confident the boards will operate to 5A per channel, to a maximum combined current of 18A as I managed to successfully test to both these levels. At higher currents the individual MOSFETs get hot and the Dupont header does. I think the header pins are only rated to 5A, so for 20A the board would need a redesign with more power pins to distribute the load. 4A per channel is way more than most of my projects need, so I’m happy with the design. If you really need to switch 20A for short periods of time, use a heatsink and solder the wires directly to the board rather than use pin headers and a Dupont connector.

Batch production

The shields were used in three of my home automation projects:

  • Automatic Garden Watering to control four water solenoids connected to garden hoses.
  • Immersion Heater Controller to control 2 high current relays to switch two 3kW hot water immersion heaters.
  • Automatic plant Pot Watering to control a small peristaltic pump to water pot plants based on moisture reading from a capacitive moisture sensor. This was the project that I added the analogue in header on the shield for. This allowed me to connect the moisture sensor and the peristaltic pump to the same shield.

Once the shields had been running in projects for a couple of months, without any issues, I decided to build a small batch to sell online. If I couldn’t find something similar online, then maybe others would like to buy these to use in their robotics or home automation projects.

MOSFET Shield for Wemos D1 mini v1.3 Panel for Fabrication

MOSFET Shield for Wemos D1 mini v1.3 Panel for Fabrication

The four channel MOSFET shield can be purchased here on Tindie.

I sell on Tindie

Final Specification

  • Dimensions : 1″ x 1.3″ x 0.063″ (25.4mm x 33.0 x 1.6mm)
  • Four MOSFETs : AO3400A – 30V N-Channel
    • Maximum Drain-Source Voltage : 30v
    • Continuous Drain Current : 5A
  • GPIO pins used : D5 (GPIO14), D6 (GPIO12), D7 (GPIO13) & D8 (GPIO15)
  • ADC pin A0 available on 0.1″ header with power pins (selectable 3.3v or 5v)

Future revisions

I have already starting thinking about additional features that could be useful.

Using four digital GPIO pins to control the MOSFETs is sometimes a pain as the GPIO pins are shared with other features on the microcontroller. The D5, D6, D7 & D8 pins used on the shield are also the SPI port, so when the MOSFET shield is connected you cannot use SPI at the same time.

An improvement would be to use a I2C device to control the four MOSFETs rather than discrete GPIO pins. Multiple I2C devices can be connected in parallel to the same pins, so if I switched the shield to use I2C you could stack other shields in parallel and all of them would work.

There is a 4-bit I2C I/O expander IC (PCA9536) which could facilitate this. The board layout would be very tight to fit this additional chip on the same top layer. I could try and place it on the bottom layer, but a dual sided board is more expensive and complex to produce.

Or I could also try and add solder jumpers on the bottom layer to allow different GPIO pins to be user selectable.

I’m interested in any feedback on the board or any additional feature requests you would like to see. Leave your feedback in the comments section below.

Home Automation – Temperature Sensors

I wanted to monitor internal and external temperatures as part of my home automation, so I decided to use Wemos D1 mini boards for this, running Tasmota, as they are small, feature rich and really inexpensive (about $2 each).

The Wemos D1 mini is a fully functional ESP8266 board with built in WiFi antenna, 11 GPIO pins that support protocols like SPI & I2C, an analog input and USB interface. There are also many shields that provide lots of different features like temperature sensors, OLED Screens, Relays, LEDs, etc. You can buy the boards and shields on AliExpress. I particularly like the OLED displays and the temperature sensor board.

I initially designed a custom PCB for the old ESP01 development boards, which contained a USB to 3.3v power supply and space for a DS18B20. However, most of the ESP01 boards only have 512kB of Flash which is too small to easily enable over-the-air updates for the firmware. So, I quickly switched to the Wemos D1 Mini boards instead.

ESP01 DS18B20 Temperature Sesnor Board

ESP01 DS18B20 Temperature Sesnor Board

 

Although it is trivial to attach a 1-wire DS18B20 temperature sensor to the Wemos, a shield makes the wiring neater.

Wemos SHT30 Temperature and Humidity Sensor Shield

Wemos SHT30 Temperature and Humidity Sensor Shield

 

The Wemos SHT30 Temperature Shield contains a SHT30 sensor, which provides accurate temperature and humidity readings over an I2C interface. Configuring the temperature sensor in Tasmota is trivial. Just configure the I2C pins in the admin interface and temperature and humidity is displayed on the home page.

Tasmota I2C Temperature Sensor Config

Tasmota I2C Temperature Sensor Config

 

The Tasmota code automatically searches for all connected I2C sensors when it boots and displays anything it finds. You do not need to tell Tasmota which sensor it is. A full list of support sensors in Tasmota can be found here.

 

Tasmota Showing SHT30 Sensor Data

Tasmota Showing SHT30 Sensor Data

Note: To get sensor support you will need to flash the devices with the tasmota-sensors.bin binary, instead if the generic tasmota.bin file. Sensor support was recently moved into its own binary to make the default binary smaller.

Reading the data – HTTP

You can query the data directly over HTTP using the url :

http://192.168.1.20/cm?cmnd=status%208

(Substituting for your IP number)

The response is a JSON structure containing all the sensor data.

{"StatusSNS":{"Time":"1970-01-09T03:28:52","ANALOG":{"A0":8},"SHT3X-0x45":{"Temperature":20.5,"Humidity":63.1,"DewPoint":13.2},"TempUnit":"C"}}

On a Raspberry Pi you can extract raw data values using jq to navigate the JSON Structure.

curl -s http://192.168.1.20/cm?cmnd=status%208 | jq '.StatusSNS."SHT3X-0x45".Temperature'

18.1

Note: you must encase the “SHT3X-0x45” in double quotes. It is an artefact of the jq library, it does not like the -0x in the middle of the sensor name. I don’t really know why … it works fine for sensors that don’t have funny characters in the middle. E.g. ‘.StatusSNS.MAX31855.ProbeTemperature’)

Reading the data – MQTT

You do not need to read the temperature directly from the device if you are using MQTT. By default Tasmota automatically sends “Telemetry” messages out over MQTT every 5 minutes containing all the sensor data, which can be received and processed by NodeRed.

An example MQTT “TELE” message:

{"topic":"tele/temp01/SENSOR","payload":"{\"Time\":\"2020-07-01T13:17:44\",\"SHT3X-0x45\":{\"Temperature\":26.0,\"Humidity\":47.4,\"DewPoint\":13.9},\"TempUnit\":\"C\"}","qos":0,"retain":false,"_msgid":"d1a72fd2.4d6fc"}

I configured a dashboard gauge in NodeRed to show the temperature data in real time for my internal and external temperature sensors.

Temperature Gauge NodeRed Flow

Temperature Gauge NodeRed Flow

 

The function to extract the payload strips all the other information from the message and just returns the value in the payload ready for the dashboard gauge to display.

msg.payload = msg.payload["SHT3X-0x45"].Temperature;
return msg;

 

Temperature Gauge NodeRed Dashboard

Temperature Gauge NodeRed Dashboard

Voila a simple, real-time, temperature gauge on my phone over MQTT.

Home Automation – MQTT, Mosquitto, Node Red, Sonoff & Tasmota

There several things in my house I have been meaning to automate for a while. Some are obvious and simple, like lights and lamps around the house and the water fountain in the garden, others are more complex, like the Economy 7 hot water immersion heater and an automated garden watering system.

After reading a lot of forums and watching a lot of YouTube videos, it was obvious that MQTT was at the heart of any DIY home automation system.

YouTube channels, like Andreas Spiess and SuperHouseTV were a hugely useful resources.
I decided to use a Raspberry Pi running Mosquitto as the MQTT broker and NodeRed for some automation.

There are plenty of tutorials online on how to install these and it’s very simple.

For Mosquitto:

apt-get install mosquitto
apt-get install mosquitto-clients

For NodeRed, the instructions are here.

bash < (curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)
node-red-start

MQTT has a simple “Publish & Subscribe” model (sometimes called “PubSub”). Things can publish messages on a topic which are sent via the broker to anything that has subscribed to that topic. You can subscribe to a particular topic, or to all messages, or filter the topic using wild cards and expressions. It’s very flexible and there is a huge ecosystem of devices that support MQTT.

I setup a simple local software test on the Raspberry Pi to check everything was working after I rebooted. By installing the mosquito clients on the Raspberry Pi I can publish and subscribe using command line tools.

I opened two separate SSH windows, in the first I subscribed to a test topic called “test/message”

mosquitto_sub -t "test/message"

This command will stay running and output any messages that have the topic name “test/message”

In another windows I published a message on that topic with the payload value “hello”

mosquitto_pub -t "test/message" -m "hello"

in the first subscription windows I see the message “hello” appear. It’s all working!

pi@localhost:~ $ mosquitto_sub -t "test/message"
hello

After watching a lot of Andreas and SuperHouse on YouTube, it was clear that the simplest way to automated devices in the home using MQTT was with a Sonoff device, and to reflash this device with an open source firmware called Tasmota.

The Sonoff devices do come with a firmware that provides some simple automation and remote control, but it is not open source. Who knows what data it is collecting. It also needs a public internet connection, whereas a local MQTT Server and Tasmota means all my devices stay on the local network and do not need an internet connection to function.

Sonoff devices are inexpensive, well made and easy to hack; plug sockets, switches and other devices that are all based on the ESP8266 chip. Using these devices Theo Arends and others built an open source MQTT based firmware for Sonoff devices called Tasmota.

Tasmota Code is here on GitHub.

Tasmota Documentation is here.

Tasmota

Tasmota has pretty much everything you need already built in to it, in a very small binary. It includes MQTT support and HTTP management interfaces. Over the air updating means you can reflash the device with new firmware releases using the HTTP interface, rather than having to connect a serial cable. It also has support for dozens of common sensors, like 1-wire temperature sensors, RGB LEDs, etc, all supported out of the box in the code.

Almost all the Sonoff devices can be reflashed to run Tasmota, plus a long list of other hardware, including other ESP8266 based devices and development boards. A full list of supported hardware and sensors is on the Tasmota Template Repository.

I bought some Sonoff S20 sockets. These are mains plug/socket combos than allow you to plug in pretty much any mains powered device into a domestic mains plug and have control over it using home automation. The sockets can switch 10A (about 2kW in the UK) and they have a manual override switch so you can manually turn the device on and off at any time as well.

The initial flashing process is very simple, but you need to take the cover off the Sonoff device, and these are mains voltage when they are plugged in. So do this at your own risk, and watch some YouTube examples first. They do not need to be, and should not be, plugged in to the mains while you flash them. Only plug them in after you have disconnected your programming cable and replaced the covers.

What this video from SuperHouseTV which gives detailed instructions.

I made simple programming lead from a USB to Serial dongle to program the boards and I didn’t solder headers in to the Sonoff device, I just pushed the pins from the lead in to the PCB hole while it programmed and held them there manually. It takes less that a minute to upload the new Tasmota firmware and once it’s running you can do everything else through the web interface, so you should never need to open the device again.

You need to install the esptool.py on your laptop / computer, which is used to transfer the firmware binary file to the ESP8266 over a serial cable. Once you have identified the com port your serial cable is attached to, the command line is simple.

Download the latest Tasmota firmware from GitHub if you scroll down in that page you’ll find a long list of binary files to download. There are lots of binary files to choose from, but don’t let this confuse you. I have yet to need anything other than the basic binary. It supports all the common functionality you need, and if you need something specific later, you can change the binary over the air.

Just download tasmota.bin from the release page, and copy it to your local directory. I like to add the version number of the release in the filename, so I know which file is which version next time I need to flash something. In this example I named tasmota.bin to tasmota-8.3.1.bin.

Then run esptool.py to upload the binary file to the ESP2866 chip on the Sonoff device.

cd Projects\Sonoff\Tasmota
esptool.py -p COM11 write_flash --flash_size 1MB --flash_mode dout 0x00 tasmota-8.3.1.bin

You will need to substitute the correct COM port for your serial cable and the correct filename for your tasmota.bin.

While flashing via the serial cable, you should see something like this:

esptool.py v2.6
Serial port COM11
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: DE:AD:BE:EF:12:34
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Compressed 519920 bytes to 355646...
Wrote 519920 bytes (355646 compressed) at 0x00000000 in 31.7 seconds (effective 131.2 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...

Once the Sonoff device is flashed with Tasmota, you can reboot it, and you should find a new WiFi SSID called “tasmota_xxxx” where “xxxx” is the last part of the devices MAC address.

  • Connect to this access point “tasmota_xxxx” on your phone or laptop.
  • Browse to 192.168.4.1 on your phone or laptop and you should get the default Tasmota configuration screen.
  • Add the WiFi SSID & Password for your house network, click save and reboot.
  • Once it has rebooted, it will connect to the house WiFi network and you should be able to find the DHCP IP address in your DHCP server.
  • Once you know the local IP you can reconnect to your house WiFi on your laptop and connect directly to the Tasmota device in a browser using its IP number.

Screenshot of the configuration screen in Tasmota where you enter your WiFi details

Screenshot of the configuration screen in Tasmota where you enter your WiFi details

You need to configure a few things in Tasmota to enable MQTT. You need to set the MQTT broker IP address and tell Tasmota what the hardware device is so it know which GPIO pins control which functions.

You can configure this in the web interface. Browse to your device IP number and from the menu select “Configuration” | “Configure MQTT”. Set the “MQTT Host ” to the IP number of your Raspberry Pi Mosquito MQTT Broker you installed earlier.

If you are using a Sonoff S20 plug, from the menu select “Configuration” | “Configure Module” | Module Type = “Sonoff S2X”

Save and reboot and that’s pretty much it. The Tasmota device is fully configured and ready to receive MQTT Messages.

Once you are familiar with the web user interface, it is sometimes quicker to configure your devices via the console. There is a full list of Tasmota commands here.

Once you have flashed your device, do not disconnect the USB cable. Open a serial terminal window with 115200 baud (8N1) and you will have access to the command console.

You can enter you local WiFi credentials using the following syntax :

backlog ssid1 YOUR_WIFI_NAME; Password1 YOUR_WIFI_PASSWORD;

Your device will reboot.

The given IP address will be visible in the serial console output:

00:00:00 Project tasmota Tasmota Version 8.3.1(tasmota)-2_7_1
00:00:00 WIF: Connecting to AP1 HouseWiFi Channel 6 BSSId DE:AD:BE:EF:12:34 in mode 11N as tasmota_3B7DE8-7656...
00:00:03 WIF: Connected
00:00:03 HTP: Web server active on tasmota_3B7DE8-7656 with IP address 10.1.0.73
16:30:48 RSL: tele/tasmota_3B7DE8/INFO1 = {"Module":"Sonoff Basic","Version":"8.3.1(tasmota)","FallbackTopic":"cmnd/DVES_3B7DE8_fb/","GroupTopic":"cmnd/tasmotas/"}
16:30:48 RSL: tele/tasmota_3B7DE8/INFO2 = {"WebServerMode":"Admin","Hostname":"tasmota_3B7DE8-7656","IPAddress":"10.1.0.73"}
16:30:48 RSL: tele/tasmota_3B7DE8/INFO3 = {"RestartReason":"External System"}
16:30:48 RSL: stat/tasmota_3B7DE8/RESULT = {"POWER":"OFF"}
16:30:48 RSL: stat/tasmota_3B7DE8/POWER = OFF
16:30:52 RSL: tele/tasmota_3B7DE8/STATE = {"Time":"2020-06-30T16:30:52","Uptime":"0T00:00:11","UptimeSec":11,"Heap":29,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":19,"MqttCount":0,"POWER":"OFF","Wifi":{"AP":1,"SSId":"HouseWiFi ","BSSId":"DE:AD:BE:EF:12:34","Channel":6,"RSSI":100,"Signal":-39,"LinkCount":1,"Downtime":"0T00:00:05"}}

Yon can either setup the device with extra commands over the serial cable, or do the same in the web console :

backlog MqttHost 10.1.0.90; NTPserver 10.1.0.110; Timezone 0; TimeDST 0,0,3,1,1,0; TimeSTD 0,0,10,1,2,0;
backlog SetOption56 1; SetOption57 1; GroupTopic alldevices;
etc.

Most commands need a reboot, but using the console is so much quicker that clicking through  the web interface.

Testing

I tested mine with a simple lamp plugged in to the socket and the socket plugged in to the mains.

By default all Tasmota devices have a “Fallback” topic. This is an MQTT topic which is unique to that device. You do not need to manually configure it (it is derived from the device mac address) and it is listed in the information page on the device.

MQTT Fallback Topic cmnd/DVES_3DDEE5_fb/

The Tasmota / Sonoff device is automatically subscribed to this topic. So, if you send an MQTT Message to this topic from anywhere, it will control the device.

From the Raspberry Pi terminal enter this command using your fallback topic details.

mosquitto_pub -t "cmnd/DVES_XXXXXX_fb/POWER" -m "ON"
then
mosquitto_pub -t "cmnd/DVES_XXXXXX_fb/POWER" -m "OFF"

The lamp will go on and off ! Genius ! 😊

I flashed about a dozen Sonoff S20 plugs and scattered them around the house on various lamps and devices I needed to control. I use them to control lamp in rooms, the lights on my fish tank, the pump in the garden fountain, etc. Nearly everything needs to come on at a particular time in the morning and go off at night.

Automation

I used NodeRed to automate my smart sockets.

Use the fallback topic for the NodeRed topic name in both elements with /POWER at the end. E.g. “cmnd/DVES_3B7DE8_fb/POWER”

Use the payload “ON” or “OFF” to turn the device on or off.

The Inject node can be set to inject at a specific time, or day, or repeat, etc.

I ran this for a few weeks and none of my devices missed a message. They all came on and went off as defined in NodeRed. The Sonoff devices are stable as are Mosquitto and NodeRed.

After a bit more reading, I discovered a custom node call BigTimer, which everyone seems to use instead of the built in “Inject” node. This can be installed through the interface. Just go to “Manage Palette” in NodeRed and search for “bigtimer” which will find “node-red-contrib-bigtimer” and install it.

This combines on and off messages in a single node, making the workspace a lot less cluttered, plus it has all kind of other useful features like “sun rise” and “sun set” which takes your GPS location and works out when it will get dark. Useful for controlling fish tank lights or outside lights.

You can also define certain days or months the command will operate in, useful for having your outside watering system only on during the summer months, for example.

I replace all my inject nodes with BigTimer and I have been using that without issue ever since.

My garden fountain is on during the day at sunrise, and automatically goes off at sunset !

The final nice to have is a mobile app that I can use to manually override the automation if required and switch things on and off manually. The easiest way to do this initially is to use the Dashboard feature of NodeRed. The limitation of this is that I can only access it from within my local network as my NodeRed server is not open to the public on my firewall. However this is acceptable for the time being. We can change it later and add more feature. There are plenty of full blown home automation interfaces I can add later, including Google Home automation with voice control.

The Dashboard feature of NodeRed can be installed using the Palette Manager, or following the instructions on the dashboard website.

You can add gauges, buttons, switches, etc. To start with, I added a switch for each socket. You can just add the switch to the flow and connect it to an MQTT topic. This works, but if you manually change the state of the switch outside of NodeRed, by pressing the physical button on the socket for example, the dashboard element wont know about this and update the state.

To fix this you have to subscribe to the “stat” status messages coming from Tasmota on the device and feed them back in to the dashboard switch element. I added a simple function before the dashboard switch element to change the topic from the “stat” topic it receives to a “cmnd” topic the switch needs to change state.

For example, For SocketA I subscribed to “stat/socketa/POWER” in NodeRed and the function after this node changes the topic to “cmnd/socketa/POWER” and feeds it in to the dashboard element. The output of the dashboard element send the message out as MQTT again when the switch is pressed.

msg.topic = "cmnd/socketa/POWER";
return msg;

My final NodeRed flow looks like this for all my sockets. I have a dashboard flow for each one, and a BigTimer node for those that I need to automate.

NodeRed flow for control of Sonoff Sockets

NodeRed flow for control of Sonoff Sockets

Screenshot of the NodeRed Dashboard interface on my phone.

Screenshot of the NodeRed Dashboard interface on my phone.

Home automation phase one complete ! 🙂

Hot water tank monitoring

I have electrically heated hot water in my house, and it takes ages to heat a whole tank. It heats up overnight on low cost electricity and we use it during the day. One constant frustration I have is there is no way of knowing how much hot water is left in the tank. I have to canvas my family and interrogate them on who’s had a shower or bath and how much washing up has been done. It would be so much better if I had a web page that showed the remaining hot water level in the tank !?

So, I attached temperature sensors up the side of the hot water tank and monitored them with a Raspberry Pi, of course ! 🙂

I have always wanted to use 1-wire devices in a project, and this was the perfect project. 1-wire devices make the cabling of many sensors easy as they all sit on a shared bus. You can get away with just 2 wires, a signal and a ground, as the devices can consume parasitic power from the signal line before communicating. However, to avoid any power issues and as I didn’t have a problem running more wires, I opted for three wires, power, signal and ground.

I am using the MAX31820 1-wire temperature sensors. They have a simple 3 pin transistor style package (TO-92) and there are lots of existing libraries and support for them. They’re also cheap. I decided to connect them using a ribbon cable, so I made little PCBs for them with a 4 pin header, to make the ribbon cable connection easy. I ended up using 6 way ribbon cable with 6 pin sockets, as it turns out 4 pin IDC sockets are a very difficult to find, where as 6 pin sockets are cheap as chips.

MAX31820 1-wire temperature sensor mounting PCB

MAX31820 1-wire temperature sensor mounting PCB

MAX31820 1-wire temperature sensors on small PCBs

MAX31820 1-wire temperature sensors on small PCBs

Example MAX31820 1-wire temperature sensors on small PCB attached to a ribbon cable

Example MAX31820 1-wire temperature sensors on small PCB attached to a ribbon cable

I already had a USB Adapter for 1-wire, which conveniently is supported by most of the 1-wire Raspberry Pi libraries. However, there are lots of ways of connecting 1-wire devices to a Raspberry Pi. The USB adapter is DS9490R. It takes an RJ11 plug to connect to the 1-wire bus, which also conveniently attaches to my ribbon cable. So, the solution is surprisingly neat.

The tank is pretty standard. Its covered in a insulated foam. I arbitrarily decided that 10 sensors was probably enough resolution. I marked the tank and made 10 equally spaced holes in the insulation with a pencil, then cleaned out the foam with the eraser end of the pencil, until I could see the shiny copper. I dabbed a blob of thermal paste in each hole, to assist with heat transfer from the copper tank to the temperature sensor, as I wouldn’t get direct mechanical contact. The boards and sensors just friction fitted in to the holes, and are kept in by the resistance of the foam on the boards. They are pretty snug and don’t fall out.

The cabling is simple, just attaching IDC connectors at the same regular intervals and then connecting the string of sensors to the Raspberry Pi.

Hot water tank

Hot water tank

Hot water tank with holes for temperature sensors marked

Hot water tank with holes for temperature sensors marked

Hole in the foam insulation showing the shiny copper tank

Hole in the foam insulation showing the shiny copper tank

Temperature sensor on mounting board inserted in the foam insulation

Temperature sensor on mounting board inserted in the foam insulation

Temperature sensors wired together with ribbon cable

Temperature sensors wired together with ribbon cable

Raspberry Pi connected via USB 1-wire adapter to string of sensors

Raspberry Pi connected via USB 1-wire adapter to string of sensors

Raspberry Pi connected via USB 1-wire adapter to string of sensors

Raspberry Pi connected via USB 1-wire adapter to string of sensors

Once the sensors were mounted and connected I installed OWFS (One Wire Filing System) on the Raspberry Pi which is a really easy way to read 1-wire sensors. It maps all the sensors found on the bus to a file system, so by reading the files you can read all the data and configure of all the connected sensors. Again there are loads of ways to access 1-wire devices. Using OWFS just made it easy for me. You could use Python or C, or any other myriad of languages, which all have 1-wire libraries.

Here are some instructions to install OWFS on a Raspberry Pi.

The OWFS maps the devices to a mount point. If you list the contents you get something like this :

root@raspberrypi:# cd /mnt/1wire/
root@raspberrypi:/mnt/1wire# ls -la
total 4
drwxr-xr-x 1 root root 4096 Nov  4 16:17 .
drwxr-xr-x 3 root root 4096 Mar  3  2015 ..
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.0BA759050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.168F59050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.229659050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.33A559050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.49B159050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.849459050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.AAB059050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.BBA459050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.C8AA59050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 28.E6B059050000
drwxrwxrwx 1 root root 4096 Mar 20 19:46 81.E1E324000000
drwxr-xr-x 1 root root 4096 Nov  4 16:17 alarm
drwxr-xr-x 1 root root 4096 Nov  4 16:17 bus.0
drwxr-xr-x 1 root root 4096 Nov  4 16:17 settings
drwxrwxrwx 1 root root 4096 Mar 20 19:46 simultaneous
drwxr-xr-x 1 root root 4096 Nov  4 16:17 statistics
drwxr-xr-x 1 root root 4096 Nov  4 16:17 structure
drwxr-xr-x 1 root root 4096 Nov  4 16:17 system
drwxr-xr-x 1 root root 4096 Nov  4 16:17 uncached

In each directory you can read either the cached or uncached version of the data, plus other details about the device.

root@raspberrypi:/mnt/1wire/28.0BA759050000# ls -la
total 0
drwxrwxrwx 1 root root 4096 Mar 20 19:46 .
drwxr-xr-x 1 root root 4096 Nov  4 16:17 ..
-r--r--r-- 1 root root   16 Nov  4 16:17 address
-rw-rw-rw- 1 root root  256 Nov  4 16:17 alias
-r--r--r-- 1 root root    2 Nov  4 16:17 crc8
drwxrwxrwx 1 root root 4096 Mar 20 19:46 errata
-r--r--r-- 1 root root    2 Nov  4 16:17 family
-r--r--r-- 1 root root   12 Nov  4 16:17 fasttemp
-r--r--r-- 1 root root   12 Nov  4 16:17 id
-r--r--r-- 1 root root   16 Nov  4 16:17 locator
-r--r--r-- 1 root root    1 Mar 20 19:46 power
-r--r--r-- 1 root root   16 Nov  4 16:17 r_address
-r--r--r-- 1 root root   12 Nov  4 16:17 r_id
-r--r--r-- 1 root root   16 Nov  4 16:17 r_locator
-r--r--r-- 1 root root    9 Mar 20 19:46 scratchpad
-r--r--r-- 1 root root   12 Nov  4 16:17 temperature
-r--r--r-- 1 root root   12 Nov  4 16:17 temperature10
-r--r--r-- 1 root root   12 Nov  4 16:17 temperature11
-r--r--r-- 1 root root   12 Nov  4 16:17 temperature12
-r--r--r-- 1 root root   12 Nov  4 16:17 temperature9
-rw-rw-rw- 1 root root   12 Mar 20 19:46 temphigh
-rw-rw-rw- 1 root root   12 Mar 20 19:46 templow
-r--r--r-- 1 root root   32 Nov  4 16:17 type

root@raspberrypi:/mnt/1wire/28.0BA759050000# cat address 
280BA759050000FA

root@raspberrypi:/mnt/1wire/28.0BA759050000# cat family 
28

root@raspberrypi:/mnt/1wire/28.0BA759050000# cat temperature
51.375

root@raspberrypi:/mnt/1wire/28.0BA759050000#

I run a shell script every 5 minutes to read the latest data from all the sensors and store it in a text file.

> cat /root/scripts/logtemp.sh 

#!/bin/sh
date | tr -d '\n' >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.E6B059050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.0BA759050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.49B159050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.168F59050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.C8AA59050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.33A559050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.849459050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.BBA459050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.229659050000/temperature >> /home/pi/templog.txt
echo -n ',' >> /home/pi/templog.txt
cat /mnt/1wire/28.AAB059050000/temperature >> /home/pi/templog.txt
echo ',END' >> /home/pi/templog.txt

I then use this data from a simple web page written in Python to display the latest temperatures in the tank. I decided 35 degrees Celsius is “cold”. If the water is below this I show it as blue (Cold), if its above this I show it as red (Hot). This is open to future expansion where I can fade the colour from red to blue depending on the temperature, more red for hot, more blue for cold, rather than a single colour, but that’s for another day.

> cat hotwater.py 

#!/usr/bin/env python
import cgi
import cgitb
cgitb.enable()

form = cgi.FieldStorage()

print 'Content-type: text/html\n\n'
print '<html><head></head><body>'

fn = '/home/pi/templog-latest.txt'
f = open(fn, 'r')
t = f.readline()
f.close()

temps = t.split(',')

o = ''

if form.getvalue("up","true") == 'true':
        up = True
else:
        up = False

for temp in temps:
        if len(temp) > 8:
                d = temp +"<br>"
        elif len(temp) < 2:
                if up:
                        o = o +'<tr><td bgcolor="#00FF00" align="center"></td></tr>'
                else:
                        o = '<tr><td bgcolor="#00FF00" align="center"></td></tr>'+ o
        elif temp.strip('\n') == 'END':
                z = 1
        else :
                n = int(float(temp))
                if n > 35:
                        if up:
                                o = o +'<tr><td bgcolor="#FF0000" align="center">'+ str(n) +'</td></tr>'
                        else:
                                o = '<tr><td bgcolor="#FF0000" align="center">'+ str(n) +'</td></tr>'+ o
                else:
                        if up:
                                o = o +'<tr><td bgcolor="#0000FF" align="center">'+ str(n) +'</td></tr>'
                        else:
                                o = '<tr><td bgcolor="#0000FF" align="center">'+ str(n) +'</td></tr>'+ o

print d +'<table width=150>'+ o +'</table>'
print '</body></html>'

I can access the web page from anywhere in my house, on my mobile phone, and it instantly shows the quantity of hot water left in the tank, plus each of the 10 individual temperature readings from the sensors. The query string parameter in the web page script reverses the order of the sensor readings in the tank. “up=false” or with no query string, is the default setting, where the temperatures are shown in the correct order, with the hottest water “floating” at the top of the tank. The alternate view, is for users who don’t want a view based on physics, and would rather the visualise a tank full of hot water emptying from the bottom. In this view the hot water is seen at the bottom, slowly draining away to empty. Not scientifically correct, but easier to explain to my 8 year old. Either way the bookmark is saved with the appropriate query string parameter, and everyone in my house can now tell how much hot water is left, before they get in the shower. No more showers suddenly going cold half way through.

Hot water monitoring web page. This shows the tank about half full of hot water. The top of the tank at 45 degrees. The bottom of the tank at 16.

Hot water monitoring web page. This shows the tank about half full of hot water. The top of the tank at 45 degrees. The bottom of the tank at 16.

 

Star Wars Death Star Christmas Bauble

A slightly unplanned project. We needed to test a 3D printer in the office, and seeing as it was Christmas, we printed a Death Star Christmas tree bauble. We already had a Star Wars themed Christmas tree, so it fitted nicely.

The Death Star model came from Thingiverse. The print took about 5 hours and as it was only our second 3D print, it was a pretty good quality.

3D printed Death Star

3D printed Death Star

3D printed Death Star

3D printed Death Star

It had a void in the middle, which fitted an Arduino Mini, so I installed some LEDs to make it flash …

I used a 24 RGB LED NeoPixel ring from Adafruit and an Arduino Pro Mini from SparkFun and a high brightness green LED.

Death Star bauble innards

Death Star bauble innards

With the help of some hot glue, I installed the flashing innards. the two halves are held together with bits magnets from an old hard drive. Its powered by a USB power adapter, and the bauble hangs from the cable.

Star Wars Themed Christmas Tree

Star Wars Themed Christmas Tree

I’m pretty pleased with the result.