The Fake ‘Nixie’ clock
So I had an idea about making fake nixie tubes with an OLED display and a laser etched filter.
I had a play for Makevember and I was quite pleased with the outcome using a 128×64 bit white I2c OLED display.
The first test was with a plain acrylic etched peice

I also engraved the numbers on the acrylic so it looked like the wires in a nixie tube, and started playing with casings and ways of mounting the OLED. I found a pack of 5 small hexagonal jars were ideal, the flat faces didn’t distort the displays as much as the round ones did.

As this was going well I ordered some orange acrylic, I also found online the NixieOne.ttf font, Ideal…
Fixie First test

As this looked so good, I thought I’d build a clock (what else do you do to prove the fixies “Fake Nixies” ) were workable. As I had a PIZeroW available I based the clock on that.
The problem is, by default the 0.96″ OLED displays can only be assigned 2 I2C addresses, and the RPI only has a single I2C bus (without software emulating I2C). I would need four displays at minimum for a clock. Luckily Pimoromi (and Adafruit) do an I2C multiplexer breakout, that allows you to connect 8 I2C busses to a single I2C bus. A bit of software playing later.

OK that works. I’d also realised that as I had 5 jam jars I may as well do seconds too. I only had a single jam jar for seconds, so it had to display both digits (This is great as it confuses real nixie fans when they see a nixie that does 0-99)
I started building a case from laser cur MDF to try to keep things tidy as I was developing (at this point I really didn’t know where I was going with this)

Of course, you get side tracked. I started to think about chiming. So I added a driver board from and ExtKits Solenoid engine, a solenoid and some brass.

With some delicate timing I could get the solenoid to hit the brass quickly enough to make a reasonable bong.
BONG!
A view without the solenoid.

And a note to self, not to connect the 12v supply for the solenoid the wrong way around 🙂

As things were coming together I started to look at the aesthetics, and laser cut / etched a front panel.

Stained the clock and front panel with a dark wood stain, and highlighted the etched pieces with gold acrylic paint

and added a top piece to the clock to both hide the bottoms of the jam jars and keep them together with a strip of brass to hide the tangs holding the clock together and some feet.

