KNX config file creation script from CSV exports

This commit is contained in:
Martin Bauer 2019-06-02 09:36:19 +02:00
parent 639f14a438
commit 6d2a193fb4
11 changed files with 269 additions and 0 deletions

View File

View File

180
config_creation/knx_conf.py Normal file
View File

@ -0,0 +1,180 @@
from typing import List
from util import DeviceInfo
__all__ = ['extent', 'import_ets5_csv_file', 'create_power_plug', 'create_lights', 'create_shutters', 'create_switches']
def first_lower(s):
if len(s) == 0:
return s
else:
return s[0].lower() + s[1:]
def extent(result_dict, input_dict):
for k, v in input_dict.items():
if k not in result_dict:
result_dict[k] = []
for entry in v:
entry['platform'] = 'knx_data'
result_dict[k] += v
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_power_plug(device_info: List[DeviceInfo],
csv_contents,
postfix_on_off_write=" Schalten",
postfix_on_off_read=" RM Schalten",
postfix_counter_value=" BSZ Wert",
postfix_consumption=" Verbrauch",
postfix_consumption_sum=" VerbrauchSumme",
postfix_consumption_reset=" Verbrauch Neustart",
postfix_counter_reset=" BSZ Neustart"):
result = {'switch': [],
'sensor': []}
for entry in device_info:
try:
# Switching
on_off_write_addr = csv_contents.get(entry.csv_name + postfix_on_off_write, None)
on_off_read_addr = csv_contents.get(entry.csv_name + postfix_on_off_read, None)
if on_off_write_addr:
device_entry = {
'name': entry.display_name,
'address': on_off_write_addr,
}
if on_off_read_addr:
device_entry['state_address'] = on_off_read_addr
result['switch'].append(device_entry)
# Counter for time (in hours) how long device was switched on
counter_value = csv_contents.get(entry.csv_name + postfix_counter_value, None)
if counter_value:
result['sensor'].append({
'name': entry.display_name + " Betriebsstunden",
'address': counter_value,
'type': '2byte_unsigned',
})
counter_reset = csv_contents.get(entry.csv_name + postfix_counter_reset, None)
if counter_reset:
result['switch'].append({
'name': entry.display_name + " Betriebsstunden Reset",
'address': counter_reset
})
# Consumption
consumption = csv_contents.get(entry.csv_name + postfix_consumption, None)
if consumption:
result['sensor'].append({
'name': entry.display_name + " Verbrauch",
'address': consumption,
'type': 'current',
})
consumption_sum = csv_contents.get(entry.csv_name + postfix_consumption_sum, None)
if consumption_sum:
result['sensor'].append({
'name': entry.display_name + " Verbrauch Summe",
'address': consumption_sum,
'type': '4byte_unsigned',
})
consumption_reset = csv_contents.get(entry.csv_name + postfix_consumption_reset, None)
if consumption_reset:
result['switch'].append({
'name': entry.display_name + " Verbrauch Reset",
'address': consumption_reset
})
except KeyError as e:
raise ValueError(f"Skipping light {entry.csv_name} - Could not find CSV File entry: {e}")
return result
def create_lights(device_info: List[DeviceInfo],
csv_contents,
postfix_on_off_write=" Schalten",
postfix_on_off_read=" RM Schalten",
postfix_brightness_write=" Helligkeit",
postfix_brightness_read=" RM Helligkeit"):
result = []
for entry in device_info:
try:
on_off_write_addr = csv_contents[entry.csv_name + postfix_on_off_write]
on_off_read_addr = csv_contents.get(entry.csv_name + postfix_on_off_read, None)
brightness_write_addr = csv_contents.get(entry.csv_name + postfix_brightness_write, None)
brightness_read_addr = csv_contents.get(entry.csv_name + postfix_brightness_read, None)
entry = {
'name': entry.display_name,
'address': on_off_write_addr,
}
if on_off_read_addr:
entry['state_address'] = on_off_read_addr
if brightness_write_addr:
entry['brightness_address'] = brightness_write_addr
if brightness_read_addr:
entry['brightness_state_address'] = brightness_read_addr
result.append(entry)
except KeyError as e:
raise ValueError(f"Skipping light {entry.csv_name} - Could not find CSV File entry: {e}")
return {'light': result}
def create_switches(device_info: List[DeviceInfo], csv_contents,
postfix_on_off_write=" Schalten",
postfix_on_off_read=" RM Schalten"):
result = []
for entry in device_info:
try:
on_off_write_addr = csv_contents.get(entry.csv_name + postfix_on_off_write, None)
if on_off_write_addr is None:
on_off_write_addr = csv_contents[entry.csv_name]
on_off_read_addr = csv_contents.get(entry.csv_name + postfix_on_off_read, None)
entry = {
'name': entry.display_name,
'address': on_off_write_addr,
}
if on_off_read_addr:
entry['state_address'] = on_off_read_addr
result.append(entry)
except KeyError as e:
raise ValueError(f"Skipping switch {entry.csv_name} - Could not find CSV File entry: {e}")
return {'switch': result}
def create_shutters(device_info: List[DeviceInfo],
csv_contents,
postfix_long_addr=" Lang", postfix_short_addr=" Kurz", postfix_read_position=" RM Position",
postfix_set_position=" Position"):
result = []
for entry in device_info:
try:
long_addr = csv_contents[entry.csv_name + postfix_long_addr]
short_addr = csv_contents[entry.csv_name + postfix_short_addr]
read_pos_addr = csv_contents[entry.csv_name + postfix_read_position]
set_pos_addr = csv_contents[entry.csv_name + postfix_set_position]
result.append({
'name': entry.display_name,
'move_long_address': long_addr,
'move_short_address': short_addr,
'position_address': set_pos_addr,
'position_state_address': read_pos_addr,
})
except KeyError as e:
raise ValueError(f"Skipping shutter {entry.csv_name} - Could not find CSV File entry: {e}")
return {'cover': result}

