Better folder structure, added a few ambient sensors
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
# Placeholder
|
||||
from . import led
|
@@ -1,91 +0,0 @@
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
|
||||
|
||||
try:
|
||||
from . import unicorn
|
||||
output = unicorn.ClockOut
|
||||
except ImportError:
|
||||
from . import sim
|
||||
output = sim.ClockOut
|
||||
|
||||
# import sim
|
||||
# output = sim.ClockOut
|
||||
|
||||
class OutputHandler():
|
||||
"""Matrix of led-points (RGB- values). It has the two given dimensions + a third which is given by the color values"""
|
||||
|
||||
# def __new__(subtype, shape, dtype=float, buffer=None, offset=0,
|
||||
# strides=None, order=None, info=None):
|
||||
# # Create the ndarray instance of our type, given the usual
|
||||
# # ndarray input arguments. This will call the standard
|
||||
# # ndarray constructor, but return an object of our type.
|
||||
# # It also triggers a call to InfoArray.__array_finalize__
|
||||
|
||||
# # expand the given tuple (flat display) to a 3d array containing the colors as well
|
||||
# nshape = (*shape, 3)
|
||||
# obj = super(OutputHandler, subtype).__new__(subtype, nshape, "int",
|
||||
# buffer, offset, strides,
|
||||
# order)
|
||||
# # set the new 'info' attribute to the value passed
|
||||
# obj.info = info
|
||||
# obj.OUT = output(shape)
|
||||
# # Finally, we must return the newly created object:
|
||||
# return obj
|
||||
def __init__(self, shape):
|
||||
nshape = (*shape, 3)
|
||||
self.array = np.array(shape, dtype=np.uint8)
|
||||
self.OUT = output(shape)
|
||||
|
||||
|
||||
# def __array_finalize__(self, obj):
|
||||
# self.OUT = sim.ClockOut()
|
||||
# # ``self`` is a new object resulting from
|
||||
# # ndarray.__new__(), therefore it only has
|
||||
# # attributes that the ndarray.__new__ constructor gave it -
|
||||
# # i.e. those of a standard ndarray.
|
||||
# #
|
||||
# # We could have got to the ndarray.__new__ call in 3 ways:
|
||||
# # From an explicit constructor - e.g. InfoArray():
|
||||
# # obj is None
|
||||
# # (we're in the middle of the InfoArray.__new__
|
||||
# # constructor, and self.info will be set when we return to
|
||||
# # InfoArray.__new__)
|
||||
# if obj is None: return
|
||||
# # From view casting - e.g arr.view(InfoArray):
|
||||
# # obj is arr
|
||||
# # (type(obj) can be InfoArray)
|
||||
# # From new-from-template - e.g infoarr[:3]
|
||||
# # type(obj) is InfoArray
|
||||
# #
|
||||
# # Note that it is here, rather than in the __new__ method,
|
||||
# # that we set the default value for 'info', because this
|
||||
# # method sees all creation of default objects - with the
|
||||
# # InfoArray.__new__ constructor, but also with
|
||||
# # arr.view(InfoArray).
|
||||
# self.info = getattr(obj, 'info', None)
|
||||
|
||||
# # We do not need to return anything
|
||||
|
||||
|
||||
|
||||
def SHOW(self):
|
||||
# self.output.set_matrix(self)
|
||||
|
||||
self.OUT.put(self.array)
|
||||
|
||||
|
||||
# def __init__(self, width, height, primary = [200, 200, 200], secondary = [10, 200, 10], error = [200, 10, 10]):
|
||||
# """width is presumed to be larger than height"""
|
||||
# self.width = width
|
||||
# self.height = height
|
||||
# self.output = HAT.UnicornHat(width, height)
|
||||
# self.primary = primary
|
||||
# self.secondary = secondary
|
||||
# self.red = error
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,27 +0,0 @@
|
||||
import matplotlib as mpl
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
mpl.rcParams['toolbar'] = 'None'
|
||||
mpl.use('WX')
|
||||
|
||||
|
||||
|
||||
|
||||
class ClockOut():
|
||||
"""Simulate a clock output on a computer screen"""
|
||||
def __init__(self, shape):
|
||||
plt.axis('off')
|
||||
plt.ion()
|
||||
nshape = (*shape, 3)
|
||||
zero = np.zeros(nshape)
|
||||
self.figure, ax = plt.subplots()
|
||||
ax.set_axis_off()
|
||||
i = Image.fromarray(zero, "RGB")
|
||||
self.canvas = ax.imshow(i)
|
||||
|
||||
def put(self, matrix):
|
||||
matrix_rescale = matrix / 255
|
||||
self.canvas.set_array(matrix_rescale)
|
||||
self.figure.canvas.draw()
|
||||
self.figure.canvas.flush_events()
|
44
clock/cin.py
Normal file
44
clock/cin.py
Normal file
@@ -0,0 +1,44 @@
|
||||
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, prst=object):
|
||||
""""""
|
||||
self.persistence = prst
|
||||
self.sensor_modules = { # we already call them, they are objects and not classes anymore
|
||||
"temperature" : hardware.sensors.TemperatureModule(),
|
||||
"humidity" : hardware.sensors.HumidityModule(),
|
||||
"brightness" : hardware.sensors.BrightnessModule(),
|
||||
# more to come?
|
||||
}
|
||||
|
||||
def start(self):
|
||||
helpers.timer.RepeatedTimer(300, self.spread_measure)
|
||||
|
||||
def spread_measure(self):
|
||||
results = 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()
|
||||
results[name].append(measure)
|
||||
time.sleep(3)
|
||||
|
||||
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]
|
||||
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import datetime
|
||||
import time
|
||||
import json
|
||||
from threading import Thread, Timer
|
||||
from threading import Thread
|
||||
import numpy
|
||||
|
||||
from . import api, helpers
|
||||
from . import hardware, helpers
|
||||
|
||||
|
||||
class ClockFace(object):
|
||||
class ClockFace:
|
||||
"""Actual functions one might need for a clock"""
|
||||
|
||||
def __init__(self, text_speed=18, prst=object):
|
||||
@@ -19,10 +18,10 @@ class ClockFace(object):
|
||||
self.primary = [200, 200, 200]
|
||||
self.secondary = [10, 200, 10]
|
||||
self.error = [200, 10, 10]
|
||||
self.shape = (16,32)
|
||||
# shape: (16,32) is hard-coded for the moment
|
||||
|
||||
self.persistence = prst
|
||||
self.IO = api.led.OutputHandler(self.shape)
|
||||
self.IO = hardware.led.get_handler()
|
||||
self.shape = self.IO.shape # (16,32) for now
|
||||
self.MOP = helpers.helper.MatrixOperations(self.shape, default_colors={"primary": self.primary, "secondary": self.secondary, "error": self.error})
|
||||
|
||||
self.output_thread = ""
|
||||
@@ -41,7 +40,8 @@ class ClockFace(object):
|
||||
self.clock_loop()
|
||||
while datetime.datetime.now().strftime("%H%M%S")[-2:] != "00":
|
||||
pass
|
||||
RepeatedTimer(60, self.clock_loop)
|
||||
helpers.timer.RepeatedTimer(60, self.clock_loop)
|
||||
self.clock_loop()
|
||||
|
||||
|
||||
def clock_loop(self):
|
||||
@@ -99,8 +99,7 @@ class ClockFace(object):
|
||||
def set_face(self):
|
||||
"""Set the clock face (time + weather) by getting updated info - gets called every minute"""
|
||||
face = self.MOP.clock_face(self.weather)
|
||||
self.IO.array = face * self.brightness
|
||||
self.IO.SHOW()
|
||||
self.IO.put(face * self.brightness)
|
||||
|
||||
|
||||
def set_brightness(self, value=-1, overwrite=[]):
|
||||
@@ -122,6 +121,7 @@ class ClockFace(object):
|
||||
|
||||
self.brightness = brightness
|
||||
|
||||
|
||||
def text_scroll(self, text, color=[[200,200,200]]):
|
||||
pixels = self.MOP.text_converter(text, 12, color)
|
||||
sleep_time = 1 / self.tspeed
|
||||
@@ -132,39 +132,7 @@ class ClockFace(object):
|
||||
|
||||
for i in range(frames):
|
||||
visible = pixels[:,i:width+i]
|
||||
self.IO.array = visible*self.brightness
|
||||
self.IO.SHOW()
|
||||
self.IO.put(visible*self.brightness)
|
||||
time.sleep(sleep_time)
|
||||
time.sleep(10 * sleep_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
|
2
clock/hardware/__init__.py
Normal file
2
clock/hardware/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Placeholder
|
||||
from . import led, sensors
|
17
clock/hardware/led.py
Normal file
17
clock/hardware/led.py
Normal file
@@ -0,0 +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
|
||||
|
||||
|
51
clock/hardware/neopixel.py
Normal file
51
clock/hardware/neopixel.py
Normal file
@@ -0,0 +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)
|
||||
|
80
clock/hardware/sensors.py
Normal file
80
clock/hardware/sensors.py
Normal file
@@ -0,0 +1,80 @@
|
||||
import time
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class TempSim:
|
||||
"""Simulates a temperature for running on windows"""
|
||||
temperature = 23 # return a celsius value
|
||||
humidity = 0.3
|
||||
|
||||
|
||||
class SensorModule:
|
||||
def __init__(self):
|
||||
logger.info("Using module " + self.__class__.__name__)
|
||||
|
||||
class LightSim:
|
||||
def input(self, *args):
|
||||
return 1
|
||||
|
||||
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:
|
||||
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 = 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
|
52
clock/hardware/sim.py
Normal file
52
clock/hardware/sim.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import sys
|
||||
import colorsys
|
||||
import pygame.gfxdraw
|
||||
import time
|
||||
import pygame
|
||||
import numpy
|
||||
|
||||
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 = numpy.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, matrix):
|
||||
self.screen.fill((0, 0, 0))
|
||||
for event in pygame.event.get(): # User did something
|
||||
if event.type == pygame.QUIT:
|
||||
print("Exiting...")
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
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,30 +1,37 @@
|
||||
import colorsys
|
||||
import time
|
||||
import numpy
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
try:
|
||||
import RPi.GPIO as GPIO
|
||||
except ImportError:
|
||||
from unittest.mock import Mock
|
||||
GPIO = Mock()
|
||||
SETUP_FAIL = True
|
||||
|
||||
|
||||
class ClockOut(object):
|
||||
def __init__(self, shape):
|
||||
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.SOF = 0x72
|
||||
self.DELAY = 1.0/120
|
||||
|
||||
self.HEIGHT = shape[0] #16
|
||||
self.WIDTH = shape[1] #32
|
||||
|
||||
self.HEIGHT = self.shape[0] #16
|
||||
self.WIDTH = self.shape[1] #32
|
||||
|
||||
self.reset_clock()
|
||||
|
||||
@@ -60,8 +67,6 @@ class ClockOut(object):
|
||||
GPIO.output(self.PIN_CLK, GPIO.LOW)
|
||||
|
||||
|
||||
|
||||
|
||||
def put(self, matrix):
|
||||
"""Sets a height x width matrix directly"""
|
||||
self.reset_clock()
|
||||
@@ -81,7 +86,7 @@ class ClockOut(object):
|
||||
buff2 = numpy.rot90(matrix[:self.HEIGHT,:16],3)
|
||||
buff1 = numpy.rot90(matrix[:self.HEIGHT,16:32],1)
|
||||
##########################################################
|
||||
|
||||
# separated these are: 16x16x3 arrays
|
||||
buff1, buff2 = [(x.reshape(768)).astype(numpy.uint8).tolist() for x in (buff1, buff2)]
|
||||
|
||||
self.spi_write(buff1, buff2)
|
@@ -1 +1 @@
|
||||
from . import helper
|
||||
from . import helper, timer
|
@@ -3,46 +3,12 @@ import numpy as np
|
||||
import datetime
|
||||
import time
|
||||
|
||||
|
||||
####### bulky hard-coded values:
|
||||
digits = {
|
||||
"1" : [[0,0,1],[0,0,1],[0,0,1],[0,0,1],[0,0,1]],
|
||||
"2" : [[1,1,1],[0,0,1],[1,1,1],[1,0,0],[1,1,1]],
|
||||
"3" : [[1,1,1],[0,0,1],[1,1,1],[0,0,1],[1,1,1]],
|
||||
"4" : [[1,0,1],[1,0,1],[1,1,1],[0,0,1],[0,0,1]],
|
||||
"5" : [[1,1,1],[1,0,0],[1,1,1],[0,0,1],[1,1,1]],
|
||||
"6" : [[1,1,1],[1,0,0],[1,1,1],[1,0,1],[1,1,1]],
|
||||
"7" : [[1,1,1],[0,0,1],[0,0,1],[0,0,1],[0,0,1]],
|
||||
"8" : [[1,1,1],[1,0,1],[1,1,1],[1,0,1],[1,1,1]],
|
||||
"9" : [[1,1,1],[1,0,1],[1,1,1],[0,0,1],[1,1,1]],
|
||||
"0" : [[1,1,1],[1,0,1],[1,0,1],[1,0,1],[1,1,1]],
|
||||
"-" : [[0,0,0],[0,0,0],[1,1,1],[0,0,0],[0,0,0]],
|
||||
"-1" : [[0,0,1],[0,0,1],[1,1,1],[0,0,1],[0,0,1]],
|
||||
"error" : [[1,0,1],[1,0,1],[0,1,0],[1,0,1],[1,0,1]],
|
||||
} # these are 2-d arrays as we only work with one or 2 colors, and not the whole rgb spectrum
|
||||
|
||||
##place of numbers, invariant (for the given shape of 16x32)
|
||||
# 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]]
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
|
103
clock/helpers/shapes.py
Normal file
103
clock/helpers/shapes.py
Normal file
@@ -0,0 +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"
|
||||
}
|
29
clock/helpers/timer.py
Normal file
29
clock/helpers/timer.py
Normal file
@@ -0,0 +1,29 @@
|
||||
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