Compare commits
	
		
			1 Commits
		
	
	
		
			main
			...
			fix/soundb
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 2c278da442 | 
|  | @ -1,32 +0,0 @@ | |||
| // For format details, see https://aka.ms/devcontainer.json. For config options, see the | ||||
| // README at: https://github.com/devcontainers/templates/tree/main/src/python | ||||
| { | ||||
| 	"name": "Python 3", | ||||
| 	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile | ||||
| 	"image": "homeassistant/home-assistant:dev", | ||||
| 	"postCreateCommand": "scripts/setup", | ||||
| 	"forwardPorts": [ | ||||
|         8123 | ||||
|     ], | ||||
|     "portsAttributes": { | ||||
|         "8123": { | ||||
|             "label": "Home Assistant", | ||||
|             "onAutoForward": "notify" | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	// Features to add to the dev container. More info: https://containers.dev/features. | ||||
| 	// "features": {}, | ||||
| 
 | ||||
| 	// Use 'forwardPorts' to make a list of ports inside the container available locally. | ||||
| 	// "forwardPorts": [], | ||||
| 
 | ||||
| 	// Use 'postCreateCommand' to run commands after the container is created. | ||||
| 	// "postCreateCommand": "pip3 install --user -r requirements.txt", | ||||
| 
 | ||||
| 	// Configure tool-specific properties. | ||||
| 	// "customizations": {}, | ||||
| 
 | ||||
| 	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. | ||||
| 	// "remoteUser": "root" | ||||
| } | ||||
|  | @ -4,11 +4,6 @@ __pycache__/ | |||
| *$py.class | ||||
| .DS_store | ||||
| 
 | ||||
| config | ||||
| .vscode | ||||
| .ruff_cache | ||||
| 
 | ||||
| 
 | ||||
| # C extensions | ||||
| *.so | ||||
| .idea | ||||
|  |  | |||
							
								
								
									
										54
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										54
									
								
								CHANGELOG.md
								
								
								
								
							|  | @ -1,59 +1,11 @@ | |||
| # Changelog | ||||
| 
 | ||||
| ## [0.4.1] Media Mystique: The Great Data Disappearing Act! | ||||
| 
 | ||||
| ### Fixed | ||||
| 
 | ||||
| - Made media data (*track title*, *artist*, *length*) optional to acoomodate soundbars that don't provide this information (🥲) | ||||
| ## [0.3.1] Let HomeAssistant schedule failing setup of integration | ||||
| 
 | ||||
| ### Added | ||||
| 
 | ||||
| - Add translations for the english translation file | ||||
| 
 | ||||
| ## [0.4.0] Started with an "ick", but is now packed with new features 💪 | ||||
| 
 | ||||
| > ⚠️ Please read the following carefully: | ||||
| > This release is a bit special. As "something" on Samsung's side changed, | ||||
| > it is currently not possible to retrieve the status of "custom capabilities", eg. | ||||
| > woofer, soundmode, eq, and others. Therefore I decided to give the option to | ||||
| > disable the entities of these features as the value of these entities is not trustworthy. | ||||
| > Instead I implemented all of these and more (thanks to @whitebearded) as service calls. | ||||
| > Have fun using them! | ||||
| 
 | ||||
| ### Added | ||||
| 
 | ||||
| - Configuration flow options for enable / disable | ||||
|   - "advanced audio" features (NightMode, Bassmode, VoiceEnhancer) | ||||
|   - "woofer" feature | ||||
|   - "soundmode" feature | ||||
|   - "eq" feature | ||||
| - added `media_player` support for next and previous track | ||||
| - Service calls for: | ||||
|   - "advanced audio" features (NightMode, Bassmode, VoiceEnhancer) | ||||
|   - "woofer" feature | ||||
|   - "soundmode" feature | ||||
|   - "speaker_level" | ||||
|   - "rear_speaker_mode" | ||||
|   - "space_fit_sound" | ||||
|   - "active_voice_amplifier" | ||||
| 
 | ||||
| ### Changed | ||||
| 
 | ||||
| - Fixed state, also displaying "playing" and "paused" values | ||||
| 
 | ||||
| ## [0.3.2] Fix division by zero | ||||
| 
 | ||||
| ### Added | ||||
| 
 | ||||
| - The config flow now also checks whether the `int` provided for `CONF_ENTRY_MAX_VOLUME` is | ||||
|   greater than `1` and lower than `100`. This will make sure that a division by zero cannot happen. | ||||
| - Add default value `100` to `CONF_ENTRY_MAX_VOLUME` | ||||
| 
 | ||||
| ## [0.3.1] Documentation enhancements | ||||
| 
 | ||||
| ### Changed | ||||
| 
 | ||||
| - Updated the `README` as well as the documentation website | ||||
| - Add a `try / catch` mechanism to the first update of the client while setup and throw a | ||||
|   `ConfigEntryNotReady` exception when the update fails | ||||
| 
 | ||||
| ## [0.3.0] Icons and Chore | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										21
									
								
								LICENSE
								
								
								
								
							
							
						
						
									
										21
									
								
								LICENSE
								
								
								
								
							|  | @ -1,21 +0,0 @@ | |||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2024 Samuel Spagl | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										5
									
								
								Pipfile
								
								
								
								
							
							
						
						
									
										5
									
								
								Pipfile
								
								
								
								
							|  | @ -9,7 +9,8 @@ rich = "*" | |||
| homeassistant = "*" | ||||
| 
 | ||||
| [dev-packages] | ||||
| ruff = "*" | ||||
| black = "*" | ||||
| isort = "*" | ||||
| 
 | ||||
| [requires] | ||||
| python_version = "3.12" | ||||
| python_version = "3.11" | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										94
									
								
								README.md
								
								
								
								
							
							
						
						
									
										94
									
								
								README.md
								
								
								
								
							|  | @ -1,22 +1,6 @@ | |||
| # YASSI: Yet Another Samsung Soundbar Integration (for Home Assistant) | ||||
| # HomeAssistant: Samsung Soundbar Integration | ||||
| 
 | ||||
| Welcome to YASSI, the Home Assistant integration designed to bring comprehensive control over your Samsung Soundbar into your smart home ecosystem. | ||||
| 
 | ||||
| > [!NOTE] | ||||
| > Please use service calls for setting the attribute of a custom capability instead of the entity. (See #43 for more information) | ||||
| 
 | ||||
| **Table of Contents:** | ||||
| <!-- TOC --> | ||||
| * [Why YASSI](#why-yassi) | ||||
| * [Features](#features) | ||||
| * [Installation / Setup](#installation--setup) | ||||
|   * [Prerequisites](#prerequisites) | ||||
|   * [Installation:](#installation) | ||||
|   * [Configuration](#configuration) | ||||
| * [Support](#support) | ||||
| * [Contributing](#contributing) | ||||
| * [General Thanks](#general-thanks) | ||||
| <!-- TOC --> | ||||
| > Yet another Samsung Soundbar Integration (YASSI) | ||||
| 
 | ||||
| ## Why YASSI | ||||
| 
 | ||||
|  | @ -34,54 +18,48 @@ are not documented... ;) | |||
| 
 | ||||
| ## Features | ||||
| 
 | ||||
| - Set-Up through HomeAssistant-UI | ||||
| - Theoretically it should be possible to have multiple Devices (not tested) | ||||
| 
 | ||||
| - **UI Setup**: You can easily set up your Soundbar through the UI. | ||||
| - **Media Player Controls**: Power, volume, mute, source selection, and media controls are all at your fingertips. | ||||
| - **Selectable Sound Modes**: Choose from various sound modes and inputs for optimal audio. | ||||
| - **Subwoofer & Equalizer Adjustment**: Fine-tune your audio experience. | ||||
| - **Switchable Enhancements**: Toggle features like night mode and voice amplification. | ||||
| - **Customizable Bass Level**: Set the bass to your preference. | ||||
| - **Multiple Devices**: should be theoretically possible but **not** tested | ||||
| - `media_player` Entity | ||||
|   - On / Off | ||||
|   - Volume | ||||
|   - Mute | ||||
|   - Input Source | ||||
|   - Sound Mode | ||||
|   - Media | ||||
|     - Play / Pause / Stop | ||||
|     - Artist | ||||
|     - Title | ||||
|     - Music Cover Art url (iTunes Api) | ||||
| - `switch` entity | ||||
|   - Night mode | ||||
|   - Bass mode | ||||
|   - Voice amplifier | ||||
| - `number` entity | ||||
|   - bass level | ||||
|   - *[to come] equalizer bands* | ||||
| - `select` entity | ||||
|   - sound mode (additional control in the "Device" tab) | ||||
|   - input (additional control in the "Device" tab) | ||||
|   - equalizer preset | ||||
| 
 | ||||
| For the full feature list per entity type, please take a look at the [documentation](ha-samsung-soundbar.vercel.app) website. | ||||
| ## How to install it: | ||||
| 
 | ||||
| ## Installation / Setup | ||||
| ### HACS:  | ||||
| >  ⚠️ not done yet but planned (hopefully) | ||||
| 
 | ||||
| ### Prerequisites | ||||
| ### Adding this repository as custom repository | ||||
| 
 | ||||
| Before you begin, ensure you have the following: | ||||
| Add this repository as custom repository in HACS and install it ;) | ||||
| 
 | ||||
| - A Samsung Soundbar compatible with SmartThings. | ||||
| - Home Assistant installed and running. | ||||
| - HACS (Home Assistant Community Store) for easy installation. | ||||
| ### Manual | ||||
| 
 | ||||
| ### Installation | ||||
| You can also copy the `samsung_soundbar` folder in the `custom_components` folder to | ||||
| your `config/custom_components` folder. | ||||
| 
 | ||||
| 1. Add this repository as a custom repository in HACS or manually copy the `samsung_soundbar` folder to the `custom_components` directory in your Home Assistant configuration. | ||||
| 
 | ||||
|   [](https://my.home-assistant.io/redirect/hacs_repository/?owner=samuelspagl&repository=ha_samsung_soundbar&category=integration) | ||||
| 2. Restart Home Assistant. | ||||
| 
 | ||||
| > [!NOTE] | ||||
| > It is planned to add it to the default `HACS` repository list, but not done yet. | ||||
| 
 | ||||
| ### Configuration | ||||
| 
 | ||||
| To integrate your Samsung Soundbar with Home Assistant using YASSI, you will be asked for the following variables: | ||||
| 
 | ||||
| - **SmartThings API Key**: [Retrieve your API key from SmartThings Tokens.](https://account.smartthings.com/tokens) | ||||
| - **Device ID**: [Find your device ID at SmartThings Devices.](https://my.smartthings.com/advanced/devices) | ||||
| - **Device Name**: Choose a name for your soundbar to be recognized in Home Assistant. | ||||
| - **Max Volume**: Define the maximum volume level for the `media_player` slider (between `1` and `100`). | ||||
| 
 | ||||
| ## Support | ||||
| 
 | ||||
| For support, feature requests, or bug reporting, please visit the Issues section of this GitHub repository. | ||||
| 
 | ||||
| ## Contributing | ||||
| 
 | ||||
| Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated. | ||||
| 
 | ||||
| ## General Thanks | ||||
| 
 | ||||
| - Like already mentioned, thanks to @PiotrMachowski / @thierryBourbon for the general idea on how to do things. | ||||
| Like already mentioned, thanks to @PiotrMachowski / @thierryBourbon for the general | ||||
| idea on how to do things. | ||||
|  | @ -1,23 +1,16 @@ | |||
| import logging | ||||
| 
 | ||||
| from aiohttp import ClientResponseError | ||||
| from homeassistant.config_entries import ConfigEntry | ||||
| from homeassistant.core import DOMAIN, HomeAssistant | ||||
| from homeassistant.exceptions import ConfigEntryNotReady | ||||
| from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||||
| from pysmartthings import SmartThings | ||||
| 
 | ||||
| from .api_extension.SoundbarDevice import SoundbarDevice | ||||
| from .const import ( | ||||
|     CONF_ENTRY_API_KEY, | ||||
|     CONF_ENTRY_DEVICE_ID, | ||||
|     CONF_ENTRY_DEVICE_NAME, | ||||
|     CONF_ENTRY_MAX_VOLUME, | ||||
|     CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES, | ||||
|     CONF_ENTRY_SETTINGS_EQ_SELECTOR, | ||||
|     CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR, | ||||
|     CONF_ENTRY_SETTINGS_WOOFER_NUMBER, | ||||
|     DOMAIN, | ||||
|     SUPPORTED_DOMAINS, | ||||
| ) | ||||
| from .const import (CONF_ENTRY_API_KEY, CONF_ENTRY_DEVICE_ID, | ||||
|                     CONF_ENTRY_DEVICE_NAME, CONF_ENTRY_MAX_VOLUME, DOMAIN, | ||||
|                     SUPPORTED_DOMAINS) | ||||
| from .models import DeviceConfig, SoundbarConfig | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | @ -30,9 +23,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | |||
|     # store shell object | ||||
| 
 | ||||
|     _LOGGER.info(f"[{DOMAIN}] Starting to setup a ConfigEntry") | ||||
|     _LOGGER.debug( | ||||
|         f"[{DOMAIN}] Setting up ConfigEntry with the following data: {entry.data}" | ||||
|     ) | ||||
|     _LOGGER.debug(f"[{DOMAIN}] Setting up ConfigEntry with the following data: {entry.data}") | ||||
|     if not DOMAIN in hass.data: | ||||
|         _LOGGER.debug(f"[{DOMAIN}] Domain not found in hass.data setting default") | ||||
|         hass.data[DOMAIN] = SoundbarConfig( | ||||
|  | @ -59,14 +50,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | |||
|             session, | ||||
|             entry.data.get(CONF_ENTRY_MAX_VOLUME), | ||||
|             entry.data.get(CONF_ENTRY_DEVICE_NAME), | ||||
|             enable_eq=entry.data.get(CONF_ENTRY_SETTINGS_EQ_SELECTOR), | ||||
|             enable_advanced_audio=entry.data.get( | ||||
|                 CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES | ||||
|             ), | ||||
|             enable_soundmode=entry.data.get(CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR), | ||||
|             enable_woofer=entry.data.get(CONF_ENTRY_SETTINGS_WOOFER_NUMBER), | ||||
|         ) | ||||
|         try: | ||||
|             await soundbar_device.update() | ||||
|         except ClientResponseError as excp: | ||||
|             raise ConfigEntryNotReady("An error occurred while setting up the soundbar device. " | ||||
|                                       "Please recheck whether the device has power or is connected to the internet.")\ | ||||
|                 from excp | ||||
|         domain_config.devices[entry.data.get(CONF_ENTRY_DEVICE_ID)] = DeviceConfig( | ||||
|             entry.data, soundbar_device | ||||
|         ) | ||||
|  |  | |||
|  | @ -2,11 +2,11 @@ import asyncio | |||
| import datetime | ||||
| import json | ||||
| import logging | ||||
| import time | ||||
| from urllib.parse import quote | ||||
| 
 | ||||
| from pysmartthings import DeviceEntity | ||||
| 
 | ||||
| from .const import SpeakerIdentifier, RearSpeakerMode | ||||
| from ..const import DOMAIN | ||||
| 
 | ||||
| log = logging.getLogger(__name__) | ||||
|  | @ -14,15 +14,7 @@ log = logging.getLogger(__name__) | |||
| 
 | ||||
| class SoundbarDevice: | ||||
|     def __init__( | ||||
|             self, | ||||
|             device: DeviceEntity, | ||||
|             session, | ||||
|             max_volume: int, | ||||
|             device_name: str, | ||||
|             enable_eq: bool = False, | ||||
|             enable_soundmode: bool = False, | ||||
|             enable_advanced_audio: bool = False, | ||||
|             enable_woofer: bool = False, | ||||
|         self, device: DeviceEntity, session, max_volume: int, device_name: str | ||||
|     ): | ||||
|         self.device = device | ||||
|         self._device_id = self.device.device_id | ||||
|  | @ -30,21 +22,17 @@ class SoundbarDevice: | |||
|         self.__session = session | ||||
|         self.__device_name = device_name | ||||
| 
 | ||||
|         self.__enable_soundmode = enable_soundmode | ||||
|         self.__supported_soundmodes = [] | ||||
|         self.__active_soundmode = "" | ||||
| 
 | ||||
|         self.__enable_woofer = enable_woofer | ||||
|         self.__woofer_level = 0 | ||||
|         self.__woofer_connection = "" | ||||
| 
 | ||||
|         self.__enable_eq = enable_eq | ||||
|         self.__active_eq_preset = "" | ||||
|         self.__supported_eq_presets = [] | ||||
|         self.__eq_action = "" | ||||
|         self.__eq_bands = [] | ||||
| 
 | ||||
|         self.__enable_advanced_audio = enable_advanced_audio | ||||
|         self.__voice_amplifier = 0 | ||||
|         self.__night_mode = 0 | ||||
|         self.__bass_mode = 0 | ||||
|  | @ -61,18 +49,12 @@ class SoundbarDevice: | |||
|         await self.device.status.refresh() | ||||
| 
 | ||||
|         await self._update_media() | ||||
| 
 | ||||
|         if self.__enable_soundmode: | ||||
|         await self._update_soundmode() | ||||
|         if self.__enable_advanced_audio: | ||||
|         await self._update_advanced_audio() | ||||
|         if self.__enable_soundmode: | ||||
|         await self._update_woofer() | ||||
|         if self.__enable_eq: | ||||
|         await self._update_equalizer() | ||||
| 
 | ||||
|     async def _update_media(self): | ||||
|         if "audioTrackData" in self.device.status._attributes: | ||||
|         self.__media_artist = self.device.status._attributes["audioTrackData"].value[ | ||||
|             "artist" | ||||
|         ] | ||||
|  | @ -88,14 +70,14 @@ class SoundbarDevice: | |||
| 
 | ||||
|     async def _update_soundmode(self): | ||||
|         await self.update_execution_data(["/sec/networkaudio/soundmode"]) | ||||
|         await asyncio.sleep(1) | ||||
|         await asyncio.sleep(0.1) | ||||
|         payload = await self.get_execute_status() | ||||
|         retry = 0 | ||||
|         while ( | ||||
|             "x.com.samsung.networkaudio.supportedSoundmode" not in payload | ||||
|             and retry < 10 | ||||
|         ): | ||||
|             await asyncio.sleep(1) | ||||
|             await asyncio.sleep(0.2) | ||||
|             payload = await self.get_execute_status() | ||||
|             retry += 1 | ||||
|         if retry == 10: | ||||
|  | @ -197,15 +179,7 @@ class SoundbarDevice: | |||
| 
 | ||||
|     @property | ||||
|     def state(self) -> str: | ||||
|         if self.device.status.switch: | ||||
|             if self.device.status.playback_status == "playing": | ||||
|                 return "playing" | ||||
|             if self.device.status.playback_status == "paused": | ||||
|                 return "paused" | ||||
|             else: | ||||
|                 return "on" | ||||
|         else: | ||||
|             return "off" | ||||
|         return "on" if self.device.status.switch else "off" | ||||
| 
 | ||||
|     async def switch_off(self): | ||||
|         await self.device.switch_off(True) | ||||
|  | @ -373,15 +347,11 @@ class SoundbarDevice: | |||
| 
 | ||||
|     @property | ||||
|     def media_duration(self) -> int | None: | ||||
|         attr = self.device.status.attributes.get("totalTime", None) | ||||
|         if attr: | ||||
|             return attr.value | ||||
|         return self.device.status.attributes.get("totalTime").value | ||||
| 
 | ||||
|     @property | ||||
|     def media_position(self) -> int | None: | ||||
|         attr = self.device.status.attributes.get("elapsedTime", None) | ||||
|         if attr: | ||||
|             return attr.value | ||||
|         return self.device.status.attributes.get("elapsedTime").value | ||||
| 
 | ||||
|     async def media_play(self): | ||||
|         await self.device.play(True) | ||||
|  | @ -392,12 +362,6 @@ class SoundbarDevice: | |||
|     async def media_stop(self): | ||||
|         await self.device.stop(True) | ||||
| 
 | ||||
|     async def media_next_track(self): | ||||
|         await self.device.command("main", "mediaPlayback", "fastForward") | ||||
| 
 | ||||
|     async def media_previous_track(self): | ||||
|         await self.device.command("main", "mediaPlayback", "rewind") | ||||
| 
 | ||||
|     @property | ||||
|     def media_app_name(self): | ||||
|         detail_status = self.device.status.attributes.get("detailName", None) | ||||
|  | @ -409,54 +373,21 @@ class SoundbarDevice: | |||
|     def media_coverart_updated(self) -> datetime.datetime: | ||||
|         return self.__media_cover_url_update_time | ||||
| 
 | ||||
|     # ------------ Speaker Level ---------------- | ||||
| 
 | ||||
|     async def set_speaker_level(self, speaker: SpeakerIdentifier, level: int): | ||||
|         await self.set_custom_execution_data( | ||||
|             href="/sec/networkaudio/channelVolume", | ||||
|             property="x.com.samsung.networkaudio.channelVolume", | ||||
|             value=[{"name": speaker.value, "value": level}], | ||||
|         ) | ||||
| 
 | ||||
|     async def set_rear_speaker_mode(self, mode: RearSpeakerMode): | ||||
|         await self.set_custom_execution_data( | ||||
|             href="/sec/networkaudio/surroundspeaker", | ||||
|             property="x.com.samsung.networkaudio.currentRearPosition", | ||||
|             value=mode.value, | ||||
|         ) | ||||
| 
 | ||||
|     # ------------ OTHER FUNCTIONS ------------ | ||||
| 
 | ||||
|     async def set_active_voice_amplifier(self, enabled: bool): | ||||
|         await self.set_custom_execution_data( | ||||
|             href="/sec/networkaudio/activeVoiceAmplifier", | ||||
|             property="x.com.samsung.networkaudio.activeVoiceAmplifier", | ||||
|             value=1 if enabled else 0 | ||||
|         ) | ||||
| 
 | ||||
|     async def set_space_fit_sound(self, enabled: bool): | ||||
|         await self.set_custom_execution_data( | ||||
|             href="/sec/networkaudio/spacefitSound", | ||||
|             property="x.com.samsung.networkaudio.spacefitSound", | ||||
|             value=1 if enabled else 0 | ||||
|         ) | ||||
| 
 | ||||
|     # ------------ SUPPORT FUNCTIONS ------------ | ||||
| 
 | ||||
|     async def update_execution_data(self, argument: str): | ||||
|         stuff = await self.device.command("main", "execute", "execute", argument) | ||||
|         return stuff | ||||
|         return await self.device.command("main", "execute", "execute", argument) | ||||
| 
 | ||||
|     async def set_custom_execution_data(self, href: str, property: str, value): | ||||
|         argument = [href, {property: value}] | ||||
|         assert await self.device.command("main", "execute", "execute", argument) | ||||
|         await self.device.command("main", "execute", "execute", argument) | ||||
| 
 | ||||
|     async def get_execute_status(self): | ||||
|         url = f"https://api.smartthings.com/v1/devices/{self._device_id}/components/main/capabilities/execute/status" | ||||
|         request_headers = {"Authorization": "Bearer " + self._api_key} | ||||
|         resp = await self.__session.get(url, headers=request_headers) | ||||
|         dict_stuff = await resp.json() | ||||
|         return dict_stuff["data"]["value"]["payload"] | ||||
|         dict = await resp.json() | ||||
|         return dict["data"]["value"]["payload"] | ||||
| 
 | ||||
|     async def get_song_title_artwork(self, artist: str, title: str) -> str: | ||||
|         """ | ||||
|  |  | |||
|  | @ -1,15 +0,0 @@ | |||
| from enum import Enum | ||||
| 
 | ||||
| 
 | ||||
| class SpeakerIdentifier(Enum): | ||||
|     CENTER = "Spk_Center" | ||||
|     SIDE = "Spk_Side" | ||||
|     WIDE = "Spk_Wide" | ||||
|     FRONT_TOP = "Spk_Front_Top" | ||||
|     REAR = "Spk_Rear" | ||||
|     REAR_TOP = "Spk_Rear_Top" | ||||
| 
 | ||||
| 
 | ||||
| class RearSpeakerMode(Enum): | ||||
|     FRONT = "Front" | ||||
|     REAR = "Rear" | ||||
|  | @ -1,24 +1,13 @@ | |||
| import logging | ||||
| from typing import Any | ||||
| 
 | ||||
| import pysmartthings | ||||
| import voluptuous as vol | ||||
| from homeassistant import config_entries | ||||
| from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||||
| from pysmartthings import APIResponseError | ||||
| from voluptuous import All, Range | ||||
| 
 | ||||
| from .const import ( | ||||
|     CONF_ENTRY_API_KEY, | ||||
|     CONF_ENTRY_DEVICE_ID, | ||||
|     CONF_ENTRY_DEVICE_NAME, | ||||
|     CONF_ENTRY_MAX_VOLUME, | ||||
|     CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES, | ||||
|     CONF_ENTRY_SETTINGS_EQ_SELECTOR, | ||||
|     CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR, | ||||
|     CONF_ENTRY_SETTINGS_WOOFER_NUMBER, | ||||
|     DOMAIN, | ||||
| ) | ||||
| from .const import (CONF_ENTRY_API_KEY, CONF_ENTRY_DEVICE_ID, | ||||
|                     CONF_ENTRY_DEVICE_NAME, CONF_ENTRY_MAX_VOLUME, DOMAIN) | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
| 
 | ||||
|  | @ -34,8 +23,20 @@ async def validate_input(api, device_id: str): | |||
| class ExampleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): | ||||
|     async def async_step_user(self, user_input=None): | ||||
|         if user_input is not None: | ||||
|             self.user_input = user_input | ||||
|             return await self.async_step_device() | ||||
|             try: | ||||
|                 session = async_get_clientsession(self.hass) | ||||
|                 api = pysmartthings.SmartThings( | ||||
|                     session, user_input.get(CONF_ENTRY_API_KEY) | ||||
|                 ) | ||||
|                 device = await validate_input(api, user_input.get(CONF_ENTRY_DEVICE_ID)) | ||||
| 
 | ||||
|                 _LOGGER.debug( | ||||
|                     f"Successfully validated Input, Creating entry with title {DOMAIN} and data {user_input}" | ||||
|                 ) | ||||
|                 return self.async_create_entry(title=DOMAIN, data=user_input) | ||||
|             except Exception as excp: | ||||
|                 _LOGGER.error(f"The ConfigFlow triggered an exception {excp}") | ||||
|                 return self.async_abort(reason="fetch_failed") | ||||
| 
 | ||||
|         return self.async_show_form( | ||||
|             step_id="user", | ||||
|  | @ -44,98 +45,7 @@ class ExampleConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): | |||
|                     vol.Required(CONF_ENTRY_API_KEY): str, | ||||
|                     vol.Required(CONF_ENTRY_DEVICE_ID): str, | ||||
|                     vol.Required(CONF_ENTRY_DEVICE_NAME): str, | ||||
|                     vol.Required(CONF_ENTRY_MAX_VOLUME, default=100): All( | ||||
|                         int, Range(min=1, max=100) | ||||
|                     ), | ||||
|                     vol.Required(CONF_ENTRY_MAX_VOLUME): int, | ||||
|                 } | ||||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|     async def async_step_device(self, user_input: dict[str, any] | None = None): | ||||
|         if user_input is not None: | ||||
|             self.user_input.update(user_input) | ||||
| 
 | ||||
|             try: | ||||
|                 session = async_get_clientsession(self.hass) | ||||
|                 api = pysmartthings.SmartThings( | ||||
|                     session, self.user_input.get(CONF_ENTRY_API_KEY) | ||||
|                 ) | ||||
|                 device = await validate_input( | ||||
|                     api, self.user_input.get(CONF_ENTRY_DEVICE_ID) | ||||
|                 ) | ||||
|                 _LOGGER.debug( | ||||
|                     f"Successfully validated Input, Creating entry with title {DOMAIN} and data {user_input}" | ||||
|                 ) | ||||
|             except Exception as excp: | ||||
|                 _LOGGER.error(f"The ConfigFlow triggered an exception {excp}") | ||||
|                 return self.async_abort(reason="fetch_failed") | ||||
|             return self.async_create_entry(title=DOMAIN, data=self.user_input) | ||||
| 
 | ||||
|         return self.async_show_form( | ||||
|             step_id="device", | ||||
|             data_schema=vol.Schema( | ||||
|                 { | ||||
|                     vol.Required(CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES): bool, | ||||
|                     vol.Required(CONF_ENTRY_SETTINGS_EQ_SELECTOR): bool, | ||||
|                     vol.Required(CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR): bool, | ||||
|                     vol.Required(CONF_ENTRY_SETTINGS_WOOFER_NUMBER): bool, | ||||
|                 } | ||||
|             ), | ||||
|         ) | ||||
| 
 | ||||
|     async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None): | ||||
|         """Handle a reconfiguration flow initialized by the user.""" | ||||
|         self.config_entry = self.hass.config_entries.async_get_entry( | ||||
|             self.context["entry_id"] | ||||
|         ) | ||||
|         return await self.async_step_reconfigure_confirm() | ||||
| 
 | ||||
|     async def async_step_reconfigure_confirm( | ||||
|         self, user_input: dict[str, Any] | None = None | ||||
|     ): | ||||
|         """Handle a reconfiguration flow initialized by the user.""" | ||||
|         errors: dict[str, str] = {} | ||||
|         assert self.config_entry | ||||
| 
 | ||||
|         if user_input is not None: | ||||
|             return self.async_update_reload_and_abort( | ||||
|                 self.config_entry, | ||||
|                 data={**self.config_entry.data, **user_input}, | ||||
|                 reason="reconfigure_successful", | ||||
|             ) | ||||
| 
 | ||||
|         return self.async_show_form( | ||||
|             step_id="reconfigure_confirm", | ||||
|             data_schema=vol.Schema( | ||||
|                 { | ||||
|                     vol.Required( | ||||
|                         CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES, | ||||
|                         default=self.config_entry.data.get( | ||||
|                             CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES | ||||
|                         ), | ||||
|                     ): bool, | ||||
|                     vol.Required( | ||||
|                         CONF_ENTRY_SETTINGS_EQ_SELECTOR, | ||||
|                         default=self.config_entry.data.get( | ||||
|                             CONF_ENTRY_SETTINGS_EQ_SELECTOR | ||||
|                         ), | ||||
|                     ): bool, | ||||
|                     vol.Required( | ||||
|                         CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR, | ||||
|                         default=self.config_entry.data.get( | ||||
|                             CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR | ||||
|                         ), | ||||
|                     ): bool, | ||||
|                     vol.Required( | ||||
|                         CONF_ENTRY_SETTINGS_WOOFER_NUMBER, | ||||
|                         default=self.config_entry.data.get( | ||||
|                             CONF_ENTRY_SETTINGS_WOOFER_NUMBER | ||||
|                         ), | ||||
|                     ): bool, | ||||
|                     vol.Required(CONF_ENTRY_MAX_VOLUME, default=100): All( | ||||
|                         int, Range(min=1, max=100) | ||||
|                     ), | ||||
|                 } | ||||
|             ), | ||||
|             errors=errors, | ||||
|         ) | ||||
|  |  | |||
|  | @ -9,12 +9,6 @@ CONF_ENTRY_API_KEY = "api_key" | |||
| CONF_ENTRY_DEVICE_ID = "device_id" | ||||
| CONF_ENTRY_DEVICE_NAME = "device_name" | ||||
| CONF_ENTRY_MAX_VOLUME = "device_volume" | ||||
| 
 | ||||
| CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES = "settings_advanced_audio" | ||||
| CONF_ENTRY_SETTINGS_EQ_SELECTOR = "settings_eq" | ||||
| CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR = "settings_soundmode" | ||||
| CONF_ENTRY_SETTINGS_WOOFER_NUMBER = "settings_woofer" | ||||
| 
 | ||||
| DEFAULT_NAME = DOMAIN | ||||
| 
 | ||||
| BUTTON = BUTTON_DOMAIN | ||||
|  |  | |||
|  | @ -1,16 +1,12 @@ | |||
| { | ||||
|   "domain": "samsung_soundbar", | ||||
|   "name": "Samsung Soundbar", | ||||
|   "codeowners": [ | ||||
|     "@samuelspagl" | ||||
|   ], | ||||
|   "codeowners": ["@samuelspagl"], | ||||
|   "config_flow": true, | ||||
|   "documentation": "https://www.example.com", | ||||
|   "integration_type": "hub", | ||||
|   "iot_class": "cloud_polling", | ||||
|   "issue_tracker": "https://github.com/samuelspagl/ha_samsung_soundbar/issues", | ||||
|   "requirements": [ | ||||
|     "pysmartthings==0.7.8" | ||||
|   ], | ||||
|   "version": "0.4.1" | ||||
|   "requirements": ["pysmartthings"], | ||||
|   "version": "0.3.1" | ||||
| } | ||||
|  | @ -1,25 +1,16 @@ | |||
| import logging | ||||
| from typing import Any, Mapping | ||||
| 
 | ||||
| from homeassistant.components.media_player import ( | ||||
|     DEVICE_CLASS_SPEAKER, | ||||
|     MediaPlayerEntity, | ||||
| ) | ||||
| from homeassistant.components.media_player.const import MediaPlayerEntityFeature | ||||
| from homeassistant.components.media_player import (DEVICE_CLASS_SPEAKER, | ||||
|                                                    MediaPlayerEntity) | ||||
| from homeassistant.components.media_player.const import \ | ||||
|     MediaPlayerEntityFeature | ||||
| from homeassistant.helpers.aiohttp_client import async_get_clientsession | ||||
| from homeassistant.helpers.entity import DeviceInfo, generate_entity_id | ||||
| from homeassistant.helpers import config_validation as cv, entity_platform, selector | ||||
| import voluptuous as vol | ||||
| 
 | ||||
| from .api_extension.SoundbarDevice import SoundbarDevice | ||||
| from .api_extension.const import SpeakerIdentifier, RearSpeakerMode | ||||
| from .const import ( | ||||
|     CONF_ENTRY_API_KEY, | ||||
|     CONF_ENTRY_DEVICE_ID, | ||||
|     CONF_ENTRY_DEVICE_NAME, | ||||
|     CONF_ENTRY_MAX_VOLUME, | ||||
|     DOMAIN, | ||||
| ) | ||||
| from .const import (CONF_ENTRY_API_KEY, CONF_ENTRY_DEVICE_ID, | ||||
|                     CONF_ENTRY_DEVICE_NAME, CONF_ENTRY_MAX_VOLUME, DOMAIN) | ||||
| from .models import DeviceConfig | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | @ -36,82 +27,14 @@ SUPPORT_SMARTTHINGS_SOUNDBAR = ( | |||
|     | MediaPlayerEntityFeature.TURN_OFF | ||||
|     | MediaPlayerEntityFeature.TURN_ON | ||||
|     | MediaPlayerEntityFeature.PLAY | ||||
|     | MediaPlayerEntityFeature.NEXT_TRACK | ||||
|     | MediaPlayerEntityFeature.PREVIOUS_TRACK | ||||
|     | MediaPlayerEntityFeature.STOP | ||||
|     | MediaPlayerEntityFeature.SELECT_SOUND_MODE | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| def addServices(): | ||||
|     platform = entity_platform.async_get_current_platform() | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "select_soundmode", | ||||
|         cv.make_entity_service_schema({vol.Required("sound_mode"): str}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_select_sound_mode.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_woofer_level", | ||||
|         cv.make_entity_service_schema( | ||||
|             {vol.Required("level"): vol.All(int, vol.Range(min=-12, max=6))} | ||||
|         ), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_woofer_level.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_night_mode", | ||||
|         cv.make_entity_service_schema({vol.Required("enabled"): bool}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_night_mode.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_bass_enhancer", | ||||
|         cv.make_entity_service_schema({vol.Required("enabled"): bool}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_bass_mode.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_voice_enhancer", | ||||
|         cv.make_entity_service_schema({vol.Required("enabled"): bool}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_voice_mode.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_speaker_level", | ||||
|         cv.make_entity_service_schema( | ||||
|             {vol.Required("speaker_identifier"): str, vol.Required("level"): int} | ||||
|         ), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_speaker_level.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_rear_speaker_mode", | ||||
|         cv.make_entity_service_schema({vol.Required("speaker_mode"): str}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_rear_speaker_mode.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_active_voice_amplifier", | ||||
|         cv.make_entity_service_schema({vol.Required("enabled"): bool}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_active_voice_amplifier.__name__, | ||||
|     ) | ||||
| 
 | ||||
|     platform.async_register_entity_service( | ||||
|         "set_space_fit_sound", | ||||
|         cv.make_entity_service_schema({vol.Required("enabled"): bool}), | ||||
|         SmartThingsSoundbarMediaPlayer.async_set_space_fit_sound.__name__, | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| async def async_setup_entry(hass, config_entry, async_add_entities): | ||||
|     domain_data = hass.data[DOMAIN] | ||||
| 
 | ||||
|     addServices() | ||||
| 
 | ||||
|     entities = [] | ||||
|     for key in domain_data.devices: | ||||
|         device_config: DeviceConfig = domain_data.devices[key] | ||||
|  | @ -248,45 +171,9 @@ class SmartThingsSoundbarMediaPlayer(MediaPlayerEntity): | |||
|     async def async_media_pause(self): | ||||
|         await self.device.media_pause() | ||||
| 
 | ||||
|     async def async_media_next_track(self): | ||||
|         await self.device.media_next_track() | ||||
| 
 | ||||
|     async def async_media_previous_track(self): | ||||
|         await self.device.media_previous_track() | ||||
| 
 | ||||
|     async def async_media_stop(self): | ||||
|         await self.device.media_stop() | ||||
| 
 | ||||
|     # ---------- SERVICE_UTILITY ------------ | ||||
| 
 | ||||
|     async def async_set_woofer_level(self, level: int): | ||||
|         await self.device.set_woofer(level) | ||||
| 
 | ||||
|     async def async_set_bass_mode(self, enabled: bool): | ||||
|         await self.device.set_bass_mode(enabled) | ||||
| 
 | ||||
|     async def async_set_voice_mode(self, enabled: bool): | ||||
|         await self.device.set_voice_amplifier(enabled) | ||||
| 
 | ||||
|     async def async_set_night_mode(self, enabled: bool): | ||||
|         await self.device.set_night_mode(enabled) | ||||
| 
 | ||||
|     # ---------- SERVICE_UTILITY ------------ | ||||
| 
 | ||||
|     async def async_set_speaker_level(self, speaker_identifier: str, level: int): | ||||
|         await self.device.set_speaker_level( | ||||
|             SpeakerIdentifier(speaker_identifier), level | ||||
|         ) | ||||
| 
 | ||||
|     async def async_set_rear_speaker_mode(self, speaker_mode: str): | ||||
|         await self.device.set_rear_speaker_mode(RearSpeakerMode(speaker_mode)) | ||||
| 
 | ||||
|     async def async_set_active_voice_amplifier(self, enabled: bool): | ||||
|         await self.device.set_active_voice_amplifier(enabled) | ||||
| 
 | ||||
|     async def async_set_space_fit_sound(self, enabled: bool): | ||||
|         await self.device.set_space_fit_sound(enabled) | ||||
| 
 | ||||
|     # This property can be uncommented for some extra_attributes | ||||
|     # Still enabling this can cause side-effects. | ||||
|     # @property | ||||
|  |  | |||
|  | @ -1,14 +1,12 @@ | |||
| import logging | ||||
| 
 | ||||
| from homeassistant.components.number import ( | ||||
|     NumberEntity, | ||||
| from homeassistant.components.number import (NumberEntity, | ||||
|                                              NumberEntityDescription, | ||||
|     NumberMode, | ||||
| ) | ||||
|                                              NumberMode) | ||||
| from homeassistant.helpers.entity import DeviceInfo | ||||
| 
 | ||||
| from .api_extension.SoundbarDevice import SoundbarDevice | ||||
| from .const import CONF_ENTRY_DEVICE_ID, CONF_ENTRY_SETTINGS_WOOFER_NUMBER, DOMAIN | ||||
| from .const import CONF_ENTRY_DEVICE_ID, DOMAIN | ||||
| from .models import DeviceConfig | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | @ -21,9 +19,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities): | |||
|     for key in domain_data.devices: | ||||
|         device_config: DeviceConfig = domain_data.devices[key] | ||||
|         device = device_config.device | ||||
|         if device.device_id == config_entry.data.get( | ||||
|             CONF_ENTRY_DEVICE_ID | ||||
|         ) and config_entry.data.get(CONF_ENTRY_SETTINGS_WOOFER_NUMBER): | ||||
|         if device.device_id == config_entry.data.get(CONF_ENTRY_DEVICE_ID): | ||||
|             entities.append( | ||||
|                 SoundbarWooferNumberEntity( | ||||
|                     device, | ||||
|  |  | |||
|  | @ -1,20 +1,14 @@ | |||
| import logging | ||||
| 
 | ||||
| from homeassistant.components.number import ( | ||||
|     NumberEntity, | ||||
| from homeassistant.components.number import (NumberEntity, | ||||
|                                              NumberEntityDescription, | ||||
|     NumberMode, | ||||
| ) | ||||
| from homeassistant.components.select import SelectEntity, SelectEntityDescription | ||||
|                                              NumberMode) | ||||
| from homeassistant.components.select import (SelectEntity, | ||||
|                                              SelectEntityDescription) | ||||
| from homeassistant.helpers.entity import DeviceInfo | ||||
| 
 | ||||
| from .api_extension.SoundbarDevice import SoundbarDevice | ||||
| from .const import ( | ||||
|     CONF_ENTRY_DEVICE_ID, | ||||
|     CONF_ENTRY_SETTINGS_EQ_SELECTOR, | ||||
|     CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR, | ||||
|     DOMAIN, | ||||
| ) | ||||
| from .const import CONF_ENTRY_DEVICE_ID, DOMAIN | ||||
| from .models import DeviceConfig | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | @ -27,17 +21,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities): | |||
|         device_config: DeviceConfig = domain_data.devices[key] | ||||
|         device = device_config.device | ||||
|         if device.device_id == config_entry.data.get(CONF_ENTRY_DEVICE_ID): | ||||
|             if config_entry.data.get(CONF_ENTRY_SETTINGS_EQ_SELECTOR): | ||||
|             entities.append( | ||||
|                 EqPresetSelectEntity(device, "eq_preset", "mdi:tune-vertical") | ||||
|             ) | ||||
|             if config_entry.data.get(CONF_ENTRY_SETTINGS_SOUNDMODE_SELECTOR): | ||||
|             entities.append( | ||||
|                     SoundModeSelectEntity( | ||||
|                         device, "sound_mode_preset", "mdi:surround-sound" | ||||
|                 SoundModeSelectEntity(device, "sound_mode_preset", "mdi:surround-sound") | ||||
|             ) | ||||
|                 ) | ||||
| 
 | ||||
|             entities.append( | ||||
|                 InputSelectEntity(device, "input_preset", "mdi:video-input-hdmi") | ||||
|             ) | ||||
|  |  | |||
|  | @ -1,10 +1,7 @@ | |||
| import logging | ||||
| 
 | ||||
| from homeassistant.components.sensor import ( | ||||
|     SensorDeviceClass, | ||||
|     SensorEntity, | ||||
|     SensorStateClass, | ||||
| ) | ||||
| from homeassistant.components.sensor import (SensorDeviceClass, SensorEntity, | ||||
|                                              SensorStateClass) | ||||
| from homeassistant.helpers.entity import DeviceInfo | ||||
| 
 | ||||
| from .api_extension.SoundbarDevice import SoundbarDevice | ||||
|  |  | |||
|  | @ -1,167 +0,0 @@ | |||
| 
 | ||||
| select_soundmode: | ||||
|   name: Select Soundmode | ||||
|   description: Some Soundbars support different "sound modes". If supported you can select them here. | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     sound_mode: | ||||
|       name: Sound Mode | ||||
|       description: Select the Soundmode you are interested in. | ||||
|       required: true | ||||
|       example: "adaptive sound" | ||||
|       # The default field value | ||||
|       default: "standard" | ||||
|       # Selector (https://www.home-assistant.io/docs/blueprint/selectors/) to control | ||||
|       # the input UI for this field | ||||
|       selector: | ||||
|         select: | ||||
|           translation_key: "soundmode" | ||||
|           options: | ||||
|             - "standard" | ||||
|             - "surround" | ||||
|             - "game" | ||||
|             - "adaptive sound" | ||||
| 
 | ||||
| set_woofer_level: | ||||
|   name: Set Woofer level | ||||
|   description: Set the subwoofer level of your soundbar | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     level: | ||||
|       name: Volume level | ||||
|       required: true | ||||
|       example: 3 | ||||
|       default: 0 | ||||
|       selector: | ||||
|         number: | ||||
|           min: -12 | ||||
|           max: 6 | ||||
|           step: 1 | ||||
| 
 | ||||
| set_night_mode: | ||||
|   name: Set NightMode | ||||
|   description: Activates / deactivates the Nightmode | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     enabled: | ||||
|       name: Enabled / Disabled | ||||
|       required: true | ||||
|       example: true | ||||
|       default: false | ||||
|       selector: | ||||
|         boolean: | ||||
| 
 | ||||
| set_bass_enhancer: | ||||
|   name: Set bass enhancement | ||||
|   description: Activates / deactivates the bass enhancement | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     enabled: | ||||
|       name: Enabled / Disabled | ||||
|       required: true | ||||
|       example: true | ||||
|       default: false | ||||
|       selector: | ||||
|         boolean: | ||||
| 
 | ||||
| set_voice_enhancer: | ||||
|   name: Set voice enhancement | ||||
|   description: Activates / deactivates the voice enhancement | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     enabled: | ||||
|       name: Enabled / Disabled | ||||
|       required: true | ||||
|       example: true | ||||
|       default: false | ||||
|       selector: | ||||
|         boolean: | ||||
| 
 | ||||
| set_speaker_level: | ||||
|   name: Set Speaker level | ||||
|   description: Set the speaker levels of your soundbar | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     speaker_identifier: | ||||
|       name: Speaker Identifier | ||||
|       required: true | ||||
|       example: Spk_Center | ||||
|       selector: | ||||
|         select: | ||||
|           translation_key: "speaker_identifier" | ||||
|           options: | ||||
|             - "Spk_Center" | ||||
|             - "Spk_Side" | ||||
|             - "Spk_Wide" | ||||
|             - "Spk_Front_Top" | ||||
|             - "Spk_Rear" | ||||
|             - "Spk_Rear_Top" | ||||
|     level: | ||||
|       name: Speaker Level | ||||
|       required: true | ||||
|       example: 0 | ||||
|       selector: | ||||
|         number: | ||||
|           min: -6 | ||||
|           max: 6 | ||||
|           step: 1 | ||||
| 
 | ||||
| set_rear_speaker_mode: | ||||
|   name: Set rear speaker mode | ||||
|   description: Set the rear speaker mode of your soundbar | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     speaker_mode: | ||||
|       name: Speaker mode | ||||
|       required: true | ||||
|       example: Rear | ||||
|       selector: | ||||
|         select: | ||||
|           translation_key: "rear_speaker_mode" | ||||
|           options: | ||||
|             - "Rear" | ||||
|             - "Front" | ||||
| 
 | ||||
| set_active_voice_amplifier: | ||||
|   name: Set active voice amplifier | ||||
|   description: Activates / deactivates the active voice amplifier | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     enabled: | ||||
|       name: Enabled / Disabled | ||||
|       required: true | ||||
|       example: true | ||||
|       default: false | ||||
|       selector: | ||||
|         boolean: | ||||
| 
 | ||||
| set_space_fit_sound: | ||||
|   name: Set SpaceFitSound | ||||
|   description: Activates / deactivates the SpaceFitSound | ||||
|   target: | ||||
|     device: | ||||
|       integration: samsung_soundbar | ||||
|   fields: | ||||
|     enabled: | ||||
|       name: Enabled / Disabled | ||||
|       required: true | ||||
|       example: true | ||||
|       default: false | ||||
|       selector: | ||||
|         boolean: | ||||
|  | @ -4,11 +4,7 @@ from homeassistant.components.switch import SwitchEntity | |||
| from homeassistant.helpers.entity import DeviceInfo | ||||
| 
 | ||||
| from .api_extension.SoundbarDevice import SoundbarDevice | ||||
| from .const import ( | ||||
|     CONF_ENTRY_DEVICE_ID, | ||||
|     CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES, | ||||
|     DOMAIN, | ||||
| ) | ||||
| from .const import CONF_ENTRY_DEVICE_ID, DOMAIN | ||||
| from .models import DeviceConfig | ||||
| 
 | ||||
| _LOGGER = logging.getLogger(__name__) | ||||
|  | @ -22,7 +18,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities): | |||
|         device_config: DeviceConfig = domain_data.devices[key] | ||||
|         device = device_config.device | ||||
|         if device.device_id == config_entry.data.get(CONF_ENTRY_DEVICE_ID): | ||||
|             if config_entry.data.get(CONF_ENTRY_SETTINGS_ADVANCED_AUDIO_SWITCHES): | ||||
|             entities.append( | ||||
|                 SoundbarSwitchAdvancedAudio( | ||||
|                     device, | ||||
|  |  | |||
|  | @ -10,143 +10,6 @@ | |||
|                   }, | ||||
|                   "description": "Bitte gib deine Daten ein.", | ||||
|                   "title": "Authentifizierung" | ||||
|             }, | ||||
|             "device":{ | ||||
|                 "data" : { | ||||
|                     "settings_advanced_audio": "'Advanced Audio switches' aktivieren (NightMode, BassMode, VoiceEnhancer)", | ||||
|                     "settings_eq": "'EQ selector' aktivieren", | ||||
|                     "settings_soundmode": "'Soundmode selector' aktivieren", | ||||
|                     "settings_woofer": "'Subwoofer Entität' aktivieren" | ||||
|                 }, | ||||
|                 "description": "Einige Soundbars haben verschiedene Featuresets. Wähle bitte aus welche Features von deiner Soundbar supported werden (einsehbar in der SmartThings App).", | ||||
|                 "title": "Geräte Einstellungen" | ||||
|             }, | ||||
|             "reconfigure_confirm":{ | ||||
|                 "data" : { | ||||
|                     "settings_advanced_audio": "'Advanced Audio switches' aktivieren (NightMode, BassMode, VoiceEnhancer)", | ||||
|                     "settings_eq": "'EQ selector' aktivieren", | ||||
|                     "settings_soundmode": "'Soundmode selector' aktivieren", | ||||
|                     "settings_woofer": "'Subwoofer Entität' aktivieren", | ||||
|                     "device_volume": "Max Volume (int)" | ||||
|                 }, | ||||
|                 "description": "Einige Soundbars haben verschiedene Featuresets. Wähle bitte aus welche Features von deiner Soundbar supported werden (einsehbar in der SmartThings App).", | ||||
|                 "title": "Geräte Einstellungen" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "selector": { | ||||
|         "soundmode": { | ||||
|             "options": { | ||||
|                 "standard": "Standard", | ||||
|                 "surround": "Surround", | ||||
|                 "game": "Gaming", | ||||
|                 "adaptive sound": "Adaptive Sound" | ||||
|             } | ||||
|         }, | ||||
|         "speaker_identifier": { | ||||
|             "options": { | ||||
|                 "Spk_Center": "Center", | ||||
|                 "Spk_Side": "Side", | ||||
|                 "Spk_Wide": "Wide", | ||||
|                 "Spk_Front_Top": "Front Top", | ||||
|                 "Spk_Rear": "Rear", | ||||
|                 "Spk_Rear_Top": "Rear Top" | ||||
|             } | ||||
|         }, | ||||
|         "rear_speaker_mode": { | ||||
|             "options": { | ||||
|                 "Rear": "Rear", | ||||
|                 "Front": "Front" | ||||
|             } | ||||
|         } | ||||
|   }, | ||||
|   "services":{ | ||||
|     "select_soundmode":{ | ||||
|         "name": "SoundMode auswählen", | ||||
|         "description": "Wähle hier zwischen, 'Standard', 'Surround', 'Game' und 'Adaptive Sound'." | ||||
|     }, | ||||
|     "set_woofer_level":{ | ||||
|         "name": "Subwoofer Level setzen", | ||||
|         "description": "Verändere die Lautstärke deines Subwoofers.", | ||||
|         "fields":{ | ||||
|             "level":{ | ||||
|                 "name": "Volume Level", | ||||
|                 "description": "Subwoofer Level, von -12 bis +6" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "set_night_mode":{ | ||||
|         "name": "Nachtmodus setzen", | ||||
|         "description": "Schalte den 'Nachtmodus' an / aus.", | ||||
|         "fields":{ | ||||
|             "enabled":{ | ||||
|                 "name": "An / ausschalten", | ||||
|                 "description": "Siehe Name." | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "set_bass_enhancer":{ | ||||
|         "name": "Bassmodus setzen", | ||||
|         "description": "Schalte den 'Bassmodus' an / aus.", | ||||
|         "fields":{ | ||||
|             "enabled":{ | ||||
|                 "name": "An / ausschalten", | ||||
|                 "description": "Siehe Name." | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "set_voice_enhancer":{ | ||||
|         "name": "Stimmenverbesserer setzen", | ||||
|         "description": "Schalte den 'Stimmenverbesserer' an / aus.", | ||||
|         "fields":{ | ||||
|             "enabled":{ | ||||
|                 "name": "An / ausschalten", | ||||
|                 "description": "Siehe Name." | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "set_speaker_level":{ | ||||
|         "name": "Lautsprecher level verändern", | ||||
|         "description": "Verändere die Lautstärke der einzelnen Lautsprecher", | ||||
|         "fields":{ | ||||
|                 "speaker_identifier": { | ||||
|                     "name": "Lautsprecher", | ||||
|                     "description": "Auszuwählender Lautsprecher" | ||||
|                 }, | ||||
|                 "level": { | ||||
|                     "name": "Lautstärke Level", | ||||
|                     "description": "Lautstärke Level zwischen -6 und 6." | ||||
|                 } | ||||
|             } | ||||
|     }, | ||||
|     "set_rear_speaker_mode":{ | ||||
|         "name": "Modus der hinteren Lautsprecher setzen", | ||||
|         "description": "Nutze deine Rücklautsprecher, als 'Vorder-' oder 'Rücklautsprecher'.", | ||||
|         "fields":{ | ||||
|                 "speaker_mode": { | ||||
|                     "name": "Lautsprecher Modus", | ||||
|                     "description": "Nutze den Lautsprecher als Front oder Rear Speaker." | ||||
|                 } | ||||
|             } | ||||
|     }, | ||||
|     "set_active_voice_amplifier":{ | ||||
|         "name": "Stimmenverstärker setzen", | ||||
|         "description": "Schalte den 'Stimmenverstärker' an / aus.", | ||||
|         "fields":{ | ||||
|             "enabled":{ | ||||
|                 "name": "An / ausschalten", | ||||
|                 "description": "Siehe Name." | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "set_space_fit_sound":{ | ||||
|         "name": "SpaceFitSound setzen", | ||||
|         "description": "Schalte den 'SpaceFitSound' an / aus.", | ||||
|         "fields":{ | ||||
|             "enabled":{ | ||||
|                 "name": "An / ausschalten", | ||||
|                 "description": "Siehe Name." | ||||
|             } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -1,152 +1,15 @@ | |||
| { | ||||
|     "config": { | ||||
|         "step": { | ||||
|             "user": { | ||||
|     "config":{ | ||||
|         "step":{ | ||||
|             "user":{ | ||||
|                 "data": { | ||||
|                     "api_key": "SmartThings API Token", | ||||
|                     "device_id": "Device ID", | ||||
|                     "device_name": "Device Name", | ||||
|                     "device_name":"Device Name", | ||||
|                     "device_volume": "Max Volume (int)" | ||||
|                   }, | ||||
|                   "description": "Please enter your credentials.", | ||||
|                   "title": "Authentication" | ||||
|             }, | ||||
|             "device": { | ||||
|                 "data": { | ||||
|                     "settings_advanced_audio": "Enable 'Advanced Audio switches' capabilities (NightMode, BassMode, VoiceEnhancer)", | ||||
|                     "settings_eq": "Enable 'EQ selector' capabilities", | ||||
|                     "settings_soundmode": "Enable 'Soundmode selector' capabilities", | ||||
|                     "settings_woofer": "Enable 'Woofer number' capability" | ||||
|                 }, | ||||
|                 "description": "Some soundbars have a different featureset than others. Please the features supported by your soundbar (visible in the SmartThings App).", | ||||
|                 "title": "Device Settings" | ||||
|             }, | ||||
|             "reconfigure_confirm": { | ||||
|                 "data": { | ||||
|                     "settings_advanced_audio": "Enable 'Advanced Audio switches' capabilities (NightMode, BassMode, VoiceEnhancer)", | ||||
|                     "settings_eq": "Enable 'EQ selector' capabilities", | ||||
|                     "settings_soundmode": "Enable 'Soundmode selector' capabilities", | ||||
|                     "settings_woofer": "Enable 'Woofer number' capability", | ||||
|                     "device_volume": "Max Volume (int)" | ||||
|                 }, | ||||
|                 "description": "Some soundbars have a different featureset than others. Please the features supported by your soundbar (visible in the SmartThings App).", | ||||
|                 "title": "Device Settings" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "selector": { | ||||
|         "soundmode": { | ||||
|             "options": { | ||||
|                 "standard": "Standard", | ||||
|                 "surround": "Surround", | ||||
|                 "game": "Gaming", | ||||
|                 "adaptive sound": "Adaptive Sound" | ||||
|             } | ||||
|         }, | ||||
|         "speaker_identifier": { | ||||
|             "options": { | ||||
|                 "Spk_Center": "Center", | ||||
|                 "Spk_Side": "Side", | ||||
|                 "Spk_Wide": "Wide", | ||||
|                 "Spk_Front_Top": "Front Top", | ||||
|                 "Spk_Rear": "Rear", | ||||
|                 "Spk_Rear_Top": "Rear Top" | ||||
|             } | ||||
|         }, | ||||
|         "rear_speaker_mode": { | ||||
|             "options": { | ||||
|                 "Rear": "Rear", | ||||
|                 "Front": "Front" | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     "services": { | ||||
|         "select_soundmode": { | ||||
|             "name": "Select Sound Mode", | ||||
|             "description": "Choose between 'Standard', 'Surround', 'Game', and 'Adaptive Sound'." | ||||
|         }, | ||||
|         "set_woofer_level": { | ||||
|             "name": "Set Subwoofer Level", | ||||
|             "description": "Change the volume of your subwoofer.", | ||||
|             "fields": { | ||||
|                 "level": { | ||||
|                     "name": "Volume Level", | ||||
|                     "description": "Subwoofer level, from -12 to +6" | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_night_mode": { | ||||
|             "name": "Set Night Mode", | ||||
|             "description": "Turn 'Night Mode' on/off.", | ||||
|             "fields": { | ||||
|                 "enabled": { | ||||
|                     "name": "On/Off", | ||||
|                     "description": "See name." | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_bass_enhancer": { | ||||
|             "name": "Set Bass Mode", | ||||
|             "description": "Turn 'Bass Mode' on/off.", | ||||
|             "fields": { | ||||
|                 "enabled": { | ||||
|                     "name": "On/Off", | ||||
|                     "description": "See name." | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_voice_enhancer": { | ||||
|             "name": "Set Voice Enhancer", | ||||
|             "description": "Turn 'Voice Enhancer' on/off.", | ||||
|             "fields": { | ||||
|                 "enabled": { | ||||
|                     "name": "On/Off", | ||||
|                     "description": "See name." | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_speaker_level": { | ||||
|             "name": "Change Speaker Level", | ||||
|             "description": "Change the volume of individual speakers.", | ||||
|             "fields":{ | ||||
|                 "speaker_identifier": { | ||||
|                     "name": "Speaker Identifier", | ||||
|                     "description": "Identifier of the speaker." | ||||
|                 }, | ||||
|                 "level": { | ||||
|                     "name": "Level", | ||||
|                     "description": "Level of the Speaker from -6 to 6." | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_rear_speaker_mode": { | ||||
|             "name": "Set Rear Speaker Mode", | ||||
|             "description": "Use your rear speakers as 'Front' or 'Rear' speakers.", | ||||
|             "fields":{ | ||||
|                 "speaker_mode": { | ||||
|                     "name": "Speaker mode", | ||||
|                     "description": "Weather the speaker are used as rear / front speakers." | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_active_voice_amplifier": { | ||||
|             "name": "Set Voice Amplifier", | ||||
|             "description": "Turn 'Voice Amplifier' on/off.", | ||||
|             "fields": { | ||||
|                 "enabled": { | ||||
|                     "name": "On/Off", | ||||
|                     "description": "See name." | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "set_space_fit_sound": { | ||||
|             "name": "Set SpaceFitSound", | ||||
|             "description": "Turn 'SpaceFitSound' on/off.", | ||||
|             "fields": { | ||||
|                 "enabled": { | ||||
|                     "name": "On/Off", | ||||
|                     "description": "See name." | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| export default defineAppConfig({ | ||||
|   docus: { | ||||
|     title: '🔊 Yassi', | ||||
|     description: 'Yet another Samsung Soundbar integration for Home Assistant', | ||||
|     title: 'YASSI', | ||||
|     description: 'HomeAssistant: Yet another Samsung soundbar integration', | ||||
|     image: 'https://user-images.githubusercontent.com/904724/185365452-87b7ca7b-6030-4813-a2db-5e65c785bf88.png', | ||||
|     socials: { | ||||
|       github: 'samuelspagl/ha_samsung_soundbar', | ||||
|  | @ -28,7 +28,7 @@ export default defineAppConfig({ | |||
|       fluid: true | ||||
|     }, | ||||
|     header: { | ||||
|       logo: false, | ||||
|       logo: true, | ||||
|       showLinkIcon: true, | ||||
|       exclude: [], | ||||
|       fluid: true | ||||
|  |  | |||
|  | @ -5,19 +5,24 @@ title: "YASSI" | |||
| --- | ||||
| cta: | ||||
|   - Why another HomeAssistant integration? | ||||
|   - /first-things-first/why-another-integration | ||||
|   - #why-another-integration | ||||
| secondary: | ||||
|   - Open on GitHub → | ||||
|   - https://github.com/samuelspagl/ha_samsung_soundbar | ||||
|   - https://github.com/nuxtlabs/docus | ||||
| snippet: | ||||
|   - Custom Components | ||||
|   - "- input selection" | ||||
|   - "- soundmode selection" | ||||
|   - "- eq-preset selection" | ||||
|   - "- woofer settings" | ||||
|   - "- other cool things" | ||||
| --- | ||||
| 
 | ||||
| #title | ||||
| Yassi - Yet another Samsung Soundbar integration | ||||
| Yassi | ||||
| 
 | ||||
| #description | ||||
| **YASSI** is a **HomeAssistant** integration for **Samsung Soundbars**. It enhances control, and adds features like equalizer settings. Install it via HACS or manually. Kudos to the original idea by @PiotrMachowski and @thierryBourbon! 🎶🔊 | ||||
| 
 | ||||
| [](https://my.home-assistant.io/redirect/hacs_repository/?owner=samuelspagl&repository=ha_samsung_soundbar&category=integration) | ||||
| Yet another Samsung soundbar integration for HomeAssistant | ||||
| :: | ||||
| 
 | ||||
| ::card-grid | ||||
|  | @ -29,42 +34,36 @@ Quick-Start | |||
| #default | ||||
|   ::card | ||||
|   #title | ||||
|   ❓ Why another integration? | ||||
|   #description | ||||
|   Whether you thought about it or not, here is the answer ;). | ||||
|   <br> | ||||
|   <br> | ||||
|   :button-link[click here]{href="/first-things-first/why-another-integration"} | ||||
|   :: | ||||
| 
 | ||||
|   ::card | ||||
|   #title | ||||
|   🚀 Getting Started | ||||
|   Getting Started. | ||||
|   #description | ||||
|   Go, Go, Go... Here you will find information on "How to install / configure". | ||||
|   <br> | ||||
|   <br> | ||||
|   :button-link[click here]{href="/first-things-first/getting-started"} | ||||
|   :button-link[click here]{href="/getting-started"} | ||||
|   :: | ||||
| 
 | ||||
|   ::card | ||||
|   #title | ||||
|   ✨ Features | ||||
|   Features | ||||
|   #description | ||||
|   Many cool features are awaiting your eyes to see ✨. | ||||
|   <br> | ||||
|   <br> | ||||
|   :button-link[click here]{href="/features"} | ||||
|   :: | ||||
| 
 | ||||
|   ::card | ||||
|   #title | ||||
|   ⚙️ SmartThings API related information | ||||
|   #description | ||||
|   If you want to know some background information on how equalizer support and | ||||
|   other things were implemented, this is your section. | ||||
|   <br> | ||||
|   <br> | ||||
|   :button-link[click here]{href="/features"} | ||||
|   :: | ||||
| :: | ||||
| 
 | ||||
| 
 | ||||
| ## Why another integration | ||||
| 
 | ||||
| The current Samsung Soundbar Integration by @PiotrMachowski / @thierryBourbon are already pretty cool. | ||||
| But I wanted it to appear as a device, and base the Foundation on the `pysmartthings` python package. | ||||
| 
 | ||||
| Additionally, I wanted full control over the *Soundmode* and more. So I tried out a few things with the API, | ||||
| and found that also the **Subwoofer** as well as the **Equalizer** are controllable. | ||||
| 
 | ||||
| I created a new wrapper around the `pysmartthings.DeviceEntity` specifically set up for a Soundbar, and this | ||||
| is the Result. | ||||
| 
 | ||||
| I hope to integrate also controls for **surround speaker** as well as **Space-Fit Sound**, but as these features | ||||
| are not documented... ;)  | ||||
|  | @ -1,13 +0,0 @@ | |||
| # ❓ Why another integration | ||||
| 
 | ||||
| The current Samsung Soundbar Integration by @PiotrMachowski / @thierryBourbon are already pretty cool. | ||||
| But I wanted it to appear as a device, and base the Foundation on the `pysmartthings` python package. | ||||
| 
 | ||||
| Additionally, I wanted full control over the *Soundmode* and more. So I tried out a few things with the API, | ||||
| and found that also the **Subwoofer** as well as the **Equalizer** are controllable. | ||||
| 
 | ||||
| I created a new wrapper around the `pysmartthings.DeviceEntity` specifically set up for a Soundbar, and this | ||||
| is the Result. | ||||
| 
 | ||||
| I hope to integrate also controls for **surround speaker** as well as **Space-Fit Sound**, but as these features | ||||
| are not documented... ;)  | ||||
|  | @ -1,43 +0,0 @@ | |||
| # 🚀 Getting Started with Yassi | ||||
| 
 | ||||
| Welcome to Yassi, the HomeAssistant integration for your Samsung Soundbar. This guide will help you get up and running in no time. | ||||
| 
 | ||||
| ## 📦 Installation Options | ||||
| 
 | ||||
| ### HACS (Home Assistant Community Store) | ||||
| 
 | ||||
| #### 🌟 Official Repository (Coming Soon) | ||||
| The Yassi integration will be available through the official HACS repository shortly. Stay tuned for updates. | ||||
| 
 | ||||
| #### ➕ Custom Repository | ||||
| In the meantime, you can manually add this repository to HACS: | ||||
| 1. Click the following button and 'open link': | ||||
| [](https://my.home-assistant.io/redirect/hacs_repository/?owner=samuelspagl&repository=ha_samsung_soundbar&category=integration) | ||||
| 2. Click 'add' to add the custom repository. | ||||
| 3. Download 'Yassi' and restart Home Assistant. | ||||
| 
 | ||||
| ### 📂 Manual Installation | ||||
| If you prefer to install Yassi manually: | ||||
| 1. Download the latest release from the repository. | ||||
| 2. Extract and copy the `custom_components/samsung_soundbar` folder. | ||||
| 3. Paste it into the `config/custom_components/samsung_soundbar` directory of your HomeAssistant setup. | ||||
| 
 | ||||
| ## ⚙️ Configuration Steps | ||||
| 
 | ||||
| Once Yassi is installed, you can configure it via the HomeAssistant UI: | ||||
| 
 | ||||
| 1. Go to 'Configuration' and then 'Integrations'. | ||||
| 2. Click on 'Add Integration' and search for 'Yassi'. | ||||
| 3. Enter the following details to complete the setup: | ||||
|    - 🔑 SmartThings API Key: [Obtain it here](https://account.smartthings.com/tokens). | ||||
|    - 🆔 Device ID: [Find your Soundbar's device ID here](https://my.smartthings.com/advanced/devices). | ||||
|    - ㍻ Soundbar Name: Choose a name for easy identification. | ||||
|    - 🔊 Max Volume: Set the maximum volume limit for your Soundbar. | ||||
| 
 | ||||
| Follow these steps, and you'll be enjoying seamless control over your Samsung Soundbar with Yassi in no time! | ||||
| 
 | ||||
| ::alert{type="info"} | ||||
| The `🔊 Max Volume` setting will readjust the internal values of the `media_player` entity from 0-100 to 0-MaxVolume. | ||||
| Therefore will the slider not display the same value as the one provided by the `sensor` entity, which will always display | ||||
| the raw value retrieved from the SmartThings API. | ||||
| :: | ||||
|  | @ -1,17 +0,0 @@ | |||
| # ‼️ Issues and other things | ||||
| 
 | ||||
| As the creator of this personal and fun project, I am thrilled to see people using it. While I won’t always have immediate availability to address every request, I’ll do my best to fix issues and implement features. Thanks a lot in advance! 🙌 | ||||
| 
 | ||||
| Here are some best practices to help me help you: | ||||
| 
 | ||||
| 1. 🐞 GitHub Issues: For any issues or bugs, please submit them via GitHub Issues. ([🔗 click here](https://github.com/samuelspagl/ha_samsung_soundbar/issues/new)) | ||||
| 2. 📋 Provide Details: Include essential information: | ||||
|     - Home Assistant OS Version | ||||
|     - Samsung Soundbar Model | ||||
|     - Other Relevant Details (like debug logs) | ||||
| 3. 🎇 Icons for Fun: | ||||
|     - 📦 = Feature Request | ||||
|     - 🐛 = Bug Report | ||||
|     - ❓ = General Questions | ||||
| 
 | ||||
| Let’s collaborate to enhance your soundbar experience! 🎶🔊 | ||||
|  | @ -0,0 +1,30 @@ | |||
| # Getting Started | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
| ### HACS (official) | ||||
| 
 | ||||
| > ⚠️ Not done yet, hopefully soon. | ||||
| 
 | ||||
| 
 | ||||
| ### HACS (custom repository) | ||||
| 
 | ||||
| You can add this repository as a custom repository to your hacs. | ||||
| After you've done that, you can search for it like with the "official" | ||||
| integrations. | ||||
| 
 | ||||
| ### Manual | ||||
| 
 | ||||
| Copy the contents of `custom_components/samsung_soundbar` to `config/custom_components/samsung_soundbar` | ||||
| on your HomeAssistant instance. | ||||
| 
 | ||||
| ## Configuration | ||||
| 
 | ||||
| After you installed the custom component, it should be possible to configure the integration | ||||
| in the `device` settings of your HomeAssistant. | ||||
| 
 | ||||
| You will need: | ||||
| - a SmartThings `api_key` [click here](https://account.smartthings.com/tokens) | ||||
| - the `device_id` of your device [click here](https://my.smartthings.com/advanced/devices) | ||||
| - a name for your Soundbar | ||||
| - and a `max_volume` | ||||
|  | @ -1,52 +1,35 @@ | |||
| # ✨ Features Overview | ||||
| # Features | ||||
| 
 | ||||
| Yassi allows you to retrieve and set the status of various features on your Samsung Soundbar. Below is a breakdown of capabilities organized by entity type. | ||||
| **YASSI** and retrieve / set the status of the following features grouped as a device: | ||||
| - `media_player`: | ||||
|   - `on / off` [*read, write*] | ||||
|   - `volume` (set, step) [*read, write*] | ||||
|   - `input` (select) [*read*, write*] | ||||
|   - `sound_mode` (select) [*read, write*] | ||||
|   - `play` (button) [*write*] | ||||
|   - `pause` (button) [*write*] | ||||
|   - `media_artwork` (image) [*read*] | ||||
|   - `media_title` (text) [*read*] | ||||
|   - `media_artist` (text) [*read*] | ||||
| 
 | ||||
| ## `media_player` Entity | ||||
| - `number` | ||||
|   - **Woofer** | ||||
|     - level (set) [*read, write*] | ||||
| - `select` | ||||
|   - **Input** | ||||
|     - `input` [*read, write*] | ||||
|     - `supported_inputs` [*read*] | ||||
|   - **Soundmode** | ||||
|     - `active_soundmode` [*read, write*] | ||||
|     - `supported_soundmodes` [*read*] | ||||
|   - **EQ-Preset** | ||||
|     - `active_eq_preset` [*read, write*] | ||||
|     - `supported_eq_preset` [*read*] | ||||
| 
 | ||||
| | **Feature**       | **Capability** | **Access Type** | | ||||
| |-------------------|----------------|-----------------| | ||||
| | Power             | on / off       | Read, Write     | | ||||
| | Volume            | set, step      | Read, Write     | | ||||
| | Input Selection   | select         | Read, Write     | | ||||
| | Sound Mode        | select         | Read, Write     | | ||||
| | Playback Control  | play, pause    | Write           | | ||||
| | Media Information | artwork, title, artist | Read    | | ||||
| - `button` | ||||
|   - `night_mode` [*read, write*] | ||||
|   - `voice_amplifier` [*read, write*] | ||||
|   - `bass_mode` [*read, write*] | ||||
| 
 | ||||
| ## `number` Entity | ||||
| 
 | ||||
| | **Feature** | **Capability** | **Access Type** | | ||||
| |-------------|----------------|-----------------| | ||||
| | Woofer Level | set           | Read, Write     | | ||||
| 
 | ||||
| ## `select` Entity | ||||
| 
 | ||||
| | **Feature**       | **Capability**        | **Access Type** | | ||||
| |-------------------|-----------------------|-----------------| | ||||
| | Input             | input, supported_inputs | Read, Write   | | ||||
| | Sound Mode        | active_soundmode, supported_soundmodes | Read, Write | | ||||
| | EQ-Preset         | active_eq_preset, supported_eq_preset | Read, Write | | ||||
| 
 | ||||
| ## `button` Entity | ||||
| 
 | ||||
| | **Feature**       | **Capability** | **Access Type** | | ||||
| |-------------------|----------------|-----------------| | ||||
| | Night Mode        | toggle         | Read, Write     | | ||||
| | Voice Amplifier   | toggle         | Read, Write     | | ||||
| | Bass Mode         | toggle         | Read, Write     | | ||||
| 
 | ||||
| ## `image` Entity | ||||
| 
 | ||||
| | **Feature**       | **Capability** | **Access Type** | | ||||
| |-------------------|----------------|-----------------| | ||||
| | Media Cover Art   | display        | Read            | | ||||
| 
 | ||||
| 
 | ||||
| ## `sensor` Entity | ||||
| 
 | ||||
| | **Feature** | **Capability**     | **Access Type** | | ||||
| |-------------|--------------------|-----------------| | ||||
| | Volume      | float sensor value | Read            | | ||||
| 
 | ||||
| 
 | ||||
| Hopefully this format provides a clear and concise view of what Yassi can do with your Samsung Soundbar, making it easier to understand and configure. | ||||
| - `image` | ||||
|   - `media_coverart` [*read*] | ||||
|  |  | |||
|  | @ -3,5 +3,5 @@ | |||
|   "filename": "samsung_soundbar.zip", | ||||
|   "render_readme": true, | ||||
|   "zip_release": true, | ||||
|   "homeassistant": "2024.3.0" | ||||
|   "homeassistant": "2024.1.0" | ||||
| } | ||||
|  | @ -1,20 +0,0 @@ | |||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| set -e | ||||
| 
 | ||||
| cd "$(dirname "$0")/.." | ||||
| 
 | ||||
| # Create config dir if not present | ||||
| if [[ ! -d "${PWD}/config" ]]; then | ||||
|     mkdir -p "${PWD}/config" | ||||
|     hass --config "${PWD}/config" --script ensure_config | ||||
| fi | ||||
| 
 | ||||
| # Set the path to custom_components | ||||
| ## This let's us have the structure we want <root>/custom_components/integration_blueprint | ||||
| ## while at the same time have Home Assistant configuration inside <root>/config | ||||
| ## without resulting to symlinks. | ||||
| export PYTHONPATH="${PYTHONPATH}:${PWD}/custom_components" | ||||
| 
 | ||||
| # Start Home Assistant | ||||
| hass --config "${PWD}/config" --debug | ||||
|  | @ -1,7 +0,0 @@ | |||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| set -e | ||||
| 
 | ||||
| cd "$(dirname "$0")/.." | ||||
| 
 | ||||
| pip install rich pysmartthings | ||||
		Loading…
	
		Reference in New Issue