86
config_creation/main.py Normal file
View File

@ -0,0 +1,86 @@
from util import DeviceInfo
from ruamel.yaml import YAML
import knx_conf as knx
def create_config():
lights = [
# Dimmers
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"),
# Normal lights
DeviceInfo('AussenleuchteHaustüren', 'Haustür Licht'),
DeviceInfo('AussenleuchteObenNW', 'Haustür Licht NW'),
DeviceInfo('TreppenhausLicht', "Treppenhaus Licht"),
DeviceInfo('WCLicht', "WC Licht"),
DeviceInfo('LampeVorratsraum', "Vorratsraum Licht"),
]
shutters = [
DeviceInfo('Wohnzimmer Fenster Rollo', 'Wohnzimmer Fenster Rollo'),
DeviceInfo('Terassentür Rollo', 'Wohnzimmer Terrassentür Rollo'),
DeviceInfo('Küchenfenster Rollo', 'Küche Fenster Rollo'),
DeviceInfo('Esszimmerfenster Rollo', 'Esszimmer Fenster Rollo'),
]
switches = [
# Bells
DeviceInfo("KlingelOben", "Klingel Oben"),
DeviceInfo("Klingel Innen", "Klingel Innentür"),
DeviceInfo("Klingel Aussen", "Klingen Außentür"),
# Bewegungsmelder LEDs
DeviceInfo("BewegungsmelderMitte LED", "Bewegungsmelder Mitte LED"),
DeviceInfo("BewegungsmelderWest LED", "Bewegungsmelder West LED"),
DeviceInfo("BewegungsmelderOst LED", "Bewegungsmelder Ost LED"),
]
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}")
for i, n in scene_button_names[2: 4]]
power_plugs = [
# Vorratsraum
DeviceInfo("VorratsraumSteckdose1", "Vorratsraum Steckdose"),
DeviceInfo("VorratsraumSteckdose2", "Vorratsraum Steckdose"),
DeviceInfo("VorratsraumSteckdose3", "Gefrierschrank"),
# Waschraum
DeviceInfo("Trockner", "Trockner"),
DeviceInfo("Waschmaschine", "Waschmaschine"),
# Küche
DeviceInfo("KücheSteckdose1", "Küche Steckdose 1"),
DeviceInfo("KücheSteckdose2", "Küche Steckdose 2"),
DeviceInfo("Spülmaschine", "Spülmaschine"),
DeviceInfo("Backofen", "Backofen"),
DeviceInfo("HerdP1", "Herd Phase 1"),
DeviceInfo("HerdP2", "Herd Phase 2"),
DeviceInfo("HerdP3", "Herd Phase 3"),
# Rest
DeviceInfo("ArbeitszimmerSteckdose", "Arbeitszimmer Steckdose"),
DeviceInfo("WohnzimmerSteckdose1", "Wohnzimmer Steckdose 1"),
DeviceInfo("WohnzimmerSteckdose2", "Wohnzimmer Steckdose 2"),
]
imported_csv = knx.import_ets5_csv_file('knx_data/export_project1.csv')
imported_csv.update(knx.import_ets5_csv_file('knx_data/export_project2.csv'))
devices = {}
knx.extent(devices, knx.create_lights(lights, imported_csv))
knx.extent(devices, knx.create_shutters(shutters, imported_csv))
knx.extent(devices, knx.create_switches(switches, imported_csv))
knx.extent(devices, knx.create_power_plug(power_plugs, imported_csv))
YAML().dump(devices, open('knx_devices.yaml', 'w'))
if __name__ == '__main__':
create_config()

3
config_creation/util.py Normal file
View File

@ -0,0 +1,3 @@
from collections import namedtuple
DeviceInfo = namedtuple("DeviceInfo", ['csv_name', 'display_name'])