331 lines
11 KiB
Python
331 lines
11 KiB
Python
from typing import Any, Optional, Mapping
|
|
import aiohttp
|
|
from .status import Status
|
|
from .pattern import PatternMeta, PatternBuilder
|
|
|
|
|
|
class Flickerstrip:
|
|
def __init__(self, host: str, port=80):
|
|
"""The initializer for the Flickerstrip class.
|
|
|
|
Args:
|
|
host (string): The host of the flickerstrip.
|
|
port (int, optional): The port of the flickerstrip.
|
|
Defaults to port 80.
|
|
"""
|
|
self.host = host
|
|
self.port = port
|
|
self.status = None
|
|
|
|
async def __check_response(self, response):
|
|
"""Check if the request was succesful.
|
|
|
|
Args:
|
|
response (requests.Response): The response from the request.
|
|
|
|
Returns:
|
|
bool: If the request was successful
|
|
"""
|
|
data = await response.json()
|
|
|
|
if "type" not in data:
|
|
if "id" in data: # create pattern response.
|
|
return True
|
|
print("ERROR: Unable to get response type!")
|
|
print(data)
|
|
return False
|
|
|
|
respType = data["type"]
|
|
if respType == "error":
|
|
message = data["message"]
|
|
print(f"ERROR: Request failed with message \"{message}\".")
|
|
return False
|
|
elif respType == "OK":
|
|
return True
|
|
elif respType == "status":
|
|
self.status = Status.from_json(data)
|
|
return True
|
|
else:
|
|
print(f"ERROR: Unrecognized response type: {respType}.")
|
|
print(data)
|
|
return False
|
|
|
|
async def __get_request(self, path: str,
|
|
params: Optional[Mapping[str, str]] = None):
|
|
"""Send a GET request to the strip.
|
|
|
|
Args:
|
|
path (string): The path for the URL to request.
|
|
params (dictionary, optional): The query string params for the
|
|
request. Defaults to None.
|
|
|
|
Returns:
|
|
bool: If the request was successful
|
|
"""
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.get(f"http://{self.host}:{self.port}/{path}",
|
|
params=params) as response:
|
|
return await self.__check_response(response)
|
|
|
|
async def __post_request(self, path,
|
|
params: Optional[Mapping[str, str]] = None,
|
|
json: Any = None,
|
|
data: Any = None):
|
|
"""Send a POST request to the strip.
|
|
|
|
Args:
|
|
path (string): The path for the URL to request.
|
|
json (dictionary, optional): The JSON encodable body for the
|
|
request. Defaults to None.
|
|
params (dictionary, optional): The query string params for the
|
|
request. Defaults to None.
|
|
data (string, optional): The raw data body. Defaults to None.
|
|
|
|
Returns:
|
|
bool: If the request was successful
|
|
"""
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.post(f"http://{self.host}:{self.port}/{path}",
|
|
params=params, json=json, data=data
|
|
) as response:
|
|
return await self.__check_response(response)
|
|
|
|
async def force_update(self):
|
|
"""Force updates the status of the strip.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("status")
|
|
|
|
async def power_on(self):
|
|
"""Trigger the strip to turn the lights on.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("power/on")
|
|
|
|
async def power_off(self):
|
|
"""Trigger the strip to turn the lights off.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("power/off")
|
|
|
|
async def power_toggle(self):
|
|
"""Trigger the strip to toggle the power status.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("power/toggle")
|
|
|
|
async def next_pattern(self):
|
|
"""Trigger the strip to switch to the next pattern in memory.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("pattern/next")
|
|
|
|
async def freeze_frame(self, frame: int):
|
|
"""Freeze the animation at the specified frame.
|
|
|
|
Args:
|
|
frame (int): The frame number to freeze on.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("pattern/frame",
|
|
params={"value": frame})
|
|
|
|
async def select_pattern(self, index: int):
|
|
"""Change the current pattern to the pattern at the specified index.
|
|
|
|
Args:
|
|
index (int): The index of the pattern.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("pattern/select",
|
|
params={"index": index})
|
|
|
|
async def delete_pattern(self,
|
|
pattern: Optional[PatternMeta] = None,
|
|
index: Optional[int] = None,
|
|
id: Optional[str] = None):
|
|
"""Delete a pattern by its meta, index, or id
|
|
|
|
Args:
|
|
pattern (PatternMeta, optional): The pattern meta.
|
|
index (int, optional): The index of the pattern.
|
|
id (string, optional): The id of the pattern.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
if pattern is not None:
|
|
if not isinstance(pattern, PatternMeta):
|
|
raise TypeError(
|
|
"Expected a PatternMeta object for the pattern arg.")
|
|
return await self.delete_pattern(id=pattern.id)
|
|
elif index is not None:
|
|
return await self.__get_request("pattern/forget",
|
|
params={"index": index})
|
|
elif id is not None:
|
|
return await self.__get_request("pattern/forget",
|
|
params={"id": id})
|
|
else:
|
|
raise TypeError(
|
|
"Deleting a pattern requires one of the three args.")
|
|
|
|
async def create_pattern(self, pattern: PatternBuilder, preview=True):
|
|
"""Create a pattern on the flickerstrip.
|
|
|
|
Args:
|
|
pattern (PatternBuilder): The pattern to send.
|
|
preview (bool, optional): Whether to only preview the pattern.
|
|
Defaults to True.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__post_request("pattern/create", params={
|
|
"name": pattern.name,
|
|
"fps": pattern.fps,
|
|
"frames": pattern.frame_count,
|
|
"pixels": pattern.pixel_count,
|
|
"preview": preview
|
|
}, data=pattern.to_binary_string())
|
|
|
|
async def set_color(self, r: int, g: int, b: int):
|
|
"""Sets the strip to a solid color (given as an RGB value).
|
|
|
|
Args:
|
|
r (int): The red value (0 - 255)
|
|
g (int): The green value (0 - 255)
|
|
b (int): The blue value (0 - 255)
|
|
|
|
Returns:
|
|
bool: If the request was successful
|
|
"""
|
|
pattern = PatternBuilder("Solid")
|
|
pattern.add_pixel(r, g, b)
|
|
return await self.create_pattern(pattern)
|
|
|
|
async def set_brightness(self, value: int):
|
|
"""Set the brightness of the flickerstrip.
|
|
|
|
Args:
|
|
value (int): The brightness level as an int from 0 to 100.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("brightness", params={"value": value})
|
|
|
|
async def set_name(self, value: str):
|
|
"""Set the name of the flickerstrip.
|
|
|
|
Args:
|
|
value (string): The new name.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__post_request("config/name", json={"name": value})
|
|
|
|
async def set_group(self, value: str):
|
|
"""Set the group of the flickerstrip.
|
|
|
|
Args:
|
|
value (string): The new group.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__post_request("config/group", json={"name": value})
|
|
|
|
async def set_cycle(self, value):
|
|
"""Set the cycle timer of the flickerstrip.
|
|
|
|
Args:
|
|
value (int): How long to cycle to next pattern.
|
|
Value is handled in seconds.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("config/cycle",
|
|
params={"value": value})
|
|
|
|
async def set_fade_duration(self, value: int):
|
|
"""Set the fade timer of the flickerstrip.
|
|
|
|
Args:
|
|
value (int): How long to fade to next pattern.
|
|
Value is handled in seconds.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("config/fade", params={"value": value})
|
|
|
|
async def set_strip_length(self, value: int):
|
|
"""Set the length of the flickerstrip.
|
|
|
|
Args:
|
|
value (int): The length of the strip in pixels.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("config/length",
|
|
params={"value": value})
|
|
|
|
async def set_strip_start(self, value: int):
|
|
"""Set the start pixel of the strip.
|
|
|
|
This will make the flickerstrip ignore all pixels before
|
|
the given number, set to 0 for the first pixel.
|
|
|
|
Args:
|
|
value (int): The new first pixel of the strip.
|
|
|
|
Returns:
|
|
bool: If the request was successful.
|
|
"""
|
|
return await self.__get_request("config/start",
|
|
params={"value": value})
|
|
|
|
async def set_strip_end(self, value: int):
|
|
"""Set the end pixel of the strip.
|
|
|
|
This will make the flickerstrip ignore all pixels after
|
|
the given number, set to -1 for the last pixel.
|
|
|
|
Args:
|
|
value (int): The new last pixel of the strip.
|
|
|
|
Returns:
|
|
bool: If the request was successful.
|
|
"""
|
|
return await self.__get_request("config/end", params={"value": value})
|
|
|
|
async def set_reversed(self, value: bool):
|
|
"""Set the reversed state of the flickerstrip.
|
|
|
|
Args:
|
|
value (bool): If the flickerstrip should animate
|
|
patterns in reverse.
|
|
|
|
Returns:
|
|
bool: If the request was succesful
|
|
"""
|
|
return await self.__get_request("config/reversed",
|
|
params={"value": 1 if value else 0})
|