Skip to content

Commit

Permalink
Maintenance
Browse files Browse the repository at this point in the history
- Add option to use an external binary_sensor for TV status detection
- Use multi-select entities list for syncronized power control options
  • Loading branch information
ollo69 committed Nov 1, 2021
1 parent 06b157f commit 0f3917e
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 53 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,12 @@ This is required for the component to know the name of the TV channel.<br/>
Check guide [here](https://github.com/jaruba/ha-samsungtv-tizen/blob/master/Logos.md)
for updating the logo database this component is relying on.

- **List of entity to Power OFF with TV (comma separated)**<br/>
A list of HA entity to Turn OFF when the TV entity is turned OFF (maximum 4).
- **List of entity to Power OFF with TV**<br/>
A list of HA entity to Turn OFF when the TV entity is turned OFF (maximum 4). Select entities from list.
This call the service `homeassistant.turn_off` for maximum the first 4 entity in the provided list.<br/>

- **List of entity to Power ON with TV (comma separated)**<br/>
A list of HA entity to Turn ON when the TV entity is turned ON (maximum 4).
- **List of entity to Power ON with TV**<br/>
A list of HA entity to Turn ON when the TV entity is turned ON (maximum 4). Select entities from list.
This call the service `homeassistant.turn_on` for maximum the first 4 entity in the provided list.<br/>

- **Show advanced options**<br/>
Expand Down Expand Up @@ -189,6 +189,12 @@ until the TV properly turn-on.<br/>
This option allow to configure a delay to wait before setting the TV status to ON. This is used to avoid false
ON status for TV that enable the network interface on regular interval also when the TV status is OFF.<br/>

- **Binary sensor to help detect power status**<br/>
An external `binary_sensor` selectable from a list than can be used to determinate TV power status.<br/>
This can be any available `binary_sensor` that can better determinate the status of the TV, for example a
`binary_sensor` based on TV power consumption. It is suggested to not use a sensor based on `ping` platform
because this method is already implemented by the integration.</br>

## Custom configuration parameters

You can configure additional option for the component using configuration variable in `configuration.yaml` section.<br/>
Expand Down
22 changes: 22 additions & 0 deletions custom_components/samsungtv_smart/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
CONF_LOAD_ALL_APPS,
CONF_SOURCE_LIST,
CONF_SHOW_CHANNEL_NR,
CONF_SYNC_TURN_OFF,
CONF_SYNC_TURN_ON,
CONF_WS_NAME,
CONF_UPDATE_METHOD,
CONF_UPDATE_CUSTOM_PING_URL,
Expand Down Expand Up @@ -193,6 +195,23 @@ def _migrate_token_file(hass: HomeAssistant, hostname: str):
return


def _migrate_options_format(hass: HomeAssistant, entry: ConfigEntry):
"""Migrate options to new format."""
opt_migrated = False
new_options = {}

for key, option in entry.options.items():
if key in [CONF_SYNC_TURN_OFF, CONF_SYNC_TURN_ON]:
if isinstance(option, str):
new_options[key] = option.split(",")
opt_migrated = True
continue
new_options[key] = option

if opt_migrated:
hass.config_entries.async_update_entry(entry, options=new_options)


async def get_device_info(hostname: str, session: ClientSession) -> dict:
"""Try retrieve device information"""
try:
Expand Down Expand Up @@ -357,6 +376,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
# migrate old token file if required
_migrate_token_file(hass, entry.unique_id)

# migrate options to new format if required
_migrate_options_format(hass, entry)

# setup entry
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN].setdefault(entry.unique_id, {}) # unique_id = host
Expand Down
72 changes: 61 additions & 11 deletions custom_components/samsungtv_smart/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.components.binary_sensor import DOMAIN as BS_DOMAIN
from homeassistant.core import callback, HomeAssistant

from homeassistant.const import (
ATTR_DEVICE_ID,
ATTR_FRIENDLY_NAME,
CONF_API_KEY,
CONF_DEVICE_ID,
CONF_HOST,
Expand All @@ -20,6 +22,7 @@
CONF_NAME,
CONF_PORT,
)
from homeassistant.helpers import config_validation as cv

# pylint:disable=unused-import
from . import SamsungTVInfo, get_device_info
Expand All @@ -35,6 +38,8 @@
CONF_DEVICE_MODEL,
CONF_DEVICE_OS,
CONF_DUMP_APPS,
CONF_EXT_POWER_ENTITY,
CONF_LOGO_OPTION,
CONF_POWER_ON_DELAY,
CONF_POWER_ON_METHOD,
CONF_USE_ST_CHANNEL_INFO,
Expand All @@ -45,13 +50,13 @@
CONF_SYNC_TURN_ON,
CONF_WOL_REPEAT,
CONF_WS_NAME,
CONF_LOGO_OPTION,
DEFAULT_POWER_ON_DELAY,
MAX_WOL_REPEAT,
RESULT_ST_DEVICE_NOT_FOUND,
RESULT_ST_DEVICE_USED,
RESULT_SUCCESS,
RESULT_WRONG_APIKEY,
SERVICE_TURN_ON,
AppLaunchMethod,
AppLoadMethod,
PowerOnMethod,
Expand Down Expand Up @@ -97,6 +102,7 @@
CONF_APP_LOAD_METHOD,
CONF_APP_LAUNCH_METHOD,
CONF_DUMP_APPS,
CONF_EXT_POWER_ENTITY,
CONF_WOL_REPEAT,
CONF_POWER_ON_DELAY,
CONF_USE_MUTE_CHECK,
Expand Down Expand Up @@ -386,6 +392,11 @@ async def async_step_init(self, user_input: dict = None):
return await self.async_step_adv_opt()
return self._save_entry(data=user_input)

