remove web and small improvements

This commit is contained in:
Lucca Ketterer 2023-11-28 02:33:26 +01:00
parent 344fe990af
commit e079294b11
8 changed files with 80 additions and 549 deletions

View File

@ -1,138 +1,20 @@
## Configuration file for CAVA. Default values are commented out. Use either ';' or '#' for commenting.
[general] [general]
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
; mode = normal
# Accepts only non-negative values.
framerate = 60 framerate = 60
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
# new as of 0.6.0 autosens of low values (dynamic range)
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
; autosens = 1
; overshoot = 20
# Manual sensitivity in %. Autosens must be turned off for this to take effect.
# 200 means double height. Accepts only non-negative values.
sensitivity = 1000
# The number of bars (0-200). 0 sets it to auto (fill up console).
# Bars' width and space between bars in number of characters.
;bars = 128
bars = 2 bars = 2
; bar_width = 2
; bar_spacing = 1
# Lower and higher cutoff frequencies for lowest and highest bars
# the bandwidth of the visualizer.
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
# Cava will automatically increase the higher cutoff if a too low band is specified.
; lower_cutoff_freq = 50
; higher_cutoff_freq = 10000
[input]
# Audio capturing method. Possible methods are: 'pulse', 'alsa' or 'fifo'.
# Defaults to 'pulse', 'alsa' or 'fifo', in that order, dependent on what support cava was built with.
#
# All input methods uses the same config variable 'source'
# to define where it should get the audio.
#
# For pulseaudio 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
#
# For alsa 'source' will be the capture device.
# For fifo 'source' will be the path to fifo-file.
; method = pulse
; source = 19
; method = alsa
; source = hw:Loopback,1
; method = fifo
; source = /tmp/mpd.fifo
[output] [output]
# Ouput method. Can be 'ncurses', 'noncurses' or 'raw'.
# 'noncurses' is for systems that does not suport ncurses.
# 'raw' is a 16 bit data stream of the bar heights that can be used to send to other applications.
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
method = raw method = raw
# Visual channels. Can be 'stereo' or 'mono'.
# 'stereo' mirrors both channels with low frequencies in center.
# 'mono' averages both channels and outputs left to right lowest to highest frequencies.
; channels = stereo
# Raw output target. A fifo will be created if target does not exist.
; raw_target = /dev/stdout
# Raw data format. Can be 'binary' or 'ascii'.
data_format = ascii data_format = ascii
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
; bit_format = 8bit
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
ascii_max_range = 1000 ascii_max_range = 1000
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
; bar_delimiter = 59
; frame_delimiter = 10
[color] [color]
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires a
# terminal that can change color definitions such as Gnome-terminal or rxvt.
; background = black
foreground = red foreground = red
# Gradient mode, only hex defined colors are supported, background must also be defined in hex
# or remain commented out. 1 = on, 0 = off. Warning: for certain terminal emulators cava will
# not able to restore color definitions on exit, simply restart your terminal to restore colors.
; gradient = 0
; gradient_color_1 = '#0099ff'
; gradient_color_2 = '#ff3399'
[smoothing] [smoothing]
# Percentage value for integral smoothing. Takes values from 0 - 100.
# Higher values means smoother, but less precise. 0 to disable.
integral = 20 integral = 20
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
; monstercat = 1
; waves = 3;
# Set gravity percentage for "drop off". Higher values means bars will drop faster.
# Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off".
gravity = 200 gravity = 200
# In bar height, bars that would have been lower that this will not be drawn.
; ignore = 0
[eq] [eq]
# This one is tricky. You can have as much keys as you want.
# Remember to uncomment more then one key! More keys = more precision.
# Look at readme.md on github for further explanations and examples.
1 = 1 # bass 1 = 1 # bass
2 = 0 2 = 0
3 = 0 # midtone 3 = 0 # midtone

11
controller/gui.py Normal file
View File

@ -0,0 +1,11 @@
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
@app.route('/set/<int:color>')
def set(color):
return f'{color}'

BIN
controller/main.bin Executable file

Binary file not shown.

View File

