Bug fixes and control volume from media screens
This commit is contained in:
21
api.py
21
api.py
@@ -1,4 +1,4 @@
|
|||||||
from requests import get
|
from requests import get, post
|
||||||
import gc
|
import gc
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -18,6 +18,17 @@ class Api:
|
|||||||
response = get(url, headers=headers)
|
response = get(url, headers=headers)
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
|
def __post(self, endpoint, d) -> bool:
|
||||||
|
gc.collect()
|
||||||
|
url = self.base_url + endpoint
|
||||||
|
headers = {
|
||||||
|
"Authorization": "Bearer " + self.access_token,
|
||||||
|
"content-type": "application/json"
|
||||||
|
}
|
||||||
|
print("Starting post request to " + endpoint)
|
||||||
|
response = post(url, headers=headers, json=d)
|
||||||
|
return response.status_code == 200
|
||||||
|
|
||||||
def getLightData(self, entity_id: str) -> dict:
|
def getLightData(self, entity_id: str) -> dict:
|
||||||
# TODO: error handling if can't access hass (e.g. no connection, invalid token)
|
# TODO: error handling if can't access hass (e.g. no connection, invalid token)
|
||||||
response = self.__request("/api/states/" + entity_id)
|
response = self.__request("/api/states/" + entity_id)
|
||||||
@@ -38,8 +49,6 @@ class Api:
|
|||||||
p = 0
|
p = 0
|
||||||
if ("media_position_updated_at" in (dict)(response["attributes"])):
|
if ("media_position_updated_at" in (dict)(response["attributes"])):
|
||||||
dts = response["attributes"]["media_position_updated_at"]
|
dts = response["attributes"]["media_position_updated_at"]
|
||||||
# p += (datetime.now() - datetime.strptime(dts, "%Y-%m-%dT%H:%M:%S.%f%z")).total_seconds()
|
|
||||||
print(dts)
|
|
||||||
t = time.mktime((int(dts[0:4]), int(dts[5:7]), int(dts[8:10]), int(dts[11:13]) + int(dts[27:29]), int(dts[14:16]) + int(dts[30:31]), int(dts[17:19]), 0, 0))
|
t = time.mktime((int(dts[0:4]), int(dts[5:7]), int(dts[8:10]), int(dts[11:13]) + int(dts[27:29]), int(dts[14:16]) + int(dts[30:31]), int(dts[17:19]), 0, 0))
|
||||||
p += time.mktime(time.localtime()) - t
|
p += time.mktime(time.localtime()) - t
|
||||||
return {
|
return {
|
||||||
@@ -55,3 +64,9 @@ class Api:
|
|||||||
"media_artist": response["attributes"]["media_artist"] if "media_artist" in (dict)(response["attributes"]) else "",
|
"media_artist": response["attributes"]["media_artist"] if "media_artist" in (dict)(response["attributes"]) else "",
|
||||||
"media_album_name": response["attributes"]["media_album_name"] if "media_album_name" in (dict)(response["attributes"]) else ""
|
"media_album_name": response["attributes"]["media_album_name"] if "media_album_name" in (dict)(response["attributes"]) else ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def changeVolume(self, entity_id: str, up: bool = True) -> None:
|
||||||
|
if (up): dir = "up"
|
||||||
|
else: dir = "down"
|
||||||
|
self.__post(f"/api/services/media_player/volume_{dir}", {"entity_id": entity_id})
|
||||||
|
self.__post(f"/api/services/media_player/volume_{dir}", {"entity_id": entity_id})
|
||||||
|
|||||||
44
app.py
44
app.py
@@ -17,9 +17,9 @@ class App:
|
|||||||
if (len(SCREENS) == 0):
|
if (len(SCREENS) == 0):
|
||||||
print("No screens configured. Check env.py.")
|
print("No screens configured. Check env.py.")
|
||||||
self.screen = -1
|
self.screen = -1
|
||||||
|
else: self.screen = 0
|
||||||
self.lcd = LCD()
|
self.lcd = LCD()
|
||||||
self.api = Api(HASS_URL, TOKEN)
|
self.api = Api(HASS_URL, TOKEN)
|
||||||
self.screen = 0
|
|
||||||
self.scr_vals = {} # stored values from the current screen
|
self.scr_vals = {} # stored values from the current screen
|
||||||
|
|
||||||
def __connect(self) -> int:
|
def __connect(self) -> int:
|
||||||
@@ -49,8 +49,8 @@ class App:
|
|||||||
self.lcd.keyB["v"] = False
|
self.lcd.keyB["v"] = False
|
||||||
self.lcd.keyX["v"] = False
|
self.lcd.keyX["v"] = False
|
||||||
self.lcd.keyY["v"] = False
|
self.lcd.keyY["v"] = False
|
||||||
self.lcd.right["v"] = False
|
|
||||||
self.lcd.left["v"] = False
|
self.lcd.left["v"] = False
|
||||||
|
self.lcd.right["v"] = False
|
||||||
self.lcd.up["v"] = False
|
self.lcd.up["v"] = False
|
||||||
self.lcd.down["v"] = False
|
self.lcd.down["v"] = False
|
||||||
self.lcd.ctrl["v"] = False
|
self.lcd.ctrl["v"] = False
|
||||||
@@ -63,7 +63,8 @@ class App:
|
|||||||
if (self.lcd.keyY["p"].value() == 0): self.lcd.keyY["v"] = True
|
if (self.lcd.keyY["p"].value() == 0): self.lcd.keyY["v"] = True
|
||||||
if (self.lcd.right["p"].value() == 0): self.lcd.right["v"] = True
|
if (self.lcd.right["p"].value() == 0): self.lcd.right["v"] = True
|
||||||
if (self.lcd.left["p"].value() == 0): self.lcd.left["v"] = True
|
if (self.lcd.left["p"].value() == 0): self.lcd.left["v"] = True
|
||||||
if (self.lcd.up["p"].value() == 0): self.lcd.up["v"] = True
|
if (self.lcd.up["p"].value() == 0):
|
||||||
|
self.lcd.up["v"] = True
|
||||||
if (self.lcd.down["p"].value() == 0): self.lcd.down["v"] = True
|
if (self.lcd.down["p"].value() == 0): self.lcd.down["v"] = True
|
||||||
if (self.lcd.ctrl["p"].value() == 0): self.lcd.ctrl["v"] = True
|
if (self.lcd.ctrl["p"].value() == 0): self.lcd.ctrl["v"] = True
|
||||||
|
|
||||||
@@ -79,16 +80,16 @@ class App:
|
|||||||
self.screen = len(SCREENS) - 1
|
self.screen = len(SCREENS) - 1
|
||||||
else:
|
else:
|
||||||
self.screen -= 1
|
self.screen -= 1
|
||||||
self.__resetButtonStatuses()
|
|
||||||
change = self.screen != orig
|
change = self.screen != orig
|
||||||
if (change):
|
if (change):
|
||||||
self.scr_vals = {}
|
self.scr_vals = {}
|
||||||
|
self.lcd.left["v"] = False
|
||||||
|
self.lcd.right["v"] = False
|
||||||
|
print(f"Screen change: {change}")
|
||||||
return change
|
return change
|
||||||
|
|
||||||
def __displayLightEntity(self, i: int, w: int, h: int, xo: int, yo: int, n: str, d) -> None:
|
def __displayLightEntity(self, i: int, w: int, h: int, xo: int, yo: int, n: str, d) -> None:
|
||||||
self.scr_vals[i] = d
|
self.scr_vals[i] = d
|
||||||
print("Checking if light is on")
|
|
||||||
# if the light is turned on, display the filled-in lightbulb icon in the colour of the light, centrally in the light's grid square
|
# if the light is turned on, display the filled-in lightbulb icon in the colour of the light, centrally in the light's grid square
|
||||||
if (d["on"]):
|
if (d["on"]):
|
||||||
color = Utils.colour(d["rgb_color"][0], d["rgb_color"][1], d["rgb_color"][2])
|
color = Utils.colour(d["rgb_color"][0], d["rgb_color"][1], d["rgb_color"][2])
|
||||||
@@ -108,9 +109,7 @@ class App:
|
|||||||
# otherwise display the outline lightbulb icon in grey, centrally in the light's grid square
|
# otherwise display the outline lightbulb icon in grey, centrally in the light's grid square
|
||||||
else:
|
else:
|
||||||
color = Utils.colour(80, 80, 80)
|
color = Utils.colour(80, 80, 80)
|
||||||
print("Opening file...")
|
|
||||||
with open("images/lightbulb-off.bmp", "rb") as file_handle:
|
with open("images/lightbulb-off.bmp", "rb") as file_handle:
|
||||||
print("Opened file")
|
|
||||||
reader = bmpr.BMPFileReader(file_handle)
|
reader = bmpr.BMPFileReader(file_handle)
|
||||||
img_height = reader.get_height()
|
img_height = reader.get_height()
|
||||||
x_offset = w//2 + xo - reader.get_width()//2
|
x_offset = w//2 + xo - reader.get_width()//2
|
||||||
@@ -137,9 +136,7 @@ class App:
|
|||||||
# TODO: handle buttons
|
# TODO: handle buttons
|
||||||
|
|
||||||
def __updateMediaPositionBar(self, d):
|
def __updateMediaPositionBar(self, d):
|
||||||
print("Redrawing media progress bar")
|
|
||||||
if (d["media_position"] != None and d["media_duration"] != None and d["media_duration"] != 0):
|
if (d["media_position"] != None and d["media_duration"] != None and d["media_duration"] != 0):
|
||||||
print(f"Progress is {(self.lcd.width * d["media_position"])//d["media_duration"]} for pos {d["media_position"]} and dur {d["media_duration"]}")
|
|
||||||
for x in range (0, (self.lcd.width * d["media_position"])//d["media_duration"]):
|
for x in range (0, (self.lcd.width * d["media_position"])//d["media_duration"]):
|
||||||
self.lcd.pixel(x, self.lcd.height - 2, self.lcd.white)
|
self.lcd.pixel(x, self.lcd.height - 2, self.lcd.white)
|
||||||
self.lcd.pixel(x, self.lcd.height - 1, self.lcd.white)
|
self.lcd.pixel(x, self.lcd.height - 1, self.lcd.white)
|
||||||
@@ -184,6 +181,10 @@ class App:
|
|||||||
# TODO: double button press to select a light, then up/down to change brightness? and single button click to turn on/off?
|
# TODO: double button press to select a light, then up/down to change brightness? and single button click to turn on/off?
|
||||||
self.lcd.show()
|
self.lcd.show()
|
||||||
|
|
||||||
|
def __handleLightsScreenButtons(self) -> bool:
|
||||||
|
# TODO: reset buttons used
|
||||||
|
return False
|
||||||
|
|
||||||
def __updateMediaScreen(self) -> None:
|
def __updateMediaScreen(self) -> None:
|
||||||
d = self.api.getMediaPlayerData(SCREENS[self.screen]["entity"])
|
d = self.api.getMediaPlayerData(SCREENS[self.screen]["entity"])
|
||||||
# if same media is playing (same title and duration), just update the position bar
|
# if same media is playing (same title and duration), just update the position bar
|
||||||
@@ -194,25 +195,46 @@ class App:
|
|||||||
else:
|
else:
|
||||||
self.__displayMediaScreen(d)
|
self.__displayMediaScreen(d)
|
||||||
|
|
||||||
|
def __handleMediaScreenButtons(self) -> bool:
|
||||||
|
up = self.lcd.up["v"]
|
||||||
|
down = self.lcd.down["v"]
|
||||||
|
self.lcd.up["v"] = False
|
||||||
|
self.lcd.down["v"] = False
|
||||||
|
a = False
|
||||||
|
if (up):
|
||||||
|
self.api.changeVolume(SCREENS[self.screen]["entity"])
|
||||||
|
a = True
|
||||||
|
elif (down):
|
||||||
|
self.api.changeVolume(SCREENS[self.screen]["entity"], False)
|
||||||
|
a = True
|
||||||
|
return a
|
||||||
|
# if (a): self.__handleMediaScreenButtons()
|
||||||
|
|
||||||
def __manageScreen(self) -> None:
|
def __manageScreen(self) -> None:
|
||||||
started = False
|
started = False
|
||||||
while (True):
|
while (True):
|
||||||
gc.collect()
|
gc.collect()
|
||||||
changed = not started or self.__changeScreen()
|
changed = not started or self.__changeScreen()
|
||||||
started = True
|
# TODO: make screen not change within given interval, as holding button too long changes it twice
|
||||||
|
if (not started): started = True
|
||||||
# if the screen has changed, redraw the whole screen
|
# if the screen has changed, redraw the whole screen
|
||||||
if (changed):
|
if (changed):
|
||||||
if (SCREENS[self.screen]["type"] == 0):
|
if (SCREENS[self.screen]["type"] == 0):
|
||||||
|
self.__resetButtonStatuses()
|
||||||
self.__displayLightsScreen()
|
self.__displayLightsScreen()
|
||||||
elif (SCREENS[self.screen]["type"] == 1):
|
elif (SCREENS[self.screen]["type"] == 1):
|
||||||
|
self.__resetButtonStatuses()
|
||||||
self.__displayMediaScreen()
|
self.__displayMediaScreen()
|
||||||
else:
|
else:
|
||||||
|
self.__resetButtonStatuses()
|
||||||
self.__displayUnknownScreen()
|
self.__displayUnknownScreen()
|
||||||
# otherwise minimise the number of pixels being changed
|
# otherwise minimise the number of pixels being changed
|
||||||
else:
|
else:
|
||||||
if (SCREENS[self.screen]["type"] == 0):
|
if (SCREENS[self.screen]["type"] == 0):
|
||||||
|
if (self.__handleLightsScreenButtons()): continue
|
||||||
self.__updateLightsScreen()
|
self.__updateLightsScreen()
|
||||||
elif (SCREENS[self.screen]["type"] == 1):
|
elif (SCREENS[self.screen]["type"] == 1):
|
||||||
|
if (self.__handleMediaScreenButtons()): continue
|
||||||
self.__updateMediaScreen()
|
self.__updateMediaScreen()
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user