mirror of https://github.com/LedFx/LedFx.git
Pre-Commit Update & Run
This commit is contained in:
parent
97529750ec
commit
858f0baeae
|
@ -13,19 +13,19 @@ repos:
|
|||
- id: trailing-whitespace
|
||||
- id: check-toml
|
||||
- repo: https://github.com/PyCQA/isort
|
||||
rev: 5.9.3
|
||||
rev: 5.10.0
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 4.0.1
|
||||
rev: 3.9.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 21.9b0 # Replace by any tag/version: https://github.com/psf/black/tags
|
||||
rev: 21.10b0 # Replace by any tag/version: https://github.com/psf/black/tags
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.23.3
|
||||
rev: v2.29.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py38-plus]
|
|
@ -1,15 +1,14 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import socket
|
||||
from abc import abstractmethod
|
||||
from functools import cached_property
|
||||
|
||||
import numpy as np
|
||||
import voluptuous as vol
|
||||
import zeroconf
|
||||
|
||||
import socket
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
import voluptuous as vol
|
||||
import zeroconf
|
||||
|
||||
from ledfx.config import save_config
|
||||
from ledfx.events import DeviceUpdateEvent, Event
|
||||
|
@ -364,12 +363,16 @@ class UDPDevice(NetworkedDevice):
|
|||
|
||||
def activate(self):
|
||||
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
_LOGGER.info(f"{self._device_type} sender for {self.config['name']} started.")
|
||||
_LOGGER.info(
|
||||
f"{self._device_type} sender for {self.config['name']} started."
|
||||
)
|
||||
super().activate()
|
||||
|
||||
def deactivate(self):
|
||||
super().deactivate()
|
||||
_LOGGER.info(f"{self._device_type} sender for {self.config['name']} stopped.")
|
||||
_LOGGER.info(
|
||||
f"{self._device_type} sender for {self.config['name']} stopped."
|
||||
)
|
||||
self._sock = None
|
||||
|
||||
|
||||
|
@ -381,6 +384,7 @@ class AvailableCOMPorts:
|
|||
for p in ports:
|
||||
available_ports.append(p.device)
|
||||
|
||||
|
||||
@BaseRegistry.no_registration
|
||||
class SerialDevice(Device):
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ class AdalightDevice(SerialDevice):
|
|||
|
||||
def flush(self, data):
|
||||
try:
|
||||
self.serial.write(packets.build_adalight_packet(data, self.color_order))
|
||||
self.serial.write(
|
||||
packets.build_adalight_packet(data, self.color_order)
|
||||
)
|
||||
|
||||
except serial.SerialException:
|
||||
_LOGGER.critical(
|
||||
|
|
|
@ -56,7 +56,11 @@ class DDPDevice(UDPDevice):
|
|||
self.frame_count += 1
|
||||
try:
|
||||
DDPDevice.send_out(
|
||||
self._sock, self.destination, self._config["port"], data, self.frame_count
|
||||
self._sock,
|
||||
self.destination,
|
||||
self._config["port"],
|
||||
data,
|
||||
self.frame_count,
|
||||
)
|
||||
except AttributeError:
|
||||
self.activate()
|
||||
|
|
|
@ -11,31 +11,34 @@ Byte Description
|
|||
4 + n*4 Green Value
|
||||
5 + n*4 Blue Value
|
||||
"""
|
||||
|
||||
|
||||
def build_warls_packet(data: np.ndarray, timeout: int, last_frame: np.array):
|
||||
packet = bytearray([1, (timeout or 1)])
|
||||
|
||||
byteData = data.astype(np.dtype("B"))
|
||||
|
||||
if last_frame is None or data.shape != last_frame.shape:
|
||||
last_frame = np.full(data.shape ,np.nan)
|
||||
'''
|
||||
last_frame = np.full(data.shape, np.nan)
|
||||
"""
|
||||
for i in range(len(byteData)): # loop through byteData
|
||||
if not np.array_equal(last_bytes[i], byteData[i]): # if index has changed from last sent frame
|
||||
packet.extend(bytes([i])) # add index as first byte
|
||||
packet.extend(byteData[i].flatten().tobytes())
|
||||
''' # do above in numpy
|
||||
""" # do above in numpy
|
||||
# get indexes of pixels that have changed
|
||||
idx=np.flatnonzero(np.any(last_frame!=data, axis=1))
|
||||
idx = np.flatnonzero(np.any(last_frame != data, axis=1))
|
||||
# make a new output array
|
||||
out=np.zeros((len(idx), 4), dtype="B")
|
||||
out = np.zeros((len(idx), 4), dtype="B")
|
||||
# first byte of each pixel is the index
|
||||
out[:,0] = idx
|
||||
out[:, 0] = idx
|
||||
# final three bytes are the pixel values
|
||||
out[:,1:] = byteData[idx]
|
||||
out[:, 1:] = byteData[idx]
|
||||
# convert out to bytes to send
|
||||
packet.extend(out.flatten().tobytes())
|
||||
return packet
|
||||
|
||||
|
||||
"""
|
||||
Generic DRGB packet encoding
|
||||
Max LEDs: 490
|
||||
|
@ -47,6 +50,8 @@ Byte Description
|
|||
4 + n*3 Blue Value
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def build_drgb_packet(data: np.ndarray, timeout: int):
|
||||
packet = bytearray([2, (timeout or 1)])
|
||||
|
||||
|
@ -54,7 +59,8 @@ def build_drgb_packet(data: np.ndarray, timeout: int):
|
|||
packet.extend(byteData.flatten().tobytes())
|
||||
return packet
|
||||
|
||||
'''
|
||||
|
||||
"""
|
||||
Generic DRGBW packet encoding
|
||||
Max LEDs: 367
|
||||
|
||||
|
@ -64,20 +70,21 @@ Byte Description
|
|||
3 + n*3 Green Value
|
||||
4 + n*3 Blue Value
|
||||
5 + n*4 White Value
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def build_drgbw_packet(data: np.ndarray, timeout: int):
|
||||
packet = bytearray([3, (timeout or 1)])
|
||||
|
||||
byteData = data.astype(np.dtype("B"))
|
||||
out = np.zeros((len(byteData), 4), dtype="B")
|
||||
out[:,:3] = byteData
|
||||
out[:, :3] = byteData
|
||||
# 4th column is unusued white channel -> 0
|
||||
packet.extend(out.flatten().tobytes())
|
||||
|
||||
|
||||
# for i in range(len(byteData)):
|
||||
# packet.extend(byteData[i].flatten().tobytes())
|
||||
# packet.extend(bytes(0))
|
||||
# packet.extend(bytes(0))
|
||||
return packet
|
||||
|
||||
|
||||
|
@ -91,13 +98,20 @@ Byte Description
|
|||
5 + n*3 Green Value
|
||||
6 + n*3 Blue Value
|
||||
"""
|
||||
def build_dnrgb_packet(data: np.ndarray, timeout: int, led_start_index: np.uint16):
|
||||
packet = bytearray([4, (timeout or 1), (led_start_index >> 8),(led_start_index & 0x00ff)]) # high byte, then low byte
|
||||
|
||||
|
||||
def build_dnrgb_packet(
|
||||
data: np.ndarray, timeout: int, led_start_index: np.uint16
|
||||
):
|
||||
packet = bytearray(
|
||||
[4, (timeout or 1), (led_start_index >> 8), (led_start_index & 0x00FF)]
|
||||
) # high byte, then low byte
|
||||
|
||||
byteData = data.astype(np.dtype("B"))
|
||||
packet.extend(byteData.flatten().tobytes())
|
||||
return packet
|
||||
|
||||
|
||||
"""
|
||||
Generic Adalight serial packet encoding
|
||||
|
||||
|
@ -107,15 +121,25 @@ Byte Description
|
|||
5 + n*3 Green Value
|
||||
6 + n*3 Blue Value
|
||||
"""
|
||||
|
||||
|
||||
def build_adalight_packet(data: np.ndarray, color_order: str):
|
||||
pixel_length = len(data)
|
||||
packet = bytearray([ord("A"), ord("d"), ord("a"), (pixel_length >> 8),(pixel_length & 0x00ff)]) # high byte, then low byte
|
||||
packet.extend([packet[3] ^ packet[4] ^ 0x55]) # checksum
|
||||
packet = bytearray(
|
||||
[
|
||||
ord("A"),
|
||||
ord("d"),
|
||||
ord("a"),
|
||||
(pixel_length >> 8),
|
||||
(pixel_length & 0x00FF),
|
||||
]
|
||||
) # high byte, then low byte
|
||||
packet.extend([packet[3] ^ packet[4] ^ 0x55]) # checksum
|
||||
|
||||
byteData = data.astype(np.dtype("B"))
|
||||
# if color_order == "RGB": pass
|
||||
if color_order == "GRB":
|
||||
byteData[:, [1, 0]] = byteData[:, [0, 1]] # swap columns
|
||||
byteData[:, [1, 0]] = byteData[:, [0, 1]] # swap columns
|
||||
elif color_order == "BGR":
|
||||
byteData[:, [2, 0]] = byteData[:, [0, 2]]
|
||||
elif color_order == "RBG":
|
||||
|
|
|
@ -8,13 +8,8 @@ from ledfx.devices import UDPDevice, packets
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SUPPORTED_PACKETS = [
|
||||
"DRGB",
|
||||
"WARLS",
|
||||
"DRGBW",
|
||||
"DNRGB",
|
||||
"adaptive_smallest"
|
||||
]
|
||||
SUPPORTED_PACKETS = ["DRGB", "WARLS", "DRGBW", "DNRGB", "adaptive_smallest"]
|
||||
|
||||
|
||||
class UDPRealtimeDevice(UDPDevice):
|
||||
"""Generic WLED UDP Realtime device support"""
|
||||
|
@ -52,12 +47,15 @@ class UDPRealtimeDevice(UDPDevice):
|
|||
def __init__(self, ledfx, config):
|
||||
super().__init__(ledfx, config)
|
||||
self._device_type = "UDP Realtime"
|
||||
self.last_frame = np.full((config['pixel_count'], 3), -1)
|
||||
self.last_frame = np.full((config["pixel_count"], 3), -1)
|
||||
self.last_frame_sent_time = 0
|
||||
|
||||
def flush(self, data):
|
||||
try:
|
||||
self.choose_and_send_packet(data, self._config["timeout"],)
|
||||
self.choose_and_send_packet(
|
||||
data,
|
||||
self._config["timeout"],
|
||||
)
|
||||
self.last_frame = np.copy(data)
|
||||
except AttributeError:
|
||||
self.activate()
|
||||
|
@ -71,56 +69,100 @@ class UDPRealtimeDevice(UDPDevice):
|
|||
|
||||
if self._config["udp_packet_type"] == "DRGB" and frame_size <= 490:
|
||||
udpData = packets.build_drgb_packet(data, timeout)
|
||||
self.transmit_packet(udpData, np.array_equal(data, self.last_frame))
|
||||
self.transmit_packet(
|
||||
udpData, np.array_equal(data, self.last_frame)
|
||||
)
|
||||
|
||||
elif self._config["udp_packet_type"] == "WARLS" and frame_size <= 255:
|
||||
udpData = packets.build_warls_packet(data, timeout, self.last_frame)
|
||||
self.transmit_packet(udpData, np.array_equal(data, self.last_frame))
|
||||
udpData = packets.build_warls_packet(
|
||||
data, timeout, self.last_frame
|
||||
)
|
||||
self.transmit_packet(
|
||||
udpData, np.array_equal(data, self.last_frame)
|
||||
)
|
||||
|
||||
elif self._config["udp_packet_type"] == "DRGBW" and frame_size <= 367:
|
||||
udpData = packets.build_drgbw_packet(data, timeout)
|
||||
self.transmit_packet(udpData, np.array_equal(data, self.last_frame))
|
||||
self.transmit_packet(
|
||||
udpData, np.array_equal(data, self.last_frame)
|
||||
)
|
||||
|
||||
elif self._config["udp_packet_type"] == "DNRGB":
|
||||
number_of_packets = int(np.ceil(frame_size / 489))
|
||||
for i in range(number_of_packets):
|
||||
start_index = i * 489
|
||||
end_index = start_index + 489
|
||||
udpData = packets.build_dnrgb_packet(data[start_index:end_index], timeout, start_index)
|
||||
self.transmit_packet(udpData, np.array_equal(data[start_index:end_index], self.last_frame[start_index:end_index]))
|
||||
udpData = packets.build_dnrgb_packet(
|
||||
data[start_index:end_index], timeout, start_index
|
||||
)
|
||||
self.transmit_packet(
|
||||
udpData,
|
||||
np.array_equal(
|
||||
data[start_index:end_index],
|
||||
self.last_frame[start_index:end_index],
|
||||
),
|
||||
)
|
||||
|
||||
elif self._config["udp_packet_type"] == "adaptive_smallest" and frame_size <= 255:
|
||||
elif (
|
||||
self._config["udp_packet_type"] == "adaptive_smallest"
|
||||
and frame_size <= 255
|
||||
):
|
||||
# compare potential size of WARLS packet to DRGB packet
|
||||
if np.count_nonzero(np.any(data!=self.last_frame, axis=1)) * 4 < len(data) * 3:
|
||||
udpData = packets.build_warls_packet(data, timeout, self.last_frame)
|
||||
self.transmit_packet(udpData, np.array_equal(data, self.last_frame))
|
||||
if (
|
||||
np.count_nonzero(np.any(data != self.last_frame, axis=1)) * 4
|
||||
< len(data) * 3
|
||||
):
|
||||
udpData = packets.build_warls_packet(
|
||||
data, timeout, self.last_frame
|
||||
)
|
||||
self.transmit_packet(
|
||||
udpData, np.array_equal(data, self.last_frame)
|
||||
)
|
||||
else:
|
||||
udpData = packets.build_drgb_packet(data, timeout)
|
||||
self.transmit_packet(udpData, np.array_equal(data, self.last_frame))
|
||||
self.transmit_packet(
|
||||
udpData, np.array_equal(data, self.last_frame)
|
||||
)
|
||||
|
||||
else: # fallback
|
||||
else: # fallback
|
||||
_LOGGER.warning(
|
||||
f"UDP packet is configured incorrectly (please choose a packet that supports {self._config['pixel_count']} LEDs): https://kno.wled.ge/interfaces/udp-realtime/#udp-realtime \n Falling back to supported udp packet."
|
||||
)
|
||||
if frame_size <= 490: # DRGB
|
||||
if frame_size <= 490: # DRGB
|
||||
udpData = packets.build_drgb_packet(data, timeout)
|
||||
self.transmit_packet(udpData, np.array_equal(data, self.last_frame))
|
||||
else: #DNRGB
|
||||
self.transmit_packet(
|
||||
udpData, np.array_equal(data, self.last_frame)
|
||||
)
|
||||
else: # DNRGB
|
||||
number_of_packets = int(np.ceil(frame_size / 489))
|
||||
for i in range(number_of_packets):
|
||||
start_index = i * 489
|
||||
end_index = start_index + 489
|
||||
udpData = packets.build_dnrgb_packet(data[start_index:end_index], timeout, start_index)
|
||||
self.transmit_packet(udpData, np.array_equal(data[start_index:end_index], self.last_frame[start_index:end_index]))
|
||||
|
||||
udpData = packets.build_dnrgb_packet(
|
||||
data[start_index:end_index], timeout, start_index
|
||||
)
|
||||
self.transmit_packet(
|
||||
udpData,
|
||||
np.array_equal(
|
||||
data[start_index:end_index],
|
||||
self.last_frame[start_index:end_index],
|
||||
),
|
||||
)
|
||||
|
||||
def transmit_packet(self, packet, frame_is_equal_to_last: bool):
|
||||
timestamp = time.time()
|
||||
if self._config["minimise_traffic"] and frame_is_equal_to_last:
|
||||
half_of_timeout = (((self._config["timeout"] * self._config["refresh_rate"]) - 1) // 2) / self._config["refresh_rate"]
|
||||
if (timestamp > self.last_frame_sent_time + half_of_timeout):
|
||||
self._sock.sendto(bytes(packet),(self.destination, self._config["port"]))
|
||||
half_of_timeout = (
|
||||
((self._config["timeout"] * self._config["refresh_rate"]) - 1)
|
||||
// 2
|
||||
) / self._config["refresh_rate"]
|
||||
if timestamp > self.last_frame_sent_time + half_of_timeout:
|
||||
self._sock.sendto(
|
||||
bytes(packet), (self.destination, self._config["port"])
|
||||
)
|
||||
self.last_frame_sent_time = timestamp
|
||||
else:
|
||||
self._sock.sendto(bytes(packet),(self.destination, self._config["port"]))
|
||||
self.last_frame_sent_time = timestamp
|
||||
self._sock.sendto(
|
||||
bytes(packet), (self.destination, self._config["port"])
|
||||
)
|
||||
self.last_frame_sent_time = timestamp
|
||||
|
|
|
@ -42,7 +42,7 @@ class WLEDDevice(NetworkedDevice):
|
|||
"ip_address": None,
|
||||
"pixel_count": None,
|
||||
"port": 21324,
|
||||
"udp_packet_type": "DNRGB"
|
||||
"udp_packet_type": "DNRGB",
|
||||
},
|
||||
"DDP": {
|
||||
"name": None,
|
||||
|
|
|
@ -94,7 +94,9 @@ class AudioInputSource:
|
|||
vol.Optional("sample_rate", default=60): int,
|
||||
vol.Optional("mic_rate", default=MIC_RATE): int,
|
||||
vol.Optional("fft_size", default=FFT_SIZE): int,
|
||||
vol.Optional("min_volume", default=0.2): vol.All(vol.Coerce(float), vol.Range(min=0.0, max=10.0)),
|
||||
vol.Optional("min_volume", default=0.2): vol.All(
|
||||
vol.Coerce(float), vol.Range(min=0.0, max=10.0)
|
||||
),
|
||||
vol.Optional(
|
||||
"audio_device", default=default_device_index
|
||||
): AudioInputSource.device_index_validator,
|
||||
|
|
|
@ -354,4 +354,4 @@ class HSVEffect(Effect):
|
|||
self.hsv,
|
||||
int(pixels_to_roll),
|
||||
axis=0,
|
||||
)
|
||||
)
|
||||
|
|
|
@ -536,7 +536,7 @@ ledfx_presets = {
|
|||
"mids_colour": "cyan",
|
||||
"mids_sensitivity": 0.05,
|
||||
"mirror": True,
|
||||
"raindrop_animation": "droplet_1.npy"
|
||||
"raindrop_animation": "droplet_1.npy",
|
||||
},
|
||||
"name": "Cold Drops",
|
||||
},
|
||||
|
@ -1033,7 +1033,7 @@ ledfx_presets = {
|
|||
"config": {
|
||||
"background_brightness": 1,
|
||||
"background_color": "black",
|
||||
"beat_decay": 2,
|
||||
"beat_decay": 2,
|
||||
"blur": 6.2,
|
||||
"brightness": 1,
|
||||
"color": "blue",
|
||||
|
@ -1057,7 +1057,7 @@ ledfx_presets = {
|
|||
"config": {
|
||||
"background_brightness": 1,
|
||||
"background_color": "black",
|
||||
"beat_decay": 2,
|
||||
"beat_decay": 2,
|
||||
"blur": 2.6,
|
||||
"brightness": 1,
|
||||
"color": "white",
|
||||
|
@ -1080,7 +1080,7 @@ ledfx_presets = {
|
|||
"config": {
|
||||
"background_brightness": 1,
|
||||
"background_color": "black",
|
||||
"beat_decay": 2,
|
||||
"beat_decay": 2,
|
||||
"blur": 2.6,
|
||||
"brightness": 1,
|
||||
"color": "white",
|
||||
|
@ -1100,7 +1100,7 @@ ledfx_presets = {
|
|||
"config": {
|
||||
"background_brightness": 1,
|
||||
"background_color": "black",
|
||||
"beat_decay": 2,
|
||||
"beat_decay": 2,
|
||||
"blur": 2.6,
|
||||
"brightness": 1,
|
||||
"color": "white",
|
||||
|
|
Loading…
Reference in New Issue