@ -5,6 +5,7 @@ import asyncio
import pickle import pickle
import re import re
import sys import sys
import subprocess
async def scan_for_pi() -> dict(): async def scan_for_pi() -> dict():
ip = socket.gethostbyname(socket.gethostname()) ip = socket.gethostbyname(socket.gethostname())
@ -71,8 +72,61 @@ def set_pixels(color):
pi.send(color) pi.send(color)
pi.disconnect() pi.disconnect()
def visualizer(color, amp_strength=0.6):
cava_config = '''
[general]
framerate = 60
bars = 2
[output]
method = raw
data_format = ascii
ascii_max_range = 1000
[color]
foreground = red
[smoothing]
integral = 20
gravity = 200
[eq]
1 = 1 # bass
2 = 0
3 = 0 # midtone
4 = 0
5 = 0 # treble
'''
with open('/tmp/lc_cava.conf', 'w') as f:
f.write(cava_config)
r = int(color[0:2], 16)
g = int(color[2:4], 16)
b = int(color[4:6], 16)
cava = subprocess.Popen(["cava", "-p", "/tmp/lc_cava.conf"], stdout=subprocess.PIPE)
for line in cava.stdout:
cava_value = int(line.decode().split(';')[0])
amp_factor = amp_strength * ((cava_value / 500) - 1) + 1
# send(rgb_to_hex(int(r * amp_factor), int(g * amp_factor), int(b * amp_factor)))
print(r,g,b, amp_factor, line)
color = f'{int(r * amp_factor):02x}{int(g * amp_factor):02x}{int(b * amp_factor):02x}'
print(color)
set_pixels(color)
cava.stdout.close()
sed.stdout.close()
def main(arg): def main(arg):
arg = ('help') if len(arg) == 0 else arg arg = ('help') if len(arg) == 0 else arg
# if len(arg) == 0:
# from gui import app
# import webview
# webview.create_window('LED Controller', app)
# webview.start()
match arg[0]: match arg[0]:
case "set": case "set":
@ -81,6 +135,9 @@ def main(arg):
return return
set_pixels(arg[1]) set_pixels(arg[1])
case "off":
set_pixels('000000')
case "search": case "search":
ip_list = asyncio.run(scan_for_pi()) ip_list = asyncio.run(scan_for_pi())
pi_list = [PI(ip) for ip in ip_list] pi_list = [PI(ip) for ip in ip_list]
@ -92,10 +149,13 @@ def main(arg):
for pi in pi_list: for pi in pi_list:
print(pi) print(pi)
case "music": case "music":
pass if len(arg) < 2:
print("color argument missing")
return
visualizer(arg[1])
case _: case _:
print("lc [help|set|search|list]") print("lc [help|set|off|search|list]")

6
test.html Normal file
View File

@ -0,0 +1,6 @@
<script>
fetch("http://192.168.188.64:5000", {
method: "POST",
body: JSON.stringify("ff8833")
});
</script>

View File

@ -1,36 +0,0 @@
import socket
import asyncio
from flask import Flask, render_template
app = Flask(__name__)
async def scan_for_pi() -> dict():
ip = socket.gethostbyname(socket.gethostname())
baseIP = '.'.join(ip.split(".")[:3])
def scan(ip: str) -> str:
try:
with socket.socket() as s:
s.settimeout(0.5)
s.connect((ip, 5000))
s.send("PING".encode())
data = s.recv(1024).decode()
if data == "PONG":
print("found:", ip)
return ip
except OSError:
pass
async def scan_async(ip: str) -> str:
return await asyncio.to_thread(scan, ip)
pi_list = await asyncio.gather(*[scan_async(baseIP + "." + str(i)) for i in range(255)])
return [pi for pi in pi_list if pi is not None]
@app.route('/')
def home():
return render_template('index.html')
@app.route('/set/<int:color>')
def set(color):
return f'{color}'

View File

