diff --git a/README.md b/README.md index 0c1bd1a..a944604 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,17 @@ You can then update your DevDeck configuration to use decks and controls from th ## Controls -* `KeylightToggleControl` +* `key_light_toggle_control.KeylightToggleControl` - Can be used to toggle the state of an Elgato Key Light + Can be used to toggle the state of an Elgato Key Light. + +* `brightness.Increase` + + Can be use to increase light brightness by a static amount. + +* `brightness.Decrease` + + Can be use to decrease light brightness by a static amount. ## Configuration @@ -29,3 +37,13 @@ Example configuration: key: 0 settings: host: 192.168.1.23 + - name: devdeck_key_light.brightness.Increase + key: 1 + settings: + host: 192.168.1.23 + step: 20 + - name: devdeck_key_light.brightness.Decrease + key: 1 + settings: + host: 192.168.1.23 + step: 20 diff --git a/devdeck_key_light/assets/brightness-high.png b/devdeck_key_light/assets/brightness-high.png new file mode 100644 index 0000000..6755897 Binary files /dev/null and b/devdeck_key_light/assets/brightness-high.png differ diff --git a/devdeck_key_light/assets/brightness-low.png b/devdeck_key_light/assets/brightness-low.png new file mode 100644 index 0000000..5e20591 Binary files /dev/null and b/devdeck_key_light/assets/brightness-low.png differ diff --git a/devdeck_key_light/assets/key-light-off.png b/devdeck_key_light/assets/key-light-off.png deleted file mode 100644 index d5c68af..0000000 Binary files a/devdeck_key_light/assets/key-light-off.png and /dev/null differ diff --git a/devdeck_key_light/assets/key-light-on.png b/devdeck_key_light/assets/key-light-on.png deleted file mode 100644 index e1d8155..0000000 Binary files a/devdeck_key_light/assets/key-light-on.png and /dev/null differ diff --git a/devdeck_key_light/assets/lightbulb-filled.png b/devdeck_key_light/assets/lightbulb-filled.png new file mode 100644 index 0000000..d14ce32 Binary files /dev/null and b/devdeck_key_light/assets/lightbulb-filled.png differ diff --git a/devdeck_key_light/assets/lightbulb-outlined.png b/devdeck_key_light/assets/lightbulb-outlined.png new file mode 100644 index 0000000..a3d000e Binary files /dev/null and b/devdeck_key_light/assets/lightbulb-outlined.png differ diff --git a/devdeck_key_light/brightness.py b/devdeck_key_light/brightness.py new file mode 100644 index 0000000..11ab466 --- /dev/null +++ b/devdeck_key_light/brightness.py @@ -0,0 +1,72 @@ +import abc +import logging +import os +import requests + +from devdeck_core.controls.deck_control import DeckControl + + +class _BrightnessBase(abc.ABC, DeckControl): + def __init__(self, key_no, **kwargs): + self.elgato = None + self.__logger = logging.getLogger('devdeck') + super().__init__(key_no, **kwargs) + + @property + @abc.abstractmethod + def image_file(self): + 'Image file to render. Relative path to assets directory.' + ... + + @property + def endpoint(self): + return 'http://{}:9123/elgato/lights'.format(self.settings['host']) + + def initialize(self): + with self.deck_context() as context: + with context.renderer() as r: + r.image(os.path.join(os.path.dirname(__file__), 'assets', self.image_file)).end() + + @property + def brightness(self): + try: + r = requests.get(self.endpoint) + except requests.exceptions.ConnectionError as ex: + self.__logger.warning("Error communicating with Elgato Key Light: %s", str(ex)) + return 0 + return r.json()['lights'][0]['brightness'] + + @brightness.setter + def brightness(self, value): + if not 0 <= value <= 100: + raise ValueError('Valid brightness values are between 0 and 100 inclusive.') + data = { + 'lights': [ + { + 'brightness': int(value), + } + ], + 'numberOfLights': 1 + } + try: + requests.put(self.endpoint, json=data) + except requests.exceptions.ConnectionError as ex: + self.__logger.warning("Error communicating with Elgato Key Light: %s", str(ex)) + + +class Increase(_BrightnessBase): + @property + def image_file(self): + return 'brightness-high.png' + + def pressed(self): + self.brightness = min(100, self.brightness + self.settings['step']) + + +class Decrease(_BrightnessBase): + @property + def image_file(self): + return 'brightness-low.png' + + def pressed(self): + self.brightness = max(0, self.brightness - self.settings['step']) \ No newline at end of file diff --git a/devdeck_key_light/key_light_toggle_control.py b/devdeck_key_light/key_light_toggle_control.py index 3d8d06c..ac7c3e7 100644 --- a/devdeck_key_light/key_light_toggle_control.py +++ b/devdeck_key_light/key_light_toggle_control.py @@ -42,10 +42,10 @@ def __render_icon(self): with self.deck_context() as context: if data['lights'][0]['on'] == 1: with context.renderer() as r: - r.image(os.path.join(os.path.dirname(__file__), "assets", 'key-light-on.png')).end() + r.image(os.path.join(os.path.dirname(__file__), "assets", 'lightbulb-filled.png')).end() else: with context.renderer() as r: - r.image(os.path.join(os.path.dirname(__file__), "assets", 'key-light-off.png')).end() + r.image(os.path.join(os.path.dirname(__file__), "assets", 'lightbulb-outlined.png')).end() except requests.exceptions.ConnectionError as ex: self.__logger.warning("Error communicating with Elgato Key Light: %s", str(ex)) with self.deck_context() as context: diff --git a/requirements.txt b/requirements.txt index a06bfeb..5d979ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ assertpy==1.1 -devdeck-core==1.0.7 +devdeck-core==1.0.8 pytest==6.2.1 requests==2.25.1 -vcrpy==4.1.1 \ No newline at end of file +vcrpy==4.1.1 diff --git a/tests/devdeck_key_light/test_brightness.py b/tests/devdeck_key_light/test_brightness.py new file mode 100644 index 0000000..b17d000 --- /dev/null +++ b/tests/devdeck_key_light/test_brightness.py @@ -0,0 +1,22 @@ +import vcr +from devdeck_core.mock_deck_context import mock_context, assert_rendered +from tests.testing_utils import TestingUtils + +from devdeck_key_light.brightness import Increase + + +class TestBrightness: + def test_simple_increase(self): + settings = { + 'host': '192.168.2.25', + 'step': 20, + } + control = Increase(0, **settings) + with vcr.use_cassette('tests/fixtures/test_brightness/test_simple_increase.yaml', + match_on=['uri', 'method', 'body']) as cass: + with mock_context(control) as ctx: + control.initialize() + assert_rendered(ctx, TestingUtils.get_filename( + '../devdeck_key_light/assets/brightness-high.png')) + control.pressed() + assert cass.all_played diff --git a/tests/devdeck_key_light/test_keylight_toggle_control.py b/tests/devdeck_key_light/test_keylight_toggle_control.py index 5eae541..3a12095 100644 --- a/tests/devdeck_key_light/test_keylight_toggle_control.py +++ b/tests/devdeck_key_light/test_keylight_toggle_control.py @@ -14,7 +14,7 @@ def test_initialize_sets_icon(self): control = KeyLightToggleControl(0, **settings) with mock_context(control) as ctx: control.initialize() - assert_rendered(ctx, TestingUtils.get_filename('../devdeck_key_light/assets/key-light-on.png')) + assert_rendered(ctx, TestingUtils.get_filename('../devdeck_key_light/assets/lightbulb-filled.png')) @vcr.use_cassette('tests/fixtures/test_key_light_toggle/test_initialize_sets_icon_off.yaml') def test_initialize_sets_icon_off(self): @@ -24,4 +24,4 @@ def test_initialize_sets_icon_off(self): control = KeyLightToggleControl(0, **settings) with mock_context(control) as ctx: control.initialize() - assert_rendered(ctx, TestingUtils.get_filename('../devdeck_key_light/assets/key-light-off.png')) + assert_rendered(ctx, TestingUtils.get_filename('../devdeck_key_light/assets/lightbulb-outlined.png')) diff --git a/tests/fixtures/test_brightness/test_simple_increase.yaml b/tests/fixtures/test_brightness/test_simple_increase.yaml new file mode 100644 index 0000000..05884f6 --- /dev/null +++ b/tests/fixtures/test_brightness/test_simple_increase.yaml @@ -0,0 +1,36 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + User-Agent: [python-requests/2.25.1] + method: GET + uri: http://192.168.2.25:9123/elgato/lights + response: + body: {string: '{"numberOfLights":1,"lights":[{"on":1,"brightness":33,"temperature":215}]}'} + headers: + Connection: [keep-alive] + Content-Length: ['74'] + Content-Type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +- request: + body: '{"lights": [{"brightness": 53}], "numberOfLights": 1}' + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['53'] + Content-Type: [application/json] + User-Agent: [python-requests/2.25.1] + method: PUT + uri: http://192.168.2.25:9123/elgato/lights + response: + body: {string: '{"numberOfLights":1,"lights":[{"on":1,"brightness":100,"temperature":215}]}'} + headers: + Connection: [keep-alive] + Content-Length: ['75'] + Content-Type: [application/json; charset=utf-8] + status: {code: 200, message: OK} +version: 1