191 lines
4.9 KiB
Python
191 lines
4.9 KiB
Python
import logging
|
|
import math
|
|
from threading import Thread, Timer
|
|
|
|
import bdfparser
|
|
from sense_hat.sense_hat import SenseHat
|
|
from sense_hat.stick import InputEvent
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
COLORS = {
|
|
"Bleu": (0, 0, 255),
|
|
"Blanc": (255, 255, 255),
|
|
"Rouge": (255, 0, 0),
|
|
"Verte": (0, 127, 31),
|
|
"Jaune": (255, 255, 0),
|
|
"heat": (255, 0, 0),
|
|
"heating": (255, 0, 0),
|
|
"idle": (127, 0, 255),
|
|
"off": (127, 127, 127),
|
|
"on_setting": (255, 255, 0),
|
|
"off_setting": (255, 255, 255),
|
|
None: (0, 0, 0),
|
|
}
|
|
|
|
|
|
class Screen:
|
|
def __init__(self) -> None:
|
|
self.sense = SenseHat()
|
|
self._value = ""
|
|
self._tmp = False
|
|
self._tmp_value = ""
|
|
self._mode = ""
|
|
self.font = bdfparser.Font("src/tom-thumb.bdf")
|
|
self._secondary: dict[int, str] = dict()
|
|
self._secondary_pixels: list[tuple[int, int, int]] = [(0, 0, 0)] * 8
|
|
|
|
self.timer = Timer(0, self.set_pixels)
|
|
self.auto_dim = AutoDim(self.sense)
|
|
self.auto_dim.start()
|
|
|
|
self._held = False
|
|
self.sense.stick.direction_middle = self.stick_click
|
|
self.sense.stick.direction_any = self.auto_dim.undim
|
|
|
|
@property
|
|
def value(self) -> None | str:
|
|
return self._value
|
|
|
|
@value.setter
|
|
def value(self, value: float) -> None:
|
|
logger.debug(f"Updated value: <{value}>")
|
|
|
|
self._value = format_value(value)
|
|
if not self._tmp:
|
|
self.set_pixels()
|
|
|
|
@property
|
|
def color(self) -> tuple[int, int, int]:
|
|
return COLORS.get(self.mode, (0, 0, 0))
|
|
|
|
@property
|
|
def mode(self) -> str:
|
|
return self._mode
|
|
|
|
@mode.setter
|
|
def mode(self, value: str) -> None:
|
|
self._mode = value
|
|
if not self._tmp:
|
|
self.set_pixels()
|
|
|
|
@property
|
|
def tmp_value(self) -> None | str:
|
|
return self._tmp_value
|
|
|
|
@tmp_value.setter
|
|
def tmp_value(self, value: float) -> None:
|
|
logger.debug(f"Show value: <{value}>")
|
|
|
|
self.timer.cancel()
|
|
self._tmp_value = format_value(value)
|
|
self.show_tmp()
|
|
|
|
def show_tmp(self) -> None:
|
|
self._tmp = True
|
|
self.set_pixels(
|
|
self.tmp_value,
|
|
color=COLORS.get("off_setting" if self.mode == "off" else "on_setting"),
|
|
)
|
|
self.timer = Timer(3, self.set_pixels)
|
|
self.timer.start()
|
|
|
|
def set_pixels(
|
|
self,
|
|
value: str | None = None,
|
|
color: tuple[int, int, int] | None = None,
|
|
bg_color: tuple[int, int, int] = (0, 0, 0),
|
|
) -> None:
|
|
if value is None:
|
|
value = self.value
|
|
self._tmp = False
|
|
if color is None:
|
|
color = self.color
|
|
|
|
if value:
|
|
pixels = [color if x else bg_color for x in self.data_from_value(value)]
|
|
else:
|
|
pixels = 48 * [(0, 0, 0)]
|
|
pixels += self.secondary_pixels
|
|
|
|
self.sense.set_pixels(pixels)
|
|
|
|
@property
|
|
def secondary(self) -> dict[int, str]:
|
|
return self._secondary
|
|
|
|
@secondary.setter
|
|
def secondary(self, value: dict[int, str]) -> None:
|
|
self._secondary = value
|
|
|
|
for idx in range(2):
|
|
self._secondary_pixels[4 * idx : 4 * (idx + 1)] = [
|
|
COLORS.get(value.get(idx, None), (0, 0, 0))
|
|
] * 4
|
|
|
|
if not self._tmp:
|
|
self.set_pixels()
|
|
|
|
@property
|
|
def secondary_pixels(self) -> list[tuple[int, int, int]]:
|
|
return self._secondary_pixels
|
|
|
|
def stick_click(self, event: InputEvent) -> None:
|
|
match (event.action, self._held):
|
|
case ("held", False):
|
|
self._held = True
|
|
case ("released", True):
|
|
self._held = False
|
|
case ("released", False):
|
|
self.show_tmp()
|
|
case _:
|
|
pass
|
|
|
|
def data_from_value(self, value: str) -> list[int]:
|
|
return self.font.draw(value, mode=0).crop(8, 7).todata(3)
|
|
|
|
|
|
class AutoDim(Thread):
|
|
def __init__(self, sense: SenseHat):
|
|
super().__init__()
|
|
|
|
self.daemon = True
|
|
self.sense = sense
|
|
self.dim = False
|
|
self.switching = False
|
|
self.sense.gamma_reset()
|
|
|
|
def run(self) -> None:
|
|
while True:
|
|
self.auto_dim()
|
|
|
|
def auto_dim(self) -> None:
|
|
accel_z = self.sense.get_accelerometer_raw()["z"]
|
|
|
|
if not self.switching and accel_z < 0.2:
|
|
self.switching = True
|
|
self.dim = not self.dim
|
|
|
|
elif self.switching and accel_z > 0.9:
|
|
self.switching = False
|
|
|
|
@property
|
|
def dim(self) -> bool:
|
|
return self._dim
|
|
|
|
@dim.setter
|
|
def dim(self, value: bool) -> None:
|
|
if value:
|
|
self.sense.gamma = [0] * 32
|
|
else:
|
|
self.sense.gamma_reset()
|
|
self._dim = value
|
|
|
|
def undim(self) -> None:
|
|
self.dim = False
|
|
|
|
|
|
def format_value(value: float) -> str:
|
|
v = math.trunc(value)
|
|
d = "." if (value - v) >= 0.5 else ""
|
|
return f"{v}{d}"
|