Doug Domke
Published © GPL3+

Self-Setting Big Clock Build with Nano ESP32 and MicroPython

An impressive self-setting clock build from extremely simple hardware thanks to the Nano ESP32 and Micro-Python.

IntermediateFull instructions provided2 hours611

Things used in this project

Hardware components

Arduino Nano ESP32
×1
32 x 8 Flexible RGB LED display
×1
9 volt 2 amp power supply
×1

Software apps and online services

Arduino Lab for MicroPytho

Story

Read more

Schematics

Clock Schematic

Code

Python Code for Clock

MicroPython
import time, ntptime, network, neopixel
from machine import Pin

WIFI_NETWORK = 'NetworkName'
WIFI_PASSWORD = 'NetworkPassword'
GMT_OFFSET = -7  # time zone adjustment here

# create instance of neopixel strip attached to ESP32 pin 9 (Arduino D6)
num_pixels = 256
panel = neopixel.NeoPixel(Pin(9), num_pixels)   

# Define colors
myColor = (0, 0, 15)  #starts out blue
black = (0, 0, 0)
# twelve colors that gradually transistion from green thhrough blue to red; changes occur every 5 seconds
colors = [(0,12,0),(0,12,3),(0,9,6),(0,7,7),(0,5,9),(0,4,12),(0,0,15),(4,0,14),(6,0,10),(8,0,7),(10,0,3),(12,0,0)]

timezone = GMT_OFFSET * 60 * 60   # change timezone offset to seconds

num = [  # our font for numbers 0-9
  [ 0x38,  # 001110   number 0  
    0x44,  # 010001  
    0x4C,  # 010011  
    0x54,  # 010101  
    0x64,  # 011001  
    0x44,  # 010001  
    0x38,  # 001110  
    0x00], # 000000        
  [ 0x10,  # 000100   number 1  
    0x30,  # 001100  
    0x10,  # 000100  
    0x10,  # 000100  
    0x10,  # 000100  
    0x10,  # 000100  
    0x38,  # 001110  
    0x00], # 000000  
  [ 0x38,  # 001110   number 2   
    0x44,  # 010001  
    0x04,  # 000001  
    0x18,  # 000110  
    0x20,  # 001000  
    0x40,  # 010000  
    0x7C,  # 011111  
    0x00], # 000000  
  [ 0x38,  # 001110   number 3   
    0x44,  # 010001  
    0x04,  # 000001  
    0x38,  # 001110  
    0x04,  # 000001  
    0x44,  # 010001  
    0x38,  # 001110  
    0x00], # 000000  
  [ 0x08,  # 000010   number 4   
    0x18,  # 000110  
    0x28,  # 001010  
    0x48,  # 010010  
    0x7C,  # 011111  
    0x08,  # 000010  
    0x08,  # 000010  
    0x00], # 000000  
  [ 0x7C,  # 011111   number 5   
    0x40,  # 010000  
    0x40,  # 010000  
    0x78,  # 011110  
    0x04,  # 000001  
    0x44,  # 010001  
    0x38,  # 001110  
    0x00], # 000000  
  [ 0x18,  # 000110   number 6   
    0x20,  # 001000  
    0x40,  # 010000  
    0x78,  # 011110  
    0x44,  # 010001  
    0x44,  # 010001  
    0x38,  # 001110  
    0x00], # 000000  
  [ 0x7C,  # 011111   number 7   
    0x04,  # 000001  
    0x08,  # 000010  
    0x10,  # 000100  
    0x20,  # 001000  
    0x20,  # 001000  
    0x20,  # 001000  
    0x00], # 000000  
  [ 0x38,  # 001110   number 8   
    0x44,  # 010001  
    0x44,  # 010001  
    0x38,  # 001110  
    0x44,  # 010001  
    0x44,  # 010001  
    0x38,  # 001110  
    0x00], # 000000  
  [ 0x38,  # 001110   number 9   
    0x44,  # 010001  
    0x44,  # 010001  
    0x3C,  # 001111  
    0x04,  # 000001  
    0x08,  # 000010  
    0x30,  # 001100  
    0x00]  # 000000  
] 

