From 20f43f4294ef4c8f5713aa987b0c325a0d197228 Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Wed, 19 Jun 2019 16:12:22 +0200 Subject: [PATCH] Dimmer service --- config_creation/manual_config.yaml | 33 +++++++-- custom_components/dimmer/__init__.py | 70 +++++++++++++++++++ custom_components/dimmer/services.yaml | 17 +++++ {fhem => custom_components/fhem}/README.md | 0 {fhem => custom_components/fhem}/__init__.py | 11 ++- .../fhem}/binary_sensor.py | 0 {fhem => custom_components/fhem}/cover.py | 3 +- {fhem => custom_components/fhem}/light.py | 15 ++-- .../fhem}/manifest.json | 0 {fhem => custom_components/fhem}/sensor.py | 0 {fhem => custom_components/fhem}/switch.py | 0 todo | 42 ++++------- 12 files changed, 146 insertions(+), 45 deletions(-) create mode 100644 custom_components/dimmer/__init__.py create mode 100644 custom_components/dimmer/services.yaml rename {fhem => custom_components/fhem}/README.md (100%) rename {fhem => custom_components/fhem}/__init__.py (93%) rename {fhem => custom_components/fhem}/binary_sensor.py (100%) rename {fhem => custom_components/fhem}/cover.py (97%) rename {fhem => custom_components/fhem}/light.py (89%) rename {fhem => custom_components/fhem}/manifest.json (100%) rename {fhem => custom_components/fhem}/sensor.py (100%) rename {fhem => custom_components/fhem}/switch.py (100%) diff --git a/config_creation/manual_config.yaml b/config_creation/manual_config.yaml index 5b9df98..4d1d75f 100644 --- a/config_creation/manual_config.yaml +++ b/config_creation/manual_config.yaml @@ -18,6 +18,13 @@ homeassistant: cover.*: half_position: 25 +dimmer: + +#logger: +# default: info +# logs: +# xknx.telegram: debug +# xknx.knx: debug # Sensors #sensor: @@ -25,23 +32,41 @@ homeassistant: # - platform: yr # Text to speech +#tts: +## - platform: google_translate +# language: 'de' +# base_url: http://192.168.178.73:8123 tts: - - platform: google_translate + - platform: watson_tts + watson_apikey: X_tnnoaZGOwxZlqUn07wkD2G-0vaaAuOw6I6d_6jpCf7 + watson_url: https://gateway-lon.watsonplatform.net/text-to-speech/api + voice: de-DE_BirgitVoice + output_format: audio/flac;rate=44100 knx: rate_limit: 20 tunneling: - host: 192.168.178.80 # knxd to work together with old home automation server + host: server # knxd to work together with old home automation server #host: 192.168.178.65 # network bridge port: 3671 - local_ip: 192.168.178.74 + local_ip: 192.168.178.73 fhem: - host: 192.168.178.80 + host: server port: 7072 cul_device_name: CUL_HM +media_player: + - platform: squeezebox + host: server + - platform: denonavr + host: avreceiver + + + + + group: !include groups.yaml automation: !include automations.yaml script: !include scripts.yaml diff --git a/custom_components/dimmer/__init__.py b/custom_components/dimmer/__init__.py new file mode 100644 index 0000000..d4b057c --- /dev/null +++ b/custom_components/dimmer/__init__.py @@ -0,0 +1,70 @@ +""" Service to increase/decrease light brightness""" +import logging +import voluptuous as vol + +from homeassistant.components.light import ATTR_BRIGHTNESS, DOMAIN as LIGHT_DOMAIN, ATTR_TRANSITION +from homeassistant.const import SERVICE_TURN_ON, ATTR_ENTITY_ID + +# The domain of your component. Should be equal to the name of your component. +from homeassistant.helpers.service import async_extract_entity_ids + +DOMAIN = "dimmer" + +# List of component names (string) your component depends upon. +# We depend on group because group will be loaded after all the components that +# initialize devices have been setup. +DEPENDENCIES = ['group', 'light'] + +# Name of the service that we expose. +SERVICE_DIM = 'dim' + +# Shortcut for the logger +_LOGGER = logging.getLogger(__name__) + +# Validate that all required config options are given. +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({}) +}, extra=vol.ALLOW_EXTRA) + + +async def async_setup(hass, config): + """Setup example component.""" + + async def async_dim_service(service): + params = service.data.copy() + + entity_ids = await async_extract_entity_ids(hass, service, expand_group=True) + + offset = params.get('offset', None) + factor = params.get('factor', None) + min_brightness = params.get('min_brightness', 6) + + transition = params.get(ATTR_TRANSITION, None) + + if factor is None and offset is None: + offset = 50 + + assert not (factor is not None and offset is not None) + + def clip_value(level): + level = int(level) + if level < min_brightness: + return min_brightness + if level > 255: + return 255 + return level + + for entity_id in entity_ids: + brightness = hass.states.get(entity_id).attributes.get('brightness', 0) + if factor is not None: + data = {ATTR_BRIGHTNESS: clip_value(brightness * factor)} + if offset is not None: + data = {ATTR_BRIGHTNESS: clip_value(brightness + offset)} + data[ATTR_ENTITY_ID] = entity_id + if transition: + data[ATTR_TRANSITION] = transition + await hass.services.async_call(LIGHT_DOMAIN, SERVICE_TURN_ON, data) + + hass.services.async_register(DOMAIN, SERVICE_DIM, async_dim_service) + + return True diff --git a/custom_components/dimmer/services.yaml b/custom_components/dimmer/services.yaml new file mode 100644 index 0000000..ed4ba52 --- /dev/null +++ b/custom_components/dimmer/services.yaml @@ -0,0 +1,17 @@ + +dim: + description: Increases or decreases brightness of lights + fields: + entity_id: + description: Name(s) of entities or groups + example: 'light.living_room' + offset: + description: New light value is old value plus this offset (full brightness is 255). + Can be negative to decrease brightness + example: 30 + factor: + description: Factor to multiply old light value with. Use either offset or factor, not both! + example: 1.3 + transition: + description: transition time in seconds + example: 1 diff --git a/fhem/README.md b/custom_components/fhem/README.md similarity index 100% rename from fhem/README.md rename to custom_components/fhem/README.md diff --git a/fhem/__init__.py b/custom_components/fhem/__init__.py similarity index 93% rename from fhem/__init__.py rename to custom_components/fhem/__init__.py index 63cb262..e7b16d6 100644 --- a/fhem/__init__.py +++ b/custom_components/fhem/__init__.py @@ -48,6 +48,10 @@ class FhemConnection: def register_device(self, id, d): self._devices[id].append(d) + if self._writer: + self._writer.writelines([ + "displayattr .*\n".encode(), + ]) async def _update_all_devices(self): for device_list in self._devices.values(): @@ -80,6 +84,9 @@ class FhemConnection: ]) while self._run: line = await reader.readline() + if not line: + _LOGGER.warning("FHEM disconnected: {}".format(line)) + raise OSError("Disconnect") line = line.decode() _LOGGER.debug("FHEM received line: {}".format(line)) await self._process_line(line) @@ -87,13 +94,13 @@ class FhemConnection: if self._connection_last_state != 'FAILED': self.hass.components.persistent_notification.async_create("FHEM connection failed", title="No FHEM connection") - _LOGGER.error("Connection to FHEM failed {}:{}".format(self._host, self._port)) + _LOGGER.error("Connection to FHEM failed {}:{}".format(self._host, self._port)) self._connection_last_state = 'FAILED' self.connected = False await self._update_all_devices() await asyncio.sleep(self.reconnect_time) - self.reconnect_time = min(2 * self.reconnect_time, self.reconnect_time) + self.reconnect_time = min(2 * self.reconnect_time, self.reconnect_time_max) self.hass.loop.create_task(self._connection()) async def _process_line(self, line): diff --git a/fhem/binary_sensor.py b/custom_components/fhem/binary_sensor.py similarity index 100% rename from fhem/binary_sensor.py rename to custom_components/fhem/binary_sensor.py diff --git a/fhem/cover.py b/custom_components/fhem/cover.py similarity index 97% rename from fhem/cover.py rename to custom_components/fhem/cover.py index af2ac6b..70137d5 100644 --- a/fhem/cover.py +++ b/custom_components/fhem/cover.py @@ -88,7 +88,8 @@ class FhemCover(CoverDevice): _, new_motor_state, new_position = line.split(':') new_position = new_position.strip().lower() new_motor_state = new_motor_state.strip().lower() - assert new_motor_state == 'stop' or new_motor_state == 'up' or new_motor_state == 'down' + assert new_motor_state == 'stop' or new_motor_state == 'up' or new_motor_state == 'down', \ + 'Unknown motor state ' + new_motor_state if new_motor_state == 'stop': if new_position == 'on': self._position = 100 diff --git a/fhem/light.py b/custom_components/fhem/light.py similarity index 89% rename from fhem/light.py rename to custom_components/fhem/light.py index 5cd3c27..bfaf735 100644 --- a/fhem/light.py +++ b/custom_components/fhem/light.py @@ -73,22 +73,19 @@ class FhemLight(Light): return None async def async_turn_on(self, **kwargs): - brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness) - transition_time = kwargs.get(ATTR_TRANSITION, None) + brightness = kwargs.get(ATTR_BRIGHTNESS, None) + transition_time = kwargs.get(ATTR_TRANSITION, 0.5) if brightness is None: brightness = 255 - if self._dimmer: - if transition_time is not None: - # zero in the middle is the time until light is switched off, - # which is disabled here when passing 0 - self.connection.fhem_set(self._ids[0], brightness / 255 * 100, 0, transition_time) - else: - self.connection.fhem_set(self._ids[0], brightness / 255 * 100) + # zero in the middle is the time until light is switched off, + # which is disabled here when passing 0 + self.connection.fhem_set(self._ids[0], int(brightness / 255 * 100), 0, transition_time) else: self.connection.fhem_set(self._ids[0], 'on') self._brightness = brightness + await self.async_update_ha_state() async def async_turn_off(self, **kwargs): self.connection.fhem_set(self._ids[0], 'off') diff --git a/fhem/manifest.json b/custom_components/fhem/manifest.json similarity index 100% rename from fhem/manifest.json rename to custom_components/fhem/manifest.json diff --git a/fhem/sensor.py b/custom_components/fhem/sensor.py similarity index 100% rename from fhem/sensor.py rename to custom_components/fhem/sensor.py diff --git a/fhem/switch.py b/custom_components/fhem/switch.py similarity index 100% rename from fhem/switch.py rename to custom_components/fhem/switch.py diff --git a/todo b/todo index 6da4cc8..ac64dc1 100644 --- a/todo +++ b/todo @@ -1,44 +1,28 @@ - - add fhem devices [ok] - - generate config [ok] - - test config [ok] - - - add shutters [ok] - - add sensors [ok] - - check out read addresses [ok] - - in bus monitor [ok] - - KNX config files -> add to git [ok] - - - configure frontend [ok] - - add scenes - - add brighter/darker action (service!) - - fix door light [ok] - - check out motion detectors in frontend - - check out shutters in frontend -Frontend: - - change cover state card for half open [ok] +- add brighter/darker action (service!) + + +- add scenes + +LIRC connection: + - + +Squeezebox: + - standard setup + - radio service FHEM: - - reconnection & message reporting code! - - add FHEM shutters [ok] - - motion detector [ok] - - service for device stuff (up/down time, auto-off stuff) - - check FHEM reconnection - - what happens when FHEM stops? + - check FHEM reconnection [ok] + - what happens when FHEM stops? [ok] - what happens when stick is pulled? Owntracks - try basic owntracks setup - Other: - grouped motion sensors (last motion where and when) - media player card: https://github.com/kalkih/mini-media-player - -2019-06-03 19:20:46 WARNING (MainThread) [xknx.log] Could not read value of 0/0/4 -2019-06-03 19:20:48 WARNING (MainThread) [xknx.log] Could not read value of 0/0/2 -