Saturday 16 November 2019

Start Stop Continue

Start Stop Continue is a virtual post-it note board for Start / Stop / Continue style retrospectives. It is implemented using Java, jQuery, and JSON files for persistence.

The project is designed for simplicity and the option for extension, rather than scalability. Even logging and error handling are secondary concerts at this point in the project.

An example instance of the site is hosted here:

Source Code

Code available in GitHub - start-stop-continue


This project requires a minimum of Java 11 JDK to build.

Build and Run

Build using Maven:
mvn clean install

Run by executing the built jar file:
java -jar start-stop-continue-jar-with-dependencies.jar

Browse to:

A new post-it note board with a unique URL will be created and notes can be added, edited and deleted. If this project is deployed to a publicly available host, the URL can be shared with other retrospective participants.

Future Improvements

Possible future improvements may include:

  • Add logging and more robust error handling
  • Integrate with a scalable datastore such as Apache Cassandra
  • Integrate with a scalable caching solution such as Redis
  • Use websockets for add/edit/delete live updates without refreshing the page
  • Port to AWS or other cloud based hosting provider

Saturday 27 July 2019

Raspberry Pi 4 Official Case Temperature

My Raspberry Pi 4, running without a case, has an idle temperature of 54°C. With the official Pi 4 case the idle temperature jumps to 72°C.

The official case is completely hotboxed, allowing for absolutely no airflow. Since the Pi 4 begins to throttle the CPU at 80°C, this makes the official case a design disaster and useless without the addition of active cooling.

The noctua range of fans get great reviews and are super well made – but you pay a premium for quality; they're pricey compared to other brands. I picked the 40mm x 20mm NF-A4x20 5v for mounting on the outside of the Pi case.

If you wanted a slimmer fan to mount inside the case, go for the 40mm x 10mm NF-A4x10 5v.

Case Modding

I cut a 38mm hole in the top part of the case with a hole saw, at the end of the case away from where the Pi's USB and Ethernet ports are. Placing the fan over the hole, I marked out and drilled some screw holes for the screws provided with the fan.

In the side of the Pi case base, I've drilled 6, 2mm holes at 1cm intervals as an air inlet/exhaust.

Fan Connector Modding

The fan comes with a big fat 3 pin connector, too big to fit on the Pi's GPIO pins. The fan does come with a 2 pin adapter which you can add your own connectors to, but I chose not to use it as it would just take up space in the Pi case. Instead, I cut off the original connector, removed some of the wire insulation and crimped some new DuPont connectors.

The black wire connects to one of the Pi's ground pins. The red wire connects to one of the Pi's 5v pins. The yellow wire is not required - I crimped a connector anyway, but then just keep it out of the way with some tape.

Suck vs Blow

Should you mount the fan to blow cooler air on to the Pi board and vent the warmer air through the side holes, or use the side holes as an inlet for cooler air and suck the warmer air away from the Pi board?

The only way to really know is to mount the fan both ways, stress test the Pi, measure the temperature and compare the results. Install the stress package on the Pi using apt with command:

sudo apt-get install stress

For the tests below I have used the stress command with the cpu, io, vm and hdd parameters, with 4 workers for each, running for 5 minutes (300 seconds):

stress -c 4 -i 4 -m 4 -d 4 -t 300

The Pi's temperature can be measured with:

vcgencmd measure_temp

For the tests below, I sample the temperature every 5 seconds in a loop for 7 minutes (84 iterations) to record temperature rise and drop off:

for i in {1..84}; do printf "`date "+%T"`\t`vcgencmd measure_temp | sed "s/[^0-9.]//g"`\n"; sleep 5; done

Test 1 – Blow

Mounting the fan with the sticker side down to blow air onto the board, connecting the power pins, closing the case and running the stress test gave the following results:

