diff --git a/i3pystatus/hassio.py b/i3pystatus/hassio.py new file mode 100644 index 0000000..8f0a5d8 --- /dev/null +++ b/i3pystatus/hassio.py @@ -0,0 +1,50 @@ +from i3pystatus import IntervalModule +from requests import get +import json + + +class Hassio(IntervalModule): + """ + Displays the state of a Homeassistant.io entity + Requires the PyPI package `requests` + """ + + settings = ( + ("entity_id", "Entity ID to track."), + ("hassio_url", "URL to your hassio install. (default: " + "https://localhost:8123)"), + ("hassio_token", "HomeAssistant API token " + "(https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token)"), + ("interval", "Update interval."), + ("desired_state", "The desired or \"good\" state of the entity."), + ("good_color", "Color of text while entity is in desired state"), + ("bad_color", "Color of text while entity is not in desired state"), + "format" + ) + required = ("hassio_url", "hassio_token", "entity_id") + desired_state = "on" + good_color = "#00FF00" # green + bad_color = "#FF0000" # red + interval = 15 + format = "{friendly_name}: {state}" + + def run(self): + headers = {"content-type": "application/json", + "Authorization": "Bearer %s" % self.hassio_token} + url = "%s/api/states/%s" % (self.hassio_url, self.entity_id) + response = get(url, headers=headers) + entity = json.loads(response.text) + + cdict = { + "friendly_name": entity['attributes']['friendly_name'] or None, + "entity_id": entity['entity_id'] or self.entity_id, + "last_change": entity['last_changed'] or None, + "last_update": entity['last_updated'] or None, + "state": entity['state'] + } + + color = self.good_color if entity['state'] == self.desired_state else self.bad_color + self.output = { + "full_text": self.format.format(**cdict), + "color": color + } diff --git a/tests/test_hassio.py b/tests/test_hassio.py new file mode 100644 index 0000000..a685490 --- /dev/null +++ b/tests/test_hassio.py @@ -0,0 +1,67 @@ +""" +Basic test for the hassio module +Requires the PyPI package `requests` +""" + +import unittest +from mock import patch +from requests import get +from i3pystatus import hassio +import json + +# inline json of hassio api response +STREAM = {'attributes': {'friendly_name': 'Light', + 'node_id': 18, + 'supported_features': 1, + 'value_id': '72054591347734729', + 'value_index': 0, + 'value_instance': 1}, + 'context': {'id': '54188133d21271036bbfb089019a3481', + 'parent_id': None, + 'user_id': None}, + 'entity_id': 'asdf1234', + 'last_changed': '2021-02-24T23:37:25.627676+00:00', + 'last_updated': '2021-02-24T23:37:25.627676+00:00', + 'state': 'off'} + +HASSIO_URL = 'http://localhost:8123' +FAKETOKEN = 'ihasatoken' + + +class HassioTest(unittest.TestCase): + + @patch('i3pystatus.hassio.get', autospec=True) + def test_not_desired_state(self, get): + """ + Test output when state matches desired state + """ + hassio.get.return_value.text = json.dumps(STREAM) + hassiostat = hassio.Hassio(entity_id='asdf1234', + hassio_url=HASSIO_URL, + hassio_token=FAKETOKEN, + good_color="#00FF00", + bad_color="#FF0000", + desired_state='on') + hassiostat.run() + import pdb + self.assertTrue(hassiostat.output == {'full_text': 'Light: off', 'color': '#FF0000'}) + + @patch('i3pystatus.hassio.get', autospec=True) + def test_desired_state(self, urlopen): + """ + Test output from side-loaded xml (generated from a real hassio server + response) + """ + hassio.get.return_value.text = json.dumps(STREAM) + hassiostat = hassio.Hassio(entity_id='asdf1234', + hassio_url=HASSIO_URL, + hassio_token=FAKETOKEN, + good_color="#00FF00", + bad_color="#FF0000", + desired_state='off') + hassiostat.run() + self.assertTrue(hassiostat.output == {'full_text': 'Light: off', 'color': '#00FF00'}) + + +if __name__ == '__main__': + unittest.main()