mirror of
				https://github.com/home-assistant/supervisor.git
				synced 2025-11-04 08:29:40 +00:00 
			
		
		
		
	* Use Systemd Journal API for all logs endpoints in API Replace all logs endpoints using container logs with wrapped advanced_logs function, adding possibility to get logs from previous boots and following the logs. Supervisor logs are an excetion where Docker logs are still used - in case an exception is raised while accessing the Systemd logs, they're used as fallback - otherwise we wouldn't have an easy way to see what went wrong. * Refactor testing of advanced logs endpoints to a common method * Send error while fetching Supervisor logs to Sentry; minor cleanup * Properly handle errors and use consistent content type in logs endpoints * Replace api_process_custom with reworked api_process_raw per @mdegat01 suggestion
		
			
				
	
	
		
			165 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Init file for Supervisor Audio RESTful API."""
 | 
						|
import asyncio
 | 
						|
from collections.abc import Awaitable
 | 
						|
from dataclasses import asdict
 | 
						|
import logging
 | 
						|
from typing import Any
 | 
						|
 | 
						|
from aiohttp import web
 | 
						|
import voluptuous as vol
 | 
						|
 | 
						|
from ..const import (
 | 
						|
    ATTR_ACTIVE,
 | 
						|
    ATTR_APPLICATION,
 | 
						|
    ATTR_AUDIO,
 | 
						|
    ATTR_BLK_READ,
 | 
						|
    ATTR_BLK_WRITE,
 | 
						|
    ATTR_CARD,
 | 
						|
    ATTR_CPU_PERCENT,
 | 
						|
    ATTR_HOST,
 | 
						|
    ATTR_INDEX,
 | 
						|
    ATTR_INPUT,
 | 
						|
    ATTR_MEMORY_LIMIT,
 | 
						|
    ATTR_MEMORY_PERCENT,
 | 
						|
    ATTR_MEMORY_USAGE,
 | 
						|
    ATTR_NAME,
 | 
						|
    ATTR_NETWORK_RX,
 | 
						|
    ATTR_NETWORK_TX,
 | 
						|
    ATTR_OUTPUT,
 | 
						|
    ATTR_UPDATE_AVAILABLE,
 | 
						|
    ATTR_VERSION,
 | 
						|
    ATTR_VERSION_LATEST,
 | 
						|
    ATTR_VOLUME,
 | 
						|
)
 | 
						|
from ..coresys import CoreSysAttributes
 | 
						|
from ..exceptions import APIError
 | 
						|
from ..host.sound import StreamType
 | 
						|
from ..validate import version_tag
 | 
						|
from .utils import api_process, api_validate
 | 
						|
 | 
						|
_LOGGER: logging.Logger = logging.getLogger(__name__)
 | 
						|
 | 
						|
SCHEMA_VERSION = vol.Schema({vol.Optional(ATTR_VERSION): version_tag})
 | 
						|
 | 
						|
SCHEMA_VOLUME = vol.Schema(
 | 
						|
    {
 | 
						|
        vol.Required(ATTR_INDEX): vol.Coerce(int),
 | 
						|
        vol.Required(ATTR_VOLUME): vol.Coerce(float),
 | 
						|
    }
 | 
						|
)
 | 
						|
 | 
						|
# pylint: disable=no-value-for-parameter
 | 
						|
SCHEMA_MUTE = vol.Schema(
 | 
						|
    {
 | 
						|
        vol.Required(ATTR_INDEX): vol.Coerce(int),
 | 
						|
        vol.Required(ATTR_ACTIVE): vol.Boolean(),
 | 
						|
    }
 | 
						|
)
 | 
						|
 | 
						|
SCHEMA_DEFAULT = vol.Schema({vol.Required(ATTR_NAME): str})
 | 
						|
 | 
						|
SCHEMA_PROFILE = vol.Schema(
 | 
						|
    {vol.Required(ATTR_CARD): str, vol.Required(ATTR_NAME): str}
 | 
						|
)
 | 
						|
 | 
						|
 | 
						|
class APIAudio(CoreSysAttributes):
 | 
						|
    """Handle RESTful API for Audio functions."""
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def info(self, request: web.Request) -> dict[str, Any]:
 | 
						|
        """Return Audio information."""
 | 
						|
        return {
 | 
						|
            ATTR_VERSION: self.sys_plugins.audio.version,
 | 
						|
            ATTR_VERSION_LATEST: self.sys_plugins.audio.latest_version,
 | 
						|
            ATTR_UPDATE_AVAILABLE: self.sys_plugins.audio.need_update,
 | 
						|
            ATTR_HOST: str(self.sys_docker.network.audio),
 | 
						|
            ATTR_AUDIO: {
 | 
						|
                ATTR_CARD: [asdict(card) for card in self.sys_host.sound.cards],
 | 
						|
                ATTR_INPUT: [asdict(stream) for stream in self.sys_host.sound.inputs],
 | 
						|
                ATTR_OUTPUT: [asdict(stream) for stream in self.sys_host.sound.outputs],
 | 
						|
                ATTR_APPLICATION: [
 | 
						|
                    asdict(stream) for stream in self.sys_host.sound.applications
 | 
						|
                ],
 | 
						|
            },
 | 
						|
        }
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def stats(self, request: web.Request) -> dict[str, Any]:
 | 
						|
        """Return resource information."""
 | 
						|
        stats = await self.sys_plugins.audio.stats()
 | 
						|
 | 
						|
        return {
 | 
						|
            ATTR_CPU_PERCENT: stats.cpu_percent,
 | 
						|
            ATTR_MEMORY_USAGE: stats.memory_usage,
 | 
						|
            ATTR_MEMORY_LIMIT: stats.memory_limit,
 | 
						|
            ATTR_MEMORY_PERCENT: stats.memory_percent,
 | 
						|
            ATTR_NETWORK_RX: stats.network_rx,
 | 
						|
            ATTR_NETWORK_TX: stats.network_tx,
 | 
						|
            ATTR_BLK_READ: stats.blk_read,
 | 
						|
            ATTR_BLK_WRITE: stats.blk_write,
 | 
						|
        }
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def update(self, request: web.Request) -> None:
 | 
						|
        """Update Audio plugin."""
 | 
						|
        body = await api_validate(SCHEMA_VERSION, request)
 | 
						|
        version = body.get(ATTR_VERSION, self.sys_plugins.audio.latest_version)
 | 
						|
 | 
						|
        if version == self.sys_plugins.audio.version:
 | 
						|
            raise APIError(f"Version {version} is already in use")
 | 
						|
        await asyncio.shield(self.sys_plugins.audio.update(version))
 | 
						|
 | 
						|
    @api_process
 | 
						|
    def restart(self, request: web.Request) -> Awaitable[None]:
 | 
						|
        """Restart Audio plugin."""
 | 
						|
        return asyncio.shield(self.sys_plugins.audio.restart())
 | 
						|
 | 
						|
    @api_process
 | 
						|
    def reload(self, request: web.Request) -> Awaitable[None]:
 | 
						|
        """Reload Audio information."""
 | 
						|
        return asyncio.shield(self.sys_host.sound.update())
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def set_volume(self, request: web.Request) -> None:
 | 
						|
        """Set audio volume on stream."""
 | 
						|
        source: StreamType = StreamType(request.match_info.get("source"))
 | 
						|
        application: bool = request.path.endswith("application")
 | 
						|
        body = await api_validate(SCHEMA_VOLUME, request)
 | 
						|
 | 
						|
        await asyncio.shield(
 | 
						|
            self.sys_host.sound.set_volume(
 | 
						|
                source, body[ATTR_INDEX], body[ATTR_VOLUME], application
 | 
						|
            )
 | 
						|
        )
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def set_mute(self, request: web.Request) -> None:
 | 
						|
        """Mute audio volume on stream."""
 | 
						|
        source: StreamType = StreamType(request.match_info.get("source"))
 | 
						|
        application: bool = request.path.endswith("application")
 | 
						|
        body = await api_validate(SCHEMA_MUTE, request)
 | 
						|
 | 
						|
        await asyncio.shield(
 | 
						|
            self.sys_host.sound.set_mute(
 | 
						|
                source, body[ATTR_INDEX], body[ATTR_ACTIVE], application
 | 
						|
            )
 | 
						|
        )
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def set_default(self, request: web.Request) -> None:
 | 
						|
        """Set audio default stream."""
 | 
						|
        source: StreamType = StreamType(request.match_info.get("source"))
 | 
						|
        body = await api_validate(SCHEMA_DEFAULT, request)
 | 
						|
 | 
						|
        await asyncio.shield(self.sys_host.sound.set_default(source, body[ATTR_NAME]))
 | 
						|
 | 
						|
    @api_process
 | 
						|
    async def set_profile(self, request: web.Request) -> None:
 | 
						|
        """Set audio default sources."""
 | 
						|
        body = await api_validate(SCHEMA_PROFILE, request)
 | 
						|
 | 
						|
        await asyncio.shield(
 | 
						|
            self.sys_host.sound.ativate_profile(body[ATTR_CARD], body[ATTR_NAME])
 | 
						|
        )
 |