From 2a3a323dc3ac0bf623b7ab200fe561b5e7ff874b Mon Sep 17 00:00:00 2001 From: David Huss <dh@atoav.com> Date: Wed, 23 Oct 2024 13:41:20 +0200 Subject: [PATCH] Major Refactor, pls test --- src/mediactl/devices/projector.py | 245 +++++++++++------------------- src/mediactl/main.py | 2 +- src/mediactl/system.py | 169 ++++++++++++++++----- static/helpers.js | 17 ++- static/modules/projector.js | 15 +- static/modules/system.js | 21 +++ static/style.css | 40 ++++- static/ws.js | 17 ++- 8 files changed, 308 insertions(+), 218 deletions(-) diff --git a/src/mediactl/devices/projector.py b/src/mediactl/devices/projector.py index 9477458..3a2718b 100644 --- a/src/mediactl/devices/projector.py +++ b/src/mediactl/devices/projector.py @@ -2,6 +2,8 @@ import asyncio import requests import mediactl from datetime import datetime, timedelta +from result import Result, Ok, Err +from functools import wraps class ConnectionState(mediactl.EnumState): @@ -62,13 +64,52 @@ class TestPatternState(mediactl.EnumState): return not self.is_off() -# self.status = { -# "power": {"state": PowerState.unknown, "time": datetime.now()}, -# "shutter": {"state": "unknown", "time": datetime.now()}, -# "lamp": {"hours": None, "time": datetime.now()}, -# "temperature": {"temperature": None, "time": datetime.now()}, -# "testpattern": "off", -# } +def projector_connection(endpoint: str, purpose: str, method: str = "post"): + def decorator(func): + @wraps(func) + async def async_wrapper(*args, **kwargs): + self = args[0] + try: + if method == "post": + request_func = requests.post + elif method == "get": + request_func = requests.get + response = await asyncio.to_thread( + request_func, + f"{self.addr}/{endpoint}", + timeout=self.timeout, + ) + except ( + requests.exceptions.ConnectTimeout, + requests.exceptions.ReadTimeout, + ): + self.status["connection"] = ConnectionState.disconnected + return Err( + f"Request to {purpose} projector on timed out after {self.timeout}s" + ) + except requests.exceptions.ConnectionError: + self.status["connection"] = ConnectionState.disconnected + return Err(f"Request to {purpose} projector: Max tries exceeded") + data = response.json() + if method == "post": + if "result" not in data: + return Err( + f"Requested to {purpose} projector: No result in response: {data}" + ) + elif data["result"] != "ok": + return Err( + f"Requested to {purpose} projector: projctl responded with Error: {data}" + ) + self.log_info( + f"Got a response, when {purpose} projector: {response.status_code}: {data}" + ) + g = func.__globals__ + g.update(response=response) + return await func(*args, **kwargs) + + return async_wrapper + + return decorator class Projector(mediactl.WithLogger): @@ -77,34 +118,17 @@ class Projector(mediactl.WithLogger): self.addr = addr self.timeout = 1.0 self.status = self.get_default_status() - self.update_status() - - def update_status(self): - try: - response = requests.get(f"{self.addr}/status", timeout=self.timeout) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Requesting status from Projector at {self.addr} timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error("Requesting status from projector: Max tries exceeded") - return - if response.status_code != 200: - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to Projector at {self.addr} returned with status {response.status_code}" - ) - return - data = response.json() + + @projector_connection(endpoint="status", purpose="get status", method="get") + async def update_status(self) -> Result[dict, str]: + data = response.json() # noqa: F821 variable "response" set by decorator self.status["connection"] = ConnectionState.connected self.status["power"] = PowerState(data["power"]["state"]) self.status["shutter"] = ShutterState(data["shutter"]["state"]) self.status["testpattern"] = TestPatternState(data["testpattern"]) self.status["lamp"] = data["lamp"]["hours"] self.status["time"] = datetime.now() + return Ok(self.status) def get_default_status(self) -> dict: return { @@ -115,135 +139,44 @@ class Projector(mediactl.WithLogger): "time": None, } - def get_status(self) -> dict: + async def get_status(self) -> dict: if ("time" not in self.status or self.status["time"] is None) or ( (datetime.now() - self.status["time"]) > timedelta(seconds=5) ): - self.update_status() + response = await self.update_status() + if response.is_err(): + self.log_error(response.err_value) + return self.status + else: + return response.unwrap() return self.status - async def power_on(self): - try: - response = await asyncio.to_thread( - requests.post, f"{self.addr}/power-on", timeout=self.timeout - ) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to power on projector on timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error("Request to power on projector: Max tries exceeded") - return - self.log_info( - f"Got a response, when switching projector on: {response.status_code}: {response.json()}" - ) - return response.json() - - async def power_off(self): - try: - response = await asyncio.to_thread( - requests.post, f"{self.addr}/power-off", timeout=self.timeout - ) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to power off projector on timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error("Request to power off projector: Max tries exceeded") - return - self.log_info( - f"Got a response, when switching projector off: {response.status_code}: {response.json()}" - ) - return response.json() - - async def shutter_close(self): - try: - response = await asyncio.to_thread( - requests.post, f"{self.addr}/shutter-close", timeout=self.timeout - ) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to close shutter of projector on timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error("Request to close shutter of projector: Max tries exceeded") - return - self.log_info( - f"Got a response, when closing shutter of projector: {response.status_code}: {response.json()}" - ) - return response.json() - - async def shutter_open(self): - try: - response = await asyncio.to_thread( - requests.post, f"{self.addr}/shutter-open", timeout=self.timeout - ) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to open shutter of projector on timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error("Request to open shutter of projector: Max tries exceeded") - return - self.log_info( - f"Got a response, when opening shutter of projector: {response.status_code}: {response.json()}" - ) - return response.json() - - async def testpattern_off(self): - try: - response = await asyncio.to_thread( - requests.post, f"{self.addr}/testpattern-off", timeout=self.timeout - ) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to hiding testpattern of projector on timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error( - "Request to hiding testpattern of projector: Max tries exceeded" - ) - return - self.log_info( - f"Got a response, when hiding testpattern of projector: {response.status_code}: {response.json()}" - ) - return response.json() - - async def testpattern_show(self): - try: - response = await asyncio.to_thread( - requests.post, - f"{self.addr}/testpattern-green-grid", - timeout=self.timeout, - ) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout): - self.status["connection"] = ConnectionState.disconnected - self.log_error( - f"Request to show testpattern of projector on timed out after {self.timeout}s" - ) - return - except requests.exceptions.ConnectionError: - self.status["connection"] = ConnectionState.disconnected - self.log_error( - "Request to show testpattern of projector: Max tries exceeded" - ) - return - self.log_info( - f"Got a response, when showing testpattern of projector: {response.status_code}: {response.json()}" - ) - return response.json() + @projector_connection(endpoint="power-on", purpose="power on") + async def power_on(self) -> Result[None, str]: + return Ok(None) + + @projector_connection(endpoint="power-off", purpose="power off") + async def power_off(self) -> Result[None, str]: + return Ok(None) + + @projector_connection(endpoint="shutter-close", purpose="close shutter") + async def shutter_close(self) -> Result[None, str]: + return Ok(None) + + @projector_connection(endpoint="shutter-open", purpose="open shutter") + async def shutter_open(self) -> Result[None, str]: + return Ok(None) + + @projector_connection(endpoint="testpattern-off", purpose="hide testpattern") + async def testpattern_off(self) -> Result[None, str]: + return Ok(None) + + @projector_connection(endpoint="testpattern-green-grid", purpose="show testpattern") + async def testpattern_show(self) -> Result[None, str]: + return Ok(None) + + +if __name__ == "__main__": + projector = Projector("http://projctl.mediahell.hfbk.net") + result = asyncio.run(projector.update_status()) + print(result) diff --git a/src/mediactl/main.py b/src/mediactl/main.py index 27f8154..4dd4210 100644 --- a/src/mediactl/main.py +++ b/src/mediactl/main.py @@ -21,7 +21,7 @@ logger.setLevel(logging.INFO) # Connect to projctl and ahm via network, other connections are GPIO, see README system = mediactl.System( - projector_address="http://projctl.mediahell.hfbk.net", + projector_address="http://projctl-intentionally-wrong.mediahell.hfbk.net", ahm_address="ahm16-m.mediahell.hfbk.net", logger=logger, ) diff --git a/src/mediactl/system.py b/src/mediactl/system.py index b65ddbf..7b35e33 100644 --- a/src/mediactl/system.py +++ b/src/mediactl/system.py @@ -1,5 +1,7 @@ import mediactl import copy +import asyncio +from datetime import datetime, timedelta from result import Ok, Err, Result, is_ok, is_err # noqa: F401 @@ -93,6 +95,7 @@ class System(mediactl.WithLogger): async def dante_mode_on(self) -> Result[None, str]: ahm_response = await self.ahm.mute_control_group(1) + self.log_info("Requested to activate Dante-Mode") if ahm_response.is_err(): self.log_error(ahm_response.err_value) return Err(f"Could not switch dante mode on: {ahm_response.err_value}") @@ -105,6 +108,7 @@ class System(mediactl.WithLogger): async def dante_mode_off(self) -> Result[None, str]: ahm_response = await self.ahm.unmute_control_group(1) + self.log_info("Requested to deactivate Dante-Mode") if ahm_response.is_err(): self.log_error(ahm_response.err_value) return Err(f"Could not switch dante mode off: {ahm_response.err_value}") @@ -116,7 +120,7 @@ class System(mediactl.WithLogger): return Ok(None) async def get_status(self, initial=False) -> dict: - self.status["projector"] = self.projector.get_status() + self.status["projector"] = await self.projector.get_status() self.status["ahm"] = await self.ahm.get_status(name=initial) self.status["kramer"] = self.kramer.get_status() self.status["system"]["health"] = SystemHealth.ok @@ -143,69 +147,152 @@ class System(mediactl.WithLogger): if ( "lamp" in self.status["projector"] and self.status["projector"]["lamp"] is not None - and self.status["projector"]["lamp"] > 29000 + and self.status["projector"]["lamp"] > 29900 ): if self.status["system"]["health"] != SystemHealth.critical: self.status["system"]["health"] = SystemHealth.problematic + # async def power_off(self, source="Script"): + # self.status["system"]["power"] = PowerState.requested_powerdown + # # Get current projector_state + # pprojector_state = self.status["projector"]["power"] + # self.log_info( + # f"Received Power-Off-Command from {source}, sending request to Projector.." + # ) + # projector_response = await self.projector.power_off() + # self.log_info( + # f"Received Power-Off-Command from {source}, Projector Response was {projector_response}" + # ) + # # If the projector returned ok we go to the shutdown state + # if projector_response.is_ok(): + # self.status["system"]["power"] = PowerState.shutting_down + # if pprojector_state.is_off(): + # self.log_info("Systching system to Off, Projector was already off") + # self.status["system"]["power"] = PowerState.off + + # ahm_result = await self.ahm.mute_control_group(3) + # if ahm_result.is_err(): + # self.log_warn( + # f"Attempted to mute AHM-16 durin power-off, but it failed: {ahm_result.err_value}" + # ) + # return projector_result + async def power_off(self, source="Script"): + # Set state to request powerdown and log + requested_at = datetime.now() self.status["system"]["power"] = PowerState.requested_powerdown - # Get current projector_state - pprojector_state = self.status["projector"]["power"] self.log_info( f"Received Power-Off-Command from {source}, sending request to Projector.." ) - projector_result = await self.projector.power_off() - if projector_result is None: - return {"result": "error"} - self.log_info( - f"Received Power-Off-Command from {source}, Result was {projector_result} (of type {type(projector_result)})" - ) - if "result" in projector_result and projector_result["result"] == "ok": - self.status["system"]["power"] = PowerState.shutting_down - if pprojector_state.is_off(): - self.log_info("Systching system to Off, Projector was already off") + + # Get current projector_state and previous projector state + projector_response = await self.projector.power_off() + + # Mute Main Control Group + ahm_response = await self.ahm.mute_control_group(3) + + self.status["system"]["power"] = PowerState.shutting_down + while not self.status["system"]["power"].is_off(): + if projector_response.is_ok() and ahm_response.is_ok(): self.status["system"]["power"] = PowerState.off + self.log_info("Shutdown nominal, all systems responded") + break + if (datetime.now() - requested_at) > timedelta(seconds=5): + self.status["system"]["power"] = PowerState.on + self.log_error( + f"Could not reach projctl at {self.projector.addr} during powerup after 5 seconds. Starting anyways" + ) + break + await asyncio.sleep(1) + if projector_response.is_err(): + projector_response = await self.projector.power_on() + if ahm_response.is_err(): + ahm_response = await self.ahm.mute_control_group(3) + + # Screen needs to go up + await self.screen.move_up() - ahm_result = await self.ahm.mute_control_group(3) - if ahm_result.is_err(): - self.log_warn( - f"Attempted to mute AHM-16 durin power-off, but it failed: {ahm_result.err_value}" - ) - return projector_result + return {"result": "ok"} async def power_on(self, source="Script"): - # Set state to request powerup + # Set state to request powerup and log + requested_at = datetime.now() self.status["system"]["power"] = PowerState.requested_powerup self.log_info( f"Received Power-On-Command from {source}, sending request to Projector.." ) - # Power Projector on + + # Power Projector on and select propper AHM-16-preset projector_response = await self.projector.power_on() - if projector_response is None: - return {"result": "error"} - self.log_info( - f"Received Power-On-Command from {source}, Result was {projector_response} (of type {type(projector_response)})" - ) - # Process Projector Response - if "result" in projector_response and projector_response["result"] == "ok": - self.status["system"]["power"] = PowerState.starting_up - if "description" in projector_response and projector_response[ - "description" - ].lower().startswith("did not power on projector, was already on"): - self.status["system"]["power"] = PowerState.on - # Request default preset for DSP ahm_response = await self.ahm.preset_recall(1) - if ahm_response.is_err(): - self.log_error(ahm_response.err_value) - # Request default media for projector - self.kramer.switch(1) + # We are now starting up + self.status["system"]["power"] = PowerState.starting_up + projector_reached = False + while not self.status["system"]["power"].is_on(): + if projector_response.is_ok() and ahm_response.is_ok(): + self.status["system"]["power"] = PowerState.on + self.log_info("Startup nominal, all systems appear to be online") + projector_reached = True + break + if (datetime.now() - requested_at) > timedelta(seconds=5): + self.status["system"]["power"] = PowerState.on + self.log_error( + f"Could not reach projctl at {self.projector.addr} during powerup after 5 seconds. Starting anyways" + ) + break + await asyncio.sleep(1) + # Retry + if projector_response.is_err(): + projector_response = await self.projector.power_on() + if ahm_response.is_err(): + ahm_response = await self.ahm.preset_recall(1) + + # Unmute all Channels if AHM was reached + if ahm_response.is_ok(): + # Control Group Main + ahm_response = await self.ahm.unmute_control_group(3) + if ahm_response.is_err(): + self.log_error( + f"Could not unmute control group 3: {ahm_response.err_value}" + ) + # Control Group Mics + ahm_response = await self.ahm.unmute_control_group(1) + if ahm_response.is_err(): + self.log_error( + f"Could not unmute control group 1: {ahm_response.err_value}" + ) + # Control Group Media + ahm_response = await self.ahm.unmute_control_group(2) + if ahm_response.is_err(): + self.log_error( + f"Could not unmute control group 2: {ahm_response.err_value}" + ) - return projector_response + # If the projector can't be reached return immidiately to not move the screen + if not projector_reached: + return {"result": "ok"} + + # Request default media for projector (this may also operate the screen motors) + self.switch_media_source(1) + + return {"result": "ok"} def switch_media_source(self, number): # First media source, screen down! if self.kramer.status["active-input"] is None: - self.screen.move_down() + # TODO: Uncomment after debugging + # self.screen.move_down() + pass return self.kramer.switch(number) + + +if __name__ == "__main__": + system = mediactl.System( + projector_address="http://projctl-intentionally-wrong.mediahell.hfbk.net", + ahm_address="ahm16-m.mediahell.hfbk.net", + logger=None, + ) + + result = asyncio.run(system.power_on2()) + print(result) diff --git a/static/helpers.js b/static/helpers.js index 9260a47..da6432e 100755 --- a/static/helpers.js +++ b/static/helpers.js @@ -296,10 +296,13 @@ class SourceSelector { console.log(`Constructing new source selector for ${this.name} (${this.number})`); } - create(parent) { + create(parent, extra_classes) { let button = document.createElement("button"); button.id = `source-selector-${this.number}`; button.classList.add(`source-selector`); + if (extra_classes !== undefined) { + extra_classes.forEach(c => button.classList.add(c)); + } button.textContent = this.name; button.source_selector = this; button.addEventListener("click", function(event) { @@ -329,10 +332,13 @@ class PushButton { console.log(`Constructing new push-button for ${this.name} (${this.command})`); } - create(parent) { + create(parent, extra_classes) { let button = document.createElement("button"); button.id = `push-button-${this.command}`; button.classList.add(`push-button`); + if (extra_classes !== undefined) { + extra_classes.forEach(c => button.classList.add(c)); + } button.textContent = this.name; button.push_button = this; button.addEventListener("click", function(event) { @@ -367,7 +373,7 @@ class ToggleButton { console.log(`Constructing new toggle button called ${this.name} (active: ${this.is_active})`); } - create(parent) { + create(parent, extra_classes) { let button = document.createElement("button"); button.id = `toggle-button-${this.name}`; button.classList.add(`toggle-button`); @@ -378,7 +384,10 @@ class ToggleButton { button.classList.add(`inactive`); button.textContent = this.label_when_inactive; } - + if (extra_classes !== undefined) { + extra_classes.forEach(c => button.classList.add(c)); + } + button.toggle_button = this; button.addEventListener("click", function(event) { let toggle_button = event.target.toggle_button; diff --git a/static/modules/projector.js b/static/modules/projector.js index fb5fe16..4d9e170 100644 --- a/static/modules/projector.js +++ b/static/modules/projector.js @@ -36,7 +36,20 @@ class Projector { // Connection if ('connection' in nstatus) { this.connection = nstatus['connection']; - if (force_update || this.pconnection != this.connection) { this.onConnectionChange(this); } + if (force_update || this.pconnection != this.connection) { + this.onConnectionChange(this); + if (this.connection == "disconnected") { + Array.from(document.getElementsByClassName("disable-when-projector-disconnected")).forEach(e => { + e.disabled = true; + }) + updateStatus(this.status_display, "disconnected", "disconnected"); + } + if (this.connection == "connected") { + Array.from(document.getElementsByClassName("disable-when-projector-disconnected")).forEach(e => { + e.disabled = false; + }) + } + } }; // Power diff --git a/static/modules/system.js b/static/modules/system.js index c7c4ecb..3ee982c 100644 --- a/static/modules/system.js +++ b/static/modules/system.js @@ -15,6 +15,8 @@ class System { this.ppower = this.power; this.phealth = this.health; + this.pdante = null; + // Callback functions this.onPowerChange = ()=>{}; this.onPowerOn = ()=>{}; @@ -99,6 +101,25 @@ class System { } }; + // Power States and Callbacks + if ('dante-on' in status) { + this.dante = status['dante-on']; + if (this.pdante != this.dante) { + let button = document.getElementById("toggle-button-dante_active_button"); + + if (this.dante) { + button.toggle_button.setInactive(); + console.log("Dante activated"); + main.classList.add("dante"); + } else { + button.toggle_button.setActive(); + console.log("Dante deactivated"); + main.classList.remove("dante"); + } + } + this.pdante = this.dante; + }; + // Store previous values this.pconnection = this.connection; this.ppower = this.power; diff --git a/static/style.css b/static/style.css index a8d490a..e275c60 100644 --- a/static/style.css +++ b/static/style.css @@ -278,6 +278,28 @@ section:first-of-type { } } +main.dante #section-audio { + opacity: 0.8; + +} +main.dante #section-audio:after { + position: absolute; + content: "DANTE"; + text-align: center; + font-size: 4em; + color: red; + left: 0; + top: 45%; + right: 0; + border-top: 2px solid; + border-color: red; + -webkit-transform: rotate(-35deg); + -moz-transform: rotate(-35deg); + -ms-transform: rotate(-35deg); + -o-transform: rotate(-35deg); + transform: rotate(-35deg); +} + #section-projector { h2 { width: 7.5em; @@ -564,12 +586,6 @@ section:first-of-type { } } -/* Does not work on chromium-browser raspi for some odd reason */ -/*dialog::backdrop { - background-color:rgba(0,0,0,0.4); - backdrop-filter: blur(3px); - transition: 2s ease-out; -}*/ /* --------------------- Tabs ------------- */ #tab-list { @@ -610,4 +626,14 @@ section:first-of-type { .tabcontent.hidden { display: none; color: white; -} \ No newline at end of file +} + + +.push-button:disabled, .toggle-button:disabled { + color: gray !important; + border-color: gray !important; + text-decoration: line-through; +} +p:disabled { + text-decoration: line-through; +} diff --git a/static/ws.js b/static/ws.js index 3ebf2cd..047681a 100644 --- a/static/ws.js +++ b/static/ws.js @@ -63,7 +63,7 @@ let screen_up_button = new PushButton("▲", "screen-up") let screen_stop_button = new PushButton("STOP", "screen-stop") let screen_down_button = new PushButton("▼", "screen-down") -let dante_active = new ToggleButton("dante_active", "Activate Dante Mode", "Back to Normal Mode", "dante-mode-on", "dante-mode-off", true); +let dante_active_button = new ToggleButton("dante_active_button", "Activate Dante Mode", "Back to Normal Mode", "dante-mode-on", "dante-mode-off", true); // Build UI initially depending on system status if (isOff()) { @@ -218,11 +218,12 @@ function buildSystemOnUi() { let projector_lamp_hours = document.createElement("p"); projector_lamp_hours.id = "projector_lamp_hours"; projector_lamp_hours.textContent = "💡 ?/40000h"; + projector_lamp_hours.classList.add("disable-when-projector-disconnected"); projector_section.appendChild(projector_lamp_hours); let projector_section_container = document.createElement("div"); projector_section.appendChild(projector_section_container); tab1_content.appendChild(projector_section); - projector_shutter.create(projector_section_container); + projector_shutter.create(projector_section_container, ["disable-when-projector-disconnected"]); system.projector.updateFromStatus(system.pstatus, true); // Add Sources Section @@ -281,8 +282,8 @@ function buildSystemOnUi() { let projector_advanced_section_container = document.createElement("div"); projector_advanced_section.appendChild(projector_advanced_section_container); tab2content.appendChild(projector_advanced_section); - projector_power.create(projector_advanced_section_container); - projector_test.create(projector_advanced_section_container); + projector_power.create(projector_advanced_section_container, ["disable-when-projector-disconnected"]); + projector_test.create(projector_advanced_section_container, ["disable-when-projector-disconnected"]); let dante_section = document.createElement("section"); @@ -293,7 +294,7 @@ function buildSystemOnUi() { let dante_description = document.createElement("p"); dante_description.innerHTML = "For control with an external Dante Audio Network device (e.g. SQ5 Mixer) activate Dante Mode. If you don't know what Dante is, leave this alone."; dante_section.appendChild(dante_description); - dante_active.create(dante_section) + dante_active_button.create(dante_section) tab2content.append(dante_section); } @@ -347,7 +348,7 @@ ws2.onmessage = function(event) { case "screen-stop": if ('ok' in response && response["ok"]) { let button = document.getElementById("push-button-screen-stop"); - if (button !== undefined) { + if (button !== null) { console.log(`--> Command ${response["command"]} was successful`); button.classList.remove("requested"); } @@ -356,7 +357,7 @@ ws2.onmessage = function(event) { case "screen-up": if ('ok' in response && response["ok"]) { let button = document.getElementById("push-button-screen-up"); - if (button !== undefined) { + if (button !== null) { console.log(`--> Command ${response["command"]} was successful`); button.classList.remove("requested"); } @@ -365,7 +366,7 @@ ws2.onmessage = function(event) { case "screen-down": if ('ok' in response && response["ok"]) { let button = document.getElementById("push-button-screen-down"); - if (button !== undefined) { + if (button !== null) { console.log(`--> Command ${response["command"]} was successful`); button.classList.remove("requested"); } -- GitLab