-
Sourcing the Vintage Soviet Displays (eBay Find!)
07/01/2026 at 20:28 • 0 comments
While these beautiful vintage displays (both the red ALS314 and the lime-green AL304V) are quite rare, a few builders have asked where to find them to build their own TinyNumberHat 9
I found a eBay seller who currently has stock of these New Old Stock (NOS) parts.
If you want to grab some for your parts bin or to complete this build, you can check out their listing here: ALS314, AL304 -
One Hertz Challenge
08/17/2025 at 18:33 • 0 commentsFor the One Hertz Challenge I had to pick between a few of my projects. I’ve always had a soft spot for retro LED displays, especially when they’re reused in modern applications. There’s something special about seeing old-school 7-segment displays glowing again driven by a Raspberry Pi.
For this contest I decided to go with my TinyNumberHat 9. It’s an expansion board for the Raspberry Pi Zero / Zero 2W that drives nine vintage ALS314 7-segment LED digits through an HT16K33 controller. It also features a Qwiic connector, allowing you to hook up additional I²C boards or connect the hat to a different host, like an Arduino.
With nine digits available, it can count pretty far, show timestamps, or even display short text messages.
The demo code is simple and written in Python. The board also has four buttons, letting you switch between different display modes:
-
Clock
-
Date
-
Timestamp
Message
Demo:
A very simple implementation on python:from smbus import SMBus from datetime import datetime import time HT16K33_ADDRESS_0 = 0x70 HT16K33_CMD_BRIGHTNESS = 0xE0 HT16K33_ENABLE_DISPLAY = 0x81 HT16K33_TURN_ON_OSCILLATOR = 0x21 LED_DRIVER_BRIGHTNESS_LEVEL = 15 SMBUS = 1 class TinynumberHat(): def __init__(self) -> None: self.bus = SMBus(SMBUS) self.ht16k33_i2c_address = HT16K33_ADDRESS_0 self.dp = True # Turn on oscillator self.bus.write_byte(self.ht16k33_i2c_address, HT16K33_TURN_ON_OSCILLATOR) # Enable display (no blinking mode) self.bus.write_byte(self.ht16k33_i2c_address, HT16K33_ENABLE_DISPLAY) # Clear display self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, [0x00] * 16) # Set brightness 0-15 self.bus.write_byte(self.ht16k33_i2c_address, HT16K33_CMD_BRIGHTNESS | LED_DRIVER_BRIGHTNESS_LEVEL) # Fill with 1, turn on all segments self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, [0xff] * 16) # Clear display self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, [0x00] * 16) self.numbers = { '0': 0b00111111, '1': 0b00000110, '2': 0b01011011, '3': 0b01001111, '4': 0b01100110, '5': 0b01101101, '6': 0b01111101, '7': 0b00000111, '8': 0b01111111, '9': 0b01101111, '.': 0b10000000, '-': 0b01000000, ' ': 0b00000000, 'A': 0b01110111, 'B': 0b01111100, 'C': 0b00111001, 'D': 0b01011110, 'E': 0b01111001, 'F': 0b01110001, 'G': 0b00111101, 'H': 0b01110110, 'I': 0b00110000, 'J': 0b00011110, 'K': 0b01011001, 'L': 0b00111000, 'M': 0b00010101, 'N': 0b01010100, 'O': 0b00111111, 'P': 0b01110011, 'Q': 0b01100111, 'R': 0b01010000, 'S': 0b01101101, 'T': 0b01111000, 'U': 0b00111110, 'V': 0b00111110, 'W': 0b00011101, 'X': 0b01110110, 'Y': 0b01101110, 'Z': 0b01011011 } self.numbers_2 = { 1: 0b00000101, 2: 0b01110110, 3: 0b00110111, 4: 0b00011011, 5: 0b00111101, 6: 0b01111101, 7: 0b00000111, 8: 0b01111111, 9: 0b00111111, 0: 0b01101111 } def show_time(self): buffer = [0x00 for x in range(0, 16)] self.dp = ~self.dp time_now = datetime.now().strftime('%H-%M-%S%f') buffer[0] = self.numbers.get(time_now[0], 0b01000000) buffer[1] = self.numbers.get(time_now[1], 0b01000000) buffer[2] = self.numbers.get(time_now[2], 0b01000000) buffer[3] = self.numbers.get(time_now[3], 0b01000000) buffer[4] = self.numbers.get(time_now[4], 0b01000000) buffer[5] = self.numbers.get(time_now[5], 0b01000000) buffer[6] = self.numbers.get(time_now[6], 0b01000000) buffer[7] = self.numbers.get(time_now[7], 0b01000000) | 0b10000000 if self.dp == True else self.numbers.get( time_now[7], 0b01000000) buffer[8] = self.numbers.get(time_now[8], 0b01000000) self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, buffer) def show_string(self, string): buffer = [0x00] * 16 buffer[0] = self.numbers.get(string[0], 0x00) buffer[1] = self.numbers.get(string[1], 0x00) buffer[2] = self.numbers.get(string[2], 0x00) buffer[3] = self.numbers.get(string[3], 0x00) buffer[4] = self.numbers.get(string[4], 0x00) buffer[5] = self.numbers.get(string[5], 0x00) buffer[6] = self.numbers.get(string[6], 0x00) buffer[7] = self.numbers.get(string[7], 0x00) buffer[8] = self.numbers.get(string[8], 0x00) self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, buffer) def show_date(self): buffer = [0x00] * 16 d = datetime.now().strftime('%d%m-%Y') for i in range(len(d)): buffer[i] = self.numbers.get(d[i], 0b01000000) buffer[1] = buffer[1] | 0b10000000 # put dot self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, buffer) def show_timestamp(self): buffer = [0x00] * 16 ts = str(int(time.time())) for i in range(min(len(ts), 9)): buffer[i] = self.numbers.get(ts[i], 0b01000000) self.bus.write_i2c_block_data(self.ht16k33_i2c_address, 0x00, buffer) def read_key_data(self): keys_data = self.bus.read_i2c_block_data(self.ht16k33_i2c_address, 0x40, 5) keys = keys_data[4] return keys if __name__ == "__main__": tiny_number_hat = TinynumberHat() text = ' HELLO HACKADAY 1HZ CHALLENGE ' mode = 16 while True: key_data = tiny_number_hat.read_key_data() if key_data != 0: mode = key_data if mode == 128: text = text[1:] + text[:1] tiny_number_hat.show_string(text) elif mode == 16: tiny_number_hat.show_time() elif mode == 32: tiny_number_hat.show_date() elif mode == 64: tiny_number_hat.show_timestamp() time.sleep(0.1)
-
Andrew Tudoroi