Compare commits

...

2 Commits

4 changed files with 83 additions and 13 deletions

View File

@ -7,7 +7,7 @@ from wakeonlan import send_magic_packet
from custom_components.easy_computer_manager import const, LOGGER from custom_components.easy_computer_manager import const, LOGGER
from custom_components.easy_computer_manager.computer.common import OSType, CommandOutput from custom_components.easy_computer_manager.computer.common import OSType, CommandOutput
from custom_components.easy_computer_manager.computer.formatter import format_gnome_monitors_args from custom_components.easy_computer_manager.computer.formatter import format_gnome_monitors_args, format_pactl_commands
from custom_components.easy_computer_manager.computer.parser import parse_gnome_monitors_output, parse_pactl_output, \ from custom_components.easy_computer_manager.computer.parser import parse_gnome_monitors_output, parse_pactl_output, \
parse_bluetoothctl parse_bluetoothctl
@ -35,7 +35,7 @@ class Computer:
asyncio.create_task(self.update()) asyncio.create_task(self.update())
async def _connect(self) -> None: async def _connect(self, retried: bool = False) -> None:
"""Open an asynchronous SSH connection.""" """Open an asynchronous SSH connection."""
try: try:
client = await asyncssh.connect( client = await asyncssh.connect(
@ -48,7 +48,10 @@ class Computer:
asyncssh.set_log_level("ERROR") asyncssh.set_log_level("ERROR")
self._connection = client self._connection = client
except (OSError, asyncssh.Error) as exc: except (OSError, asyncssh.Error) as exc:
raise ValueError(f"Failed to connect to {self.host}: {exc}") if retried:
await self._connect(retried=True)
else:
raise ValueError(f"Failed to connect to {self.host}: {exc}")
async def _renew_connection(self) -> None: async def _renew_connection(self) -> None:
"""Renew the SSH connection if it is closed.""" """Renew the SSH connection if it is closed."""
@ -159,18 +162,21 @@ class Computer:
input_device: str | None = None, input_device: str | None = None,
output_device: str | None = None) -> None: output_device: str | None = None) -> None:
"""Change the audio configuration.""" """Change the audio configuration."""
# Implementation needed if self.is_linux():
pass # TODO: other DE support
if self.desktop_environment == 'gnome':
pactl_commands = format_pactl_commands(self.audio_config, volume, mute, input_device, output_device)
for command in pactl_commands:
await self.run_action("set_audio_config", params={"args": command})
async def install_nircmd(self) -> None: async def install_nircmd(self) -> None:
"""Install NirCmd tool (Windows specific).""" """Install NirCmd tool (Windows specific)."""
# Implementation needed await self.run_action("install_nircmd", params={"download_url": "https://www.nirsoft.net/utils/nircmd.zip",
pass "install_path": f"C:\\Users\\{self.username}\\AppData\\Local\\EasyComputerManager"})
async def steam_big_picture(self, action: str) -> None: async def steam_big_picture(self, action: str) -> None:
"""Start, stop or exit Steam Big Picture mode.""" """Start, stop or exit Steam Big Picture mode."""
# Implementation needed await self.run_action(f"{action}_steam_big_picture")
pass
async def run_action(self, id: str, params=None, raise_on_error: bool = None) -> CommandOutput: async def run_action(self, id: str, params=None, raise_on_error: bool = None) -> CommandOutput:
"""Run a predefined command via SSH.""" """Run a predefined command via SSH."""

View File

@ -20,3 +20,43 @@ def format_gnome_monitors_args(monitors_config: dict):
args.extend(['-t', settings["transform"]]) args.extend(['-t', settings["transform"]])
return ' '.join(args) return ' '.join(args)
def format_pactl_commands(current_config: {}, volume: int, mute: bool, input_device: str = "@DEFAULT_SOURCE@",
output_device: str = "@DEFAULT_SINK@"):
"""Change audio configuration on the host system."""
commands = []
def get_device_id(device_type, user_device):
for device in current_config[device_type]:
if device['description'] == user_device:
return device['name']
return user_device
# Set default sink and source if not specified
if not output_device:
output_device = "@DEFAULT_SINK@"
if not input_device:
input_device = "@DEFAULT_SOURCE@"
# Set default sink if specified
if output_device and output_device != "@DEFAULT_SINK@":
output_device = get_device_id('sinks', output_device)
commands.append(f"set-default-sink {output_device}")
# Set default source if specified
if input_device and input_device != "@DEFAULT_SOURCE@":
input_device = get_device_id('sources', input_device)
commands.append(f"set-default-source {input_device}")
# Set sink volume if specified
if volume is not None:
commands.append(f"set-sink-volume {output_device} {volume}%")
# Set sink and source mute status if specified
if mute is not None:
commands.append(f"set-sink-mute {output_device} {'yes' if mute else 'no'}")
commands.append(f"set-source-mute {input_device} {'yes' if mute else 'no'}")
return commands

View File

@ -7,7 +7,7 @@ async def format_debug_information(computer: 'Computer'): # importing Computer
'version': computer.operating_system_version, 'version': computer.operating_system_version,
'desktop_environment': computer.desktop_environment 'desktop_environment': computer.desktop_environment
}, },
'connection':{ 'connection': {
'host': computer.host, 'host': computer.host,
'mac': computer.mac, 'mac': computer.mac,
'username': computer.username, 'username': computer.username,
@ -15,10 +15,10 @@ async def format_debug_information(computer: 'Computer'): # importing Computer
'dualboot': computer.dualboot, 'dualboot': computer.dualboot,
'is_on': await computer.is_on() 'is_on': await computer.is_on()
}, },
'grub':{ 'grub': {
'windows_entry': computer.windows_entry_grub 'windows_entry': computer.windows_entry_grub
}, },
'audio':{ 'audio': {
'speakers': computer.audio_config.get('speakers'), 'speakers': computer.audio_config.get('speakers'),
'microphones': computer.audio_config.get('microphones') 'microphones': computer.audio_config.get('microphones')
}, },

View File

@ -64,10 +64,34 @@ ACTIONS = {
"get_microphones": { "get_microphones": {
"linux": ["LANG=en_US.UTF-8 pactl list sources"] "linux": ["LANG=en_US.UTF-8 pactl list sources"]
}, },
"set_audio_config": {
"linux": {
"command": "LANG=en_US.UTF-8 pactl %args%",
"params": ["args"]
}
},
"get_bluetooth_devices": { "get_bluetooth_devices": {
"linux": { "linux": {
"command": "bluetoothctl info", "command": "bluetoothctl info",
"raise_on_error": False, "raise_on_error": False,
} }
} },
"install_nirmcd": {
"windows": {
"command": "powershell -Command \"Invoke-WebRequest -Uri %download_url% -OutFile %install_path%\\nircmd.zip -UseBasicParsing; Expand-Archive %install_path%\\nircmd.zip -DestinationPath %install_path%; Remove-Item %install_path%\\nircmd.zip\"",
"params": ["download_url", "install_path"]
}
},
"start_steam_big_picture": {
"linux": "export WAYLAND_DISPLAY=wayland-0; export DISPLAY=:0; steam -bigpicture &",
"windows": "start steam://open/bigpicture"
},
"stop_steam_big_picture": {
"linux": "export WAYLAND_DISPLAY=wayland-0; export DISPLAY=:0; steam -shutdown &",
"windows": "C:\\Program Files (x86)\\Steam\\steam.exe -shutdown"
},
"exit_steam_big_picture": {
"linux": "", # TODO: find a way to exit steam big picture
"windows": "nircmd win close title \"Steam Big Picture Mode\""
},
} }