Skip to content

Commit

Permalink
many updates
Browse files Browse the repository at this point in the history
  • Loading branch information
NickWaterton committed Dec 18, 2024
1 parent 5b5ee96 commit 6f0470a
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 42 deletions.
5 changes: 3 additions & 2 deletions example/art.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def parseargs():
# Add command line argument parsing
parser = argparse.ArgumentParser(description='Example art Samsung Frame TV.')
parser.add_argument('ip', action="store", type=str, default=None, help='ip address of TV (default: %(default)s))')
parser.add_argument('-t','--token_file', action="store", type=str, default="token_file.txt", help='default token file to use (default: %(default)s))')
parser.add_argument('-D','--debug', action='store_true', default=False, help='Debug mode (default: %(default)s))')
return parser.parse_args()

Expand All @@ -21,11 +22,11 @@ def main():
level=logging.DEBUG if args.debug else logging.INFO)
logging.debug('debug mode')

# Example showing different token files for different tv's, with default of "token_file.txt"
# Example showing different token files for different tv's, with default of "token_file.txt" from args.token_file
tokens = { '192.168.100.32' : "token_file1.txt",
'192.168.100.73' : "token_file2.txt"
}
token_file = tokens.get(args.ip, "token_file.txt")
token_file = tokens.get(args.ip, args.token_file)

# Normal constructor (will ask for connection every time)
#tv = SamsungTVWS(host=args.ip)
Expand Down
6 changes: 4 additions & 2 deletions example/async_art.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def parseargs():
# Add command line argument parsing
parser = argparse.ArgumentParser(description='Example async art Samsung Frame TV.')
parser.add_argument('ip', action="store", type=str, default=None, help='ip address of TV (default: %(default)s))')
parser.add_argument('-t','--token_file', action="store", type=str, default="token_file.txt", help='default token file to use (default: %(default)s))')
parser.add_argument('-D','--debug', action='store_true', default=False, help='Debug mode (default: %(default)s))')
return parser.parse_args()

Expand All @@ -21,10 +22,11 @@ async def image_callback(event, response):

async def main():
args = parseargs()
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
logging.basicConfig(format='%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s',
level=logging.DEBUG if args.debug else logging.INFO)
logging.debug('debug mode')
# Autosave token to file
token_file = os.path.dirname(os.path.realpath(__file__)) + '/tv-token.txt'
token_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), args.token_file)
tv = SamsungTVAsyncArt(host=args.ip, port=8002, token_file=token_file)
await tv.start_listening()

Expand Down
4 changes: 3 additions & 1 deletion example/async_art_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def parseargs():
# Add command line argument parsing
parser = argparse.ArgumentParser(description='Example async art Samsung Frame TV.')
parser.add_argument('ip', action="store", type=str, default=None, help='ip address of TV (default: %(default)s))')
parser.add_argument('-t','--token_file', action="store", type=str, default="token_file.txt", help='default token file to use (default: %(default)s))')
parser.add_argument('-D','--debug', action='store_true', default=False, help='Debug mode (default: %(default)s))')
return parser.parse_args()

Expand All @@ -23,7 +24,8 @@ async def main():
logging.debug('debug mode')

logging.info('opening art websocket with token')
tv = SamsungTVAsyncArt(host=args.ip, port=8002, token_file="token_file.txt")
token_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), args.token_file)
tv = SamsungTVAsyncArt(host=args.ip, port=8002, token_file=token_file)
await tv.start_listening()

logging.info('getting tv info')
Expand Down
15 changes: 8 additions & 7 deletions example/async_art_slideshow_anything.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def parseargs():
parser = argparse.ArgumentParser(description='Async Slideshow Any art on Samsung TV.')
parser.add_argument('ip', action="store", type=str, default=None, help='ip address of TV (default: %(default)s))')
parser.add_argument('-f','--folder', action="store", type=str, default="./slideshow", help='folder to store images in (default: %(default)s))')
parser.add_argument('-t','--token_file', action="store", type=str, default="token_file.txt", help='default token file to use (default: %(default)s))')
parser.add_argument('-c','--check', action="store", type=int, default=60, help='how often to check for new art 0=run once (default: %(default)s))')
parser.add_argument('-u','--update', action="store", type=float, default=2, help='random update period (mins) 0.25 minnimum (default: %(default)s))')
parser.add_argument('-D','--debug', action='store_true', default=False, help='Debug mode (default: %(default)s))')
Expand All @@ -64,18 +65,20 @@ class slideshow:
type=artDataMixin,
)

def __init__(self, ip, folder, period=60, random_update=1440):
def __init__(self, ip, folder, period=60, random_update=1440, token_file=None):
self.log = logging.getLogger('Main.'+__class__.__name__)
self.debug = self.log.getEffectiveLevel() <= logging.DEBUG
self.ip = ip
self.random_update = max(0.25, random_update)*60 #convert minutes to seconds
self.period = int(min(60, self.random_update)) if period else 0
# Autosave token to file
self.token_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), token_file) if token_file else token_file
self.category.SLIDESHOW.dir = folder
self.category.MY_PHOTOS.dir = os.path.join(folder, self.category.MY_PHOTOS.dir_name)
self.category.FAVOURITES.dir = os.path.join(folder, self.category.FAVOURITES.dir_name)
self.api_version = 1
self.start = time.time()
self.tv = SamsungTVAsyncArt(host=self.ip, port=8002)
self.tv = SamsungTVAsyncArt(host=self.ip, port=8002, token_file=self.token_file)

