Andreas Motzek
Published © CC BY

Clock and Green Energy Display with Cosmic Unicorn

Get the time and share of renewable energy in power generation at a glance.

BeginnerFull instructions provided1 hour390
Clock and Green Energy Display with Cosmic Unicorn

Things used in this project

Hardware components

Pimoroni Cosmic Unicorn
×1

Software apps and online services

Thonny

Story

Read more

Code

main.py

MicroPython
Fill in your WLAN credentials in lines 6 and 7.
from time import sleep
import network

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
ssid = '...'
password = '...'

def connect_wifi():
    if wlan.isconnected():
        return True
    wlan.connect(ssid, password)
    sleep(15)
    return wlan.isconnected()

def get_data():
    socket, stream = send_request()
    return receive_response(socket, stream)

import usocket
import ussl
import ure
import ujson

service_hostname = 'smard-renewables-service-3hbx73e5ra-ey.a.run.app'

def send_request():
    socket = usocket.socket()
    #
    try:
        socket.connect(usocket.getaddrinfo(service_hostname, 443)[0][-1])
        stream = ussl.wrap_socket(socket)
        stream.write('GET / HTTP/1.0\r\n')
        stream.write('Host: ')
        stream.write(service_hostname)
        stream.write('\r\n')
        stream.write('\r\n')
        return socket, stream
    except:
        socket.close()
        raise

def read_line(stream):
    return str(stream.readline(), 'ascii')

def receive_response(socket, stream):
    try:
        local_time = None
        line = read_line(stream)
        while len(line) > 2:
            line = read_line(stream)
            local_time = local_time or parse_local_time(line)
        share_renewables = parse_share_renewables(stream)
        return local_time, share_renewables
    finally:
        stream.close()
        socket.close()

offset_by_day_of_week = {'Mon': 6, 'Tue': 5, 'Wed': 4, 'Thu': 3, 'Fri': 2, 'Sat': 1, 'Sun': 0}

def last_sunday(day_of_week, day):
    offset = offset_by_day_of_week[day_of_week]
    last_sun = day + offset
    while last_sun <= 31:
        last_sun += 7
    return last_sun - 7

def is_daylight_saving(day_of_week, day, month, hour):
    if month in ('Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'):
        return True
    if month in ('Jan', 'Feb', 'Nov', 'Dec'):
        return False
    last_sun = last_sunday(day_of_week, day)
    if day < last_sun:
        return month == 'Oct'
    if day > last_sun:
        return month == 'Mar'
    return (hour > 1) == (month == 'Mar')

regexp = ure.compile('Date: (Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0-9]+) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]+) ([0-9]+):([0-9]+):([0-9]+) GMT')

def parse_local_time(line):
    match = regexp.match(line)
    if match is not None:
        day_of_week = match.group(1)
        day = int(match.group(2))
        month = match.group(3)
        hour = int(match.group(5))
        minute = int(match.group(6))
        hour += 2 if is_daylight_saving(day_of_week, day, month, hour) else 1
        return (hour, minute)
    return None

def parse_share_renewables(stream):
    payload = ujson.loads(read_line(stream))
    value = payload['Share Renewables']
    return None if value is None else int(100 * value)

import uos
from cosmic import CosmicUnicorn
from picographics import PicoGraphics, DISPLAY_COSMIC_UNICORN

board = CosmicUnicorn()
board.set_brightness(0.3)
graphics = PicoGraphics(DISPLAY_COSMIC_UNICORN)
graphics.set_font('bitmap6')
colors = [(255, 0, 0), (220, 220, 0), (0, 255, 0), (0, 0, 255)]

def display_data(data):
    display_clear()
    message = create_message(data)
    if len(message) > 0:
        position = random_position(message)
        color = random_color()
        display_message(position, color, message)
    display_update()

def display_clear():
    pen = graphics.create_pen(0, 0, 0)
    graphics.set_pen(pen)
    graphics.clear()

def create_message(data):
    local_time, share_renewables = data
    message = []
    if local_time is not None:
        hour, minute = local_time
        line = str(hour)
        line += ':'
        if minute < 10:
            line += '0'
        line += str(minute)
        message.append(line)
    if share_renewables is not None:
        message.append(str(share_renewables) + '%')
    return message

def random_position(message):
    message_width = 0
    for line in message:
        line_width = graphics.measure_text(line, 1)
        if line_width > message_width:
            message_width = line_width
    position = (randint(0, CosmicUnicorn.WIDTH - message_width), randint(0, CosmicUnicorn.HEIGHT - 6 * len(message)))
    return position

def random_color():
    return colors[randint(0, len(colors) - 1)]

def randint(low, high):
    s = 0
    bs = uos.urandom(4)
    for b in bs:
        s = (s << 8) | b
    return low + (s % (high - low + 1))

def display_message(position, color, message):
    x, y = position
    r, g, b = color
    pen = graphics.create_pen(r, g, b)
    graphics.set_pen(pen)
    for line in message:
        graphics.text(line, x, y, -1, 1)
        y += 6

def display_update():
    board.update(graphics)

while True:
    try:
        print('connect')
        if connect_wifi():
            while True:
                print('get data')
                data = get_data()
                print('display data')
                display_data(data)
                sleep(60)
    except:
        pass
    sleep(30)

Credits

Andreas Motzek

Andreas Motzek

16 projects • 9 followers
I love mathematics and computer science. I work for an international consulting company.

Comments