# turn a specific LED at position x,y to off (0) or on (1)
def SetLED(y,x,onOff):
    if (x%2==0):
        LEDnum = 8*x + y
    else:
        LEDnum = 8*x + 7 - y
    if (onOff==1):
        panel[LEDnum] = myColor
    else:
        panel[LEDnum] = black
    # note that we haven't written this change to the panel yet
    

# put numbers onto the display using our font in positions 0-3. 
# positions 0 and 1 are for hours, while 2 and 3 are seconds
def setNum(number, myPos):
    if (myPos==0): pos = 2   # change pos to the real location in the array
    elif (myPos==1): pos = 8
    elif (myPos==2): pos = 18
    elif (myPos==3): pos = 24
    for x in range(0,6):  # now place the digit's 6x8 font on the display
        for y in range(0,8):
            if (x%2==0):  # the LEDs in the strip zigzag up and down across the display
                LEDnum = 8*(x + pos) + y
            else:
                LEDnum = 8*(x + pos) + 7 - y
            if (num[number][y] & (0b01000000 >> x)): 
                panel[LEDnum] = myColor
            else:
                panel[LEDnum] = black
    panel.write()
            
def setColon(onOff):  # turn the colon on (1) or off (0)
  SetLED(2,16,onOff)
  SetLED(1,16,onOff)
  SetLED(5,16,onOff)
  SetLED(4,16,onOff)
  SetLED(2,15,onOff)
  SetLED(1,15,onOff)
  SetLED(5,15,onOff)
  SetLED(4,15,onOff)
  panel.write()
  

# Make panel black
def clearPanel():
    panel.fill(black)   
    panel.write()    


#connect to WiFi and set the RTC
def getNTPtime():
    myWiFi = network.WLAN(network.STA_IF)
    myWiFi.active(True)
    myWiFi.connect(WIFI_NETWORK, WIFI_PASSWORD)
    # this 3 second delay worked 100% of the time for me, but you might need longer.
    time.sleep(3) # wait for connection before trying to set the time
    print()
    print("Connected to", WIFI_NETWORK)
    ntptime.settime()	# this queries the time from an NTP server and sets RTC
    myWiFi.disconnect
    
# program start
getNTPtime() # set the RTC
mytime = time.localtime(time.time() + timezone) # get time from RTC
clearPanel()

# Main loop
while(1):
    myhours = mytime[3] # store the current hour, so it can be converted to 12 hour time
    if myhours>12:  # converting to 12 hour clock; remove these 2 line if you want 24
        myhours= myhours-12  
    myseconds = mytime[5]  # store the current second so we can tell when it changes
    print("The time is", myhours,":", mytime[4], ":", mytime[5])
    if (mytime[5]%5==0): # every 5 seconds rewrite the time in a new color
        myColor = colors[int(mytime[5]/5)] # change color as minute progresses
        digit0 = int(myhours/10) # get the four individual numbers
        digit1 = int(myhours%10)
        digit2 = int(mytime[4]/10)
        digit3 = int(mytime[4]%10)
        setNum(digit0, 0)  # put them onto the display
        setNum(digit1, 1)
        setNum(digit2, 2)
        setNum(digit3, 3)
    setColon(1) # blink the colon on for 1/2 sec
    time.sleep(0.5)
    setColon(0) # blink colon off for the remaining 1/2 sec
    while (mytime[5] == myseconds):  # wait here until the second changes
        mytime = time.localtime(time.time() + timezone)
    if (mytime[3] == 2 and mytime[4] == 2 and mytime[5] == 2): # i.e at 02:02:02 each day
        getNTPtime() # get NTP time again and re-set the RTC
        mytime = time.localtime(time.time() + timezone)

Credits

Doug Domke

Doug Domke

37 projects • 104 followers

Comments