Merge branch 'main' into led-strips/zengge-magichome

This commit is contained in:
Shaun Eccles-Smith 2023-03-18 15:57:11 +11:00 committed by GitHub
commit fbc1204f4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 453 additions and 60 deletions

View File

@ -13,14 +13,14 @@ jobs:
python: [3.8,3.9,3.10.x]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3.4.0
- name: Install build dependencies
run: |
sudo apt-get update && sudo apt-get install -y \
gcc libatlas3-base portaudio19-dev
- name: Setup Python ${{ matrix.python }}
id: python
uses: actions/setup-python@v2.2.1
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ matrix.python }}
- name: Build a binary wheel
@ -39,10 +39,10 @@ jobs:
python: [3.8,3.9,3.10.x]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3.4.0
- name: Setup Python ${{ matrix.python }}
id: python
uses: actions/setup-python@v2.2.1
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ matrix.python }}
- name: Build a binary wheel
@ -61,13 +61,13 @@ jobs:
python: [3.8,3.9,3.10.x]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3.4.0
- name: Install build dependencies
run: |
brew install portaudio
- name: Setup Python ${{ matrix.python }}
id: python
uses: actions/setup-python@v2.2.1
uses: actions/setup-python@v4.5.0
with:
python-version: ${{ matrix.python }}
- name: Build a binary wheel
@ -86,7 +86,7 @@ jobs:
# node-version: [10, 12, 14]
# steps:
# - name: Check out code from GitHub
# uses: actions/checkout@v2
# uses: actions/checkout@v3.4.0
# - name: Use Node.js ${{ matrix.node-version }}
# uses: actions/setup-node@v2
# with:

View File

@ -44,3 +44,11 @@ jobs:
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
- name: Trigger HomeAssistant Add-on
uses: benc-uk/workflow-dispatch@v1
with:
workflow: Builder
repo: YeonV/home-assistant-addons
ref: refs/heads/master
token: ${{ secrets.LEDFX_HOMEASSISTANT_ADDON }}
inputs: '{ "version": "${{ github.ref_name }}" }'

45
hiddenimports.py Normal file
View File

@ -0,0 +1,45 @@
hiddenimports = [
"sacn",
"aubio",
"numpy",
"notifypy",
"math",
"voluptuous",
"numpy",
"notifypy",
"aiohttp",
"mido",
"mido.frozen",
"paho",
"paho.mqtt",
"openrgb-python",
"openrgb",
"python-rtmidi",
"rtmidi",
"mido.backends.rtmidi",
"paho.mqtt.client",
"samplerate",
"samplerate._src",
"samplerate._samplerate_data",
"sounddevice",
"sentry_sdk",
"sentry_sdk.integrations.django",
"sentry_sdk.integrations.flask",
"sentry_sdk.integrations.bottle",
"sentry_sdk.integrations.falcon",
"sentry_sdk.integrations.sanic",
"sentry_sdk.integrations.celery",
"sentry_sdk.integrations.aiohttp",
"sentry_sdk.integrations.rq",
"sentry_sdk.integrations.tornado",
"sentry_sdk.integrations.sqlalchemy",
"sentry_sdk.integrations.boto3",
"_cffi_backend",
"serial",
"pystray._win32",
"serial.tools.list_ports",
"tcp_latency",
"aiohttp_cors",
"psutil",
"yappi",
]

View File