$ stress -c 4 -i 4 -m 4 -d 4 -t 300
stress: info: [1074] dispatching hogs: 4 cpu, 4 io, 4 vm, 4 hdd
stress: info: [1074] successful run completed in 303s
$ for i in {1..84}; do printf "`date "+%T"`\t`vcgencmd measure_temp | sed "s/[^0-9.]//g"`\n"; sleep 5; done
10:59:42        38.0
10:59:47        37.0
10:59:52        43.0
10:59:57        45.0
11:00:02        47.0
11:00:07        48.0
11:00:12        48.0
11:00:17        49.0
11:00:22        49.0
11:00:27        50.0
11:00:32        50.0
11:00:37        51.0
11:00:42        51.0
11:00:48        52.0
11:00:53        52.0
11:00:58        51.0
11:01:03        53.0
11:01:08        52.0
11:01:13        52.0
11:01:18        53.0
11:01:23        53.0
11:01:28        53.0
11:01:34        53.0
11:01:42        52.0
11:01:48        53.0
11:01:55        52.0
11:02:00        54.0
11:02:05        54.0
11:02:10        54.0
11:02:15        53.0
11:02:20        53.0
11:02:25        53.0
11:02:30        53.0
11:02:35        54.0
11:02:41        54.0
11:02:46        54.0
11:02:51        53.0
11:02:56        52.0
11:03:01        54.0
11:03:06        53.0
11:03:11        54.0
11:03:16        53.0
11:03:21        54.0
11:03:26        54.0
11:03:31        54.0
11:03:36        54.0
11:03:41        54.0
11:03:46        54.0
11:03:51        54.0
11:03:56        54.0
11:04:01        53.0
11:04:06        54.0
11:04:11        53.0
11:04:16        54.0
11:04:21        53.0
11:04:26        54.0
11:04:31        53.0
11:04:37        54.0
11:04:42        53.0
11:04:47        54.0
11:04:52        49.0
11:04:57        46.0
11:05:02        45.0
11:05:07        44.0
11:05:12        46.0
11:05:17        43.0
11:05:22        42.0
11:05:27        42.0
11:05:32        41.0
11:05:37        40.0
11:05:42        41.0
11:05:47        40.0
11:05:52        40.0
11:05:57        41.0
11:06:02        39.0
11:06:07        40.0
11:06:12        39.0
11:06:17        39.0
11:06:22        38.0
11:06:27        38.0
11:06:32        38.0
11:06:37        38.0
11:06:42        39.0
11:06:47        38.0

Test 2 – Suck

Re-mounting the fan with the sticker side up to suck air away from the board, connecting the power pins, closing the case and running the stress test gave the following results:

$ stress -c 4 -i 4 -m 4 -d 4 -t 300
stress: info: [1041] dispatching hogs: 4 cpu, 4 io, 4 vm, 4 hdd
stress: info: [1041] successful run completed in 302s
$ for i in {1..84}; do printf "`date "+%T"`\t`vcgencmd measure_temp | sed "s/[^0-9.]//g"`\n"; sleep 5; done
11:22:41        39.0
11:22:46        40.0
11:22:51        46.0
11:22:56        49.0
11:23:01        50.0
11:23:06        51.0
11:23:11        52.0
11:23:16        52.0
11:23:21        52.0
11:23:26        52.0
11:23:31        53.0
11:23:36        54.0
11:23:41        54.0
11:23:46        54.0
11:23:51        55.0
11:23:56        55.0
11:24:01        55.0
11:24:06        54.0
11:24:11        55.0
11:24:16        55.0
11:24:22        55.0
11:24:27        54.0
11:24:37        55.0
11:24:42        56.0
11:24:47        57.0
11:24:52        56.0
11:24:57        57.0
11:25:02        55.0
11:25:07        56.0
11:25:12        56.0
11:25:17        57.0
11:25:22        56.0
11:25:27        57.0
11:25:32        56.0
11:25:37        57.0
11:25:42        58.0
11:25:47        58.0
11:25:53        58.0
11:25:58        58.0
11:26:03        57.0
11:26:08        58.0
11:26:13        57.0
11:26:18        58.0
11:26:23        58.0
11:26:28        57.0
11:26:33        58.0
11:26:38        57.0
11:26:43        57.0
11:26:48        58.0
11:26:53        58.0
11:26:58        59.0
11:27:03        58.0
11:27:08        58.0
11:27:13        57.0
11:27:18        58.0
11:27:23        59.0
11:27:28        58.0
11:27:33        58.0
11:27:38        58.0
11:27:43        58.0
11:27:48        55.0
11:27:53        51.0
11:27:58        49.0
11:28:03        48.0
11:28:09        47.0
11:28:14        46.0
11:28:19        46.0
11:28:24        46.0
11:28:29        45.0
11:28:34        45.0
11:28:39        44.0
11:28:44        44.0
11:28:49        43.0
11:28:54        44.0
11:28:59        44.0
11:29:04        42.0
11:29:09        42.0
11:29:14        42.0
11:29:19        42.0
11:29:24        43.0
11:29:29        43.0
11:29:34        42.0
11:29:39        42.0
11:29:44        42.0


