2025-05-13 02:08:13 +03:00

152 lines
4.7 KiB
Python

# ------------------------------ BUTTON MAPPINGS ------------------------------------------
# BUTTON MATRIX: OK, VOL_UP, VOL_DOWN, SRC_UP, SRC_DOWN, PAUSE, WHEEL_UP, WHEEL_DOWN
# CD CHANGER: NEXT, PREV, FAST_FORW, PLAY, PAUSE, RESUME, STOP, FAST_BACK, CD_(1-6), STALK, RAND_ON, RAND_OFF
# RADIO: VOL_UP, VOL_DOWN, PAUSE
# ANDROID AUTO: ENTER, LEFT, RIGHT, UP, DOWN, BACK, HOME, PHONE, CALL_END, PLAY, PAUSE, PREV_TRACK, NEXT_TRACK, TOGGLE_PLAY, VOICE, WHEEL_LEFT, WHEEL_RIGHT
def send_to_radio(btn):
tunerlist.send_button(btn)
def send_to_aa(btn):
queue.put_nowait(dumps({"button": btn}))
BUTTON_MAPPINGS = {
"VOL_UP": (send_to_radio, "VOL_UP"),
"VOL_DOWN": (send_to_radio, "VOL_DOWN"),
"PAUSE": (send_to_radio, "PAUSE")
}
# -----------------------------------------------------------------------------------------
from tunerlist import TunerList, TunerListState
from bluetooth import Bluetooth, BluetoothState
from buttondecoder import ButtonDecoder
from json import dumps
from fastapi import FastAPI, WebSocket, Request
from fastapi.responses import PlainTextResponse, JSONResponse, HTMLResponse
from fastapi.staticfiles import StaticFiles
from asyncio import create_task, CancelledError, Queue, sleep
from uvicorn import run
import os
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
background_tasks = []
tunerlist = TunerList()
bluetooth = Bluetooth()
buttons = ButtonDecoder()
last_tunerlist_state: TunerListState = None
last_bluetooth_state: BluetoothState = None
state_to_send: dict = {}
queue = Queue()
def build_state_to_send():
if not last_tunerlist_state:
return
if not last_bluetooth_state:
state_to_send= {"radio": last_tunerlist_state.to_dict()}
elif last_tunerlist_state.is_temp_view and last_bluetooth_state.status == "playing":
state_to_send = {"bluetooth": last_bluetooth_state.to_dict()}
state_to_send["bluetooth"]["screen"] = last_tunerlist_state.text
elif last_tunerlist_state.is_playing_ext:
state_to_send = {"bluetooth": last_bluetooth_state.to_dict()}
else:
state_to_send = {"radio": last_tunerlist_state.to_dict()}
queue.put_nowait(state_to_send)
async def tunerlist_listener():
global last_tunerlist_state
try:
while True:
last_tunerlist_state = await tunerlist.queue.get()
build_state_to_send()
except CancelledError:
pass
async def bluetooth_listener():
global last_bluetooth_state
try:
while True:
last_bluetooth_state = await bluetooth.queue.get()
build_state_to_send()
except CancelledError:
pass
async def button_listener():
try:
while True:
button = await buttons.queue.get()
if button in BUTTON_MAPPINGS:
func, arg = BUTTON_MAPPINGS[button]
func(arg)
except CancelledError:
pass
@app.on_event("startup")
async def startup_event():
for i in [
tunerlist.run(),
# bluetooth.run(),
buttons.run(),
tunerlist_listener(),
bluetooth_listener()
]:
background_tasks.append(create_task(i))
@app.on_event("shutdown")
async def shutdown_event():
for task in background_tasks:
task.cancel()
@app.get("/", response_class=HTMLResponse)
async def root():
html_file_path = os.path.join(os.getcwd(), "static", "index.html")
with open(html_file_path, "r") as file:
return file.read()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
global state_to_send
await websocket.accept()
try:
while True:
payload = await queue.get()
print(payload)
await websocket.send_text(dumps(payload))
except CancelledError:
return
@app.get("/state", response_class=JSONResponse)
async def state_endpoint():
return dumps(state_to_send)
@app.get("/btn", response_class=PlainTextResponse)
async def emulated_button(request: Request):
btn = request.query_params.get("btn")
print("CD Changer button: ", btn)
buttons.queue.put_nowait(btn)
@app.get("/settext", response_class=JSONResponse)
async def set_text(request: Request):
text = request.query_params.get("txt")
tunerlist.set_text(text)
return dumps(state_to_send)
@app.get("/connect", response_class=PlainTextResponse)
async def connect_aa(request: Request):
ip = request.query_params.get("ip")
queue.put_nowait({"wireless_aa_ip": ip})
return ip
@app.get("/aabtn", response_class=PlainTextResponse)
async def aabtn(request: Request):
btn = request.query_params.get("btn")
queue.put_nowait({"button": {"btn": btn, "state": 2}})
return btn
if __name__ == "__main__":
run(app=app, host="0.0.0.0", port=5959, log_level="info")