Skip to content

Commit

Permalink
Update constants and documentation (#89)
Browse files Browse the repository at this point in the history
* Add links to 'get_properties' methods

* Add links to the commands used by 'get_properties'

* Add links to the commands used by 'get_properties'

* Rename constants

* `VALID_PROPERTIES` -> `VALID_STATE_PROPERTIES
* `VALID_CONDITIONS` -> `VALID_PROPERTIES`

* Update constants, change 'condition' to 'propert'

* Rename 'property' -> 'prop'

* Rename some constants; improve documentation
  • Loading branch information
JeffLIrion committed Sep 7, 2019
1 parent f35b466 commit f9082e7
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 28 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ release:
scripts/git_tag.sh
python setup.py sdist bdist_wheel
twine upload dist/*

.PHONY: docs
docs:
@cd docs/source && rm -f androidtv*.rst
@cd docs && sphinx-apidoc -f -e -o source/ ../androidtv/
@cd docs && make html && make html

.PHONY: coverage
coverage:
coverage run --source androidtv setup.py test && coverage html && coverage report
5 changes: 5 additions & 0 deletions androidtv/androidtv.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ def update(self):
def get_properties(self, lazy=False):
"""Get the properties needed for Home Assistant updates.
This will send one of the following ADB commands:
* :py:const:`androidtv.constants.CMD_ANDROIDTV_PROPERTIES_LAZY`
* :py:const:`androidtv.constants.CMD_ANDROIDTV_PROPERTIES_NOT_LAZY`
Parameters
----------
lazy : bool
Expand Down
39 changes: 25 additions & 14 deletions androidtv/basetv.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class BaseTV(object):
{'paused': {'media_session_state': 3, 'wake_lock_size': 1}},
'standby']}
The keys are app IDs, and the values are lists of rules that are evaluated in order by the :meth:`_custom_state_detection` method.
The keys are app IDs, and the values are lists of rules that are evaluated in order.
:py:const:`~androidtv.constants.VALID_STATES`
Expand Down Expand Up @@ -1096,6 +1096,21 @@ def volume_down(self, current_volume_level=None):
def state_detection_rules_validator(rules, exc=KeyError):
"""Validate the rules (i.e., the ``state_detection_rules`` value) for a given app ID (i.e., a key in ``state_detection_rules``).
For each ``rule`` in ``rules``, this function checks that:
* ``rule`` is a string or a dictionary
* If ``rule`` is a string:
* Check that ``rule`` is in :py:const:`~androidtv.constants.VALID_STATES` or :py:const:`~androidtv.constants.VALID_STATE_PROPERTIES`
* If ``rule`` is a dictionary:
* Check that each key is in :py:const:`~androidtv.constants.VALID_STATES`
* Check that each value is a dictionary
* Check that each key is in :py:const:`~androidtv.constants.VALID_PROPERTIES`
* Check that each value is of the right type, according to :py:const:`~androidtv.constants.VALID_PROPERTIES_TYPES`
See :class:`~androidtv.basetv.BaseTV` for more info about the ``state_detection_rules`` parameter.
Parameters
Expand All @@ -1118,8 +1133,8 @@ def state_detection_rules_validator(rules, exc=KeyError):

# If a rule is a string, check that it is valid
if isinstance(rule, str):
if rule not in constants.VALID_PROPERTIES + constants.VALID_STATES:
raise exc("Invalid rule '{0}' is not in {1}".format(rule, constants.VALID_PROPERTIES + constants.VALID_STATES))
if rule not in constants.VALID_STATE_PROPERTIES + constants.VALID_STATES:
raise exc("Invalid rule '{0}' is not in {1}".format(rule, constants.VALID_STATE_PROPERTIES + constants.VALID_STATES))

# If a rule is a dictionary, check that it is valid
else:
Expand All @@ -1132,17 +1147,13 @@ def state_detection_rules_validator(rules, exc=KeyError):
if not isinstance(conditions, dict):
raise exc("Expected a map for entry '{0}' in 'state_detection_rules', got {1}".format(state, type(conditions).__name__))

for condition, value in conditions.items():
# The keys of the dictionary must be valid conditions that can be checked
if condition not in constants.VALID_CONDITIONS:
raise exc("Invalid property '{0}' is not in {1}".format(condition, constants.VALID_CONDITIONS))

# The value for the `audio_state` property must be a string
if condition == "audio_state" and not isinstance(value, str):
raise exc("Conditional value for property 'audio_state' must be a string, not {}".format(type(value).__name__))
for prop, value in conditions.items():
# The keys of the dictionary must be valid properties that can be checked
if prop not in constants.VALID_PROPERTIES:
raise exc("Invalid property '{0}' is not in {1}".format(prop, constants.VALID_PROPERTIES))

# The value for the `media_session_state` and `wake_lock_size` properties must be an int
if condition != "audio_state" and not isinstance(value, int):
raise exc("Conditional value for property '{0}' must be an int, not {1}".format(condition, type(value).__name__))
# Make sure the value is of the right type
if not isinstance(value, constants.VALID_PROPERTIES_TYPES[prop]):
raise exc("Conditional value for property '{0}' must be of type {1}, not {2}".format(prop, constants.VALID_PROPERTIES_TYPES[prop].__name__, type(value).__name__))

return rules
27 changes: 16 additions & 11 deletions androidtv/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,22 @@
#: Get the wake lock size
CMD_WAKE_LOCK_SIZE = "dumpsys power | grep Locks | grep 'size='"

#: Get the properties for an :py:class:`~androidtv.androidtv.AndroidTV` device (``lazy=True``)
#: Get the properties for an :py:class:`~androidtv.androidtv.AndroidTV` device (``lazy=True``); see :py:meth:`androidtv.androidtv.AndroidTV.get_properties`
CMD_ANDROIDTV_PROPERTIES_LAZY = CMD_SCREEN_ON + CMD_SUCCESS1 + " && " + CMD_AWAKE + CMD_SUCCESS1 + " && " + CMD_AUDIO_STATE + " && " + CMD_WAKE_LOCK_SIZE + " && " + CMD_CURRENT_APP + " && (" + CMD_MEDIA_SESSION_STATE + " || echo) && " + CMD_STREAM_MUSIC

#: Get the properties for an :py:class:`~androidtv.androidtv.AndroidTV` device (``lazy=False``)
#: Get the properties for an :py:class:`~androidtv.androidtv.AndroidTV` device (``lazy=False``); see :py:meth:`androidtv.androidtv.AndroidTV.get_properties`
CMD_ANDROIDTV_PROPERTIES_NOT_LAZY = CMD_SCREEN_ON + CMD_SUCCESS1_FAILURE0 + " && " + CMD_AWAKE + CMD_SUCCESS1_FAILURE0 + " && " + CMD_AUDIO_STATE + " && " + CMD_WAKE_LOCK_SIZE + " && " + CMD_CURRENT_APP + " && (" + CMD_MEDIA_SESSION_STATE + " || echo) && " + CMD_STREAM_MUSIC

#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=True, get_running_apps=True``)
#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=True, get_running_apps=True``); see :py:meth:`androidtv.firetv.FireTV.get_properties`
CMD_FIRETV_PROPERTIES_LAZY_RUNNING_APPS = CMD_SCREEN_ON + CMD_SUCCESS1 + " && " + CMD_AWAKE + CMD_SUCCESS1 + " && " + CMD_WAKE_LOCK_SIZE + " && " + CMD_CURRENT_APP + " && (" + CMD_MEDIA_SESSION_STATE + " || echo) && " + CMD_RUNNING_APPS

#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=True, get_running_apps=False``)
#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=True, get_running_apps=False``); see :py:meth:`androidtv.firetv.FireTV.get_properties`
CMD_FIRETV_PROPERTIES_LAZY_NO_RUNNING_APPS = CMD_SCREEN_ON + CMD_SUCCESS1 + " && " + CMD_AWAKE + CMD_SUCCESS1 + " && " + CMD_WAKE_LOCK_SIZE + " && " + CMD_CURRENT_APP + " && (" + CMD_MEDIA_SESSION_STATE + " || echo)"

#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=False, get_running_apps=True``)
#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=False, get_running_apps=True``); see :py:meth:`androidtv.firetv.FireTV.get_properties`
CMD_FIRETV_PROPERTIES_NOT_LAZY_RUNNING_APPS = CMD_SCREEN_ON + CMD_SUCCESS1_FAILURE0 + " && " + CMD_AWAKE + CMD_SUCCESS1_FAILURE0 + " && " + CMD_WAKE_LOCK_SIZE + " && " + CMD_CURRENT_APP + " && (" + CMD_MEDIA_SESSION_STATE + " || echo) && " + CMD_RUNNING_APPS

#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=False, get_running_apps=False``)
#: Get the properties for a :py:class:`~androidtv.firetv.FireTV` device (``lazy=False, get_running_apps=False``); see :py:meth:`androidtv.firetv.FireTV.get_properties`
CMD_FIRETV_PROPERTIES_NOT_LAZY_NO_RUNNING_APPS = CMD_SCREEN_ON + CMD_SUCCESS1_FAILURE0 + " && " + CMD_AWAKE + CMD_SUCCESS1_FAILURE0 + " && " + CMD_WAKE_LOCK_SIZE + " && " + CMD_CURRENT_APP + " && (" + CMD_MEDIA_SESSION_STATE + " || echo)"

# `getprop` commands
Expand Down Expand Up @@ -224,14 +224,19 @@
STATE_STOPPED = 'stopped'
STATE_UNKNOWN = 'unknown'

#: States that are valid (used by the :meth:`~androidtv.basetv.BaseTV._custom_state_detection` method)
#: States that are valid (used by :func:`~androidtv.basetv.state_detection_rules_validator`)
VALID_STATES = (STATE_IDLE, STATE_OFF, STATE_PLAYING, STATE_PAUSED, STATE_STANDBY)

#: Properties that can be used to determine the current state
VALID_PROPERTIES = ("audio_state", "media_session_state")
#: Properties that can be used to determine the current state (used by :func:`~androidtv.basetv.state_detection_rules_validator`)
VALID_STATE_PROPERTIES = ("audio_state", "media_session_state")

#: Conditions that can be checked by the :meth:`~androidtv.basetv.BaseTV._conditions_are_true` method
VALID_CONDITIONS = VALID_PROPERTIES + ("wake_lock_size",)
#: Properties that can be checked for custom state detection (used by :func:`~androidtv.basetv.state_detection_rules_validator`)
VALID_PROPERTIES = VALID_STATE_PROPERTIES + ("wake_lock_size",)

#: The required type for each entry in `VALID_PROPERTIES` (used by :func:`~androidtv.basetv.state_detection_rules_validator`)
VALID_PROPERTIES_TYPES = {"audio_state": str,
"media_session_state": int,
"wake_lock_size": int}

# https://developer.android.com/reference/android/media/session/PlaybackState.html
#: States for the :attr:`~androidtv.basetv.BaseTV.media_session_state` property
Expand Down
7 changes: 7 additions & 0 deletions androidtv/firetv.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,13 @@ def stop_app(self, app):
def get_properties(self, get_running_apps=True, lazy=False):
"""Get the properties needed for Home Assistant updates.
This will send one of the following ADB commands:
* :py:const:`androidtv.constants.CMD_FIRETV_PROPERTIES_LAZY_RUNNING_APPS`
* :py:const:`androidtv.constants.CMD_FIRETV_PROPERTIES_LAZY_NO_RUNNING_APPS`
* :py:const:`androidtv.constants.CMD_FIRETV_PROPERTIES_NOT_LAZY_RUNNING_APPS`
* :py:const:`androidtv.constants.CMD_FIRETV_PROPERTIES_NOT_LAZY_NO_RUNNING_APPS`
Parameters
----------
get_running_apps : bool
Expand Down
2 changes: 0 additions & 2 deletions setup.cfg

This file was deleted.

4 changes: 4 additions & 0 deletions tests/test_firetv.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ def test_get_properties(self):
properties = self.ftv.get_properties_dict(lazy=True, get_running_apps=False)
self.assertDictEqual(properties, GET_PROPERTIES_DICT3E)

with patchers.patch_shell(GET_PROPERTIES_OUTPUT3E)[self.PATCH_KEY]:
properties = self.ftv.get_properties_dict(lazy=False, get_running_apps=False)
self.assertDictEqual(properties, GET_PROPERTIES_DICT3E)

with patchers.patch_shell(GET_PROPERTIES_OUTPUT4)[self.PATCH_KEY]:
properties = self.ftv.get_properties_dict(lazy=True)
self.assertDictEqual(properties, GET_PROPERTIES_DICT4)
Expand Down

0 comments on commit f9082e7

Please sign in to comment.