vu1-py/vu1.py

195 lines
5.3 KiB
Python
Raw Normal View History

2024-03-01 16:30:22 +01:00
from os.path import join as joinpath
import json
import zlib
2024-03-01 16:30:22 +01:00
import colorsys
import requests
API_BASE = "api/v0/dial"
# taken from https://stackoverflow.com/a/2387880
def file_crc(fileName):
prev = 0
for eachLine in open(fileName, "rb"):
prev = zlib.crc32(eachLine, prev)
return "%X"%(prev & 0xFFFFFFFF)
2024-03-01 16:30:22 +01:00
class DialServer():
def __init__(self, url, key):
self.url = url
self._base = joinpath(self.url, API_BASE)
self.key = key
self._dials = []
2024-07-04 23:34:33 +02:00
self.refresh()
2024-03-01 16:30:22 +01:00
pass
2024-07-04 23:34:33 +02:00
def refresh(self):
2024-03-01 16:30:22 +01:00
dial_data = self._req("list")
for d in dial_data:
dial = Dial(self, d["uid"])
if not dial in self._dials:
self._dials.append(dial)
2024-07-04 23:34:33 +02:00
@property
def dials(self):
2024-03-01 16:30:22 +01:00
return self._dials
@property
def color(self):
return None
@color.setter
def color(self, color):
for dial in self._dials:
dial.color = color
def _req(self, endpoint, params={}, post=False):
data_dict_base = {
"key": self.key
}
data_dict = {**data_dict_base, **params}
req = requests.post(joinpath(self._base, endpoint), data=data_dict_base, files=data_dict) if post else requests.get(joinpath(self._base, endpoint), data=data_dict)
try:
result = req.json()
if result["status"] == "ok":
return result["data"]
else:
raise Exception
except KeyError as e:
raise e
class Dial():
def __init__(self, server, uid):
self._server = server
self.uid = uid
pass
def __eq__(self, other):
try:
return self.uid.lower() == other.uid.lower() #if other is another dial instance
except AttributeError:
return self.uid.lower() == other.lower() #fall back to uid string comparision
def __repr__(self):
return f"{super().__repr__()} - {self.name}, {self.uid}"
def _get_status(self):
s = self._server._req(f"{self.uid}/status")
self._index = int(s["index"])
self._name = s["dial_name"]
self._value = int(s["value"])
self._fw_hash = s["fw_hash"]
self._fw_version = s["fw_version"]
self._hw_version = s["hw_version"]
self._protocol_version = s["protocol_version"]
2024-03-02 02:01:13 +01:00
self._color = VUColor(*s["backlight"].values())
2024-03-01 16:30:22 +01:00
self._image = s["image_file"]
@property
def index(self):
self._get_status()
return self._index
@property
def name(self):
self._get_status()
return self._name
@name.setter
def name(self, new_name):
self._server._req(f"{self.uid}/name", {"name": new_name})
@property
def value(self):
self._get_status()
return self._value
@value.setter
def value(self, new_value):
self._server._req(f"{self.uid}/set", {"value": max(0, min(100, int(new_value)))})
@property
def fw_hash(self):
self._get_status()
return self._fw_hash
@property
def fw_version(self):
self._get_status()
return self._fw_version
@property
def hw_version(self):
self._get_status()
return self._hw_version
@property
def protocol_version(self):
self._get_status()
return self._protocol_version
@property
def color(self):
self._get_status()
return self._color
@color.setter
def color(self, new_color):
self._server._req(f"{self.uid}/backlight", dict(new_color))
@property
def image_crc(self):
crc = self._server._req(f"{self.uid}/image/crc")
return crc
2024-03-01 16:30:22 +01:00
@property
def image(self):
self._get_status()
return self._image
@image.setter
def image(self, new_image):
if file_crc(new_image) != self.image_crc:
file = {'imgfile': (open(new_image, 'rb'))}
self._server._req(f"{self.uid}/image/set", file, post=True)
2024-03-01 16:30:22 +01:00
2024-03-02 02:01:13 +01:00
class VUColor():
def __init__(self, red=0, green=0, blue=0):
self._red = max(0, min(100, red))
self._green = max(0, min(100, green))
self._blue = max(0, min(100, blue))
2024-03-01 16:30:22 +01:00
def __iter__(self):
for attr in ["red", "green", "blue"]:
2024-03-02 02:01:13 +01:00
yield (attr, self.__dict__[f"_{attr}"])
def to_rgb(self):
return RGBColor(self._red/100, self._green/100, self._blue/100)
def to_hsv(self):
return self.to_rgb().to_hsv()
class RGBColor(VUColor):
def __init__(self, red=0.0, green=0.0, blue=0.0):
self.red = max(0.0, min(1.0, red))
self.green = max(0.0, min(1.0, green))
self.blue = max(0.0, min(1.0, blue))
super().__init__(int(red*100), int(green*100), int(blue*100))
def to_hsv(self):
h, s, v = colorsys.rgb_to_hsv(self.red, self.green, self.blue)
return HSVColor(h, s, v)
class HSVColor(VUColor):
def __init__(self, hue=0.0, saturation=0.0, value=0.0):
self.hue = max(0.0, min(1.0, hue))
self.saturation = max(0.0, min(1.0, saturation))
self.value = max(0.0, min(1.0, value))
r, g, b = colorsys.hsv_to_rgb(self.hue, self.saturation, self.value)
super().__init__(int(r*100), int(g*100), int(b*100))
def to_rgb(self):
r, g, b = colorsys.hsv_to_rgb(self.hue, self.saturation, self.value)
return RGBColor(r, g, b)