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
+