Finish discovery method and rename all methods
This commit is contained in:
parent
fa438c8266
commit
5665d57191
|
@ -4,7 +4,6 @@
|
|||
],
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"python.pythonPath": "/home/evanf/.cache/pypoetry/virtualenvs/flickerstrip-py-zxDi65bL-py3.9/bin/python",
|
||||
"python.linting.flake8Enabled": true,
|
||||
"python.linting.enabled": true
|
||||
}
|
|
@ -1,18 +1,31 @@
|
|||
from ssdpy import SSDPClient
|
||||
import re
|
||||
import json
|
||||
from flickerstrip import Flickerstrip
|
||||
|
||||
|
||||
class FlickerstripDiscoveryClient:
|
||||
def __init__(self):
|
||||
self.client = SSDPClient()
|
||||
self.client = SSDPClient(timeout=10)
|
||||
|
||||
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):
|
||||
print("Discovering devices...")
|
||||
devices = self.client.m_search("ssdp:all")
|
||||
print(f"Discovered {len(devices)} devices.")
|
||||
for device in devices:
|
||||
print(device)
|
||||
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).")
|
||||
mapped = [self.__discovered(d) for d in filtered]
|
||||
return mapped
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
client = FlickerstripDiscoveryClient()
|
||||
client.discover()
|
||||
flickerstrips = client.discover()
|
||||
flickerstrips[0].force_update()
|
||||
print(json.dumps(flickerstrips[0].status.to_json()))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import requests
|
||||
from pattern import PatternMeta
|
||||
from status import Status
|
||||
from pattern import PatternMeta
|
||||
|
||||
|
||||
class Flickerstrip:
|
||||
|
@ -13,7 +13,7 @@ class Flickerstrip:
|
|||
self.ip_address = ip_address
|
||||
self.status = None
|
||||
|
||||
def __checkResponse(self, response):
|
||||
def __check_response(self, response):
|
||||
"""Check if the request was succesful.
|
||||
|
||||
Args:
|
||||
|
@ -22,22 +22,22 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was successful
|
||||
"""
|
||||
json = response.json()
|
||||
respType = json["type"]
|
||||
data = response.json()
|
||||
respType = data["type"]
|
||||
if respType == "error":
|
||||
message = json["message"]
|
||||
message = data["message"]
|
||||
print(f"ERROR: Request failed with message \"{message}\".")
|
||||
return False
|
||||
elif respType == "OK":
|
||||
return True
|
||||
elif respType == "status":
|
||||
self.status = Status.fromJSON(json)
|
||||
self.status = Status.from_json(data)
|
||||
return True
|
||||
else:
|
||||
print(f"ERROR: Unrecognized response type: {respType}.")
|
||||
return False
|
||||
|
||||
def __getRequest(self, path, params=None):
|
||||
def __get_request(self, path, params=None):
|
||||
"""Send a GET request to the strip.
|
||||
|
||||
Args:
|
||||
|
@ -49,9 +49,9 @@ class Flickerstrip:
|
|||
boolean: If the request was successful
|
||||
"""
|
||||
resp = requests.get(f"http://{self.ip_address}/{path}", params=params)
|
||||
return self.__checkResponse(resp)
|
||||
return self.__check_response(resp)
|
||||
|
||||
def __postRequest(self, path, json=None, data=None):
|
||||
def __post_request(self, path, json=None, data=None):
|
||||
"""Send a POST request to the strip.
|
||||
|
||||
Args:
|
||||
|
@ -65,49 +65,49 @@ class Flickerstrip:
|
|||
"""
|
||||
resp = requests.post(f"http://{self.ip_address}/{path}",
|
||||
json=json, data=data)
|
||||
return self.__checkResponse(resp)
|
||||
return self.__check_response(resp)
|
||||
|
||||
def forceUpdate(self):
|
||||
def force_update(self):
|
||||
"""Force updates the status of the strip.
|
||||
|
||||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("status")
|
||||
return self.__get_request("status")
|
||||
|
||||
def powerOn(self):
|
||||
def power_on(self):
|
||||
"""Trigger the strip to turn the lights on.
|
||||
|
||||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("power/on")
|
||||
return self.__get_request("power/on")
|
||||
|
||||
def powerOff(self):
|
||||
def power_off(self):
|
||||
"""Trigger the strip to turn the lights off.
|
||||
|
||||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("power/off")
|
||||
return self.__get_request("power/off")
|
||||
|
||||
def powerToggle(self):
|
||||
def power_toggle(self):
|
||||
"""Trigger the strip to toggle the power status.
|
||||
|
||||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("power/toggle")
|
||||
return self.__get_request("power/toggle")
|
||||
|
||||
def nextPattern(self):
|
||||
def next_pattern(self):
|
||||
"""Trigger the strip to switch to the next pattern in memory.
|
||||
|
||||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("pattern/next")
|
||||
return self.__get_request("pattern/next")
|
||||
|
||||
def freezeFrame(self, frame):
|
||||
def freeze_frame(self, frame):
|
||||
"""Freeze the animation at the specified frame.
|
||||
|
||||
Args:
|
||||
|
@ -116,9 +116,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("pattern/frame", {"value": frame})
|
||||
return self.__get_request("pattern/frame", {"value": frame})
|
||||
|
||||
def setPattern(self, index):
|
||||
def select_pattern(self, index):
|
||||
"""Change the current pattern to the pattern at the specified index.
|
||||
|
||||
Args:
|
||||
|
@ -127,23 +127,23 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("pattern/select", {"index": index})
|
||||
return self.__get_request("pattern/select", {"index": index})
|
||||
|
||||
def deletePattern(self, pattern=None, index=None, id=None):
|
||||
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.deletePattern(id=pattern.id)
|
||||
return self.delete_pattern(id=pattern.id)
|
||||
elif index is not None:
|
||||
return self.__getRequest("pattern/forget", {"index": index})
|
||||
return self.__get_request("pattern/forget", {"index": index})
|
||||
elif id is not None:
|
||||
return self.__getRequest("pattern/forget", {"id": id})
|
||||
return self.__get_request("pattern/forget", {"id": id})
|
||||
else:
|
||||
raise TypeError(
|
||||
"Deleting a pattern requires one of the three args.")
|
||||
|
||||
def setBrightness(self, value):
|
||||
def set_brightness(self, value):
|
||||
"""Set the brightness of the flickerstrip.
|
||||
|
||||
Args:
|
||||
|
@ -152,9 +152,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("brightness", {"value": value})
|
||||
return self.__get_request("brightness", {"value": value})
|
||||
|
||||
def setName(self, value):
|
||||
def set_name(self, value):
|
||||
"""Set the name of the flickerstrip.
|
||||
|
||||
Args:
|
||||
|
@ -163,9 +163,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__postRequest("config/name", {"name": value})
|
||||
return self.__post_request("config/name", {"name": value})
|
||||
|
||||
def setGroup(self, value):
|
||||
def set_group(self, value):
|
||||
"""Set the group of the flickerstrip.
|
||||
|
||||
Args:
|
||||
|
@ -174,9 +174,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__postRequest("config/group", {"name": value})
|
||||
return self.__post_request("config/group", {"name": value})
|
||||
|
||||
def setCycle(self, value):
|
||||
def set_cycle(self, value):
|
||||
"""Set the cycle timer of the flickerstrip.
|
||||
|
||||
Args:
|
||||
|
@ -186,9 +186,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("config/cycle", {"value": value})
|
||||
return self.__get_request("config/cycle", {"value": value})
|
||||
|
||||
def setFadeDuration(self, value):
|
||||
def set_fade_duration(self, value):
|
||||
"""Set the fade timer of the flickerstrip.
|
||||
|
||||
Args:
|
||||
|
@ -198,20 +198,20 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("config/fade", {"value": value})
|
||||
return self.__get_request("config/fade", {"value": value})
|
||||
|
||||
def setStripLength(self, value):
|
||||
def set_strip_length(self, value):
|
||||
"""Set the length of the flickerstrip.
|
||||
|
||||
Args:
|
||||
value (int): The length of the strip.
|
||||
value (int): The length of the strip in pixels.
|
||||
|
||||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("config/length", {"value": value})
|
||||
return self.__get_request("config/length", {"value": value})
|
||||
|
||||
def setStripStart(self, value):
|
||||
def set_strip_start(self, value):
|
||||
"""Set the start pixel of the strip.
|
||||
|
||||
This will make the flickerstrip ignore all pixels before
|
||||
|
@ -223,9 +223,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was successful.
|
||||
"""
|
||||
return self.__getRequest("config/start", {"value": value})
|
||||
return self.__get_request("config/start", {"value": value})
|
||||
|
||||
def setStripEnd(self, value):
|
||||
def set_strip_end(self, value):
|
||||
"""Set the end pixel of the strip.
|
||||
|
||||
This will make the flickerstrip ignore all pixels after
|
||||
|
@ -237,9 +237,9 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was successful.
|
||||
"""
|
||||
return self.__getRequest("config/end", {"value": value})
|
||||
return self.__get_request("config/end", {"value": value})
|
||||
|
||||
def setReversed(self, value):
|
||||
def set_reversed(self, value):
|
||||
"""Set the reversed state of the flickerstrip.
|
||||
|
||||
Args:
|
||||
|
@ -249,5 +249,5 @@ class Flickerstrip:
|
|||
Returns:
|
||||
boolean: If the request was succesful
|
||||
"""
|
||||
return self.__getRequest("config/reversed",
|
||||
return self.__get_request("config/reversed",
|
||||
{"value": 1 if value else 0})
|
||||
|
|
|
@ -7,11 +7,15 @@ class PatternMeta:
|
|||
self.flags = flags
|
||||
self.fps = fps
|
||||
|
||||
def fromJSON(json):
|
||||
return PatternMeta(
|
||||
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"]
|
||||
)
|
||||
|
||||
def fromJSONArray(array):
|
||||
return map(PatternMeta.fromJSON, array)
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
# Copyright 2014 Dan Krause, Python 3 hack 2016 Adam Baxter
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import socket
|
||||
import http.client
|
||||
import io
|
||||
|
||||
|
||||
class SSDPResponse(object):
|
||||
class _FakeSocket(io.BytesIO):
|
||||
def makefile(self, *args, **kw):
|
||||
return self
|
||||
|
||||
def __init__(self, response):
|
||||
r = http.client.HTTPResponse(self._FakeSocket(response))
|
||||
r.begin()
|
||||
self.location = r.getheader("location")
|
||||
self.usn = r.getheader("usn")
|
||||
self.st = r.getheader("st")
|
||||
self.cache = r.getheader("cache-control").split("=")[1]
|
||||
|
||||
def __repr__(self):
|
||||
return "<SSDPResponse({location}, {st}, {usn})>"\
|
||||
.format(**self.__dict__)
|
||||
|
||||
|
||||
def discover(service, timeout=5, retries=1, mx=3):
|
||||
group = ("239.255.255.250", 1900)
|
||||
message = "\r\n".join([
|
||||
'M-SEARCH * HTTP/1.1',
|
||||
'HOST: {0}:{1}',
|
||||
'MAN: "ssdp:discover"',
|
||||
'ST: {st}', 'MX: {mx}', '', ''])
|
||||
socket.setdefaulttimeout(timeout)
|
||||
responses = {}
|
||||
for _ in range(retries):
|
||||
sock = socket.socket(
|
||||
socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
|
||||
message_bytes = message.format(
|
||||
*group, st=service, mx=mx).encode('utf-8')
|
||||
sock.sendto(message_bytes, group)
|
||||
|
||||
while True:
|
||||
try:
|
||||
response = SSDPResponse(sock.recv(1024))
|
||||
responses[response.location] = response
|
||||
except socket.timeout:
|
||||
break
|
||||
return list(responses.values())
|
||||
|
||||
# Example:
|
||||
# import ssdp
|
||||
# ssdp.discover("roku:ecp")
|
|
@ -3,12 +3,18 @@ from pattern import PatternMeta
|
|||
|
||||
class MemoryUsage:
|
||||
def __init__(self, used, free, total):
|
||||
self.used
|
||||
self.free
|
||||
self.total
|
||||
self.used = used
|
||||
self.free = free
|
||||
self.total = total
|
||||
|
||||
def fromJSON(json):
|
||||
return MemoryUsage(json["used"], json["free"], json["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:
|
||||
|
@ -35,12 +41,25 @@ class Status:
|
|||
self.memory = memory
|
||||
self.patterns = patterns
|
||||
|
||||
def fromJSON(json):
|
||||
return Status(
|
||||
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"] == 1,
|
||||
json["uptime"], MemoryUsage.fromJSON(json["memory"]),
|
||||
PatternMeta.fromJSONArray(json["patterns"])
|
||||
json["fade"], json["reversed"] == 1, json["cycle"],
|
||||
json["uptime"], MemoryUsage.from_json(json["memory"]),
|
||||
[PatternMeta.from_json(p) for p in json["patterns"]]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue