Skip to content

Commit

Permalink
Fixes running application identification (issue #145 and #224)
Browse files Browse the repository at this point in the history
  • Loading branch information
ollo69 committed Jan 31, 2023
1 parent eb12200 commit c97395b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 50 deletions.
21 changes: 0 additions & 21 deletions .devcontainer/configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,3 @@ logger:
default: info
#logs:
# custom_components.samsungtv_smart: debug

samsungtv_smart:
# TV Samnsung
- host: 192.168.10.11
source_list:
{ "TV": "ST_TV", "Sky Italia": "ST_HDMI1", "BluRay Player": "ST_HDMI2" }
app_list:
{
"Netflix": "3201907018807/org.tizen.netflix-app",
"Disney+": "3201901017640/MCmYXNxgcu.DisneyPlus",
"Paramount+": "3202110025305/rJyOSqC6Up.PPlusIntl",
"PrimeVideo": "3201512006785/org.tizen.ignition",
"Infinity": "3201609010702/g3zzYA7yO8.InfinityNew",
"RaiPlay": "111399002034/5im3FztIhW.RaiTVtizen",
"CHILI": "3201505002690/vYlbEeT4gk.ChiliTizen",
"DAZN": "3201806016390/yu1NM3vHsU.DAZN",
"YouTube": "111299001912/9Ur5IzDKqV.TizenYouTube",
"Internet": "org.tizen.browser",
}
channel_list: '{"Rai1": "1@TV", "Rai2": "2@TV", "SkyTG24": "100@Sky Italia", "FoxHD": "112@Sky Italia"}'
#timeout: 5
68 changes: 40 additions & 28 deletions custom_components/samsungtv_smart/api/samsungws.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
from .shortcuts import SamsungTVShortcuts

DEFAULT_POWER_ON_DELAY = 120
MIN_APP_SCAN_INTERVAL = 10
MIN_APP_SCAN_INTERVAL = 8
MAX_APP_VALIDITY_SEC = 60
MAX_WS_PING_INTERVAL = 10
PING_TIMEOUT = 3
TYPE_DEEP_LINK = "DEEP_LINK"
Expand All @@ -55,6 +56,7 @@
_WS_ENDPOINT_ART = "/api/v2/channels/com.samsung.art-app"
_WS_LOG_NAME = "websocket"

_LOG_PING_PONG = False
_LOGGING = logging.getLogger(__name__)


Expand Down Expand Up @@ -99,6 +101,13 @@ def _process_api_response(response, *, raise_error=True):
return response


def _log_ping_pong(msg, *args):
"""Log ping pong message if enabled."""
if not _LOG_PING_PONG:
return
_LOGGING.debug(msg=msg, args=args)


class Ping:
"""Class for handling Ping to a specific host."""

Expand Down Expand Up @@ -495,7 +504,7 @@ def _client_remote_thread(self):

def _on_ping_remote(self, _, payload):
"""Manage ping message received by remote WS connection."""
_LOGGING.debug("Received WS remote ping %s, sending pong", payload)
_log_ping_pong("Received WS remote ping %s, sending pong", payload)
self._last_ping = datetime.utcnow()
if self._ws_remote.sock:
try:
Expand Down Expand Up @@ -532,7 +541,7 @@ def _on_message_remote(self, _, message):
self._handle_installed_app(response)
elif event == "ed.edenTV.update":
_LOGGING.debug("Message remote: received edenTV")
self.get_running_app(force_scan=True)
self._get_running_app(force_scan=True)

def _request_apps_list(self):
"""Request to the TV the list of installed apps."""
Expand Down Expand Up @@ -584,7 +593,7 @@ def _client_control_thread(self):

def _on_ping_control(self, _, payload):
"""Manage ping message received by control WS channel."""
_LOGGING.debug("Received WS control ping %s, sending pong", payload)
_log_ping_pong("Received WS control ping %s, sending pong", payload)
self._last_control_ping = datetime.utcnow()
if self._ws_control.sock:
try:
Expand Down Expand Up @@ -612,7 +621,7 @@ def _on_message_control(self, _, message):
if not self._check_conn_id(conn_data):
return
_LOGGING.debug("Message control: received connect")
self.get_running_app()
self._get_running_app()
elif event == "ed.installedApp.get":
_LOGGING.debug("Message control: received installedApp")
self._handle_installed_app(response)
Expand All @@ -623,14 +632,16 @@ def _set_running_app(self, response):
return
if (result := response.get("result")) is None:
return
if not isinstance(result, dict):
self._running_app = None
return
if (is_running := result.get("visible")) is None:
if isinstance(result, bool):
is_running = result
elif (is_running := result.get("visible")) is None:
return

self._last_running_scan = datetime.utcnow()
self._running_apps[app_id] = self._last_running_scan
call_time = datetime.utcnow()
with self._sync_lock:
self._last_app_scan = call_time
self._last_running_scan = call_time
self._running_apps[app_id] = call_time
if self._running_app:
if is_running and app_id != self._running_app:
_LOGGING.debug("app running: %s", app_id)
Expand Down Expand Up @@ -717,7 +728,7 @@ def _client_art_thread(self):

def _on_ping_art(self, _, payload):
"""Manage ping message received by art WS channel."""
_LOGGING.debug("Received WS art ping %s, sending pong", payload)
_log_ping_pong("Received WS art ping %s, sending pong", payload)
self._last_art_ping = datetime.utcnow()
if self._ws_art.sock:
try:
Expand Down Expand Up @@ -833,7 +844,8 @@ def is_app_running(self, app_id: str) -> bool | None:
return True
if (last_seen := self._running_apps.get(app_id)) is None:
return None
if (self._last_running_scan - last_seen).total_seconds() >= 60:
app_age = (self._last_running_scan - last_seen).total_seconds()
if app_age >= MAX_APP_VALIDITY_SEC:
self._running_apps.pop(app_id)
return None
return False
Expand Down Expand Up @@ -863,6 +875,7 @@ def _check_remote(self):
self._artmode_status = ArtModeStatus.Unavailable
else:
self._check_art_mode()
self._get_running_app()
self._notify_app_change()

if self._power_on_requested:
Expand Down Expand Up @@ -894,28 +907,16 @@ def _notify_app_change(self):
self._running_app_changed = False
self._status_callback()

def set_power_on_request(self, set_art_mode=False, power_on_delay=0):
"""Set a power on request status and save the time of the rquest."""
self._power_on_requested = True
self._power_on_requested_time = datetime.utcnow()
self._power_on_artmode = set_art_mode
self._power_on_delay = max(power_on_delay, 0) or DEFAULT_POWER_ON_DELAY

def set_power_off_request(self):
"""Remove a previous power on request."""
self._power_on_requested = False

def get_running_app(self, *, force_scan=False):
def _get_running_app(self, *, force_scan=False):
"""Query current running app using control channel."""
if not self._ws_control:
return

scan_interval = 1 if force_scan else MIN_APP_SCAN_INTERVAL
with self._sync_lock:
call_time = datetime.utcnow()
difference = (call_time - self._last_app_scan).total_seconds()
if (
difference < MIN_APP_SCAN_INTERVAL and not force_scan
) or difference < 1:
if difference <= scan_interval:
return
self._last_app_scan = call_time

Expand All @@ -937,6 +938,17 @@ def get_running_app(self, *, force_scan=False):
for app in app_to_check.values():
self._get_app_status(app.app_id, app.app_type)

def set_power_on_request(self, set_art_mode=False, power_on_delay=0):
"""Set a power on request status and save the time of the rquest."""
self._power_on_requested = True
self._power_on_requested_time = datetime.utcnow()
self._power_on_artmode = set_art_mode
self._power_on_delay = max(power_on_delay, 0) or DEFAULT_POWER_ON_DELAY

def set_power_off_request(self):
"""Remove a previous power on request."""
self._power_on_requested = False

def start_poll(self):
"""Start polling the TV for status."""
if self._ping_thread is None or not self._ping_thread.is_alive():
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 @@ -14,5 +14,5 @@
"codeowners": ["@jaruba", "@ollo69", "@screwdgeh"],
"config_flow": true,
"iot_class": "cloud_polling",
"version": "0.11.4b1"
"version": "0.11.4"
}

0 comments on commit c97395b

Please sign in to comment.