Blowing air keeps the Pi cooler than sucking air, with temperature ranges of 37°C-54°C and 39°C-59°C respectively for this fan/vent combination.

When sucking air, the Pi doesn't reach the original idle temperature 2 minutes after the stress test has ended.

Parts list and prices

Part Price Link
38mm Hole Saw £4.59
DuPont Connectors £2.60
Noctua NF-A4x20 5V £13.40

Saturday 6 July 2019

Raspberry Pi Backup Server

Getting Old

Recently I've found myself lying awake at night worrying if my documents, code and photos are backed up and recoverable. Or to put it another way - I've officially become old :-(

With a new Raspberry Pi 4B on order it's time to re-purpose the old Raspberry Pi 3B to create a backup solution.


I want my backup solution and backup media to be small, cheap and redundant. Speed isn't really an issue, so I've chosen micro SD as my backup media for this project.

I've picked up an Anker 4-Port USB hub, 2 SanDisk 64 GB micro SD cards and 2 SanDisk MobileMate micro SD card readers. I ordered this kit from Amazon and the prices at the time of writing were:

Anker 4-Port USB 3.0 Ultra Slim Data Hub £10.99
SanDisk Ultra 64 GB microSDXC £11.73
SanDisk MobileMate USB 3.0 Reader £7.50

They fit together really well, with room for two more SD cards and readers if I need to expand:

The plan is to make one of the SD cards available over the network as a share, via the Pi using SAMBA. The share can be mapped as a Windows network drive and files can easily be dragged and dropped for backup. In case the first backup SD card fails, the Pi will copy the files and folders from the first SD card to the second SD card using rsync to create a backup of the backup.


Download and upgrade the Pi 3B to the lastest version of Raspbian. I've chosen Rapbian Lite to save a bit of space on the Pi's SD card:

At the time of writing the lastest download was:

Write the OS to the Pi's SD card using Etcher. Top tip - Etcher can write a .zip file, but it's much quicker to extract the .iso file from the .zip file and write that instead.

Don't forget to add an empty ssh file to the boot partition on the Pi's SD card if you are going to run the Pi headless.

Put the Pi's SD card into the Pi, attached the USB hub and micro SD cards, and boot the Pi and login via SSH. Update and upgrade any new packages first, enable unattended security updates and install your editor of choice:

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install unattended-upgrades
$ sudo apt-get install vim

Because I've got a Pi 4 on the way, I want to call this Pi 'raspberrypi3'. Modify the /etc/hostname and /etc/hosts files:

$ sudo vim /etc/hostname

$ sudo vim /etc/hosts       raspberrypi3
$ sudo reboot

At this point, the backup SD cards should be available to Linux as devices /dev/sda and /dev/sdb.

I want the backup SD cards to be readable on Linux and Windows machines using the exFAT file system. A good tutorial on how to do this on Linux using FUSE and gdisk is available here:

$ sudo apt-get install exfat-fuse exfat-utils
$ sudo apt-get install gdisk

Use gdisk to remove any existing partitions, create a new partition and write this to the SD cards. Make sure to create the new partition as type 0700 (Microsoft basic data) when prompted:

$ sudo gdisk /dev/sda

GPT fdisk (gdisk) version 0.8.8

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help):
Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): Y
Command (? for help): n
Partition number (1-128, default 1):
First sector (34-16326462, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-16326462, default = 16326462) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): 0700
Changed type of partition to 'Microsoft basic data'
Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sda.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot.
The operation has completed successfully.