@ -44,7 +44,7 @@ from ledfx.consts import (
REQUIRED_PYTHON_VERSION,
)
from ledfx.core import LedFxCore
from ledfx.utils import currently_frozen
from ledfx.utils import currently_frozen, get_icon_path
# Logger Variables
PYUPDATERLOGLEVEL = 35
@ -193,12 +193,23 @@ def parse_args():
default=None,
type=str,
)
parser.add_argument(
group = parser.add_mutually_exclusive_group()
group.add_argument(
"--tray",
dest="tray",
action="store_true",
help="Hide LedFx console to the system tray",
help="Force LedFx system tray icon",
)
group.add_argument(
"--no-tray",
dest="no_tray",
action="store_true",
help="Force no LedFx system tray icon",
)
parser.add_argument(
"--offline",
dest="offline_mode",
@ -290,6 +301,29 @@ def update_ledfx(icon=None):
)
def log_packages():
from platform import (
processor,
python_build,
python_implementation,
python_version,
release,
system,
)
from pkg_resources import working_set
_LOGGER.debug(f"{system()} : {release()} : {processor()}")
_LOGGER.debug(
f"{python_version()} : {python_build()} : {python_implementation()}"
)
_LOGGER.debug("Packages")
dists = [d for d in working_set]
dists.sort(key=lambda x: x.project_name)
for dist in dists:
_LOGGER.debug(f"{dist.project_name} : {dist.version}")
def main():
"""Main entry point allowing external calls"""
args = parse_args()
@ -331,7 +365,7 @@ def main():
_LOGGER.warning("Steering LedFx into a brick wall")
div_by_zero = 1 / 0
if args.tray or currently_frozen():
if (args.tray or currently_frozen()) and not args.no_tray:
# If pystray is imported on a device that can't display it, it explodes. Catch it
try:
import pystray
@ -343,22 +377,18 @@ def main():
from PIL import Image
if currently_frozen():
current_directory = os.path.dirname(__file__)
icon_location = os.path.join(current_directory, "tray.png")
else:
current_directory = os.path.dirname(__file__)
icon_location = os.path.join(
current_directory, "..", "icons/" "tray.png"
)
icon_location = get_icon_path("tray.png")
icon = pystray.Icon(
"LedFx", icon=Image.open(icon_location), title="LedFx"
)
icon.visible = True
else:
icon = None
# icon = None
if _LOGGER.isEnabledFor(logging.DEBUG):
log_packages()
# if have_updater and not args.offline_mode and currently_frozen():
# update_ledfx(icon)
@ -372,6 +402,9 @@ def entry_point(icon=None):
# have to re-parse args here :/ no way to pass them through pysicon's setup
args = parse_args()
if icon:
icon.visible = True
exit_code = 4
while exit_code == 4:
_LOGGER.info("LedFx Core is initializing")

64
ledfx/api/notification.py Normal file
View File

@ -0,0 +1,64 @@
import logging
from json import JSONDecodeError
from aiohttp import web
from notifypy import Notify
from ledfx.api import RestEndpoint
from ledfx.utils import get_icon_path
_LOGGER = logging.getLogger(__name__)
class NotifyEndpoint(RestEndpoint):
"""REST end-point that exposes a notification api"""
ENDPOINT_PATH = "/api/notify"
def __init__(self, ledfx):
self.icon = ledfx.icon
async def put(self, request) -> web.Response:
try:
data = await request.json()
except JSONDecodeError:
response = {
"status": "failed",
"reason": "JSON Decoding failed",
}
return web.json_response(data=response, status=400)
title = data.get("title")
if title is None:
response = {
"status": "failed",
"reason": 'Required attribute "title" was not provided',
}
return web.json_response(data=response, status=400)
text = data.get("text")
if text is None:
response = {
"status": "failed",
"reason": 'Required attribute "text" was not provided',
}
return web.json_response(data=response, status=400)
_LOGGER.info(f"notify: {title} --- {text}")
if self.icon is not None:
if self.icon.HAS_NOTIFICATION:
self.icon.notify(f"{title}:\n{text}")
else:
icon_location = get_icon_path("tray.png")
notification = Notify()
notification.application_name = "LedFx"
notification.title = title
notification.message = text
notification.icon = icon_location
notification.send(block=False)
response = {
"status": "success",
}
return web.json_response(data=response, status=200)

View File

@ -39,7 +39,7 @@ class ScenesEndpoint(RestEndpoint):
if scene_id is None:
response = {
"status": "failed",
"reason": 'Required attribute "scene_id" was not provided',
"reason": 'Required attribute "id" was not provided',
}
return web.json_response(data=response, status=400)
@ -92,7 +92,7 @@ class ScenesEndpoint(RestEndpoint):
if scene_id is None:
response = {
"status": "failed",
"reason": 'Required attribute "scene_id" was not provided',
"reason": 'Required attribute "id" was not provided',
}
return web.json_response(data=response, status=400)

View File

@ -16,7 +16,7 @@ REQUIRED_PYTHON_STRING = ">={}.{}.{}".format(
MAJOR_VERSION = 2
MINOR_VERSION = 0
MICRO_VERSION = 60
MICRO_VERSION = 62
POST = 0
DEV = 0
PROJECT_VERSION = "{}.{}.{}".format(

View File

@ -618,12 +618,14 @@ class Devices(RegistryLoader):
if hasattr(device, "async_initialize"):
await device.async_initialize()
device_config = device.config
device_config["name"] = wled_name
# Update and save the configuration
self._ledfx.config["devices"].append(
{
"id": device.id,
"type": device.type,
"config": device.config,
"config": device_config,
}
)
@ -717,3 +719,7 @@ class WLEDListener(zeroconf.ServiceBrowser):
loop=self._ledfx.loop,
exc_handler=handle_exception,
)
def update_service(self, zeroconf_obj, type, name):
"""Callback when a service is updated."""
pass

182
ledfx/devices/nanoleaf.py Normal file
View File

@ -0,0 +1,182 @@
import logging
import socket
import struct
from typing import Dict, Optional, Tuple
import requests
import voluptuous as vol
from ledfx.devices import NetworkedDevice
_LOGGER = logging.getLogger(__name__)
class NanoleafDevice(NetworkedDevice):
"""
Dedicated WLED device support
This class fetches its config (px count, etc) from the WLED device
at launch, and lets the user choose a sync mode to use.
"""
CONFIG_SCHEMA = vol.Schema(
{
vol.Required(
"ip_address",
description="Hostname or IP address of the device",
): str,
vol.Optional("port", description="port", default=16021): int,
vol.Optional("udp_port", description="port", default=60222): int,
vol.Optional(
"auth_token",
description="Auth token",
): str,
vol.Optional(
"sync_mode",
description="Streaming protocol to Nanoleaf device",
default="UDP",
): vol.In(["TCP", "UDP"]),
}
)
status: Dict[int, Tuple[int, int, int]]
_sock: Optional[socket.socket] = None
def __init__(self, ledfx, config):
super().__init__(ledfx, config)
self.status = {}
def config_updated(self, config):
self.setup_subdevice()
def url(self, token: str) -> str:
return "http://%s:%i/api/v1/%s" % (
self._config["ip_address"],
self._config["port"],
token,
)
def setup_subdevice(self):
self.status = {}
self.deactivate()
self.activate()
def activate(self):
if self.config["sync_mode"] == "UDP":
response = requests.put(
self.url(self._config["auth_token"]) + "/effects",
json={
"write": {
"command": "display",
"animType": "extControl",
"extControlVersion": "v2",
}
},
)
if response.status_code == 400:
raise Exception("Invalid effect dictionary")
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._sock.connect(
(self._config["ip_address"], self._config["udp_port"])
)
super().activate()
def deactivate(self):
if self._sock is not None:
self._sock.close()
self._sock = None
super().deactivate()
def write_udp(self):
send_data = struct.pack(">H", len(self.status))
w = 0
transition = 0
for panel_id, (r, g, b) in self.status.items():
send_data += struct.pack(
">HBBBBH", panel_id, r, g, b, w, transition
)
self._sock.send(send_data)
def write_tcp(self):
"""Syncs the digital twin's changes to the real Nanoleaf device.
:returns: True if success, otherwise False
"""
anim_data = str(len(self.status))
for key, (r, g, b) in self.status.items():
anim_data += f" {str(key)} 1 {r} {g} {b} 0 0"
response = requests.put(
self.url(self._config["auth_token"]) + "/effects",
json={
"write": {
"command": "display",
"animType": "custom",
"loop": True,
"palette": [],
"animData": anim_data,
}
},
)
if response.status_code == 400:
raise Exception("Invalid effect dictionary")
def flush(self, data):
for panel, col in zip(
self.config["pixel_layout"], data.astype(int).clip(0, 255)
):
self.status[panel["panelId"]] = col.tolist()
if self.config["sync_mode"] == "TCP":
self.write_tcp()
elif self.config["sync_mode"] == "UDP":
self.write_udp()
def get_token(self):
response = requests.post(self.url("new"))
if response and response.status_code == 200:
data = response.json()
if "auth_token" in data:
return data["auth_token"]
raise Exception("No token, press sync button first")
async def async_initialize(self):
await super().async_initialize()
auth_token = self.config.get("auth_token")
if not auth_token:
auth_token = self.get_token()
self.update_config({"auth_token": auth_token})
self.setup_subdevice()
nanoleaf_config = requests.get(
self.url(self.config["auth_token"])
).json()
panels = [
{"x": i["x"], "y": i["y"], "panelId": i["panelId"]}
for i in sorted(
nanoleaf_config["panelLayout"]["layout"]["positionData"],
key=lambda x: (x["x"], x["y"]),
)
if i["panelId"] != 0
]
config = {
"name": nanoleaf_config["name"],
"pixel_count": len(panels),
"pixel_layout": panels,
"refresh_rate": 30, # problems with too fast udp packets
}
self.update_config(config)

View File

@ -58,6 +58,7 @@ class WLEDDevice(NetworkedDevice):
},
"DDP": {
"name": None,
"port": 4048,
"ip_address": None,
"pixel_count": None,
},

View File

@ -91,6 +91,8 @@ def _gaussian_kernel1d(sigma, order, array_len):
# Choose a radius for the filter kernel large enough to include all significant elements. Using
# a radius of 4 standard deviations (rounded to int) will only truncate tail values that are of
# the order of 1e-5 or smaller. For very small sigma values, just use a minimal radius.
# trapping very small values of sigma to arbitarily 0.00001 to preven div zero crash
sigma = max(0.00001, sigma)
radius = max(1, int(round(4.0 * sigma)))
radius = min(int((array_len - 1) / 2), radius)
radius = max(radius, 1)

View File

@ -46,6 +46,11 @@ class Strobe(AudioReactiveEffect, GradientEffect):
description="Percussive strobe decay rate. Higher -> decays faster.",
default=0.5,
): vol.All(vol.Coerce(float), vol.Range(min=0, max=1)),
vol.Optional(
"color_shift_delay",
description="color shift delay for percussive strobes. Lower -> more shifts",
default=1,
): vol.All(vol.Coerce(float), vol.Range(min=0, max=1)),
}
)
@ -67,7 +72,7 @@ class Strobe(AudioReactiveEffect, GradientEffect):
)
self.last_color_shift_time = 0
self.strobe_width = self._config["strobe_width"]
self.color_shift_delay_in_seconds = 1
self.color_shift_delay_in_seconds = self._config["color_shift_delay"]
self.color_idx = 0
self.last_strobe_time = 0

