Merge branch 'dev' into 'main'
Implemented API See merge request efiordeliso/flickerstrip-py!1
This commit is contained in:
commit
d808ca8ac8
|
@ -0,0 +1,183 @@
|
||||||
|
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
||||||
|
|
||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,python
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,python
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
.ionide
|
||||||
|
|
||||||
|
# Support for Project snippet scope
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,python
|
||||||
|
|
||||||
|
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
|
||||||
|
|
|
@ -3,5 +3,8 @@
|
||||||
"tests"
|
"tests"
|
||||||
],
|
],
|
||||||
"python.testing.unittestEnabled": false,
|
"python.testing.unittestEnabled": false,
|
||||||
"python.testing.pytestEnabled": true
|
"python.testing.pytestEnabled": true,
|
||||||
|
"python.linting.flake8Enabled": true,
|
||||||
|
"python.linting.enabled": true,
|
||||||
|
"python.pythonPath": ".venv/bin/python",
|
||||||
}
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
from ssdpy import SSDPClient
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
from flickerstrip_py.flickerstrip import Flickerstrip
|
||||||
|
|
||||||
|
|
||||||
|
class FlickerstripDiscoveryClient:
|
||||||
|
def __init__(self, max_attempts=3):
|
||||||
|
self.max_attempts = max_attempts
|
||||||
|
self.client = SSDPClient()
|
||||||
|
|
||||||
|
def __discovered(self, device):
|
||||||
|
loc = device["location"]
|
||||||
|
result = re.search("http://(.*):80/description.xml", loc)
|
||||||
|
ip_address = result.group(1)
|
||||||
|
return Flickerstrip(ip_address)
|
||||||
|
|
||||||
|
def discover(self):
|
||||||
|
for i in range(self.max_attempts):
|
||||||
|
print(f"Discovering devices... (Attempt {i + 1})")
|
||||||
|
devices = self.client.m_search("ssdp:all")
|
||||||
|
print(f"Discovered {len(devices)} device(s).")
|
||||||
|
filtered = [d for d in devices if "Flickerstrip" in d["server"]]
|
||||||
|
print(f"Discovered {len(filtered)} flickerstrip(s).")
|
||||||
|
if len(filtered) > 0:
|
||||||
|
mapped = [self.__discovered(d) for d in filtered]
|
||||||
|
return mapped
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
client = FlickerstripDiscoveryClient()
|
||||||
|
flickerstrips = client.discover()
|
||||||
|
if len(flickerstrips) > 0:
|
||||||
|
flickerstrips[0].force_update()
|
||||||
|
print(json.dumps(flickerstrips[0].status.to_json()))
|
|
@ -0,0 +1,308 @@
|
||||||
|
import requests
|
||||||
|
from flickerstrip_py.status import Status
|
||||||
|
from flickerstrip_py.pattern import PatternMeta, PatternBuilder
|
||||||
|
|
||||||
|
|
||||||
|
class Flickerstrip:
|
||||||
|
def __init__(self, ip_address):
|
||||||
|
"""The initializer for the Flickerstrip class.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ip_address (string): The ip address of the flickerstrip.
|
||||||
|
"""
|
||||||
|
self.ip_address = ip_address
|
||||||
|
self.status = None
|
||||||
|
|
||||||
|
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 = 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
|
||||||
|
|
||||||
|
def __get_request(self, path, params=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
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
resp = requests.get(f"http://{self.ip_address}/{path}",
|
||||||
|
params=params)
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
print("Unable to connect to flickerstrip, is it online?")
|
||||||
|
return False
|
||||||
|
return self.__check_response(resp)
|
||||||
|
|
||||||
|
def __post_request(self, path, json=None, params=None, data=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
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
resp = requests.post(f"http://{self.ip_address}/{path}",
|
||||||
|
params=params, json=json, data=data)
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
print("Unable to connect to flickerstrip, is it online?")
|
||||||
|
return False
|
||||||
|
return self.__check_response(resp)
|
||||||
|
|
||||||
|
def force_update(self):
|
||||||
|
"""Force updates the status of the strip.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("status")
|
||||||
|
|
||||||
|
def power_on(self):
|
||||||
|
"""Trigger the strip to turn the lights on.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("power/on")
|
||||||
|
|
||||||
|
def power_off(self):
|
||||||
|
"""Trigger the strip to turn the lights off.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("power/off")
|
||||||
|
|
||||||
|
def power_toggle(self):
|
||||||
|
"""Trigger the strip to toggle the power status.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("power/toggle")
|
||||||
|
|
||||||
|
def next_pattern(self):
|
||||||
|
"""Trigger the strip to switch to the next pattern in memory.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("pattern/next")
|
||||||
|
|
||||||
|
def freeze_frame(self, frame):
|
||||||
|
"""Freeze the animation at the specified frame.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
frame (int): The frame number to freeze on.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("pattern/frame", {"value": frame})
|
||||||
|
|
||||||
|
def select_pattern(self, index):
|
||||||
|
"""Change the current pattern to the pattern at the specified index.
|
||||||
|
s of the flickerstrip.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
index (int): The index of the pattern.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("pattern/select", {"index": index})
|
||||||
|
|
||||||
|
def delete_pattern(self, pattern=None, index=None, id=None):
|
||||||
|
if pattern is not None:
|
||||||
|
if not isinstance(pattern, PatternMeta):
|
||||||
|
raise TypeError(
|
||||||
|
"Expected a PatternMeta object for the pattern arg.")
|
||||||
|
return self.delete_pattern(id=pattern.id)
|
||||||
|
elif index is not None:
|
||||||
|
return self.__get_request("pattern/forget", {"index": index})
|
||||||
|
elif id is not None:
|
||||||
|
return self.__get_request("pattern/forget", {"id": id})
|
||||||
|
else:
|
||||||
|
raise TypeError(
|
||||||
|
"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):
|
||||||
|
"""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 self.__get_request("brightness", {"value": value})
|
||||||
|
|
||||||
|
def set_name(self, value):
|
||||||
|
"""Set the name of the flickerstrip.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (string): The new name.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__post_request("config/name", {"name": value})
|
||||||
|
|
||||||
|
def set_group(self, value):
|
||||||
|
"""Set the group of the flickerstrip.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (string): The new group.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__post_request("config/group", {"name": value})
|
||||||
|
|
||||||
|
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 self.__get_request("config/cycle", {"value": value})
|
||||||
|
|
||||||
|
def set_fade_duration(self, value):
|
||||||
|
"""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 self.__get_request("config/fade", {"value": value})
|
||||||
|
|
||||||
|
def set_strip_length(self, value):
|
||||||
|
"""Set the length of the flickerstrip.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (int): The length of the strip in pixels.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: If the request was succesful
|
||||||
|
"""
|
||||||
|
return self.__get_request("config/length", {"value": value})
|
||||||
|
|
||||||
|
def set_strip_start(self, value):
|
||||||
|
"""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 self.__get_request("config/start", {"value": value})
|
||||||
|
|
||||||
|
def set_strip_end(self, value):
|
||||||
|
"""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 self.__get_request("config/end", {"value": value})
|
||||||
|
|
||||||
|
def set_reversed(self, value):
|
||||||
|
"""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 self.__get_request("config/reversed",
|
||||||
|
{"value": 1 if value else 0})
|
|
@ -0,0 +1,48 @@
|
||||||
|
class PatternMeta:
|
||||||
|
def __init__(self, id, name, frames, pixels, flags, fps):
|
||||||
|
self.id = id
|
||||||
|
self.name = name
|
||||||
|
self.frames = frames
|
||||||
|
self.pixels = pixels
|
||||||
|
self.flags = flags
|
||||||
|
self.fps = fps
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"id": self.id, "name": self.name, "frames": self.frames,
|
||||||
|
"pixels": self.pixels, "flags": self.flags, "fps": self.fps
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
json["id"], json["name"], json["frames"],
|
||||||
|
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])
|
|
@ -0,0 +1,65 @@
|
||||||
|
from flickerstrip_py.pattern import PatternMeta
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryUsage:
|
||||||
|
def __init__(self, used, free, total):
|
||||||
|
self.used = used
|
||||||
|
self.free = free
|
||||||
|
self.total = total
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"used": self.used, "free": self.free, "total": self.total
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(json["used"], json["free"], json["total"])
|
||||||
|
|
||||||
|
|
||||||
|
class Status:
|
||||||
|
def __init__(
|
||||||
|
self, ap, name, group, firmware, power, mac,
|
||||||
|
selectedPattern, brightness, length, start, end,
|
||||||
|
fade, isReversed, cycle, uptime, memory, patterns
|
||||||
|
):
|
||||||
|
self.ap = ap
|
||||||
|
self.name = name
|
||||||
|
self.group = group
|
||||||
|
self.firmware = firmware
|
||||||
|
self.power = power
|
||||||
|
self.mac = mac
|
||||||
|
self.selectedPattern = selectedPattern
|
||||||
|
self.brightness = brightness
|
||||||
|
self.length = length
|
||||||
|
self.start = start
|
||||||
|
self.end = end
|
||||||
|
self.fade = fade
|
||||||
|
self.isReversed = isReversed
|
||||||
|
self.cycle = cycle
|
||||||
|
self.uptime = uptime
|
||||||
|
self.memory = memory
|
||||||
|
self.patterns = patterns
|
||||||
|
|
||||||
|
def to_json(self):
|
||||||
|
return {
|
||||||
|
"ap": self.ap, "name": self.name, "group": self.group,
|
||||||
|
"firmware": self.firmware, "power": 1 if self.power else 0,
|
||||||
|
"mac": self.mac, "selectedPattern": self.selectedPattern,
|
||||||
|
"brightness": self.brightness, "length": self.length,
|
||||||
|
"start": self.start, "end": self.end, "fade": self.fade,
|
||||||
|
"reversed": 1 if self.isReversed else 0, "cycle": self.cycle,
|
||||||
|
"uptime": self.uptime, "memory": self.memory.to_json(),
|
||||||
|
"patterns": [p.to_json() for p in self.patterns]
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_json(cls, json):
|
||||||
|
return cls(
|
||||||
|
json["ap"], json["name"], json["group"], json["firmware"],
|
||||||
|
json["power"] == 1, json["mac"], json["selectedPattern"],
|
||||||
|
json["brightness"], json["length"], json["start"], json["end"],
|
||||||
|
json["fade"], json["reversed"] == 1, json["cycle"],
|
||||||
|
json["uptime"], MemoryUsage.from_json(json["memory"]),
|
||||||
|
[PatternMeta.from_json(p) for p in json["patterns"]]
|
||||||
|
)
|
|
@ -20,6 +20,37 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
|
||||||
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autopep8"
|
||||||
|
version = "1.6.0"
|
||||||
|
description = "A tool that automatically formats Python code to conform to the PEP 8 style guide"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pycodestyle = ">=2.8.0"
|
||||||
|
toml = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "certifi"
|
||||||
|
version = "2021.10.8"
|
||||||
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "charset-normalizer"
|
||||||
|
version = "2.0.9"
|
||||||
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
unicode_backport = ["unicodedata2"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
@ -28,6 +59,27 @@ category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flake8"
|
||||||
|
version = "4.0.1"
|
||||||
|
description = "the modular source code checker: pep8 pyflakes and co"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
mccabe = ">=0.6.0,<0.7.0"
|
||||||
|
pycodestyle = ">=2.8.0,<2.9.0"
|
||||||
|
pyflakes = ">=2.4.0,<2.5.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "3.3"
|
||||||
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iniconfig"
|
name = "iniconfig"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
@ -36,6 +88,14 @@ category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mccabe"
|
||||||
|
version = "0.6.1"
|
||||||
|
description = "McCabe checker, plugin for flake8"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "21.3"
|
version = "21.3"
|
||||||
|
@ -67,6 +127,22 @@ category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycodestyle"
|
||||||
|
version = "2.8.0"
|
||||||
|
description = "Python style guide checker"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyflakes"
|
||||||
|
version = "2.4.0"
|
||||||
|
description = "passive checker of Python programs"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyparsing"
|
name = "pyparsing"
|
||||||
version = "3.0.6"
|
version = "3.0.6"
|
||||||
|
@ -111,6 +187,32 @@ python-versions = ">=3.6"
|
||||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||||
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-virtualenv", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-virtualenv", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "requests"
|
||||||
|
version = "2.26.0"
|
||||||
|
description = "Python HTTP for Humans."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
certifi = ">=2017.4.17"
|
||||||
|
charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
|
||||||
|
idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
|
||||||
|
urllib3 = ">=1.21.1,<1.27"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||||
|
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ssdpy"
|
||||||
|
version = "0.4.1"
|
||||||
|
description = "Python SSDP library"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
|
@ -119,10 +221,23 @@ category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "urllib3"
|
||||||
|
version = "1.26.7"
|
||||||
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
brotli = ["brotlipy (>=0.6.0)"]
|
||||||
|
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||||
|
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "571d381d2064ea8457d036b507628156c663014be7afe579d6f8f0247353665d"
|
content-hash = "3a12befea5c0f2cdf0b7779be1a2af0ff1d396566df3dfc771bf2e93c5f83c38"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
atomicwrites = [
|
atomicwrites = [
|
||||||
|
@ -133,14 +248,38 @@ attrs = [
|
||||||
{file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
|
{file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
|
||||||
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
|
{file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
|
||||||
]
|
]
|
||||||
|
autopep8 = [
|
||||||
|
{file = "autopep8-1.6.0-py2.py3-none-any.whl", hash = "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"},
|
||||||
|
{file = "autopep8-1.6.0.tar.gz", hash = "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979"},
|
||||||
|
]
|
||||||
|
certifi = [
|
||||||
|
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
|
||||||
|
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
|
||||||
|
]
|
||||||
|
charset-normalizer = [
|
||||||
|
{file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"},
|
||||||
|
{file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"},
|
||||||
|
]
|
||||||
colorama = [
|
colorama = [
|
||||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||||
]
|
]
|
||||||
|
flake8 = [
|
||||||
|
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
|
||||||
|
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
|
||||||
|
]
|
||||||
|
idna = [
|
||||||
|
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
|
||||||
|
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
|
||||||
|
]
|
||||||
iniconfig = [
|
iniconfig = [
|
||||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||||
]
|
]
|
||||||
|
mccabe = [
|
||||||
|
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||||
|
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||||
|
]
|
||||||
packaging = [
|
packaging = [
|
||||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||||
|
@ -153,6 +292,14 @@ py = [
|
||||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||||
]
|
]
|
||||||
|
pycodestyle = [
|
||||||
|
{file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
|
||||||
|
{file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
|
||||||
|
]
|
||||||
|
pyflakes = [
|
||||||
|
{file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
|
||||||
|
{file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
|
||||||
|
]
|
||||||
pyparsing = [
|
pyparsing = [
|
||||||
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
|
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
|
||||||
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
|
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
|
||||||
|
@ -165,7 +312,19 @@ pytest-runner = [
|
||||||
{file = "pytest-runner-5.3.1.tar.gz", hash = "sha256:0fce5b8dc68760f353979d99fdd6b3ad46330b6b1837e2077a89ebcf204aac91"},
|
{file = "pytest-runner-5.3.1.tar.gz", hash = "sha256:0fce5b8dc68760f353979d99fdd6b3ad46330b6b1837e2077a89ebcf204aac91"},
|
||||||
{file = "pytest_runner-5.3.1-py3-none-any.whl", hash = "sha256:85f93af814438ee322b4ea08fe3f5c2ad53b253577f3bd84b2ad451fee450ac5"},
|
{file = "pytest_runner-5.3.1-py3-none-any.whl", hash = "sha256:85f93af814438ee322b4ea08fe3f5c2ad53b253577f3bd84b2ad451fee450ac5"},
|
||||||
]
|
]
|
||||||
|
requests = [
|
||||||
|
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
|
||||||
|
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
|
||||||
|
]
|
||||||
|
ssdpy = [
|
||||||
|
{file = "ssdpy-0.4.1-py2.py3-none-any.whl", hash = "sha256:f2a84915140a8df9d9432e35a487c8712fe23158d278f90f72ed5bd49fcf2bb5"},
|
||||||
|
{file = "ssdpy-0.4.1.tar.gz", hash = "sha256:4971c6a010f77f147ecdbec9593f2d9187c3fb63658b0f5ec08f4c7be2387425"},
|
||||||
|
]
|
||||||
toml = [
|
toml = [
|
||||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||||
]
|
]
|
||||||
|
urllib3 = [
|
||||||
|
{file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"},
|
||||||
|
{file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"},
|
||||||
|
]
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
|
@ -6,10 +6,14 @@ authors = ["Evan Fiordeliso <evan.fiordeliso@gmail.com>"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.9"
|
python = "^3.9"
|
||||||
|
requests = "^2.26.0"
|
||||||
|
ssdpy = "^0.4.1"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "^6.2.5"
|
pytest = "^6.2.5"
|
||||||
pytest-runner = "^5.3.1"
|
pytest-runner = "^5.3.1"
|
||||||
|
flake8 = "^4.0.1"
|
||||||
|
autopep8 = "^1.6.0"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
|
|
Loading…
Reference in New Issue