Repeat for the second SD card:

$ sudo gdisk /dev/sdb

Create exFAT partitions on both SD cards and label the partitions PRIMARY and SECONDARY:

$ sudo mkfs.exfat /dev/sda1
$ sudo exfatlabel /dev/sda1 PRIMARY
$ sudo mkfs.exfat /dev/sdb1
$ sudo exfatlabel /dev/sdb1 SECONDARY

Create directories to mount the new partitions on:

$ sudo mkdir -p /media/usb/backup/primary
$ sudo mkdir -p /media/usb/backup/secondary

Modify /etc/fstab to mount the SD cards by partition label. This allows us to mount the correct card regardless of it's device path or UUID:

$ sudo vim /etc/fstab

LABEL=PRIMARY /media/usb/backup/primary exfat defaults 0 0
LABEL=SECONDARY /media/usb/backup/secondary exfat defaults 0 0

Mount the SD cards:

$ sudo mount /media/usb/backup/primary
$ sudo mount /media/usb/backup/secondary

Create a cron job to rsync files from the primary card to the secondary card. The following entry syncs the files every day at 4am:

$ sudo crontab -e

0 4 * * * rsync -av --delete /media/usb/backup/primary/ /media/usb/backup/secondary/

To sync files immediately, rsync can be run from the command line at any time with:

$ sudo rsync -av --delete /media/usb/backup/primary/ /media/usb/backup/secondary/

To make the primary SD card available as a Windows share, install and configure SAMBA:

$ sudo apt-get install samba samba-common-bin
$ sudo vim /etc/samba/smb.conf

   comment = Pi backup share
   path = /media/usb/backup/primary
   public = yes
   browseable = yes
   writable = yes
   create mask = 0777
   directory mask = 0777

$ sudo service smbd restart

Finally, install and configure UFW firewall, allowing incoming connections for SSH and SAMBA only:

$ sudo apt-get install ufw
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
$ sudo ufw allow ssh
$ sudo ufw allow samba
$ sudo ufw enable

Saturday 9 March 2019

Card Table

Card Table is a multi-player web based virtual card table implemented using Java, plain JavaScript, WebSockets and Postgres.

Source Code

Code available in GitHub - card-table


This project requires a minimum of Java 8 JDK to build and a Postgres installation.

A drop/create Postgres SQL script needs to be run to create and initalise the database with default data:

Configure the Java web application's database dev configuration:

Build and Run

Build and run using Maven with an embedded Tomcat:

mvn clean install tomcat7:run-war

Browse to:


A new card table will be created with a unique URL. If this project is deployed to a publicly available host, the URL can be shared with other players to play against.

Mouse Controls

Packs of cards can be dragged from the side bar and dropped on the table to create a new deck. Currently there are 2 decks - both standard 52 card decks, one with a black back and one with a red back.

Single cards can be clicked and dragged to move them around the table. Multiple cards can be selected by clicking and dragging the mouse and drawing a selection box around the cards to be selected. Selected cards can be clicked and dragged to move more than one card.

Clicking a single card will turn the card face up/face down. Clicking multiple selected cards will shuffle the selected cards.

Moving cards to the bottom of the table, below the green line, hides them from other players. Any card actions which take place here, e.g. moving, turning and shuffling will not be broadcast to other players.

Dragging single or multiple cards off the screen removes them from the table.

See the video above for examples of all these actions.

Supported Browsers

Currently only desktop browsers are supported due to the lack of native drag-and-drop JavaScript support on mobile devices. At the time of writing, Card Table has been tested on Chrome 72, Firefox 65, Edge 42, IE 11 and Opera 58.