From 639f14a438d34619faf4487faf2c69789df672b1 Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Sat, 1 Jun 2019 16:17:51 +0200 Subject: [PATCH] Initial commit --- fhem/README.md | 0 fhem/__init__.py | 101 ++++++ fhem/cover.py | 0 fhem/light.py | 147 +++++++++ fhem/manifest.json | 9 + fhem/switch.py | 0 knx_config/Nemsdorf_2019_06.knxproj | Bin 0 -> 1132824 bytes knx_config/Nemsdorf_2019_07.knxproj | Bin 0 -> 1132974 bytes .../Nemsdorf_Bewegungsmelder_2019_06.knxproj | Bin 0 -> 135029 bytes .../Nemsdorf_Bewegungsmelder_2019_07.knxproj | Bin 0 -> 135030 bytes knx_config/export_project1.csv | 293 ++++++++++++++++++ knx_config/export_project2.csv | 11 + knx_config/knx_devices.yaml | 61 ++++ knx_config/knx_file_creator.py | 158 ++++++++++ playground/asyncio_test.py | 24 ++ playground/xknxtest.py | 50 +++ todo | 74 +++++ 17 files changed, 928 insertions(+) create mode 100644 fhem/README.md create mode 100644 fhem/__init__.py create mode 100644 fhem/cover.py create mode 100644 fhem/light.py create mode 100644 fhem/manifest.json create mode 100644 fhem/switch.py create mode 100644 knx_config/Nemsdorf_2019_06.knxproj create mode 100644 knx_config/Nemsdorf_2019_07.knxproj create mode 100644 knx_config/Nemsdorf_Bewegungsmelder_2019_06.knxproj create mode 100644 knx_config/Nemsdorf_Bewegungsmelder_2019_07.knxproj create mode 100644 knx_config/export_project1.csv create mode 100644 knx_config/export_project2.csv create mode 100644 knx_config/knx_devices.yaml create mode 100644 knx_config/knx_file_creator.py create mode 100644 playground/asyncio_test.py create mode 100644 playground/xknxtest.py create mode 100644 todo diff --git a/fhem/README.md b/fhem/README.md new file mode 100644 index 0000000..e69de29 diff --git a/fhem/__init__.py b/fhem/__init__.py new file mode 100644 index 0000000..b9c3f77 --- /dev/null +++ b/fhem/__init__.py @@ -0,0 +1,101 @@ +"""FHEM integration""" + +import logging +import voluptuous as vol +import asyncio + +import homeassistant.helpers.config_validation as cv +from homeassistant.const import CONF_HOST, CONF_PORT, EVENT_HOMEASSISTANT_STOP + +_LOGGER = logging.getLogger(__name__) +CONF_CUL_DEVICE_NAME = 'cul_device_name' +DOMAIN = 'fhem' +DATA_FHEM = "data_fhem" +CONFIG_SCHEMA = vol.Schema({ + DOMAIN: vol.Schema({ + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_PORT, default=7072): cv.port, + vol.Required(CONF_CUL_DEVICE_NAME): cv.string, + }) +}, extra=vol.ALLOW_EXTRA) + + +async def async_setup(hass, config): + connection = FhemConnection(hass, config) + hass.data[DATA_FHEM] = connection + await connection.start() + return True + + +class FhemConnection: + + def __init__(self, hass, config): + self.hass = hass + self._host = config[DOMAIN][CONF_HOST] + self._port = config[DOMAIN][CONF_PORT] + self._cul_device_name = config[DOMAIN][CONF_CUL_DEVICE_NAME] + + self.connected = False + self.reconnect_time_start = 1 + self.reconnect_time_max = 60 + self.reconnect_time = self.reconnect_time_start + self.devices = {} + self._run = False + self._writer = None + + async def start(self): + self._run = True + self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.stop) + self.hass.loop.create_task(self._connection()) + + async def stop(self): + self._run = False + self.connected = False + + async def _connection(self): + try: + reader, writer = await asyncio.open_connection(self._host, self._port) + _LOGGER.info("Connected to FHEM {}:{}".format(self._host, self._port)) + self._writer = writer + self.connected = True + self.reconnect_time = self.reconnect_time_start + writer.writelines([ + "displayattr .*\n".encode(), + "inform on\n".encode(), + ]) + while self._run: + line = await reader.readline() + line = line.decode() + _LOGGER.debug("FHEM received line: {}".format(line)) + await self._process_line(line) + except OSError: + _LOGGER.warning("Connection to FHEM failed {}:{}".format(self._host, self._port)) + self.connected = False + await asyncio.sleep(self.reconnect_time) + self.reconnect_time = min(2 * self.reconnect_time, self.reconnect_time) + self.hass.loop.create_task(self._connection()) + + async def _process_line(self, line): + if line.startswith(self._cul_device_name + " "): # Status update message + _, device_name, command = line.split(" ", 2) + if device_name in self.devices: + await self.devices[device_name].line_received(command.strip()) + else: # potential response to displayattr + split_line = line.split(" ", 1) + if len(split_line) == 2: + device_name, command = split_line + if device_name in self.devices: + await self.devices[device_name].line_received(command.strip()) + + def write_line(self, line): + if self._writer: + line += '\n' + self._writer.write(line.encode()) + + def fhem_set(self, id, *arguments): + """ + Send command to FHEM using this device + :param arguments: string or list of strings containing command parameters + """ + arguments = " ".join([str(a) for a in arguments]) + self._writer.write("set {} {}\n".format(id, arguments).encode()) diff --git a/fhem/cover.py b/fhem/cover.py new file mode 100644 index 0000000..e69de29 diff --git a/fhem/light.py b/fhem/light.py new file mode 100644 index 0000000..83d66fd --- /dev/null +++ b/fhem/light.py @@ -0,0 +1,147 @@ +"""Support for lights from FHEM""" + +import voluptuous as vol +import logging + +from homeassistant.components.light import ATTR_BRIGHTNESS, PLATFORM_SCHEMA, SUPPORT_BRIGHTNESS, Light +from homeassistant.const import CONF_NAME +import homeassistant.helpers.config_validation as cv + +from . import DATA_FHEM + +_LOGGER = logging.getLogger(__name__) + + +CONF_FHEM_IDS = 'fhem_ids' +CONF_DIMMER = 'dimmer' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_FHEM_IDS): vol.All(cv.ensure_list, [cv.string]), + vol.Optional(CONF_DIMMER, default=False): cv.boolean, + vol.Required(CONF_NAME): cv.string, +}) + + +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): + """Set up lights for KNX platform.""" + connection = hass.data[DATA_FHEM] + #_LOGGER.error("FHEM platform config\n" + str(config)) + + light = FhemLight(connection, config[CONF_NAME], config[CONF_FHEM_IDS], dimmer=config[CONF_DIMMER]) + for dev_id in config[CONF_FHEM_IDS]: + connection.devices[dev_id] = light + async_add_entities([light]) + + +class FhemLight(Light): + + def __init__(self, connection, name, ids, dimmer=False): + self._brightness = None + self.connection = connection + self._dimmer = dimmer + self._ids = ids + self._name = name + self._available = True + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def brightness(self): + return self._brightness + + @property + def is_on(self): + """Return true if light is on.""" + if self._brightness is not None: + return self._brightness > 0 + else: + return None + + @property + def name(self): + """Return the name of the KNX device.""" + return self._name + + @property + def available(self) -> bool: + return self._available and self.connection.connected + + @property + def supported_features(self): + """Flag supported features.""" + flags = 0 + if self._dimmer: + flags |= SUPPORT_BRIGHTNESS + return flags + + async def async_turn_on(self, **kwargs): + brightness = kwargs.get(ATTR_BRIGHTNESS, self.brightness) + if brightness is None: + brightness = 255 + + if self._dimmer: + self.connection.fhem_set(self._ids[0], brightness / 255 * 100) + else: + self.connection.fhem_set(self._ids[0], 'on') + + async def async_turn_off(self, **kwargs): + self.connection.fhem_set(self._ids[0], 'off') + + async def line_received(self, line): + _LOGGER.info("FHEM line received (device): " + self.name + ": " + line) + if line.startswith('dim:'): + self._available = True + _, new_dim_state, new_level = line.split(':') + new_level = new_level.strip().lower() + new_dim_state = new_dim_state.strip().lower() + assert new_dim_state == 'stop' or new_dim_state == 'up' or new_dim_state == 'down' + if new_dim_state == 'stop': + if new_level == 'on': + self._brightness = 255 + elif new_level == 'off': + self._brightness = 0 + else: + new_level = int(float(new_level)) # first convert from string to floating point then truncate + assert 0 <= new_level <= 100 + self._brightness = int(new_level / 100 * 255) + await self.async_update_ha_state() + elif line.startswith('level:') and not self._dimmer: + self._available = True + _, new_level = line.split(':') + new_level = new_level.strip().lower() + if new_level == 'on': + self._brightness = 255 + elif new_level == 'off': + self._brightness = 0 + else: + try: + new_level = int(float(new_level)) # first convert from string to floating point then truncate + assert 0 <= new_level <= 100 + self._brightness = int(new_level / 100 * 255) + except ValueError: + pass + await self.async_update_ha_state() + elif line.startswith('overheat'): + overheat = line.split(':')[1] + overheat = overheat.strip().lower() + assert overheat == 'on' or overheat == 'off' + if overheat == 'on': + self.hass.components.persistent_notification.async_create( + "FHEM: Light overheated:
" + "{0}".format(self.entity_id), + title="Light overheat") + elif line.startswith('overload'): + overload = line.split(':')[1] + overload = overload.strip().lower() + assert overload == 'on' or overload == 'off' + if overload == 'on': + self.hass.components.persistent_notification.async_create( + "FHEM: Light overloaded:
" + "{0}".format(self.entity_id), + title="Light overloaded") + elif line.startswith('ResndFail') or line.startswith('MISSING ACK'): + self._available = False + await self.async_update_ha_state() diff --git a/fhem/manifest.json b/fhem/manifest.json new file mode 100644 index 0000000..1d39a3a --- /dev/null +++ b/fhem/manifest.json @@ -0,0 +1,9 @@ + +{ + "domain": "fhem", + "name": "FHEM", + "documentation": "", + "dependencies": [], + "codeowners": ["@mabau"], + "requirements": [] +} \ No newline at end of file diff --git a/fhem/switch.py b/fhem/switch.py new file mode 100644 index 0000000..e69de29 diff --git a/knx_config/Nemsdorf_2019_06.knxproj b/knx_config/Nemsdorf_2019_06.knxproj new file mode 100644 index 0000000000000000000000000000000000000000..1a3cf6398fc5cda5781d27df2cc0933dfe31109b GIT binary patch literal 1132824 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