Add create pattern

This commit is contained in:
Evan Fiordeliso 2021-12-18 22:30:14 -05:00
parent 7db59c7588
commit 74c6ee0987
4 changed files with 112 additions and 35 deletions

View File

@ -1,12 +1,13 @@
from ssdpy import SSDPClient from ssdpy import SSDPClient
import re import re
import json import json
from flickerstrip import Flickerstrip from flickerstrip_py.flickerstrip import Flickerstrip
class FlickerstripDiscoveryClient: class FlickerstripDiscoveryClient:
def __init__(self): def __init__(self, max_attempts=3):
self.client = SSDPClient(timeout=15) self.max_attempts = max_attempts
self.client = SSDPClient()
def __discovered(self, device): def __discovered(self, device):
loc = device["location"] loc = device["location"]
@ -15,13 +16,16 @@ class FlickerstripDiscoveryClient:
return Flickerstrip(ip_address) return Flickerstrip(ip_address)
def discover(self): def discover(self):
print("Discovering devices...") for i in range(self.max_attempts):
print(f"Discovering devices... (Attempt {i + 1})")
devices = self.client.m_search("ssdp:all") devices = self.client.m_search("ssdp:all")
print(f"Discovered {len(devices)} device(s).") print(f"Discovered {len(devices)} device(s).")
filtered = [d for d in devices if "Flickerstrip" in d["server"]] filtered = [d for d in devices if "Flickerstrip" in d["server"]]
print(f"Discovered {len(filtered)} flickerstrip(s).") print(f"Discovered {len(filtered)} flickerstrip(s).")
if len(filtered) > 0:
mapped = [self.__discovered(d) for d in filtered] mapped = [self.__discovered(d) for d in filtered]
return mapped return mapped
return []
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,6 +1,6 @@
import requests import requests
from status import Status from flickerstrip_py.status import Status
from pattern import PatternMeta from flickerstrip_py.pattern import PatternMeta, PatternBuilder
class Flickerstrip: class Flickerstrip:
@ -20,9 +20,17 @@ class Flickerstrip:
response (requests.Response): The response from the request. response (requests.Response): The response from the request.
Returns: Returns:
boolean: If the request was successful bool: If the request was successful
""" """
data = response.json() data = 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"] respType = data["type"]
if respType == "error": if respType == "error":
message = data["message"] message = data["message"]
@ -35,6 +43,7 @@ class Flickerstrip:
return True return True
else: else:
print(f"ERROR: Unrecognized response type: {respType}.") print(f"ERROR: Unrecognized response type: {respType}.")
print(data)
return False return False
def __get_request(self, path, params=None): def __get_request(self, path, params=None):
@ -46,32 +55,34 @@ class Flickerstrip:
request. Defaults to None. request. Defaults to None.
Returns: Returns:
boolean: If the request was successful bool: If the request was successful
""" """
resp = requests.get(f"http://{self.ip_address}/{path}", params=params) resp = requests.get(f"http://{self.ip_address}/{path}", params=params)
return self.__check_response(resp) return self.__check_response(resp)
def __post_request(self, path, json=None, data=None): def __post_request(self, path, json=None, params=None, data=None):
"""Send a POST request to the strip. """Send a POST request to the strip.
Args: Args:
path (string): The path for the URL to request. path (string): The path for the URL to request.
json (dictionary, optional): The JSON encodable body for the json (dictionary, optional): The JSON encodable body for the
request. Defaults to None. 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. data (string, optional): The raw data body. Defaults to None.
Returns: Returns:
boolean: If the request was successful bool: If the request was successful
""" """
resp = requests.post(f"http://{self.ip_address}/{path}", resp = requests.post(f"http://{self.ip_address}/{path}",
json=json, data=data) params=params, json=json, data=data)
return self.__check_response(resp) return self.__check_response(resp)
def force_update(self): def force_update(self):
"""Force updates the status of the strip. """Force updates the status of the strip.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("status") return self.__get_request("status")
@ -79,7 +90,7 @@ class Flickerstrip:
"""Trigger the strip to turn the lights on. """Trigger the strip to turn the lights on.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("power/on") return self.__get_request("power/on")
@ -87,7 +98,7 @@ class Flickerstrip:
"""Trigger the strip to turn the lights off. """Trigger the strip to turn the lights off.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("power/off") return self.__get_request("power/off")
@ -95,7 +106,7 @@ class Flickerstrip:
"""Trigger the strip to toggle the power status. """Trigger the strip to toggle the power status.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("power/toggle") return self.__get_request("power/toggle")
@ -103,7 +114,7 @@ class Flickerstrip:
"""Trigger the strip to switch to the next pattern in memory. """Trigger the strip to switch to the next pattern in memory.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("pattern/next") return self.__get_request("pattern/next")
@ -114,18 +125,19 @@ class Flickerstrip:
frame (int): The frame number to freeze on. frame (int): The frame number to freeze on.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("pattern/frame", {"value": frame}) return self.__get_request("pattern/frame", {"value": frame})
def select_pattern(self, index): def select_pattern(self, index):
"""Change the current pattern to the pattern at the specified index. """Change the current pattern to the pattern at the specified index.
s of the flickerstrip.
Args: Args:
index (int): The index of the pattern. index (int): The index of the pattern.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("pattern/select", {"index": index}) return self.__get_request("pattern/select", {"index": index})
@ -143,6 +155,40 @@ class Flickerstrip:
raise TypeError( raise TypeError(
"Deleting a pattern requires one of the three args.") "Deleting a pattern requires one of the three args.")
def create_pattern(self, pattern, 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 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())
def set_color(self, r, g, b):
"""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 self.create_pattern(pattern)
def set_brightness(self, value): def set_brightness(self, value):
"""Set the brightness of the flickerstrip. """Set the brightness of the flickerstrip.
@ -150,7 +196,7 @@ class Flickerstrip:
value (int): The brightness level as an int from 0 to 100. value (int): The brightness level as an int from 0 to 100.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("brightness", {"value": value}) return self.__get_request("brightness", {"value": value})
@ -161,7 +207,7 @@ class Flickerstrip:
value (string): The new name. value (string): The new name.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__post_request("config/name", {"name": value}) return self.__post_request("config/name", {"name": value})
@ -172,7 +218,7 @@ class Flickerstrip:
value (string): The new group. value (string): The new group.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__post_request("config/group", {"name": value}) return self.__post_request("config/group", {"name": value})
@ -184,7 +230,7 @@ class Flickerstrip:
Value is handled in seconds. Value is handled in seconds.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("config/cycle", {"value": value}) return self.__get_request("config/cycle", {"value": value})
@ -196,7 +242,7 @@ class Flickerstrip:
Value is handled in seconds. Value is handled in seconds.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("config/fade", {"value": value}) return self.__get_request("config/fade", {"value": value})
@ -207,7 +253,7 @@ class Flickerstrip:
value (int): The length of the strip in pixels. value (int): The length of the strip in pixels.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("config/length", {"value": value}) return self.__get_request("config/length", {"value": value})
@ -221,7 +267,7 @@ class Flickerstrip:
value (int): The new first pixel of the strip. value (int): The new first pixel of the strip.
Returns: Returns:
boolean: If the request was successful. bool: If the request was successful.
""" """
return self.__get_request("config/start", {"value": value}) return self.__get_request("config/start", {"value": value})
@ -235,7 +281,7 @@ class Flickerstrip:
value (int): The new last pixel of the strip. value (int): The new last pixel of the strip.
Returns: Returns:
boolean: If the request was successful. bool: If the request was successful.
""" """
return self.__get_request("config/end", {"value": value}) return self.__get_request("config/end", {"value": value})
@ -243,11 +289,11 @@ class Flickerstrip:
"""Set the reversed state of the flickerstrip. """Set the reversed state of the flickerstrip.
Args: Args:
value (boolean): If the flickerstrip should animate value (bool): If the flickerstrip should animate
patterns in reverse. patterns in reverse.
Returns: Returns:
boolean: If the request was succesful bool: If the request was succesful
""" """
return self.__get_request("config/reversed", return self.__get_request("config/reversed",
{"value": 1 if value else 0}) {"value": 1 if value else 0})

View File

@ -19,3 +19,30 @@ class PatternMeta:
json["id"], json["name"], json["frames"], json["id"], json["name"], json["frames"],
json["pixels"], json["flags"], json["fps"] json["pixels"], json["flags"], json["fps"]
) )
class PatternBuilder:
def __init__(self, name, fps=1):
self.pixels = []
self.name = name
self.fps = fps
self.frame_count = 1
self.pixel_count = 0
self.frame_pixels = 0
def add_pixel(self, r, g, b):
if self.frame_count == 1:
self.pixel_count += 1
self.frame_pixels += 1
self.pixels += [r, g, b]
def next_frame(self):
self.frame_count += 1
self.frame_pixels = 0
def is_valid(self):
self.frame_pixels == self.pixel_count
def to_binary_string(self):
return ''.join([chr(item) for item in self.pixels])

View File

@ -1,4 +1,4 @@
from pattern import PatternMeta from flickerstrip_py.pattern import PatternMeta
class MemoryUsage: class MemoryUsage: