diff --git a/config_creation/main.py b/config_creation/main.py index 768349f..c09ab53 100644 --- a/config_creation/main.py +++ b/config_creation/main.py @@ -46,10 +46,10 @@ def add_knx_devices(devices, groups): ] scene_button_names = ['ObenLinks', 'ObenRechts', 'MitteLinks', 'MitteRechts', 'UntenLinks', 'UntenRechts'] scene_button_names = [(i, e) for i, e in enumerate(scene_button_names)] - switches += [DeviceInfo(f"SzeneEsszimmer{n}", "Esszimmer Szene {i}") for i, n in scene_button_names] - switches += [DeviceInfo(f"SzeneWohnzimmer{n}", "Wohnzimmer Szene {i}") for i, n in scene_button_names] - switches += [DeviceInfo(f"SzeneEingang{n}", "Eingang Szene {i}") for i, n in scene_button_names[2:]] - switches += [DeviceInfo(f"SzeneTerrassentuer{n}", "Wohnzimmer Terrassentür Szene {i}") + switches += [DeviceInfo(f"SzeneEsszimmer{n}", f"Esszimmer Szene {i}") for i, n in scene_button_names] + switches += [DeviceInfo(f"SzeneWohnzimmer{n}", f"Wohnzimmer Szene {i}") for i, n in scene_button_names] + switches += [DeviceInfo(f"SzeneEingang{n}", f"Eingang Szene {i}") for i, n in scene_button_names[2:]] + switches += [DeviceInfo(f"SzeneTerrassentuer{n}", f"Wohnzimmer Terrassentür Szene {i}") for i, n in scene_button_names[2: 4]] power_plugs = [ @@ -82,8 +82,9 @@ def add_knx_devices(devices, groups): knx.extent(devices, knx.create_switches(switches, imported_csv)) knx.extent(devices, knx.create_power_plug(power_plugs, imported_csv)) - for device in lights + shutters + switches + power_plugs: - add_to_group(groups, device.groups, device.display_name) + for device_type, devices in [('light', lights), ('cover', shutters), ('switch', switches)]: + for device in devices: + add_to_group(groups, device.groups, device.display_name, device_type) def add_fhem_devices(devices, groups): @@ -94,7 +95,7 @@ def add_fhem_devices(devices, groups): for device in device_list: device['platform'] = 'fhem' if 'groups' in device: - add_to_group(groups, device['groups'], device['name']) + add_to_group(groups, device['groups'], device['name'], device_type) del device['groups'] devices[device_type].append(device) @@ -109,7 +110,7 @@ def main(): with open('output/configuration.yaml', 'w') as output: output.write(open('manual_config.yaml', 'r').read()) yaml.dump(all_devices, output) - yaml.dump(group_dict, open('output/groups.yaml', 'a')) + yaml.dump(group_dict, open('output/groups.yaml', 'w')) if __name__ == '__main__': diff --git a/config_creation/manual_config.yaml b/config_creation/manual_config.yaml index 6d1299d..5b9df98 100644 --- a/config_creation/manual_config.yaml +++ b/config_creation/manual_config.yaml @@ -14,6 +14,11 @@ homeassistant: latitude: 49.369477 longitude: 10.9831468 + customize_glob: + cover.*: + half_position: 25 + + # Sensors #sensor: # Weather prediction diff --git a/config_creation/ui-lovelace.yaml b/config_creation/ui-lovelace.yaml new file mode 100644 index 0000000..f5216d0 --- /dev/null +++ b/config_creation/ui-lovelace.yaml @@ -0,0 +1,103 @@ +resources: + - type: js + url: /local/custom_ui/state-card-custom-cover.js +title: Home +views: + - cards: + - entities: + - light.wohnzimmer_deckenlampe + - light.wohnzimmer_kugel + image: /local/living_room.jpg + title: Wohnzimmer + type: picture-glance + - entities: + - entity: light.kuche_deckenlampe + name: Decke Küche + - entity: light.esszimmer_deckenlampe_mitte + name: Decke Esszimmer Mitte + - entity: light.esszimmer_deckenlampe_west + name: Decke Esszimmer + - type: divider + - entity: light.kuche_links + name: Küche LED links + - entity: light.kuche_rechts + name: Küche LED rechts + - entity: light.kuche_vorne + name: Küche LED vorne + - type: divider + - entity: cover.kuche_fenster_rollo + name: Küche + type: 'custom:state-card-custom-cover' + - entity: cover.esszimmer_fenster_rollo + name: Esszimmer + type: 'custom:state-card-custom-cover' + show_header_toggle: true + title: Küche/Esszimmer + type: entities + - entities: + - entity: light.wohnzimmer_deckenlampe + name: Decke + - type: divider + - entity: light.wohnzimmer_kugel + name: Kugel + - entity: light.wohnzimmer_regal_links + name: Regal links + - entity: light.wohnzimmer_regal_rechts + name: Regal rechts + - type: divider + - entity: light.wohnzimmer_stehlampe_oben + name: Stehlampe oben + - entity: light.wohnzimmer_stehlampe + name: Stehlampe unten + - type: divider + - entity: cover.wohnzimmer_fenster_rollo + name: Fenster + type: 'custom:state-card-custom-cover' + - entity: cover.wohnzimmer_terrassentur_rollo + name: Tür + type: 'custom:state-card-custom-cover' + show_header_toggle: true + title: Wohnzimmer + type: entities + - entities: + - entity: light.gang_licht + name: Licht + - entity: light.gang_bogen + name: Bogen + show_header_toggle: true + title: Gang + type: entities + title: Wohnbereich + - badges: + - sensor.fritz_box_7490_kbyte_sec_received + - sensor.fritz_box_7490_kbyte_sec_sent + cards: + - entities: + - entity: sensor.trockner_verbrauch + name: Trockner aktuell + - entity: sensor.trockner_verbrauch_summe + name: Trockner insgesamt + - entity: sensor.trockner_betriebsstunden + name: Trockner Stunden + - type: divider + - entity: sensor.waschmaschine_verbrauch + name: Waschmaschine aktuell + - entity: sensor.waschmaschine_verbrauch_summe + name: Waschmaschine insgesamt + - entity: sensor.waschmaschine_betriebsstunden + name: Waschmaschine Stunden + show_header_toggle: false + title: Verbrauch + type: entities + - entities: + - switch.trockner + - switch.waschmaschine + - switch.spulmaschine + - switch.backofen + - switch.herd_phase_1 + - switch.herd_phase_2 + - switch.herd_phase_3 + show_header_toggle: false + title: Sicherheitsabschaltung + type: entities + title: Admin diff --git a/config_creation/util.py b/config_creation/util.py index e6e9fe0..f6f62b7 100644 --- a/config_creation/util.py +++ b/config_creation/util.py @@ -19,14 +19,14 @@ def extent(result_dict, input_dict, platform): result_dict[k] += v -def name_to_id(name): - return slugify.slugify(name, separator='_') +def name_to_id(name, device_type): + return "{}.{}".format(device_type, slugify.slugify(name, separator='_')) -def add_to_group(groups_dict, device_groups, device_name): +def add_to_group(groups_dict, device_groups, device_name, device_type): for group in device_groups: if group not in groups_dict: raise ValueError(f"FHEM device {device_name} wants to be added to unknown group {group}") if 'entities' not in groups_dict[group]: groups_dict[group]['entities'] = [] - groups_dict[group]['entities'].append(name_to_id(device_name)) + groups_dict[group]['entities'].append(name_to_id(device_name, device_type)) diff --git a/fhem/__init__.py b/fhem/__init__.py index b9c3f77..81dd237 100644 --- a/fhem/__init__.py +++ b/fhem/__init__.py @@ -58,6 +58,9 @@ class FhemConnection: _LOGGER.info("Connected to FHEM {}:{}".format(self._host, self._port)) self._writer = writer self.connected = True + for device in self.devices.values(): + await device.async_update_ha_state() + self.reconnect_time = self.reconnect_time_start writer.writelines([ "displayattr .*\n".encode(), @@ -71,6 +74,8 @@ class FhemConnection: except OSError: _LOGGER.warning("Connection to FHEM failed {}:{}".format(self._host, self._port)) self.connected = False + for device in self.devices.values(): + await device.async_update_ha_state() await asyncio.sleep(self.reconnect_time) self.reconnect_time = min(2 * self.reconnect_time, self.reconnect_time) self.hass.loop.create_task(self._connection()) diff --git a/fhem/light.py b/fhem/light.py index 83d66fd..b067fa5 100644 --- a/fhem/light.py +++ b/fhem/light.py @@ -25,7 +25,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 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]: @@ -91,7 +90,7 @@ class FhemLight(Light): self.connection.fhem_set(self._ids[0], 'off') async def line_received(self, line): - _LOGGER.info("FHEM line received (device): " + self.name + ": " + line) + _LOGGER.debug("FHEM line received (device): " + self.name + ": " + line) if line.startswith('dim:'): self._available = True _, new_dim_state, new_level = line.split(':') diff --git a/knx_config/knx_devices.yaml b/knx_config/knx_devices.yaml deleted file mode 100644 index 412f2bc..0000000 --- a/knx_config/knx_devices.yaml +++ /dev/null @@ -1,61 +0,0 @@ -light: -- platform: knx - address: 0/1/3 - state_address: 0/1/8 - name: Wohnzimmer Deckenlampe - brightness_address: 0/1/7 - brightness_state_address: 0/1/9 -- platform: knx - address: 0/1/21 - state_address: 0/1/26 - name: Esszimmer Deckenlampe West - brightness_address: 0/1/25 - brightness_state_address: 0/1/27 -- platform: knx - address: 0/1/39 - state_address: 0/1/44 - name: Esszimmer Deckenlampe Mitte - brightness_address: 0/1/43 - brightness_state_address: 0/1/45 -- platform: knx - address: 0/2/39 - state_address: 0/2/44 - name: Esszimmer Schrankleuchte - brightness_address: 0/2/43 - brightness_state_address: 0/2/45 -- platform: knx - address: 0/1/57 - state_address: 0/1/62 - name: Küche Deckenlampe - brightness_address: 0/1/61 - brightness_state_address: 0/1/63 -- platform: knx - address: 0/2/21 - state_address: 0/2/26 - name: Aussen Terassenlicht - brightness_address: 0/2/25 - brightness_state_address: 0/2/27 -- platform: knx - address: 0/3/3 - state_address: 0/3/8 - name: Gang Licht - brightness_address: 0/3/7 - brightness_state_address: 0/3/9 -- platform: knx - address: 0/3/21 - state_address: 0/3/26 - name: Bad Licht - brightness_address: 0/3/25 - brightness_state_address: 0/3/27 -- platform: knx - address: 0/3/39 - state_address: 0/3/44 - name: Gang Einganglicht - brightness_address: 0/3/43 - brightness_state_address: 0/3/45 -- platform: knx - address: 0/3/57 - state_address: 0/3/62 - name: Waschküche Licht - brightness_address: 0/3/61 - brightness_state_address: 0/3/63 diff --git a/knx_config/knx_file_creator.py b/knx_config/knx_file_creator.py deleted file mode 100644 index 01d5193..0000000 --- a/knx_config/knx_file_creator.py +++ /dev/null @@ -1,158 +0,0 @@ -from collections import namedtuple -from typing import List -from ruamel.yaml import YAML - -DeviceInfo = namedtuple("DeviceInfo", ['csv_name', 'display_name']) -yaml = YAML() - - -def first_lower(s): - if len(s) == 0: - return s - else: - return s[0].lower() + s[1:] - - -def import_ets5_csv_file(csv_file): - result = dict() - with open(csv_file, encoding='utf-8') as f: - for line in f: - splitted_line = line.split(",") - name = splitted_line[0].replace('"', "") - group_address = splitted_line[1].replace('"', "") - if '-' not in group_address: - result[name.strip()] = splitted_line[1].replace('"', "").strip() - return result - - -def create_dimmable_lights(device_info : List[DeviceInfo], - csv_contents, - postfix_on_off_write=" Schalten", - postfix_on_off_read=" RM Schalten", - postfix_dim=" Dimmen", - postfix_brightness_write=" Helligkeit", - postfix_brightness_read=" RM Helligkeit"): - - result = [] - for entry in device_info: - try: - display_name = entry.display_name - on_off_write_addr = csv_contents[entry.csv_name + postfix_on_off_write] - on_off_read_addr = csv_contents[entry.csv_name + postfix_on_off_read] - dimm_addr = csv_contents[entry.csv_name + postfix_dim] - brightness_write_addr = csv_contents[entry.csv_name + postfix_brightness_write] - brightness_read_addr = csv_contents[entry.csv_name + postfix_brightness_read] - - result.append({ - 'platform': 'knx', - 'address': on_off_write_addr, - 'state_address': on_off_read_addr, - 'name': display_name, - 'brightness_address': brightness_write_addr, - 'brightness_state_address': brightness_read_addr, - }) - except KeyError as e: - raise ValueError("Skipping %s - Could not find CSV File entry: %s" % (entry.csv_name, str(e))) - - return result - - -def write_yaml(device_dict): - pass - - -if __name__ == '__main__': - knx_dimmable_lights = [ - DeviceInfo('Wohnzimmerlampe', 'Wohnzimmer Deckenlampe'), - DeviceInfo('EsszimmerlampeWest', 'Esszimmer Deckenlampe West'), - DeviceInfo('EsszimmerlampeMitte', 'Esszimmer Deckenlampe Mitte'), - DeviceInfo("EsszimmerWandlampe", 'Esszimmer Schrankleuchte'), - DeviceInfo("Küchenlampe", "Küche Deckenlampe"), - DeviceInfo("AussenleuchteUntenSO", "Aussen Terassenlicht"), - DeviceInfo("Gang", "Gang Licht"), - DeviceInfo("Bad", "Bad Licht"), - DeviceInfo("GangWindfang", "Gang Einganglicht"), - DeviceInfo("LichtWaschküche", "Waschküche Licht"), - ] - imported_csv = import_ets5_csv_file('export_project1.csv') - imported_csv.update(import_ets5_csv_file('export_project2.csv')) - - devices = { - 'light': create_dimmable_lights(knx_dimmable_lights, imported_csv), - } - yaml.dump(devices, open('knx_devices.yaml', 'w')) - - -def createLights(csvContents, idToRoomMap, knxSendClient, knxRecvClient, - postfixWrite=" Schalten", postfixRead=" RM Schalten"): - from pysmarthome.backends.knx.devices import Light - result = [] - - for csvName, info in idToRoomMap.items(): - try: - room = info['room'] - displayName = info['displayName'] - deviceId = info['id'] - onOffWriteAddr = csvContents[csvName + postfixWrite] - onOffReadAddr = csvContents[csvName + postfixRead] - l = Light(deviceId, displayName, room, onOffWriteAddr, onOffReadAddr, knxSendClient, knxRecvClient, ) - result.append(l) - except KeyError as e: - raise ValueError("Skipping %s - Could not find CSV File entry: %s" % (csvName, str(e))) - - return result - - -def createBells(csvContents, idToRoomMap, knxSendClient, knxRecvClient, - postfixWrite=" Schalten", postfixRead=" RM Schalten"): - from pysmarthome.backends.knx.devices import Bell - result = [] - - for csvName, info in idToRoomMap.items(): - try: - room = info['room'] - displayName = info['displayName'] - deviceId = info['id'] - onOffWriteAddr = csvContents[csvName + postfixWrite] - if csvName + postfixRead in csvContents: - onOffReadAddr = csvContents[csvName + postfixRead] - else: - onOffReadAddr = None - - l = Bell(deviceId, displayName, room, onOffWriteAddr, onOffReadAddr, knxSendClient, knxRecvClient, ) - result.append(l) - except KeyError as e: - raise ValueError("Skipping %s - Could not find CSV File entry: %s" % (csvName, str(e))) - - return result - - -def createShutters(csvContents, idToRoomMap, knxSendClient, knxRecvClient, - postfixLongAddr=" Lang", postfixShortAddr=" Kurz", postfixReadPosition=" RM Position", - postfixSetPosition=" Position"): - from pysmarthome.backends.knx.devices import Shutter - result = [] - - for csvName, contents in idToRoomMap.items(): - try: - longAddr = csvContents[csvName + postfixLongAddr] - shortAddr = csvContents[csvName + postfixShortAddr] - readPosAddr = csvContents[csvName + postfixReadPosition] - setPosAddr = csvContents[csvName + postfixSetPosition] - if type(contents) is dict: - displayName = contents['displayName'] - room = contents['room'] - deviceId = contents['id'] - else: - displayName = csvName - room = contents - deviceId = first_lower(csvName) - - s = Shutter(deviceId, displayName, room, shortAddr, longAddr, setPosAddr, readPosAddr, - knxSendClient, knxRecvClient) - result.append(s) - - except KeyError as e: - raise ValueError("Skipping %s - Could not find CSV File entry: %s" % (csvName, str(e))) - - return result diff --git a/todo b/todo index a8fb0ac..166fe7f 100644 --- a/todo +++ b/todo @@ -1,74 +1,40 @@ -KNX: - - add shutters - - add sensors - - check out read addresses - - in bus monitor - - KNX config files -> add to git + - 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 + - add scenes + - add brighter/darker action + - fix door light [ok] - check out motion detectors in frontend - check out shutters in frontend -Config: - - add rooms as groups - - frontend room grouping - -> how to configure frontend? - - set up scenes for living room - - +Frontend: + - change cover state card for half open FHEM: - add FHEM shutters - - add - check FHEM reconnection - what happens when FHEM stops? - what happens when stick is pulled? - - - - - - - - - -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw deviceMsg: 50 (to 62A77D) -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw dim: stop:50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw level: 50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw overheat: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw overload: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw pct: 50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw phyLevel: 50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw reduced: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw 50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw timedOn: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_01 phyLevel: 50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_01 chn:??? phys:50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_02 phyLevel: 50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_02 chn:??? phys:50 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw deviceMsg: off (to 62A77D) -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw dim: stop:off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw level: 0 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw overheat: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw overload: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw pct: 0 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw phyLevel: 0 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw reduced: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw timedOn: off -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_01 phyLevel: 0 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_01 chn:??? phys:0 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_02 phyLevel: 0 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw1_V_02 chn:??? phys:0 - - - - - - -CUL_HM ArbeitszimmerMartin_Bewegungsmelder brightness: 45 -CUL_HM ArbeitszimmerMartin_Bewegungsmelder motion: on (to 62A77D) -CUL_HM ArbeitszimmerMartin_Bewegungsmelder motionCount: 3_next:29s -CUL_HM ArbeitszimmerMartin_Bewegungsmelder motion -CUL_HM ArbeitszimmerMartin_Bewegungsmelder trigDst_62A77D: noConfig -CUL_HM ArbeitszimmerMartin_Bewegungsmelder trigger_cnt: 3 -CUL_HM ArbeitszimmerMartin_Deckenlampe_Sw deviceMsg: 50 (to 62A77D) +Owntracks + - try basic owntracks setup + + +Other: + - 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 +