self.log.info('check thumbnails {}, slideshow rotation every: {}'.format('every {}s'.format(self.period) if self.period else 'once', datetime.timedelta(seconds = self.random_update)))
try:
Expand Down Expand Up @@ -234,10 +237,7 @@ async def select_artwork(self):
start = True
while True:
try:
if not self.tv.is_alive():
self.log.warning('reconnecting websocket')
await self.tv.start_listening()
if await self.tv.is_artmode():
if await self.tv.in_artmode():
self.log.info('time to next rotation: {}'.format(self.get_countdown()))
if not await self.do_random_update() and not start:
await self.download_thmbnails()
Expand All @@ -264,7 +264,8 @@ async def main():
mon = slideshow(args.ip,
os.path.normpath(args.folder),
period = args.check,
random_update = args.update)
random_update = args.update,
token_file = args.token_file)
await mon.start_slideshow()


Expand Down
41 changes: 21 additions & 20 deletions samsungtvws/async_art.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,21 @@ async def open(self):
raise exceptions.ConnectionFailure(response)

return self.connection

async def close(self):
if self.session and not self.session.closed:
if self.session:
await self.session.close()
await super().close()

async def start_listening(self) -> None:
# Override base class to process events
await super().start_listening(self.process_event)
try:
await self.get_artmode()
except AssertionError:
pass
if not self.is_alive():
await self.open()
if await super().start_listening(self.process_event):
try:
await self.get_artmode()
except AssertionError:
pass

def get_uuid(self):
self.art_uuid = str(uuid.uuid4())
Expand Down Expand Up @@ -140,6 +142,7 @@ async def _send_art_request(
request_data["id"] = self.get_uuid() #old api
request_data["request_id"] = request_data["id"] #new api
self.pending_requests[wait_for_event or request_data["id"]] = asyncio.Future()
await self.start_listening()
await self.send_command(ArtChannelEmitCommand.art_app_request(request_data))
return await self.wait_for_response(wait_for_event or request_data["id"])

Expand Down Expand Up @@ -187,24 +190,22 @@ def _get_rest_api(self) -> SamsungTVAsyncRest:
if self._rest_api is None:
self._rest_api = SamsungTVAsyncRest(host=self.host, port=self.port, session=self.session)
return self._rest_api

async def supported(self) -> bool:
async def _get_device_info(self):
try:
await asyncio.sleep(0.1) #do not hit rest api to frequently
data = await self._get_rest_api().rest_device_info()
return data.get("device", {}).get("FrameTVSupport") == "true"
return await self._get_rest_api().rest_device_info()
except Exception as e:
pass
return False
return {}

async def supported(self) -> bool:
data = await self._get_device_info()
return data.get("device", {}).get("FrameTVSupport") == "true"

async def on(self) -> bool:
try:
await asyncio.sleep(0.1) #do not hit rest api to frequently
data = await self._get_rest_api().rest_device_info()
return data.get("device", {}).get('PowerState', 'off') == 'on'
except Exception as e:
pass
return False
data = await self._get_device_info()
return data.get("device", {}).get('PowerState', 'off') == 'on'

async def is_artmode(self) -> bool:
return await self.on() and self.art_mode
Expand Down
24 changes: 14 additions & 10 deletions samsungtvws/async_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async def __aexit__(
await self.close()

async def open(self) -> WebSocketClientProtocol:
if self.connection:
if self.is_alive():
# someone else already created a new connection
return self.connection

Expand Down Expand Up @@ -83,21 +83,23 @@ async def start_listening(
self, callback: Optional[Callable[[str, Any], Optional[Awaitable[None]]]] = None
) -> None:
"""Open, and start listening."""
if self.connection:
raise exceptions.ConnectionFailure("Connection already exists")
if not self._recv_loop:
if not self.is_alive():
self.connection = await self.open()

self.connection = await self.open()

self._recv_loop = asyncio.ensure_future(
self._do_start_listening(callback, self.connection)
)
self._recv_loop = asyncio.ensure_future(
self._do_start_listening(callback, self.connection)
)
return True
return False

async def _do_start_listening(
self,
callback: Optional[Callable[[str, Any], Optional[Awaitable[None]]]],
connection: WebSocketClientProtocol,
) -> None:
"""Do start listening."""
_LOGGING.debug("Listening Connection Started")
with contextlib.suppress(ConnectionClosed):
while True:
data = await connection.recv()
Expand All @@ -108,9 +110,11 @@ async def _do_start_listening(
awaitable = callback(event, response)
if awaitable:
await awaitable
_LOGGING.debug("Listening Connection closed")
self._recv_loop = None

async def close(self) -> None:
if self.connection:
if self.is_alive():
await self.connection.close()
if self._recv_loop:
await self._recv_loop
Expand All @@ -123,7 +127,7 @@ async def send_commands(
commands: Sequence[Union[SamsungTVCommand, Dict[str, Any]]],
key_press_delay: Optional[float] = None,
) -> None:
if self.connection is None:
if not self.is_alive():
self.connection = await self.open()

delay = self.key_press_delay if key_press_delay is None else key_press_delay
Expand Down

0 comments on commit 6f0470a

Please sign in to comment.