View File

@ -86,6 +86,8 @@ class Water(AudioReactiveEffect, HSVEffect):
# Just bail out with uselessly-small pixel counts.
if self.pixel_count < 5:
return
if self.drops_queue is None:
return
intensities = np.fromiter(
(i.max() ** 2 for i in self.melbank_thirds()), float

View File

@ -1413,6 +1413,25 @@ ledfx_presets = {
},
"name": "Glitter",
},
"color-shift": {
"config": {
"background_brightness": 1.0,
"background_color": "black",
"bass_strobe_decay_rate": 0,
"blur": 0.0,
"brightness": 1.0,
"color_shift_delay": 0.1,
"color_step": 0.0625,
"flip": False,
"gradient": "linear-gradient(90deg, rgb(255, 0, 0) 0%, rgb(255, 120, 0) 14%, rgb(255, 200, 0) 28%, rgb(0, 255, 0) 42%, rgb(0, 199, 140) 56%, rgb(0, 0, 255) 70%, rgb(128, 0, 128) 84%, rgb(255, 0, 178) 98%)",
"gradient_roll": 0.0,
"mirror": False,
"strobe_color": "black",
"strobe_decay_rate": 1,
"strobe_width": 0,
},
"name": "Color shift",
},
},
"blade_power_plus": {
"reset": {"config": {}, "name": "Reset"},

View File

@ -540,6 +540,27 @@ def currently_frozen():
return getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS")
def get_icon_path(icon_filename) -> str:
"""returns fully qualified path for icon, tests for frozen
and logs error if does not exist
Parameters:
icon_filename(str): the filename of the icon to be pathed
Returns:
icon_location(str): fully qualified path
"""
current_directory = os.path.dirname(__file__)
icon_location = os.path.normpath(
os.path.join(current_directory, "..", "icons", icon_filename)
)
if not os.path.isfile(icon_location):
_LOGGER.error(f"No icon found at {icon_location}")
return icon_location
def generate_id(name):
"""Converts a name to a id"""
part1 = re.sub("[^a-zA-Z0-9]", " ", name).lower()

View File

@ -1,7 +1,7 @@
{
"files": {
"main.css": "/static/css/main.4f91d95d.css",
"main.js": "/static/js/main.6548a54d.js",
"main.css": "/static/css/main.7161fcbe.css",
"main.js": "/static/js/main.d11734a7.js",
"static/js/729.58abe218.chunk.js": "/static/js/729.58abe218.chunk.js",
"static/media/xmas.png": "/static/media/xmas.c633287113d46706b711.png",
"static/media/fireworks.jpg": "/static/media/fireworks.81f25863cf1ec0b30fa2.jpg",
@ -13,12 +13,12 @@
"static/media/ring.png": "/static/media/ring.1faea45b576b5380bde1.png",
"static/media/blademod.svg": "/static/media/blademod.f939f478785a84b3edcc820eef654556.svg",
"index.html": "/index.html",
"main.4f91d95d.css.map": "/static/css/main.4f91d95d.css.map",
"main.6548a54d.js.map": "/static/js/main.6548a54d.js.map",
"main.7161fcbe.css.map": "/static/css/main.7161fcbe.css.map",
"main.d11734a7.js.map": "/static/js/main.d11734a7.js.map",
"729.58abe218.chunk.js.map": "/static/js/729.58abe218.chunk.js.map"
},
"entrypoints": [
"static/css/main.4f91d95d.css",
"static/js/main.6548a54d.js"
"static/css/main.7161fcbe.css",
"static/js/main.d11734a7.js"
]
}

View File

@ -10,7 +10,7 @@ const {
app,
Menu,
Tray,
// Notification,
// Notification,
nativeTheme,
BrowserWindow,
ipcMain,
@ -83,11 +83,21 @@ function createWindow(args = {}) {
// const NOTIFICATION_TITLE = 'LedFx Client - by Blade';
// const NOTIFICATION_BODY = 'Testing Notification from the Main process';
// function showNotification() {
// // function showNotification(title = NOTIFICATION_TITLE, body = NOTIFICATION_BODY) {
// function showNotification(title = NOTIFICATION_TITLE, body = NOTIFICATION_BODY) {
// new Notification({
// title: NOTIFICATION_TITLE,
// body: NOTIFICATION_BODY,
// }).show();
// toastXml: `<toast>
// <visual>
// <binding template="ToastText02">
// <text id="1">LedFx Update available</text>
// <text id="2">Click the button to see more informations.</text>
// </binding>
// </visual>
// <actions>
// <action content="Goto Release" activationType="protocol" arguments="https://github.com/YeonV/LedFx-Builds/releases/latest" />
// </actions>
// </toast>`,
// }).show();
// }
let tray = null;
@ -160,7 +170,7 @@ const ready = () => (
if (process.platform === 'darwin') app.dock.hide()
wind.hide()
}},
// { label: 'Test Notifiation', click: () => showNotification() },
// { label: 'Test Notifiation', click: () => showNotification('Update Available', 'v2.0.62') },
{ label: 'seperator', type: 'separator' },
{ label: 'Dev', click: () => wind.webContents.openDevTools() },
{ label: 'seperator', type: 'separator' },
@ -197,7 +207,7 @@ const ready = () => (
if (process.platform === 'darwin') app.dock.hide()
wind.hide()
}},
// { label: 'Test Notifiation', click: () => showNotification() },
// { label: 'Test Notifiation', click: () => showNotification('Update Available', 'v2.0.62') },
{ label: 'seperator', type: 'separator' },
{ label: 'Dev', click: () => wind.webContents.openDevTools() },
{ label: 'seperator', type: 'separator' },

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="description" content="LedFx Client - by Blade"/><link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-icon-57x57.png"><link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-icon-60x60.png"><link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-icon-72x72.png"><link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-icon-76x76.png"><link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-icon-114x114.png"><link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-icon-120x120.png"><link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-icon-144x144.png"><link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-icon-152x152.png"><link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-icon-180x180.png"><link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-192x192.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"><link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"><meta name="msapplication-TileColor" content="#333333"><meta name="msapplication-TileImage" content="/favicon/ms-icon-144x144.png"><meta name="theme-color" content="#333333"><meta name="background-color" content="#020202"><link rel="manifest" href="/manifest.json"/><title>LedFx</title><script defer="defer" src="/static/js/main.6548a54d.js"></script><link href="/static/css/main.4f91d95d.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><script type="application/javascript">"serviceWorker"in navigator&&window.addEventListener("load",(function(){navigator.serviceWorker.register("serviceWorker.js",{scope:"."}).then((function(e){console.debug("ServiceWorker registration successful with scope: ",e.scope)}),(function(e){console.debug("ServiceWorker registration failed: ",e)}))}))</script><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="description" content="LedFx Client - by Blade"/><link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-icon-57x57.png"><link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-icon-60x60.png"><link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-icon-72x72.png"><link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-icon-76x76.png"><link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-icon-114x114.png"><link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-icon-120x120.png"><link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-icon-144x144.png"><link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-icon-152x152.png"><link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-icon-180x180.png"><link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-192x192.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"><link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"><meta name="msapplication-TileColor" content="#333333"><meta name="msapplication-TileImage" content="/favicon/ms-icon-144x144.png"><meta name="theme-color" content="#333333"><meta name="background-color" content="#020202"><link rel="manifest" href="/manifest.json"/><title>LedFx</title><script defer="defer" src="/static/js/main.d11734a7.js"></script><link href="/static/css/main.7161fcbe.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><script type="application/javascript">"serviceWorker"in navigator&&window.addEventListener("load",(function(){navigator.serviceWorker.register("serviceWorker.js",{scope:"."}).then((function(e){console.debug("ServiceWorker registration successful with scope: ",e.scope)}),(function(e){console.debug("ServiceWorker registration failed: ",e)}))}))</script><div id="root"></div></body></html>

View File

@ -1,4 +0,0 @@
+ Release 2.0.60
+ Merge branch 'main' of https://github.com/YeonV/LedFx-Frontend-v2
+ Release 2.0.60
+ Release 2.0.58

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,7 @@
certifi~=2020.12.5
multidict~=5.0.0
numpy~=1.23
notify-py>=0.3.42
openrgb-python~=0.2.10
paho-mqtt~=1.5.1
psutil>=5.8.0
@ -25,5 +26,5 @@
tcp-latency~=0.0.10
voluptuous~=0.12.1
yappi~=1.3.3
zeroconf==0.39.4
flux_led==0.28.35
zeroconf~=0.39.4

View File

@ -29,6 +29,7 @@ INSTALL_REQUIRES = [
"cython>=0.29.21",
"certifi>=2020.12.5",
"multidict~=5.0.0",
"notify-py>=0.3.42",
"openrgb-python~=0.2.10",
"paho-mqtt>=1.5.1",
"psutil>=5.8.0",
@ -42,7 +43,7 @@ INSTALL_REQUIRES = [
"samplerate>=0.1.0",
"tcp-latency>=0.0.10",
"voluptuous~=0.12.1",
"zeroconf==0.39.4",
"zeroconf~=0.39.4",
"pillow>=8.4.0",
# Conditional Requirement
# We need pywin32 for Windows

View File

@ -1,6 +1,6 @@
# -*- mode: python ; coding: utf-8 -*-
import os
from hiddenimports import hiddenimports
spec_root = os.path.abspath(SPECPATH)
venv_root = os.path.abspath(os.path.join(SPECPATH, '..'))
@ -12,10 +12,7 @@ a = Analysis([f'{spec_root}\\ledfx\\__main__.py'],
pathex=[f'{spec_root}', f'{spec_root}\\ledfx'],
binaries=[],
datas=[(f'{spec_root}/ledfx_frontend', 'ledfx_frontend/'), (f'{spec_root}/ledfx/', 'ledfx/'), (f'{spec_root}/icons', 'icons/'),(f'{spec_root}/icons/tray.png','.')],
hiddenimports=['sacn', 'aubio', 'numpy', 'math', 'voluptuous', 'numpy', 'aiohttp', 'mido','mido.frozen', 'paho', 'paho.mqtt', 'openrgb-python', 'openrgb', 'python-rtmidi','rtmidi', 'mido.backends.rtmidi', 'paho.mqtt.client','samplerate','_samplerate_data', 'sounddevice',
'sentry_sdk', 'sentry_sdk.integrations.django','sentry_sdk.integrations.flask','sentry_sdk.integrations.bottle','sentry_sdk.integrations.falcon','sentry_sdk.integrations.sanic',
'sentry_sdk.integrations.celery','sentry_sdk.integrations.aiohttp','sentry_sdk.integrations.rq','sentry_sdk.integrations.tornado','sentry_sdk.integrations.sqlalchemy',
'sentry_sdk.integrations.boto3','_cffi_backend','serial','pystray._win32','serial.tools.list_ports','tcp_latency','aiohttp_cors','psutil','yappi'],
hiddenimports=hiddenimports,
hookspath=[f'{venv_root}\\lib\\site-packages\\pyupdater\\hooks'],
runtime_hooks=[],
excludes=[],
@ -43,4 +40,4 @@ coll = COLLECT(exe,
strip=False,
upx=True,
upx_exclude=[],
name='LedFx')
name='LedFx')