Compare commits

..

1 Commits

Author SHA1 Message Date
samuelspagl 2c278da442 Add `ConfigEntryNotReady` exception when the update during setup fails 2024-03-12 15:04:30 +01:00
31 changed files with 688 additions and 1786 deletions

View File

@ -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"
}

5
.gitignore vendored
View File

@ -4,11 +4,6 @@ __pycache__/
*$py.class
.DS_store
config
.vscode
.ruff_cache
# C extensions
*.so
.idea

View File

@ -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
View File

@ -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.

View File

@ -9,7 +9,8 @@ rich = "*"
homeassistant = "*"
[dev-packages]
ruff = "*"
black = "*"
isort = "*"
[requires]
python_version = "3.12"
python_version = "3.11"

972
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -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.
[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](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.

View File

@ -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),
)
await soundbar_device.update()
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
)

View File

@ -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,41 +49,35 @@ 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()
await self._update_soundmode()
await self._update_advanced_audio()
await self._update_woofer()
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"
]
self.__media_title = self.device.status._attributes["audioTrackData"].value[
"title"
]
if self.__media_title != self.__old_media_title:
self.__old_media_title = self.__media_title
self.__media_cover_url_update_time = datetime.datetime.now()
self.__media_cover_url = await self.get_song_title_artwork(
self.__media_artist, self.__media_title
)
self.__media_artist = self.device.status._attributes["audioTrackData"].value[
"artist"
]
self.__media_title = self.device.status._attributes["audioTrackData"].value[
"title"
]
if self.__media_title != self.__old_media_title:
self.__old_media_title = self.__media_title
self.__media_cover_url_update_time = datetime.datetime.now()
self.__media_cover_url = await self.get_song_title_artwork(
self.__media_artist, self.__media_title
)
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
"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:
"""

View File

@ -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"

View File

@ -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,
)

View File

@ -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

View File

@ -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"
}

View File

@ -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

View File

@ -1,14 +1,12 @@
import logging
from homeassistant.components.number import (
NumberEntity,
NumberEntityDescription,
NumberMode,
)
from homeassistant.components.number import (NumberEntity,
NumberEntityDescription,
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,

View File

@ -1,20 +1,14 @@
import logging
from homeassistant.components.number import (
NumberEntity,
NumberEntityDescription,
NumberMode,
)
from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.components.number import (NumberEntity,
NumberEntityDescription,
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"
)
)
entities.append(
EqPresetSelectEntity(device, "eq_preset", "mdi:tune-vertical")
)
entities.append(
SoundModeSelectEntity(device, "sound_mode_preset", "mdi:surround-sound")
)
entities.append(
InputSelectEntity(device, "input_preset", "mdi:video-input-hdmi")
)

View File

@ -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

View File

@ -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:

View File

@ -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,37 +18,36 @@ 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,
"nightmode",
lambda: device.night_mode,
device.set_night_mode,
device.set_night_mode,
"mdi:weather-night",
)
entities.append(
SoundbarSwitchAdvancedAudio(
device,
"nightmode",
lambda: device.night_mode,
device.set_night_mode,
device.set_night_mode,
"mdi:weather-night",
)
entities.append(
SoundbarSwitchAdvancedAudio(
device,
"bassmode",
lambda: device.bass_mode,
device.set_bass_mode,
device.set_bass_mode,
"mdi:speaker-wireless",
)
)
entities.append(
SoundbarSwitchAdvancedAudio(
device,
"bassmode",
lambda: device.bass_mode,
device.set_bass_mode,
device.set_bass_mode,
"mdi:speaker-wireless",
)
entities.append(
SoundbarSwitchAdvancedAudio(
device,
"voice_amplifier",
lambda: device.voice_amplifier,
device.set_voice_amplifier,
device.set_voice_amplifier,
"mdi:account-voice",
)
)
entities.append(
SoundbarSwitchAdvancedAudio(
device,
"voice_amplifier",
lambda: device.voice_amplifier,
device.set_voice_amplifier,
device.set_voice_amplifier,
"mdi:account-voice",
)
)
async_add_entities(entities)
return True

View File

@ -10,144 +10,7 @@
},
"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."
}
}
}
}
}

View File

@ -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."
}
},
"description": "Please enter your credentials.",
"title": "Authentication"
}
}
}

View File

@ -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

View File

@ -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! 🎶🔊
[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](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... ;)

View File

@ -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... ;)

View File

@ -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':
[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](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.
::

View File

@ -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 wont always have immediate availability to address every request, Ill 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
Lets collaborate to enhance your soundbar experience! 🎶🔊

View File

@ -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`

View File

@ -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*]

View File

@ -3,5 +3,5 @@
"filename": "samsung_soundbar.zip",
"render_readme": true,
"zip_release": true,
"homeassistant": "2024.3.0"
"homeassistant": "2024.1.0"
}

View File

@ -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

View File

@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")/.."
pip install rich pysmartthings