The finished clock
Software
Config File – oledclockconfig.py
#12/24hour
twelvehour=0
#gpio for bongs
BONGPIN=12
#hour to start bonging from (till 00:00)
BongFromHour=9
# Raspberry Pi pin configuration:
RST = 24
#define display font
from PIL import Image,ImageDraw,ImageFont
#font for Nixies
fontb = ImageFont.truetype('/home/NixieOne.ttf', 110)
fontl = ImageFont.truetype('/home/NixieOne.ttf', 78)
#font for 7 segs
#fontb = ImageFont.truetype('/home/digital-7.ttf', 110)
#fontl = ImageFont.truetype('/home/digital-7.ttf', 78)
#define display size
width=128
height=64
#global variables
#Maximum Displays to initalise
MaxDisplays=5
#Global display object
disp =[None] * MaxDisplays
Routines – oledclockroutines.py
import smbus
import Adafruit_SSD1306
import oledclockconfig
from PIL import Image,ImageDraw,ImageFont
def DrawBigNumber(bus,number,chan):
SelectI2C(bus,chan)
oledclockconfig.disp[chan].clear()
image = Image.new('1', (oledclockconfig.width, oledclockconfig.height))
i1 = Image.new('1', ( oledclockconfig.width,oledclockconfig.width))
oledclockconfig.draw = ImageDraw.Draw(i1)
num=number % 10
oledclockconfig.draw.text((1, 1), str(num), font=oledclockconfig.fontb, fill=255)
i2= i1.rotate(270) # needs shift
#bodge to centre 1
if num==1:
image.paste(i2,(0,14)) # rot 270
else:
image.paste(i2,(0,-2)) # rot 270
oledclockconfig.disp[chan].image(image)
oledclockconfig.disp[chan].display()
def DrawLittleNumber(bus,number,chan):
SelectI2C(bus,chan)
oledclockconfig.disp[chan].clear()
image = Image.new('1', (oledclockconfig.width, oledclockconfig.height))
i1 = Image.new('1', ( oledclockconfig.width,oledclockconfig.height))
oledclockconfig.draw = ImageDraw.Draw(i1)
num=number % 100
oledclockconfig.draw.text((20, -12), str(num // 10), font=oledclockconfig.fontl, fill=255)
oledclockconfig.draw.text((70, -12), str(num % 10), font=oledclockconfig.fontl, fill=255)
oledclockconfig.draw.text((21, -11), str(num // 10), font=oledclockconfig.fontl, fill=255)
oledclockconfig.draw.text((71, -11), str(num % 10), font=oledclockconfig.fontl, fill=255)
i2= i1.rotate(180)
image.paste(i2,(0,0)) # rot 180
oledclockconfig.disp[chan].image(image)
oledclockconfig.disp[chan].display()
def DrawLittleText(bus,text,chan):
SelectI2C(bus,chan)
oledclockconfig.disp[chan].clear()
image = Image.new('1', (oledclockconfig.width, oledclockconfig.height))
i1 = Image.new('1', ( oledclockconfig.width,oledclockconfig.height))
oledclockconfig.draw = ImageDraw.Draw(i1)
# num=number % 100
oledclockconfig.draw.text((20, -12), text, font=oledclockconfig.fontl, fill=255)
# oledclockconfig.draw.text((70, -12), str(num % 10), font=oledclockconfig.fontl, fill=255)
# oledclockconfig.draw.text((21, -11), str(num // 10), font=oledclockconfig.fontl, fill=255)
# oledclockconfig.draw.text((71, -11), str(num % 10), font=oledclockconfig.fontl, fill=255)
i2= i1.rotate(180)
image.paste(i2,(0,0)) # rot 180
oledclockconfig.disp[chan].image(image)
oledclockconfig.disp[chan].display()
def SelectI2C(bus,chan):
chanb=(1<<chan)
bus.write_byte_data(0x70,0,chanb)
def InitDisplay(bus,chan):
global width,height,disp
print ("INIT Display")
print (chan)
SelectI2C(bus,chan)
# 128x32 display with hardware I2C:
#disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST)
# 128x64 display with hardware I2C:
oledclockconfig.disp[chan] = Adafruit_SSD1306.SSD1306_128_64(rst=oledclockconfig.RST, i2c_address=0x3C)
# Initialize library.
oledclockconfig.disp[chan].begin()
# Clear display.
oledclockconfig.disp[chan].clear()
oledclockconfig.disp[chan].display()
# oledclockconfig.width = disp[chan].width
# oledclockconfig.height = disp[chan].height
Main – oledclock.py
#Install
#python < 3
#sudo python -m pip install --upgrade pip setuptools wheel
#sudo pip install Adafruit-SSD1306
#
#or
#
#python >= 3
#sudo python -m pip3 install --upgrade pip setuptools wheel
#sudo pip3 install Adafruit-SSD1306
#
#settings in oledclockconfig.py
#
#
import time
from datetime import datetime
import smbus
import threading
import RPi.GPIO as GPIO
import oledclockroutines
import oledclockconfig
GPIO.setmode(GPIO.BCM)
GPIO.setup(oledclockconfig.BONGPIN, GPIO.OUT) #pin12
#init i2c bus
bus = smbus.SMBus(1) # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)
def bongs(name):
now = datetime.now()
hour=now.hour
bongs=hour % 12
if (bongs==0): bongs=12
print ("Bongs")
for x in range(bongs):
GPIO.output(oledclockconfig.BONGPIN, 1)
time.sleep(0.009)
GPIO.output(oledclockconfig.BONGPIN, 0)
time.sleep(1.5)
#init the displays
for c in range(0,oledclockconfig.MaxDisplays):
oledclockroutines.InitDisplay(bus,c)
#init variables
oldsec=0
oldmin=0
#main thread
if __name__ == "__main__":
while(1):
for n in range(10):
now = datetime.now()
sec = now.second
if (sec!=oldsec): #if seconds changed do display
oldsec=sec
min=now.minute
hour=now.hour
oledclockroutines.DrawLittleNumber(bus,sec,0) #display seconds
print (now)
if (min!=oldmin): #if minutes changed do mins/hours display
oldmin=min
minH=min % 10
minL=min // 10
if (oledclockconfig.twelvehour):hour=hour % 12 #12 hour clock?
hourH=hour % 10
hourL=hour // 10
#display minutes
oledclockroutines.DrawBigNumber(bus,minH,1)
oledclockroutines.DrawBigNumber(bus,minL,2)
#display hours
oledclockroutines.DrawBigNumber(bus,hourH ,3)
oledclockroutines.DrawBigNumber(bus,hourL,4)
#bongs
if (hour>oledclockconfig.BongFromHour): #bong only from 7 to midnight
if (min==0 and sec==0):
#if we need bongs start a new bong thread
x = threading.Thread(target=bongs, args=(1,))
x.start()
time.sleep(0.2) #DFA for 200ms