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.
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
Config File – oledclockconfig.py
<p>#12/24hour twelvehour=0 #gpio for bongs BONGPIN=12 # 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</p>
Routines – oledclockroutines.py
<p>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 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()</p>
Main – oledclock.py
<p>#Install #sudo python -m pip install --upgrade pip setuptools wheel #sudo pip 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>6): #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) #Do nothing for 200ms</p>