t
This commit is contained in:
@@ -1 +1 @@
|
||||
# Placeholder
|
||||
# Placeholder
|
||||
|
146
clock/c_back.py
146
clock/c_back.py
@@ -1,73 +1,73 @@
|
||||
import numpy as np
|
||||
import datetime
|
||||
|
||||
from . import helpers
|
||||
|
||||
class ClockBackend:
|
||||
"""Heavy lifting of matrix operations"""
|
||||
def __init__(self):
|
||||
self.MOP = helpers.computations.MatrixOperations()
|
||||
|
||||
self.weather = {"weather":"", "high":"", "low":""}
|
||||
self.weather_raw = {}
|
||||
self.weather_face_swap = False
|
||||
|
||||
|
||||
def start(self):
|
||||
self.out = self.modules["broadcast"]
|
||||
helpers.timer.RepeatedTimer(15, self.clock_loop)
|
||||
|
||||
|
||||
def clock_loop(self):
|
||||
t = int(datetime.datetime.now().strftime("%H%M"))
|
||||
|
||||
if t % 5 == 0:
|
||||
# switch secondary face every 5 minutes
|
||||
weather = self.modules["bot"].api_weather.show_weather([47.3769, 8.5417]) # zürich
|
||||
|
||||
if weather != self.weather_raw and len(weather) != 0:
|
||||
td = weather[1]
|
||||
low = td["temps"][0]
|
||||
high = td["temps"][1]
|
||||
self.weather["weather"] = td["short"]
|
||||
self.weather["high"] = high
|
||||
self.weather["low"] = low
|
||||
elif len(weather) == 0:
|
||||
self.weather["weather"] = "error"
|
||||
self.weather["high"] = "error"
|
||||
self.weather["low"] = "error"
|
||||
|
||||
self.weather_face_swap = not self.weather_face_swap
|
||||
|
||||
self.send_face()
|
||||
|
||||
|
||||
|
||||
|
||||
def send_face(self):
|
||||
"""Set the clock face (time + weather) by getting updated info - gets called every minute"""
|
||||
matrices = self.MOP.clock_face(self.weather)
|
||||
if self.weather_face_swap:
|
||||
matrices = [matrices[0], matrices[2], matrices[1]]
|
||||
|
||||
matrices = [m.tolist() for m in matrices]
|
||||
self.out.queue.append({"matrices" : matrices})
|
||||
|
||||
|
||||
|
||||
|
||||
# def text_scroll(self, text, color=[[200,200,200]]):
|
||||
# pixels = self.MOP.text_converter(text, 12, color)
|
||||
# sleep_time = 1 / self.tspeed
|
||||
# width = self.shape[1]
|
||||
# frames = pixels.shape[1] - width
|
||||
# if frames <= 0:
|
||||
# frames = 1
|
||||
|
||||
# for i in range(frames):
|
||||
# visible = pixels[:,i:width+i]
|
||||
# self.IO.put(visible*self.brightness)
|
||||
# time.sleep(sleep_time)
|
||||
# time.sleep(10 * sleep_time)
|
||||
|
||||
|
||||
import numpy as np
|
||||
import datetime
|
||||
|
||||
from . import helpers
|
||||
|
||||
class ClockBackend:
|
||||
"""Heavy lifting of matrix operations"""
|
||||
def __init__(self):
|
||||
self.MOP = helpers.computations.MatrixOperations()
|
||||
|
||||
self.weather = {"weather":"", "high":"", "low":""}
|
||||
self.weather_raw = {}
|
||||
self.weather_face_swap = False
|
||||
|
||||
|
||||
def start(self):
|
||||
self.out = self.modules["broadcast"]
|
||||
helpers.timer.RepeatedTimer(15, self.clock_loop)
|
||||
|
||||
|
||||
def clock_loop(self):
|
||||
t = int(datetime.datetime.now().strftime("%H%M"))
|
||||
|
||||
if t % 5 == 0:
|
||||
# switch secondary face every 5 minutes
|
||||
weather = self.modules["bot"].api_weather.show_weather([47.3769, 8.5417]) # zürich
|
||||
|
||||
if weather != self.weather_raw and len(weather) != 0:
|
||||
td = weather[1]
|
||||
low = td["temps"][0]
|
||||
high = td["temps"][1]
|
||||
self.weather["weather"] = td["short"]
|
||||
self.weather["high"] = high
|
||||
self.weather["low"] = low
|
||||
elif len(weather) == 0:
|
||||
self.weather["weather"] = "error"
|
||||
self.weather["high"] = "error"
|
||||
self.weather["low"] = "error"
|
||||
|
||||
self.weather_face_swap = not self.weather_face_swap
|
||||
|
||||
self.send_face()
|
||||
|
||||
|
||||
|
||||
|
||||
def send_face(self):
|
||||
"""Set the clock face (time + weather) by getting updated info - gets called every minute"""
|
||||
matrices = self.MOP.clock_face(self.weather)
|
||||
if self.weather_face_swap:
|
||||
matrices = [matrices[0], matrices[2], matrices[1]]
|
||||
|
||||
matrices = [m.tolist() for m in matrices]
|
||||
self.out.queue.append({"matrices" : matrices})
|
||||
|
||||
|
||||
|
||||
|
||||
# def text_scroll(self, text, color=[[200,200,200]]):
|
||||
# pixels = self.MOP.text_converter(text, 12, color)
|
||||
# sleep_time = 1 / self.tspeed
|
||||
# width = self.shape[1]
|
||||
# frames = pixels.shape[1] - width
|
||||
# if frames <= 0:
|
||||
# frames = 1
|
||||
|
||||
# for i in range(frames):
|
||||
# visible = pixels[:,i:width+i]
|
||||
# self.IO.put(visible*self.brightness)
|
||||
# time.sleep(sleep_time)
|
||||
# time.sleep(10 * sleep_time)
|
||||
|
||||
|
||||
|
112
clock/c_in.py
112
clock/c_in.py
@@ -1,56 +1,56 @@
|
||||
import datetime
|
||||
import time
|
||||
from threading import Thread, Timer
|
||||
|
||||
from . import hardware, helpers
|
||||
|
||||
|
||||
class SensorReadout:
|
||||
"""Overview class for (actual and potential) sensor sources"""
|
||||
|
||||
def __init__(self):
|
||||
""""""
|
||||
self.sensor_modules = { # we already call them, they are objects and not classes anymore
|
||||
"temperature" : hardware.sensors.TemperatureModule(),
|
||||
"humidity" : hardware.sensors.HumidityModule(),
|
||||
"luminosity" : hardware.sensors.BrightnessModule(),
|
||||
# more to come?
|
||||
}
|
||||
|
||||
def start(self):
|
||||
helpers.timer.RepeatedTimer(300, self.spread_measure)
|
||||
|
||||
def spread_measure(self):
|
||||
measurements = dict((el,[]) for el in self.sensor_modules.keys())
|
||||
# create an empty dict with a list for each readout-type
|
||||
|
||||
for _ in range(5): # number of measures to average out
|
||||
for name in self.sensor_modules.keys():
|
||||
measure = self.sensor_modules[name].readout()
|
||||
measurements[name].append(measure)
|
||||
time.sleep(3)
|
||||
|
||||
results = {}
|
||||
for e in measurements.keys():
|
||||
lst = measurements[e]
|
||||
results[e] = int(sum(lst) / len(lst))
|
||||
|
||||
self.save_results(**results)
|
||||
|
||||
|
||||
# def save_results(self, results):
|
||||
# current_minute = int(datetime.datetime.now().timestamp() // 60)
|
||||
|
||||
# self.persistence["clock"]["sensors"]["time"] += [current_minute]
|
||||
|
||||
# for name in results.keys():
|
||||
# keep_value = sum(results[name]) / len(results[name])
|
||||
# self.persistence["clock"]["sensors"][name] += [keep_value]
|
||||
|
||||
|
||||
def save_results(self, **results):
|
||||
data = self.db.sensors(
|
||||
time=datetime.datetime.now(),
|
||||
**results,
|
||||
)
|
||||
data.save()
|
||||
import datetime
|
||||
import time
|
||||
from threading import Thread, Timer
|
||||
|
||||
from . import hardware, helpers
|
||||
|
||||
|
||||
class SensorReadout:
|
||||
"""Overview class for (actual and potential) sensor sources"""
|
||||
|
||||
def __init__(self):
|
||||
""""""
|
||||
self.sensor_modules = { # we already call them, they are objects and not classes anymore
|
||||
"temperature" : hardware.sensors.TemperatureModule(),
|
||||
"humidity" : hardware.sensors.HumidityModule(),
|
||||
"luminosity" : hardware.sensors.BrightnessModule(),
|
||||
# more to come?
|
||||
}
|
||||
|
||||
def start(self):
|
||||
helpers.timer.RepeatedTimer(300, self.spread_measure)
|
||||
|
||||
def spread_measure(self):
|
||||
measurements = dict((el,[]) for el in self.sensor_modules.keys())
|
||||
# create an empty dict with a list for each readout-type
|
||||
|
||||
for _ in range(5): # number of measures to average out
|
||||
for name in self.sensor_modules.keys():
|
||||
measure = self.sensor_modules[name].readout()
|
||||
measurements[name].append(measure)
|
||||
time.sleep(3)
|
||||
|
||||
results = {}
|
||||
for e in measurements.keys():
|
||||
lst = measurements[e]
|
||||
results[e] = int(sum(lst) / len(lst))
|
||||
|
||||
self.save_results(**results)
|
||||
|
||||
|
||||
# def save_results(self, results):
|
||||
# current_minute = int(datetime.datetime.now().timestamp() // 60)
|
||||
|
||||
# self.persistence["clock"]["sensors"]["time"] += [current_minute]
|
||||
|
||||
# for name in results.keys():
|
||||
# keep_value = sum(results[name]) / len(results[name])
|
||||
# self.persistence["clock"]["sensors"][name] += [keep_value]
|
||||
|
||||
|
||||
def save_results(self, **results):
|
||||
data = self.db.sensors(
|
||||
time=datetime.datetime.now(),
|
||||
**results,
|
||||
)
|
||||
data.save()
|
||||
|
130
clock/c_out.py
130
clock/c_out.py
@@ -1,65 +1,65 @@
|
||||
import datetime
|
||||
import time
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
|
||||
from . import hardware, helpers
|
||||
|
||||
|
||||
class ClockFace:
|
||||
"""Actual functions one might need for a clock"""
|
||||
|
||||
def __init__(self):
|
||||
""""""
|
||||
# added by the launcher, we have self.modules (dict)
|
||||
|
||||
self.IO = hardware.led.get_handler()
|
||||
self.shape = self.IO.shape # (16,32) for now
|
||||
# TODO handle differently!
|
||||
self.MOP = helpers.computations.MatrixOperations()
|
||||
|
||||
self.kill_output = False
|
||||
|
||||
def start(self):
|
||||
Thread(target = self.clock_loop).start()
|
||||
|
||||
|
||||
def clock_loop(self):
|
||||
while True: # TODO: allow this to be exited gracefully
|
||||
|
||||
t_start = datetime.datetime.now()
|
||||
|
||||
self.set_brightness()
|
||||
|
||||
has_queue, data = self.modules["receive"].fetch_data()
|
||||
tnext = 1 if has_queue else 30
|
||||
|
||||
if data == {}:
|
||||
matrices = self.MOP.get_fallback()
|
||||
matrices[0][0,0] = [255, 0, 0] # red dot on the top left
|
||||
else:
|
||||
matrices = [np.asarray(d).astype(int) for d in data["matrices"]]
|
||||
matrices[0][0,0] = [0, 255, 0] # green dot on the top left
|
||||
|
||||
if not self.kill_output:
|
||||
self.IO.put(matrices)
|
||||
else:
|
||||
z = np.zeros((16,16,3))
|
||||
self.IO.put([z,z,z])
|
||||
|
||||
|
||||
t_end = datetime.datetime.now()
|
||||
delta_planned = datetime.timedelta(seconds = tnext)
|
||||
delta = delta_planned - (t_end - t_start)
|
||||
|
||||
time.sleep(max(delta.total_seconds(), 0))
|
||||
|
||||
|
||||
def set_brightness(self):
|
||||
"""Kill the brightness at night"""
|
||||
|
||||
is_WE = datetime.datetime.now().weekday() > 4
|
||||
now = int(datetime.datetime.now().strftime("%H%M"))
|
||||
|
||||
self.kill_output = (now < 1000 or now > 2200) if is_WE else (now < 830 or now > 2130)
|
||||
|
||||
import datetime
|
||||
import time
|
||||
from threading import Thread
|
||||
import numpy as np
|
||||
|
||||
from . import hardware, helpers
|
||||
|
||||
|
||||
class ClockFace:
|
||||
"""Actual functions one might need for a clock"""
|
||||
|
||||
def __init__(self):
|
||||
""""""
|
||||
# added by the launcher, we have self.modules (dict)
|
||||
|
||||
self.IO = hardware.led.get_handler()
|
||||
self.shape = self.IO.shape # (16,32) for now
|
||||
# TODO handle differently!
|
||||
self.MOP = helpers.computations.MatrixOperations()
|
||||
|
||||
self.kill_output = False
|
||||
|
||||
def start(self):
|
||||
Thread(target = self.clock_loop).start()
|
||||
|
||||
|
||||
def clock_loop(self):
|
||||
while True: # TODO: allow this to be exited gracefully
|
||||
|
||||
t_start = datetime.datetime.now()
|
||||
|
||||
self.set_brightness()
|
||||
|
||||
has_queue, data = self.modules["receive"].fetch_data()
|
||||
tnext = 1 if has_queue else 30
|
||||
|
||||
if data == {}:
|
||||
matrices = self.MOP.get_fallback()
|
||||
matrices[0][0,0] = [255, 0, 0] # red dot on the top left
|
||||
else:
|
||||
matrices = [np.asarray(d).astype(int) for d in data["matrices"]]
|
||||
matrices[0][0,0] = [0, 255, 0] # green dot on the top left
|
||||
|
||||
if not self.kill_output:
|
||||
self.IO.put(matrices)
|
||||
else:
|
||||
z = np.zeros((16,16,3))
|
||||
self.IO.put([z,z,z])
|
||||
|
||||
|
||||
t_end = datetime.datetime.now()
|
||||
delta_planned = datetime.timedelta(seconds = tnext)
|
||||
delta = delta_planned - (t_end - t_start)
|
||||
|
||||
time.sleep(max(delta.total_seconds(), 0))
|
||||
|
||||
|
||||
def set_brightness(self):
|
||||
"""Kill the brightness at night"""
|
||||
|
||||
is_WE = datetime.datetime.now().weekday() > 4
|
||||
now = int(datetime.datetime.now().strftime("%H%M"))
|
||||
|
||||
self.kill_output = (now < 1000 or now > 2200) if is_WE else (now < 830 or now > 2130)
|
||||
|
||||
|
@@ -1,2 +1,2 @@
|
||||
# Placeholder
|
||||
# Placeholder
|
||||
from . import led, sensors
|
@@ -1,17 +1,17 @@
|
||||
from . import unicorn as led
|
||||
# or neopixel soon:
|
||||
# from . import neopixel as led
|
||||
|
||||
def get_handler():
|
||||
OUT = led.ClockOut()
|
||||
shape = OUT.shape
|
||||
|
||||
if led.SETUP_FAIL:
|
||||
# we use the sim
|
||||
del OUT
|
||||
from . import sim
|
||||
OUT = sim.ClockOut(shape)
|
||||
|
||||
return OUT
|
||||
|
||||
|
||||
from . import unicorn as led
|
||||
# or neopixel soon:
|
||||
# from . import neopixel as led
|
||||
|
||||
def get_handler():
|
||||
OUT = led.ClockOut()
|
||||
shape = OUT.shape
|
||||
|
||||
if led.SETUP_FAIL:
|
||||
# we use the sim
|
||||
del OUT
|
||||
from . import sim
|
||||
OUT = sim.ClockOut(shape)
|
||||
|
||||
return OUT
|
||||
|
||||
|
||||
|
@@ -1,51 +1,51 @@
|
||||
import time
|
||||
import numpy as np
|
||||
import colorsys
|
||||
import random
|
||||
|
||||
try:
|
||||
import rpi_ws281x as ws
|
||||
except ImportError:
|
||||
from unittest.mock import Mock
|
||||
ws = Mock()
|
||||
SETUP_FAIL = True
|
||||
|
||||
|
||||
class ClockOut:
|
||||
def __init__(self):
|
||||
self.shape = (45, 20) # H x W
|
||||
num = self.shape[0] * self.shape[1]
|
||||
pin = 18
|
||||
freq = 800000 # maybe higher
|
||||
dma = 5
|
||||
invert = False
|
||||
brightness = 100
|
||||
channel = 0
|
||||
led_type = None # ??
|
||||
self.strip = ws.PixelStrip(num, pin, freq, dma, invert, brightness, channel, led_type)
|
||||
self.strip.begin()
|
||||
|
||||
|
||||
def put(self, matrix):
|
||||
self.render(matrix)
|
||||
|
||||
|
||||
def render(self, matrix):
|
||||
p = 0
|
||||
for i in range(matrix.shape[0]):
|
||||
for j in range(matrix.shape[1]):
|
||||
col = int(ws.Color(*matrix[i,j]))
|
||||
|
||||
self.strip.setPixelColor(p, col)
|
||||
p += 1
|
||||
self.strip.show()
|
||||
|
||||
|
||||
# test = ClockOut()
|
||||
# z = np.zeros((30,30, 3), dtype=int)
|
||||
# for i in range(30):
|
||||
# for j in range(30):
|
||||
# z[i, j, ...] = [random.randint(0,255), random.randint(0,255), random.randint(0,255)]
|
||||
# test.put(z)
|
||||
# #time.sleep(0.1)
|
||||
|
||||
import time
|
||||
import numpy as np
|
||||
import colorsys
|
||||
import random
|
||||
|
||||
try:
|
||||
import rpi_ws281x as ws
|
||||
except ImportError:
|
||||
from unittest.mock import Mock
|
||||
ws = Mock()
|
||||
SETUP_FAIL = True
|
||||
|
||||
|
||||
class ClockOut:
|
||||
def __init__(self):
|
||||
self.shape = (45, 20) # H x W
|
||||
num = self.shape[0] * self.shape[1]
|
||||
pin = 18
|
||||
freq = 800000 # maybe higher
|
||||
dma = 5
|
||||
invert = False
|
||||
brightness = 100
|
||||
channel = 0
|
||||
led_type = None # ??
|
||||
self.strip = ws.PixelStrip(num, pin, freq, dma, invert, brightness, channel, led_type)
|
||||
self.strip.begin()
|
||||
|
||||
|
||||
def put(self, matrix):
|
||||
self.render(matrix)
|
||||
|
||||
|
||||
def render(self, matrix):
|
||||
p = 0
|
||||
for i in range(matrix.shape[0]):
|
||||
for j in range(matrix.shape[1]):
|
||||
col = int(ws.Color(*matrix[i,j]))
|
||||
|
||||
self.strip.setPixelColor(p, col)
|
||||
p += 1
|
||||
self.strip.show()
|
||||
|
||||
|
||||
# test = ClockOut()
|
||||
# z = np.zeros((30,30, 3), dtype=int)
|
||||
# for i in range(30):
|
||||
# for j in range(30):
|
||||
# z[i, j, ...] = [random.randint(0,255), random.randint(0,255), random.randint(0,255)]
|
||||
# test.put(z)
|
||||
# #time.sleep(0.1)
|
||||
|
||||
|
@@ -1,87 +1,87 @@
|
||||
import time
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class TempSim:
|
||||
"""Simulates a temperature for running on windows"""
|
||||
temperature = 23 # return a celsius value
|
||||
humidity = 30
|
||||
|
||||
|
||||
class LightSim:
|
||||
def input(self, *args):
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
|
||||
class SensorModule:
|
||||
def __init__(self):
|
||||
logger.info("Using module " + self.__class__.__name__)
|
||||
|
||||
|
||||
|
||||
## Real sensors!
|
||||
try:
|
||||
import board
|
||||
import adafruit_dht
|
||||
dht11 = adafruit_dht.DHT11(board.D18)
|
||||
import RPi.GPIO as GPIO
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(4, GPIO.IN)
|
||||
except ImportError:
|
||||
logger.warn("Simulating sensor modules")
|
||||
dht11 = TempSim()
|
||||
GPIO = LightSim()
|
||||
|
||||
|
||||
class TemperatureModule(SensorModule):
|
||||
"""Takes readouts from the DHT 11
|
||||
Returns: temperature"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.device = dht11
|
||||
|
||||
def readout(self):
|
||||
try:
|
||||
temp = self.device.temperature
|
||||
except:
|
||||
time.sleep(1)
|
||||
try:
|
||||
temp = self.device.temperature
|
||||
except:
|
||||
temp = -1
|
||||
|
||||
return temp
|
||||
|
||||
class HumidityModule(SensorModule):
|
||||
"""Takes readouts from the DHT 11
|
||||
Returns: humidity"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.device = dht11
|
||||
|
||||
def readout(self):
|
||||
try:
|
||||
hum = self.device.humidity
|
||||
except:
|
||||
time.sleep(1)
|
||||
try:
|
||||
hum = self.device.humidity
|
||||
except:
|
||||
hum = -1
|
||||
|
||||
return hum
|
||||
|
||||
class BrightnessModule(SensorModule):
|
||||
"""Returns one for HIGH and zero for LOW"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def readout(self):
|
||||
# The sensor is reversed: 0 when bright and 1 if dark
|
||||
light = GPIO.input(4)
|
||||
if light == 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
import time
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class TempSim:
|
||||
"""Simulates a temperature for running on windows"""
|
||||
temperature = 23 # return a celsius value
|
||||
humidity = 30
|
||||
|
||||
|
||||
class LightSim:
|
||||
def input(self, *args):
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
|
||||
class SensorModule:
|
||||
def __init__(self):
|
||||
logger.info("Using module " + self.__class__.__name__)
|
||||
|
||||
|
||||
|
||||
## Real sensors!
|
||||
try:
|
||||
import board
|
||||
import adafruit_dht
|
||||
dht11 = adafruit_dht.DHT11(board.D18)
|
||||
import RPi.GPIO as GPIO
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(4, GPIO.IN)
|
||||
except ImportError:
|
||||
logger.warn("Simulating sensor modules")
|
||||
dht11 = TempSim()
|
||||
GPIO = LightSim()
|
||||
|
||||
|
||||
class TemperatureModule(SensorModule):
|
||||
"""Takes readouts from the DHT 11
|
||||
Returns: temperature"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.device = dht11
|
||||
|
||||
def readout(self):
|
||||
try:
|
||||
temp = self.device.temperature
|
||||
except:
|
||||
time.sleep(1)
|
||||
try:
|
||||
temp = self.device.temperature
|
||||
except:
|
||||
temp = -1
|
||||
|
||||
return temp
|
||||
|
||||
class HumidityModule(SensorModule):
|
||||
"""Takes readouts from the DHT 11
|
||||
Returns: humidity"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.device = dht11
|
||||
|
||||
def readout(self):
|
||||
try:
|
||||
hum = self.device.humidity
|
||||
except:
|
||||
time.sleep(1)
|
||||
try:
|
||||
hum = self.device.humidity
|
||||
except:
|
||||
hum = -1
|
||||
|
||||
return hum
|
||||
|
||||
class BrightnessModule(SensorModule):
|
||||
"""Returns one for HIGH and zero for LOW"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def readout(self):
|
||||
# The sensor is reversed: 0 when bright and 1 if dark
|
||||
light = GPIO.input(4)
|
||||
if light == 0:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
@@ -1,55 +1,55 @@
|
||||
import sys
|
||||
import colorsys
|
||||
import pygame.gfxdraw
|
||||
import time
|
||||
import pygame
|
||||
import numpy as np
|
||||
|
||||
class ClockOut:
|
||||
"""Creates a drawable window in case the real hardware is not accessible. For development"""
|
||||
def __init__(self, shape):
|
||||
self.pixel_size = 20
|
||||
|
||||
self.shape = shape
|
||||
self.pixels = np.zeros((*shape,3), dtype=int)
|
||||
self.WIDTH = shape[1]
|
||||
self.HEIGHT = shape[0]
|
||||
self.window_width = self.WIDTH * self.pixel_size
|
||||
self.window_height = self.HEIGHT * self.pixel_size
|
||||
|
||||
pygame.init()
|
||||
pygame.display.set_caption("Unicorn HAT simulator")
|
||||
self.screen = pygame.display.set_mode([self.window_width, self.window_height])
|
||||
|
||||
|
||||
def put(self, matrices):
|
||||
self.screen.fill((0, 0, 0))
|
||||
for event in pygame.event.get(): # User did something
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
if self.shape == (16, 32):
|
||||
matrix = np.concatenate((matrices[0], matrices[1]), axis=1)
|
||||
|
||||
self.pixels = matrix
|
||||
self.draw_pixels()
|
||||
|
||||
pygame.display.flip()
|
||||
pygame.event.pump()
|
||||
|
||||
|
||||
def draw_pixels(self):
|
||||
p = self.pixel_size
|
||||
|
||||
r = int(p / 4)
|
||||
for i in range(self.HEIGHT):
|
||||
for j in range(self.WIDTH):
|
||||
w_x = int(j * p + p / 2)
|
||||
#w_y = int((self.HEIGHT - 1 - y) * p + p / 2)
|
||||
w_y = int(i * p + p / 2)
|
||||
color = self.pixels[i,j,:]
|
||||
color = color.astype("int")
|
||||
|
||||
pygame.gfxdraw.aacircle(self.screen, w_x, w_y, r, color)
|
||||
pygame.gfxdraw.filled_circle(self.screen, w_x, w_y, r, color)
|
||||
import sys
|
||||
import colorsys
|
||||
import pygame.gfxdraw
|
||||
import time
|
||||
import pygame
|
||||
import numpy as np
|
||||
|
||||
class ClockOut:
|
||||
"""Creates a drawable window in case the real hardware is not accessible. For development"""
|
||||
def __init__(self, shape):
|
||||
self.pixel_size = 20
|
||||
|
||||
self.shape = shape
|
||||
self.pixels = np.zeros((*shape,3), dtype=int)
|
||||
self.WIDTH = shape[1]
|
||||
self.HEIGHT = shape[0]
|
||||
self.window_width = self.WIDTH * self.pixel_size
|
||||
self.window_height = self.HEIGHT * self.pixel_size
|
||||
|
||||
pygame.init()
|
||||
pygame.display.set_caption("Unicorn HAT simulator")
|
||||
self.screen = pygame.display.set_mode([self.window_width, self.window_height])
|
||||
|
||||
|
||||
def put(self, matrices):
|
||||
self.screen.fill((0, 0, 0))
|
||||
for event in pygame.event.get(): # User did something
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
if self.shape == (16, 32):
|
||||
matrix = np.concatenate((matrices[0], matrices[1]), axis=1)
|
||||
|
||||
self.pixels = matrix
|
||||
self.draw_pixels()
|
||||
|
||||
pygame.display.flip()
|
||||
pygame.event.pump()
|
||||
|
||||
|
||||
def draw_pixels(self):
|
||||
p = self.pixel_size
|
||||
|
||||
r = int(p / 4)
|
||||
for i in range(self.HEIGHT):
|
||||
for j in range(self.WIDTH):
|
||||
w_x = int(j * p + p / 2)
|
||||
#w_y = int((self.HEIGHT - 1 - y) * p + p / 2)
|
||||
w_y = int(i * p + p / 2)
|
||||
color = self.pixels[i,j,:]
|
||||
color = color.astype("int")
|
||||
|
||||
pygame.gfxdraw.aacircle(self.screen, w_x, w_y, r, color)
|
||||
pygame.gfxdraw.filled_circle(self.screen, w_x, w_y, r, color)
|
||||
|
@@ -1,96 +1,96 @@
|
||||
import colorsys
|
||||
import time
|
||||
import numpy as np
|
||||
try:
|
||||
import RPi.GPIO as GPIO
|
||||
SETUP_FAIL = False
|
||||
except ImportError:
|
||||
from unittest.mock import Mock
|
||||
GPIO = Mock()
|
||||
SETUP_FAIL = True
|
||||
|
||||
|
||||
class ClockOut:
|
||||
def __init__(self):
|
||||
self.PIN_CLK = 11
|
||||
##################################
|
||||
# Hardcoded vaules:
|
||||
# GPIO Pins for the actual signal. The other ones are for signal clocks and resets.
|
||||
self.PINS_DAT = [10, 22]
|
||||
self.PIN_CS = 8
|
||||
# for data transmission
|
||||
self.SOF = 0x72
|
||||
self.DELAY = 1.0/120
|
||||
# shape of 2 unicorn hats
|
||||
self.shape = (16, 32)
|
||||
##################################
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
GPIO.setup(self.PIN_CS, GPIO.OUT, initial=GPIO.HIGH)
|
||||
GPIO.setup(self.PIN_CLK, GPIO.OUT, initial=GPIO.LOW)
|
||||
GPIO.setup(self.PINS_DAT, GPIO.OUT, initial=GPIO.LOW)
|
||||
|
||||
self.HEIGHT = self.shape[0] #16
|
||||
self.WIDTH = self.shape[1] #32
|
||||
|
||||
self.reset_clock()
|
||||
|
||||
|
||||
def reset_clock(self):
|
||||
GPIO.output(self.PIN_CS, GPIO.LOW)
|
||||
time.sleep(0.00001)
|
||||
GPIO.output(self.PIN_CS, GPIO.HIGH)
|
||||
|
||||
|
||||
def spi_write(self, buf1, buf2):
|
||||
GPIO.output(self.PIN_CS, GPIO.LOW)
|
||||
|
||||
self.spi_write_byte(self.SOF, self.SOF)
|
||||
|
||||
for x in range(len(buf1)):
|
||||
b1, b2= buf1[x], buf2[x]
|
||||
self.spi_write_byte(b1, b2)
|
||||
|
||||
|
||||
GPIO.output(self.PIN_CS, GPIO.HIGH)
|
||||
|
||||
|
||||
def spi_write_byte(self, b1, b2):
|
||||
for x in range(8):
|
||||
GPIO.output(self.PINS_DAT[0], b1 & 0b10000000)
|
||||
GPIO.output(self.PINS_DAT[1], b2 & 0b10000000)
|
||||
GPIO.output(self.PIN_CLK, GPIO.HIGH)
|
||||
|
||||
b1 <<= 1
|
||||
b2 <<= 1
|
||||
#time.sleep(0.00000001)
|
||||
GPIO.output(self.PIN_CLK, GPIO.LOW)
|
||||
|
||||
|
||||
def put(self, matrices):
|
||||
"""Sets a height x width matrix directly"""
|
||||
self.reset_clock()
|
||||
matrix = np.concatenate((matrices[0], matrices[1]), axis=1) # or 1??
|
||||
self.show(matrix)
|
||||
|
||||
|
||||
def clear(self):
|
||||
"""Clear the buffer."""
|
||||
zero = np.zero((self.HEIGHT, self. WIDTH))
|
||||
self.put(zero)
|
||||
|
||||
|
||||
def show(self, matrix):
|
||||
"""Output the contents of the buffer to Unicorn HAT HD."""
|
||||
##########################################################
|
||||
## Change to desire
|
||||
buff2 = np.rot90(matrix[:self.HEIGHT,:16],3)
|
||||
buff1 = np.rot90(matrix[:self.HEIGHT,16:32],1)
|
||||
##########################################################
|
||||
# separated these are: 16x16x3 arrays
|
||||
buff1, buff2 = [(x.reshape(768)).astype(np.uint8).tolist() for x in (buff1, buff2)]
|
||||
|
||||
self.spi_write(buff1, buff2)
|
||||
|
||||
time.sleep(self.DELAY)
|
||||
import colorsys
|
||||
import time
|
||||
import numpy as np
|
||||
try:
|
||||
import RPi.GPIO as GPIO
|
||||
SETUP_FAIL = False
|
||||
except ImportError:
|
||||
from unittest.mock import Mock
|
||||
GPIO = Mock()
|
||||
SETUP_FAIL = True
|
||||
|
||||
|
||||
class ClockOut:
|
||||
def __init__(self):
|
||||
self.PIN_CLK = 11
|
||||
##################################
|
||||
# Hardcoded vaules:
|
||||
# GPIO Pins for the actual signal. The other ones are for signal clocks and resets.
|
||||
self.PINS_DAT = [10, 22]
|
||||
self.PIN_CS = 8
|
||||
# for data transmission
|
||||
self.SOF = 0x72
|
||||
self.DELAY = 1.0/120
|
||||
# shape of 2 unicorn hats
|
||||
self.shape = (16, 32)
|
||||
##################################
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
GPIO.setup(self.PIN_CS, GPIO.OUT, initial=GPIO.HIGH)
|
||||
GPIO.setup(self.PIN_CLK, GPIO.OUT, initial=GPIO.LOW)
|
||||
GPIO.setup(self.PINS_DAT, GPIO.OUT, initial=GPIO.LOW)
|
||||
|
||||
self.HEIGHT = self.shape[0] #16
|
||||
self.WIDTH = self.shape[1] #32
|
||||
|
||||
self.reset_clock()
|
||||
|
||||
|
||||
def reset_clock(self):
|
||||
GPIO.output(self.PIN_CS, GPIO.LOW)
|
||||
time.sleep(0.00001)
|
||||
GPIO.output(self.PIN_CS, GPIO.HIGH)
|
||||
|
||||
|
||||
def spi_write(self, buf1, buf2):
|
||||
GPIO.output(self.PIN_CS, GPIO.LOW)
|
||||
|
||||
self.spi_write_byte(self.SOF, self.SOF)
|
||||
|
||||
for x in range(len(buf1)):
|
||||
b1, b2= buf1[x], buf2[x]
|
||||
self.spi_write_byte(b1, b2)
|
||||
|
||||
|
||||
GPIO.output(self.PIN_CS, GPIO.HIGH)
|
||||
|
||||
|
||||
def spi_write_byte(self, b1, b2):
|
||||
for x in range(8):
|
||||
GPIO.output(self.PINS_DAT[0], b1 & 0b10000000)
|
||||
GPIO.output(self.PINS_DAT[1], b2 & 0b10000000)
|
||||
GPIO.output(self.PIN_CLK, GPIO.HIGH)
|
||||
|
||||
b1 <<= 1
|
||||
b2 <<= 1
|
||||
#time.sleep(0.00000001)
|
||||
GPIO.output(self.PIN_CLK, GPIO.LOW)
|
||||
|
||||
|
||||
def put(self, matrices):
|
||||
"""Sets a height x width matrix directly"""
|
||||
self.reset_clock()
|
||||
matrix = np.concatenate((matrices[0], matrices[1]), axis=1) # or 1??
|
||||
self.show(matrix)
|
||||
|
||||
|
||||
def clear(self):
|
||||
"""Clear the buffer."""
|
||||
zero = np.zero((self.HEIGHT, self. WIDTH))
|
||||
self.put(zero)
|
||||
|
||||
|
||||
def show(self, matrix):
|
||||
"""Output the contents of the buffer to Unicorn HAT HD."""
|
||||
##########################################################
|
||||
## Change to desire
|
||||
buff2 = np.rot90(matrix[:self.HEIGHT,:16],3)
|
||||
buff1 = np.rot90(matrix[:self.HEIGHT,16:32],1)
|
||||
##########################################################
|
||||
# separated these are: 16x16x3 arrays
|
||||
buff1, buff2 = [(x.reshape(768)).astype(np.uint8).tolist() for x in (buff1, buff2)]
|
||||
|
||||
self.spi_write(buff1, buff2)
|
||||
|
||||
time.sleep(self.DELAY)
|
||||
|
@@ -1,178 +1,178 @@
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import numpy as np
|
||||
import datetime
|
||||
import time
|
||||
|
||||
# bulky hard-coded values:
|
||||
from . import shapes
|
||||
digits = shapes.digits
|
||||
weather_categories = shapes.weather_categories
|
||||
digit_position = [[2,4], [2,10], [9,4], [9,10]]
|
||||
|
||||
|
||||
days = np.append(np.zeros((15,16)), np.array([0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,1])).reshape((16,16))
|
||||
|
||||
|
||||
|
||||
|
||||
class MatrixOperations():
|
||||
"""Helper functions to generate frequently-used images"""
|
||||
def __init__(self, shape=[16,16]):
|
||||
self.shape = shape
|
||||
# shape is going to be (16,32) for the moment
|
||||
self.primary = [200, 200, 200]
|
||||
self.secondary = [10, 200, 10]
|
||||
self.error = [200, 10, 10]
|
||||
|
||||
|
||||
def time_converter(self, top="", bottom=""):
|
||||
"""Converts 4-digit time to a 16x16 pixel-matrix
|
||||
returns: np.array"""
|
||||
# nshape = (self.shape[0], int(self.shape[1]/2))
|
||||
nshape = (16, 16)
|
||||
pixels = np.zeros(nshape, dtype=np.uint8)
|
||||
|
||||
if bottom == "" or top == "":
|
||||
top = datetime.datetime.now().strftime("%H")
|
||||
bottom = datetime.datetime.now().strftime("%M")
|
||||
|
||||
if len(top) < 2:
|
||||
top = "0" * (2 - len(top)) + top
|
||||
if len(bottom) < 2:
|
||||
bottom = "0" * (2 - len(bottom)) + bottom
|
||||
|
||||
if ("-" in top and len(top) > 2) or ("-" in bottom and len(bottom) > 2):
|
||||
time_split = 4*["-"]
|
||||
elif "error" in top and "error" in bottom:
|
||||
time_split = 4*["error"]
|
||||
else:
|
||||
time_split = [i for i in top] + [i for i in bottom]
|
||||
|
||||
if "-1" in top and len(top) != 2:
|
||||
time_split = ["-1", top[-1]] + [i for i in bottom]
|
||||
if "-1" in bottom and len(bottom) != 2:
|
||||
time_split = [i for i in top] + ["-1", bottom[-1]]
|
||||
|
||||
for i in range(4):
|
||||
x = digit_position[i][0]
|
||||
y = digit_position[i][1]
|
||||
number = digits[time_split[i]]
|
||||
pixels[x: x + 5, y: y + 3] = np.array(number)
|
||||
|
||||
return pixels
|
||||
|
||||
|
||||
def date_converter(self):
|
||||
# nshape = (self.shape[0], int(self.shape[1]/2))
|
||||
nshape = (16, 16)
|
||||
today = datetime.datetime.today()
|
||||
weekday = datetime.datetime.weekday(today)
|
||||
# size of the reduced array according to weekday
|
||||
size = [2,4,6,8,10,13,16]
|
||||
|
||||
pixels = days.copy() #base color background
|
||||
lrow = np.append(pixels[15,:size[weekday]], [0 for i in range(16 - size[weekday])])
|
||||
lrow = np.append(np.zeros((15,16)), lrow).reshape(nshape)
|
||||
pixels += lrow
|
||||
return pixels
|
||||
|
||||
|
||||
def weather_converter(self, name):
|
||||
"""Fills one half of the screen with weather info."""
|
||||
# nshape = (self.shape[0], int(self.shape[1]/2))
|
||||
nshape = (16, 16)
|
||||
result = np.zeros(nshape)
|
||||
cwd = __file__.replace("\\","/") # for windows
|
||||
cwd = cwd.rsplit("/", 1)[0] # the current working directory (where this file is)
|
||||
if len(cwd) == 0:
|
||||
cwd = "."
|
||||
icon_spritesheet = cwd + "/weather-icons.bmp"
|
||||
|
||||
icons = Image.open(icon_spritesheet)
|
||||
icons_full = np.array(icons)
|
||||
|
||||
icon_loc = ["sun","moon","sun and clouds", "moon and clouds", "cloud","fog and clouds","2 clouds", "3 clouds", "rain and cloud", "rain and clouds", "rain and cloud and sun", "rain and cloud and moon", "thunder and cloud", "thunder and cloud and moon", "snow and cloud", "snow and cloud and moon", "fog","fog night"]
|
||||
#ordered 1 2 \n 3 4 \ 5 5 ...
|
||||
if name == "":
|
||||
name = "error"
|
||||
name = weather_categories[name]
|
||||
try:
|
||||
iy, ix = int(icon_loc.index(name)/2), icon_loc.index(name)%2
|
||||
# x and y coords
|
||||
except:
|
||||
return np.zeros((*nshape,3))
|
||||
|
||||
icon_single = icons_full[16*iy:16*(iy + 1),16*ix:16*(ix + 1),...]
|
||||
return icon_single
|
||||
|
||||
|
||||
def matrix_add_depth(self, matrix, colors = []):
|
||||
"""transforms a 2d-array with 0,1,2 to a 3d-array with the rgb values for primary and secondary color"""
|
||||
|
||||
c1 = self.primary
|
||||
c2 = self.secondary
|
||||
c3 = self.error
|
||||
if len(colors) > 0:
|
||||
c1 = colors[0]
|
||||
if len(colors) > 1:
|
||||
c2 = colors[1]
|
||||
if len(colors) > 2:
|
||||
c3 = colors[2]
|
||||
if len(colors) > 3:
|
||||
print("Too many colors")
|
||||
|
||||
r3 = np.zeros((matrix.shape[0],matrix.shape[1],3),dtype=int)
|
||||
for i in range(matrix.shape[0]):
|
||||
for j in range(matrix.shape[1]):
|
||||
t = int(matrix[i, j])
|
||||
if t == 0:
|
||||
r3[i, j, :] = [0,0,0]
|
||||
elif t == 1:
|
||||
r3[i, j, :] = c1
|
||||
elif t == 2:
|
||||
r3[i, j, :] = c2
|
||||
else:
|
||||
r3[i, j, :] = c3
|
||||
return r3
|
||||
|
||||
|
||||
|
||||
def clock_face(self, weather):
|
||||
"""weather as a dict"""
|
||||
hour = self.time_converter()
|
||||
day = self.date_converter()
|
||||
face1 = hour + day
|
||||
# time + date:
|
||||
face1_3d = self.matrix_add_depth(face1)
|
||||
# weather icons
|
||||
face2_3d = self.weather_converter(weather["weather"])
|
||||
# weather temps
|
||||
face3 = self.time_converter(top=str(weather["low"]), bottom=str(weather["high"]))
|
||||
face3 = np.concatenate((face3[:8,...],2*face3[8:,...]))
|
||||
face3_3d = self.matrix_add_depth(face3,[[0, 102, 255],[255, 102, 0]])
|
||||
|
||||
return [face1_3d, face2_3d, face3_3d]
|
||||
|
||||
|
||||
def text_converter(self, text, height, color):
|
||||
"""Converts a text to a pixel-matrix
|
||||
returns: np.array((16, x, 3))"""
|
||||
|
||||
font = ImageFont.truetype("verdanab.ttf", height)
|
||||
size = font.getsize(text)
|
||||
img = Image.new("1",size,"black")
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.text((0, 0), text, "white", font=font)
|
||||
pixels = np.array(img, dtype=np.uint8)
|
||||
pixels3d = self.matrix_add_depth(pixels, color)
|
||||
return pixels3d
|
||||
|
||||
|
||||
def get_fallback(self):
|
||||
hour = self.time_converter()
|
||||
day = self.date_converter()
|
||||
face1 = hour + day
|
||||
face1_3d = self.matrix_add_depth(face1)
|
||||
|
||||
face2_3d = face3_3d = np.zeros((16,16,3))
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import numpy as np
|
||||
import datetime
|
||||
import time
|
||||
|
||||
# bulky hard-coded values:
|
||||
from . import shapes
|
||||
digits = shapes.digits
|
||||
weather_categories = shapes.weather_categories
|
||||
digit_position = [[2,4], [2,10], [9,4], [9,10]]
|
||||
|
||||
|
||||
days = np.append(np.zeros((15,16)), np.array([0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,1])).reshape((16,16))
|
||||
|
||||
|
||||
|
||||
|
||||
class MatrixOperations():
|
||||
"""Helper functions to generate frequently-used images"""
|
||||
def __init__(self, shape=[16,16]):
|
||||
self.shape = shape
|
||||
# shape is going to be (16,32) for the moment
|
||||
self.primary = [200, 200, 200]
|
||||
self.secondary = [10, 200, 10]
|
||||
self.error = [200, 10, 10]
|
||||
|
||||
|
||||
def time_converter(self, top="", bottom=""):
|
||||
"""Converts 4-digit time to a 16x16 pixel-matrix
|
||||
returns: np.array"""
|
||||
# nshape = (self.shape[0], int(self.shape[1]/2))
|
||||
nshape = (16, 16)
|
||||
pixels = np.zeros(nshape, dtype=np.uint8)
|
||||
|
||||
if bottom == "" or top == "":
|
||||
top = datetime.datetime.now().strftime("%H")
|
||||
bottom = datetime.datetime.now().strftime("%M")
|
||||
|
||||
if len(top) < 2:
|
||||
top = "0" * (2 - len(top)) + top
|
||||
if len(bottom) < 2:
|
||||
bottom = "0" * (2 - len(bottom)) + bottom
|
||||
|
||||
if ("-" in top and len(top) > 2) or ("-" in bottom and len(bottom) > 2):
|
||||
time_split = 4*["-"]
|
||||
elif "error" in top and "error" in bottom:
|
||||
time_split = 4*["error"]
|
||||
else:
|
||||
time_split = [i for i in top] + [i for i in bottom]
|
||||
|
||||
if "-1" in top and len(top) != 2:
|
||||
time_split = ["-1", top[-1]] + [i for i in bottom]
|
||||
if "-1" in bottom and len(bottom) != 2:
|
||||
time_split = [i for i in top] + ["-1", bottom[-1]]
|
||||
|
||||
for i in range(4):
|
||||
x = digit_position[i][0]
|
||||
y = digit_position[i][1]
|
||||
number = digits[time_split[i]]
|
||||
pixels[x: x + 5, y: y + 3] = np.array(number)
|
||||
|
||||
return pixels
|
||||
|
||||
|
||||
def date_converter(self):
|
||||
# nshape = (self.shape[0], int(self.shape[1]/2))
|
||||
nshape = (16, 16)
|
||||
today = datetime.datetime.today()
|
||||
weekday = datetime.datetime.weekday(today)
|
||||
# size of the reduced array according to weekday
|
||||
size = [2,4,6,8,10,13,16]
|
||||
|
||||
pixels = days.copy() #base color background
|
||||
lrow = np.append(pixels[15,:size[weekday]], [0 for i in range(16 - size[weekday])])
|
||||
lrow = np.append(np.zeros((15,16)), lrow).reshape(nshape)
|
||||
pixels += lrow
|
||||
return pixels
|
||||
|
||||
|
||||
def weather_converter(self, name):
|
||||
"""Fills one half of the screen with weather info."""
|
||||
# nshape = (self.shape[0], int(self.shape[1]/2))
|
||||
nshape = (16, 16)
|
||||
result = np.zeros(nshape)
|
||||
cwd = __file__.replace("\\","/") # for windows
|
||||
cwd = cwd.rsplit("/", 1)[0] # the current working directory (where this file is)
|
||||
if len(cwd) == 0:
|
||||
cwd = "."
|
||||
icon_spritesheet = cwd + "/weather-icons.bmp"
|
||||
|
||||
icons = Image.open(icon_spritesheet)
|
||||
icons_full = np.array(icons)
|
||||
|
||||
icon_loc = ["sun","moon","sun and clouds", "moon and clouds", "cloud","fog and clouds","2 clouds", "3 clouds", "rain and cloud", "rain and clouds", "rain and cloud and sun", "rain and cloud and moon", "thunder and cloud", "thunder and cloud and moon", "snow and cloud", "snow and cloud and moon", "fog","fog night"]
|
||||
#ordered 1 2 \n 3 4 \ 5 5 ...
|
||||
if name == "":
|
||||
name = "error"
|
||||
name = weather_categories[name]
|
||||
try:
|
||||
iy, ix = int(icon_loc.index(name)/2), icon_loc.index(name)%2
|
||||
# x and y coords
|
||||
except:
|
||||
return np.zeros((*nshape,3))
|
||||
|
||||
icon_single = icons_full[16*iy:16*(iy + 1),16*ix:16*(ix + 1),...]
|
||||
return icon_single
|
||||
|
||||
|
||||
def matrix_add_depth(self, matrix, colors = []):
|
||||
"""transforms a 2d-array with 0,1,2 to a 3d-array with the rgb values for primary and secondary color"""
|
||||
|
||||
c1 = self.primary
|
||||
c2 = self.secondary
|
||||
c3 = self.error
|
||||
if len(colors) > 0:
|
||||
c1 = colors[0]
|
||||
if len(colors) > 1:
|
||||
c2 = colors[1]
|
||||
if len(colors) > 2:
|
||||
c3 = colors[2]
|
||||
if len(colors) > 3:
|
||||
print("Too many colors")
|
||||
|
||||
r3 = np.zeros((matrix.shape[0],matrix.shape[1],3),dtype=int)
|
||||
for i in range(matrix.shape[0]):
|
||||
for j in range(matrix.shape[1]):
|
||||
t = int(matrix[i, j])
|
||||
if t == 0:
|
||||
r3[i, j, :] = [0,0,0]
|
||||
elif t == 1:
|
||||
r3[i, j, :] = c1
|
||||
elif t == 2:
|
||||
r3[i, j, :] = c2
|
||||
else:
|
||||
r3[i, j, :] = c3
|
||||
return r3
|
||||
|
||||
|
||||
|
||||
def clock_face(self, weather):
|
||||
"""weather as a dict"""
|
||||
hour = self.time_converter()
|
||||
day = self.date_converter()
|
||||
face1 = hour + day
|
||||
# time + date:
|
||||
face1_3d = self.matrix_add_depth(face1)
|
||||
# weather icons
|
||||
face2_3d = self.weather_converter(weather["weather"])
|
||||
# weather temps
|
||||
face3 = self.time_converter(top=str(weather["low"]), bottom=str(weather["high"]))
|
||||
face3 = np.concatenate((face3[:8,...],2*face3[8:,...]))
|
||||
face3_3d = self.matrix_add_depth(face3,[[0, 102, 255],[255, 102, 0]])
|
||||
|
||||
return [face1_3d, face2_3d, face3_3d]
|
||||
|
||||
|
||||
def text_converter(self, text, height, color):
|
||||
"""Converts a text to a pixel-matrix
|
||||
returns: np.array((16, x, 3))"""
|
||||
|
||||
font = ImageFont.truetype("verdanab.ttf", height)
|
||||
size = font.getsize(text)
|
||||
img = Image.new("1",size,"black")
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.text((0, 0), text, "white", font=font)
|
||||
pixels = np.array(img, dtype=np.uint8)
|
||||
pixels3d = self.matrix_add_depth(pixels, color)
|
||||
return pixels3d
|
||||
|
||||
|
||||
def get_fallback(self):
|
||||
hour = self.time_converter()
|
||||
day = self.date_converter()
|
||||
face1 = hour + day
|
||||
face1_3d = self.matrix_add_depth(face1)
|
||||
|
||||
face2_3d = face3_3d = np.zeros((16,16,3))
|
||||
return [face1_3d, face2_3d, face3_3d]
|
@@ -1,103 +1,103 @@
|
||||
import numpy as np
|
||||
|
||||
digits = {
|
||||
"1" : np.array([
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"2" : np.array([
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1],
|
||||
[1,0,0],
|
||||
[1,1,1]]),
|
||||
"3" : np.array([
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1]]),
|
||||
"4" : np.array([
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"5" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,0],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1]]),
|
||||
"6" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,0],
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1]]),
|
||||
"7" : np.array([
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"8" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1]]),
|
||||
"9" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1]]),
|
||||
"0" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[1,1,1]]),
|
||||
"-" : np.array([
|
||||
[0,0,0],
|
||||
[0,0,0],
|
||||
[1,1,1],
|
||||
[0,0,0],
|
||||
[0,0,0]]),
|
||||
"-1" : np.array([
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"error" : np.array([
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[0,1,0],
|
||||
[1,0,1],
|
||||
[1,0,1]]),
|
||||
}
|
||||
|
||||
|
||||
weather_categories = {
|
||||
"Clouds": "cloud",
|
||||
"Rain": "rain and cloud",
|
||||
"Thunderstorm": "thunder and cloud",
|
||||
"Drizzle": "rain and cloud",
|
||||
"Snow": "snow and cloud",
|
||||
"Clear": "sun",
|
||||
"Mist": "fog and clouds",
|
||||
"Smoke": "Smoke",
|
||||
"Haze": "Haze",
|
||||
"Dust": "Dust",
|
||||
"Fog": "fog",
|
||||
"Sand": "Sand",
|
||||
"Dust": "Dust",
|
||||
"Ash": "Ash",
|
||||
"Squal": "Squal",
|
||||
"Tornado": "Tornado",
|
||||
"error" : "moon"
|
||||
import numpy as np
|
||||
|
||||
digits = {
|
||||
"1" : np.array([
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"2" : np.array([
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1],
|
||||
[1,0,0],
|
||||
[1,1,1]]),
|
||||
"3" : np.array([
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1]]),
|
||||
"4" : np.array([
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"5" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,0],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1]]),
|
||||
"6" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,0],
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1]]),
|
||||
"7" : np.array([
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"8" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1]]),
|
||||
"9" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[1,1,1]]),
|
||||
"0" : np.array([
|
||||
[1,1,1],
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[1,1,1]]),
|
||||
"-" : np.array([
|
||||
[0,0,0],
|
||||
[0,0,0],
|
||||
[1,1,1],
|
||||
[0,0,0],
|
||||
[0,0,0]]),
|
||||
"-1" : np.array([
|
||||
[0,0,1],
|
||||
[0,0,1],
|
||||
[1,1,1],
|
||||
[0,0,1],
|
||||
[0,0,1]]),
|
||||
"error" : np.array([
|
||||
[1,0,1],
|
||||
[1,0,1],
|
||||
[0,1,0],
|
||||
[1,0,1],
|
||||
[1,0,1]]),
|
||||
}
|
||||
|
||||
|
||||
weather_categories = {
|
||||
"Clouds": "cloud",
|
||||
"Rain": "rain and cloud",
|
||||
"Thunderstorm": "thunder and cloud",
|
||||
"Drizzle": "rain and cloud",
|
||||
"Snow": "snow and cloud",
|
||||
"Clear": "sun",
|
||||
"Mist": "fog and clouds",
|
||||
"Smoke": "Smoke",
|
||||
"Haze": "Haze",
|
||||
"Dust": "Dust",
|
||||
"Fog": "fog",
|
||||
"Sand": "Sand",
|
||||
"Dust": "Dust",
|
||||
"Ash": "Ash",
|
||||
"Squal": "Squal",
|
||||
"Tornado": "Tornado",
|
||||
"error" : "moon"
|
||||
}
|
@@ -1,30 +1,30 @@
|
||||
from threading import Timer
|
||||
import time
|
||||
|
||||
class RepeatedTimer(object):
|
||||
def __init__(self, interval, function, *args, **kwargs):
|
||||
self._timer = None
|
||||
self.interval = interval
|
||||
self.function = function
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.is_running = False
|
||||
self.next_call = time.time()
|
||||
self.start()
|
||||
|
||||
def _run(self):
|
||||
self.is_running = False
|
||||
self.start()
|
||||
self.function(*self.args, **self.kwargs)
|
||||
|
||||
def start(self):
|
||||
if not self.is_running:
|
||||
self.next_call += self.interval
|
||||
self._timer = Timer(self.next_call - time.time(), self._run)
|
||||
self._timer.start()
|
||||
self.is_running = True
|
||||
|
||||
def stop(self):
|
||||
self._timer.cancel()
|
||||
self.is_running = False
|
||||
from threading import Timer
|
||||
import time
|
||||
|
||||
class RepeatedTimer(object):
|
||||
def __init__(self, interval, function, *args, **kwargs):
|
||||
self._timer = None
|
||||
self.interval = interval
|
||||
self.function = function
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.is_running = False
|
||||
self.next_call = time.time()
|
||||
self.start()
|
||||
|
||||
def _run(self):
|
||||
self.is_running = False
|
||||
self.start()
|
||||
self.function(*self.args, **self.kwargs)
|
||||
|
||||
def start(self):
|
||||
if not self.is_running:
|
||||
self.next_call += self.interval
|
||||
self._timer = Timer(self.next_call - time.time(), self._run)
|
||||
self._timer.start()
|
||||
self.is_running = True
|
||||
|
||||
def stop(self):
|
||||
self._timer.cancel()
|
||||
self.is_running = False
|
||||
|
Reference in New Issue
Block a user