@ -1,392 +0,0 @@
#!/usr/bin/python3
import socket
import os
import asyncio
import click
import pickle
import re
import webview
# function generate fibonacci sequence
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
async def scan_for_pi() -> dict():
ip = socket.gethostbyname(socket.gethostname())
baseIP = '.'.join(ip.split(".")[:3])
def scan(ip: str) -> str:
try:
with socket.socket() as s:
s.settimeout(0.5)
s.connect((ip, 5000))
s.send("PING".encode())
data = s.recv(1024).decode()
if data == "PONG":
print("found:", ip)
return ip
except OSError:
pass
async def scan_async(ip: str) -> str:
return await asyncio.to_thread(scan, ip)
pi_list = await asyncio.gather(*[scan_async(baseIP + "." + str(i)) for i in range(255)])
return [pi for pi in pi_list if pi is not None]
class PI:
def __init__(self, ip, port=5000):
self.ip = ip
self.port = port
self.connected = False
self.socket = socket.socket()
def __str__(self):
return self.ip
def connect(self):
self.socket.connect((self.ip, self.port))
def send(self, data):
self.socket.send(data.encode())
def disconnect(self):
self.socket.close()
def load_config(path=os.path.expanduser("~/.config/lc/lc.conf")):
try:
with open(path, 'rb') as f:
return [PI(ip) for ip in pickle.load(f)]
except FileNotFoundError:
print("Config does not exist")
exit()
def save_config(obj, path=os.path.expanduser("~/.config/lc/lc.conf")):
os.makedirs(path[::-1].split('/',1)[-1][::-1], exist_ok=True)
with open(path, 'wb') as f:
pickle.dump(list([o.ip for o in obj]), f)
def set_pixels(color):
if not re.match("[0-9a-f]{6}$", color):
print(f"{color} not a valid hex color code")
return
pi_list = load_config()
for pi in pi_list:
pi.connect()
pi.send(color)
pi.disconnect()
@click.command()
@click.argument("arg", nargs=-1)
# @click.option("-s", help="Set HEX Color: -s ffffff")
# @click.option("-v", help="Set HEX Color as base visualizer color: -v ffffff")
def main(arg):
if arg == ():
# proc = subprocess.Popen(["python", "-m", "streamlit", "run", "/var/lib/lc/gui.py", "--server.headless", "True", "--theme.base", "dark", "--theme.primaryColor", "#9f0000", "--theme.backgroundColor", "#181a1b", "--theme.secondaryBackgroundColor", "#1f2123", "--theme.textColor", "#c4c0b8"], stdout=subprocess.PIPE)
# for line in proc.stdout:
# if line == b' You can now view your Streamlit app in your browser.\n':
# break
import streamlit.web.bootstrap as bootstrap
from streamlit import config
import gui as gui
di = {'global_disableWatchdogWarning': None, 'global_showWarningOnDirectExecution': None, 'global_developmentMode': None, 'global_logLevel': None, 'global_unitTest': None, 'global_suppressDeprecationWarnings': None, 'global_minCachedMessageSize': None, 'global_maxCachedMessageAge': None, 'global_dataFrameSerialization': None, 'logger_level': None, 'logger_messageFormat': None, 'logger_enableRich': None, 'client_caching': None, 'client_displayEnabled': None, 'client_showErrorDetails': None, 'runner_magicEnabled': None, 'runner_installTracer': None, 'runner_fixMatplotlib': None, 'runner_postScriptGC': None, 'runner_fastReruns': None, 'server_folderWatchBlacklist': None, 'server_fileWatcherType': None, 'server_cookieSecret': None, 'server_headless': True, 'server_runOnSave': None, 'server_allowRunOnSave': None, 'server_address': None, 'server_port': None, 'server_scriptHealthCheckEnabled': None, 'server_baseUrlPath': None, 'server_enableCORS': None, 'server_enableXsrfProtection': None, 'server_maxUploadSize': None, 'server_maxMessageSize': None, 'server_enableWebsocketCompression': None, 'browser_serverAddress': None, 'browser_gatherUsageStats': None, 'browser_serverPort': None, 'ui_hideTopBar': None, 'ui_hideSidebarNav': None, 'mapbox_token': None, 'deprecation_showfileUploaderEncoding': None, 'deprecation_showImageFormat': None, 'deprecation_showPyplotGlobalUse': None, 'theme_base': None, 'theme_primaryColor': None, 'theme_backgroundColor': None, 'theme_secondaryBackgroundColor': None, 'theme_textColor': None, 'theme_font': None}
import multiprocessing
def run():
config.set_option('server.headless', True)
bootstrap.run(gui.__file__, 'streamlit run gui.py --server.headless True', [], di)
p = multiprocessing.Process(target=run)
p.start()
# import requests
# while True:
# try:
# print(requests.get('http://localhost:8501'))
# except:
# continue
# print('asdf')
# break
# cli.main_run(str(gui.__file__))
# from streamlit.web.server import Server
# server = Server(gui.__file__, 'streamlit run gui.py --server.headless True')
# import tornado.web
# class MainHandler(tornado.web.RequestHandler):
# def get(self):
# self.write("Hello, world")
# application = tornado.web.Application([
# (r"/", ), ])
# application.listen(8888)
webview.create_window('LED Control', 'http://localhost:8501')
webview.start()
# proc.terminate()
exit()
match arg[0]:
case "help":
print("lc [help|set|search|list]")
case "set":
if len(arg) < 2:
print("color argument missing")
set_pixels(arg[1])
case "search":
ip_list = asyncio.run(scan_for_pi())
pi_list = [PI(ip) for ip in ip_list]
save_config(pi_list)
case "list":
pi_list = load_config()
if pi_list is not None:
for pi in pi_list:
print(pi)
case "music":
pass
if __name__ == '__main__':
main()
# def helpmenu():
# print("light controll\n")
# print("Options:")
# print("-h show help")
# print("-s <hex-color> set static color")
# print("-v <hex-color> visualizer")
# print("-i interactive interface")
# print("-a ambient light")
# print("-t test function (debug)")
# def base_color(color):
# return [i // min(color) for i in color]
# def visualizer(color, amp_strength=0.6):
# r,g,b = hex_to_rgb(color)
# cava = subprocess.Popen(["cava", "-p", "/etc/lc/cava.conf"], stdout=subprocess.PIPE)
# sed = subprocess.Popen(["sed", "-u", "s/;.*;$//"], stdin=cava.stdout, stdout=subprocess.PIPE)
# for line in sed.stdout:
# amp_factor = amp_strength * ((int(line) / 500) - 1) + 1
# send(rgb_to_hex(int(r * amp_factor), int(g * amp_factor), int(b * amp_factor)))
# cava.stdout.close()
# sed.stdout.close()
# def visualizer_cava_thread():
# global volume_amp
# cava = subprocess.Popen(["cava", "-p", "/etc/lc/cava.conf"], stdout=subprocess.PIPE)
# sed = subprocess.Popen(["sed", "-u", "s/;.*;$//"], stdin=cava.stdout, stdout=subprocess.PIPE)
# for line in sed.stdout:
# volume_amp = int(line)
# print(volume_amp)
# cava.stdout.close()
# sed.stdout.close()
# def amp_by_vol(color, amp_strength):
# global volume_amp
# # amp_strength in percentage
# amp_factor = amp_strength*((volume_amp/500)-1)+1
# #print(amp_factor, color,[c*amp_factor for c in color], volume_amp)
# return [c*amp_factor for c in color]
# def vibrant(r,g,b):
# intensity = 50 # usabel range 1-100 max:1000
# intensity = 1+intensity/1000
# rgb = [r,g,b]
# #min_idx = rgb.index(min(rgb))
# d = (r+g+b)/3
# for c in range(3):
# if rgb[c] < d:
# rgb[c] = int(rgb[c]*(intensity**(rgb[c]-d)))
# elif rgb[c] > d:
# rgb[c] = int(rgb[c]*(-intensity**(-rgb[c]+d)+2))
# if rgb[c] > 255:
# rgb[c] = 255
# #rgb[min_idx] = int(rgb[min_idx]*(rgb[min_idx]/d)**2)
# return rgb
# def ambient_light_thread():
# r,g,b = 0,0,0
# brighness = 1
# active_color = ''
# while True:
# # P-Regler
# r,g,b = [w+((y-w)*0.1) for y,w in zip((_r,_g,_b),(r,g,b))]
# if ((round(r),round(g),round(b)) == (_r,_g,_b)):
# active_color = '\033[0;32;40m'
# else:
# active_color = '\033[0;31;40m'
# r_out,g_out,b_out = amp_by_vol((r,g,b), 0.6)
# #r_out,g_out,b_out = r,g,b
# print(active_color, round(r),round(g),round(b), round(r_out),round(g_out),round(b_out), '\033[0;37;40m')
# send(rgb_to_hex(int(r_out*brighness),int(g_out*brighness),int(b_out*brighness)))
# time.sleep(0.01)
# ups_counter = 0
# start_time = time.time()
# def ups():
# global ups_counter
# global start_time
# ups_counter += 1
# time_d = time.time()-start_time
# ups = ups_counter/time_d
# print(ups)
# def color_correction(r,g,b):
# amp = [1,1,0.8]
# threshold = 10
# if r < threshold and g < threshold and b < threshold:
# return 0,0,0
# return int(r*amp[0]), int(g*amp[1]), int(b*amp[2])
# def ambient_light():
# t1 = Thread(target=ambient_light_thread)
# t1.start()
# t2 = Thread(target=visualizer_cava_thread)
# t2.start()
# global _r,_g,_b
# counter = 0
# start_time = time.time()
# while True:
# # screenshot
# # Xorg
# img = pyscreenshot.grab(backend="mss", childprocess=False, bbox=(1920,0,4480,1440))
# #Wayland
# #time.sleep(0.1)
# #cap = cv2.VideoCapture('/tmp/a')
# #count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
# #cap.set(cv2.CAP_PROP_POS_FRAMES, count-1)
# #ret, frame = cap.read()
# #frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
# #img = Image.fromarray(frame)
# #cap.release()
# # find dominant color
# img.thumbnail((2,2))
# r,g,b = img.getpixel((0, 0))
# r,g,b = vibrant(r,g,b)
# _r,_g,_b = color_correction(r,g,b)
# time.sleep(0.05)
# def rgb_to_hex(r,g,b):
# return "%02x%02x%02x" % (r,g,b)
# def hex_to_rgb(hex):
# r = int(hex[0:2],16)
# g = int(hex[2:4],16)
# b = int(hex[4:6],16)
# return r,g,b
# def test():
# for i in range(256):
# h = rgb_to_hex(0,i,0)
# send(h)
# print(h)
# time.sleep(0.0)
# def tui_main(scr, *args):
# # -- Perform an action with Screen --
# scr.border(0)
# scr.addstr(5, 5, 'Hello from Curses!', curses.A_BOLD)
# scr.addstr(6, 5, 'Press q to close this screen', curses.A_NORMAL)
# scr.addstr(8, 5, '\u250C')
# rgb = [0,0,0]
# color_selector = 0
# while True:
# status = '{},{},{} {}'.format(rgb[0], rgb[1], rgb[2], color_selector)
# scr.addstr(1, 1, status)
# ch = scr.getch()
# if ch == ord('q'):
# break
# elif ch == ord('j'):
# if rgb[color_selector] > 0:
# rgb[color_selector] -= 1
# send(rgb_to_hex(rgb[0], rgb[1], rgb[2]))
# elif ch == ord('k'):
# if rgb[color_selector] < 255:
# rgb[color_selector] += 1
# send(rgb_to_hex(rgb[0], rgb[1], rgb[2]))
# elif ch == ord('l'):
# if color_selector < 3:
# color_selector += 1
# elif ch == ord('h'):
# if color_selector > 0:
# color_selector -= 1
# def main(argv):
# if not sys.stdin.isatty():
# connect()
# for volume in sys.stdin:
# volume = int(volume)
# hex_color = rgb_to_hex(volume,0,0)
# send(hex_color)
# sys.exit()
# try:
# opts, args = getopt.getopt(argv, "s:v:ahti")
# except getopt.GetoptError:
# print(sys.argv[0], "invalid option")
# print("Try", sys.argv[0], "-h for help")
# sys.exit(1)
# for opt, arg in opts:
# if opt == "-h":
# helpmenu()
# elif opt == "-s":
# connect()
# send(arg)
# disconnect()
# elif opt == "-a":
# connect()
# ambient_light()
# disconnect()
# elif opt == "-v":
# connect()
# visualizer(arg)
# disconnect()
# elif opt == "-t":
# connect()
# test()
# disconnect()
# elif opt == '-i':
# connect()
# curses.wrapper(tui_main)
# disconnect()
# sys.exit()
# if __name__ == "__main__":
# main(sys.argv[1:])