switch_entities = _async_get_matching_entities(
self.hass,
_async_get_domains_service(self.hass, SERVICE_TURN_ON),
_async_get_entry_entities(self.hass, self.config_entry.entry_id),
)
options = self.config_entry.options
data_schema = vol.Schema({})

Expand Down Expand Up @@ -432,19 +443,15 @@ async def async_step_init(self, user_input: dict = None):
vol.Optional(
CONF_SYNC_TURN_OFF,
description={
"suggested_value": options.get(
CONF_SYNC_TURN_OFF, ""
)
"suggested_value": options.get(CONF_SYNC_TURN_OFF)
},
): str,
): cv.multi_select(switch_entities),
vol.Optional(
CONF_SYNC_TURN_ON,
description={
"suggested_value": options.get(
CONF_SYNC_TURN_ON, ""
)
"suggested_value": options.get(CONF_SYNC_TURN_ON)
},
): str,
): cv.multi_select(switch_entities),
vol.Optional(CONF_SHOW_ADV_OPT, default=False): bool,
}
)
Expand All @@ -460,15 +467,19 @@ async def async_step_adv_opt(self, user_input=None):
user_input[CONF_APP_LAUNCH_METHOD] = _get_key_from_value(
APP_LAUNCH_METHODS, user_input.pop(OPT_APP_LAUNCH_METHOD, None)
)
self._adv_options.update(user_input)
self._adv_options = user_input
return await self.async_step_init()

return self._async_adv_opt_form()

@callback
def _async_adv_opt_form(self):
"""Return configuration form for advanced options."""
external_entities = _async_get_matching_entities(
self.hass, [BS_DOMAIN]
)
options = self._adv_options

data_schema = vol.Schema(
{
vol.Optional(
Expand Down Expand Up @@ -508,6 +519,12 @@ def _async_adv_opt_form(self):
CONF_POWER_ON_DELAY, DEFAULT_POWER_ON_DELAY
),
): vol.All(vol.Coerce(int), vol.Clamp(min=0, max=60)),
vol.Optional(
CONF_EXT_POWER_ENTITY,
description={
"suggested_value": options.get(CONF_EXT_POWER_ENTITY)
}
): vol.In(external_entities),
}
)

Expand All @@ -521,3 +538,36 @@ def _get_key_from_value(source: dict, value: str):
if src_value == value:
return src_key
return None


def _async_get_matching_entities(hass: HomeAssistant, domains=None, excl_entities=None):
"""Fetch all entities or entities in the given domains."""
return {
state.entity_id: f"{state.attributes.get(ATTR_FRIENDLY_NAME, state.entity_id)} ({state.entity_id})"
for state in sorted(
hass.states.async_all(domains and set(domains)),
key=lambda item: item.entity_id,
)
if state.entity_id not in (excl_entities or [])
}


def _async_get_domains_service(hass: HomeAssistant, service_name: str):
"""Fetch list of domain that provide a specific service."""
return [
domain
for domain, service in hass.services.async_services().items()
if service_name in service
]


def _async_get_entry_entities(hass: HomeAssistant, entry_id: str):
"""Get the entities related to current entry"""
return [
entry.entity_id
for entry in (
hass.helpers.entity_registry.async_entries_for_config_entry(
hass.helpers.entity_registry.async_get(hass), entry_id
)
)
]
6 changes: 5 additions & 1 deletion custom_components/samsungtv_smart/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ class PowerOnMethod(Enum):
CONF_DEVICE_NAME = "device_name"
CONF_DEVICE_OS = "device_os"
CONF_DUMP_APPS = "dump_apps"
CONF_EXT_POWER_ENTITY = "ext_power_entity"
CONF_LOAD_ALL_APPS = "load_all_apps"
CONF_LOGO_OPTION = "logo_option"
CONF_POWER_ON_DELAY = "power_on_delay"
CONF_POWER_ON_METHOD = "power_on_method"
CONF_SHOW_CHANNEL_NR = "show_channel_number"
Expand All @@ -49,7 +51,6 @@ class PowerOnMethod(Enum):
CONF_USE_ST_STATUS_INFO = "use_st_status_info"
CONF_WOL_REPEAT = "wol_repeat"
CONF_WS_NAME = "ws_name"
CONF_LOGO_OPTION = "logo_option"

# obsolete
CONF_UPDATE_METHOD = "update_method"
Expand All @@ -75,6 +76,9 @@ class PowerOnMethod(Enum):
SERVICE_SELECT_PICTURE_MODE = "select_picture_mode"
SERVICE_SET_ART_MODE = "set_art_mode"

SERVICE_TURN_OFF = "turn_off"
SERVICE_TURN_ON = "turn_on"

STD_APP_LIST = {
# app_id: smartthings app id (if different and available)
"org.tizen.browser": "", # Internet
Expand Down
2 changes: 1 addition & 1 deletion custom_components/samsungtv_smart/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"dependencies": [],
"codeowners": ["@jaruba", "@ollo69", "@screwdgeh"],
"config_flow": true,
"version": "0.4.4"
"version": "0.4.5"
}
Loading

0 comments on commit 0f3917e

Please sign in to comment.