Rule creation for IR remotes
This commit is contained in:
		
							parent
							
								
									bf0a15bf5f
								
							
						
					
					
						commit
						08c18b3dee
					
				|  | @ -1,8 +1,8 @@ | ||||||
| # Add only entities here that are auto-discovered (not FHEM and KNX devices) | # Add only entities here that are auto-discovered (not FHEM and KNX devices) | ||||||
| 
 | 
 | ||||||
| default_view: | #default_view: | ||||||
|   view: true | #  view: true | ||||||
|   icon: mdi:home | #  icon: mdi:home | ||||||
| 
 | 
 | ||||||
| living_area: | living_area: | ||||||
|   name: Wohnbereich |   name: Wohnbereich | ||||||
|  | @ -30,9 +30,9 @@ hallway: | ||||||
|     - light.gang_bogen |     - light.gang_bogen | ||||||
|     - light.gang_einganglicht |     - light.gang_einganglicht | ||||||
|     - light.gang_licht |     - light.gang_licht | ||||||
|     - switch.bewegungsmelder_west_led |     - light.bewegungsmelder_west_led | ||||||
|     - switch.bewegungsmelder_ost_led |     - light.bewegungsmelder_ost_led | ||||||
|     - switch.bewegungsmelder_mitte_led |     - light.bewegungsmelder_mitte_led | ||||||
| 
 | 
 | ||||||
| outside: | outside: | ||||||
|   name: Außen |   name: Außen | ||||||
|  | @ -66,5 +66,7 @@ other: | ||||||
| 
 | 
 | ||||||
| first_floor: | first_floor: | ||||||
|   name: Oben |   name: Oben | ||||||
|  |   entities: | ||||||
|  |     - light.wohnzimmer_stehlampe_oben | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,226 @@ | ||||||
|  | import re | ||||||
|  | import os | ||||||
|  | from ruamel.yaml import YAML | ||||||
|  | 
 | ||||||
|  | yaml = YAML() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # -------------------------------------- put the config here ----------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | def get_config(): | ||||||
|  |     return { | ||||||
|  |         'bedroom': { | ||||||
|  |             'ir_host': 'bedroompi', | ||||||
|  |             'media_player': 'media_player.bedroompi', | ||||||
|  |             'group': 'group.bedroom', | ||||||
|  | 
 | ||||||
|  |             'mapping': { | ||||||
|  |                 'key_1': '[playlist] Good Morning', | ||||||
|  |                 'key_2': '[playlist] Good Night Long', | ||||||
|  |                 'key_3': '[playlist] Good Night', | ||||||
|  | 
 | ||||||
|  |                 'key_4': '[playlist] Bar Classics', | ||||||
|  |                 'key_5': '[playlist] Sentimental Moods', | ||||||
|  |                 'key_6': '[playlist] Pop', | ||||||
|  | 
 | ||||||
|  |                 'key_7': '[radio] B 5 aktuell', | ||||||
|  |                 'key_8': '[radio] BR-Klassik', | ||||||
|  |                 'key_9': '[playlist] http://opml.radiotime.com/Tune.ashx?id=s25028',  # Klassik Radio | ||||||
|  | 
 | ||||||
|  |                 'key_numeric_star': '[radio] Antenne Bayern', | ||||||
|  |                 'key_0': '[radio] Bayern 3', | ||||||
|  |                 'key_numeric_pound': '[radio] Bayern 2', | ||||||
|  | 
 | ||||||
|  |                 'key_red': '[scene] schlafzimmer_orange', | ||||||
|  |                 'key_green': '[scene] schlafzimmer_rot', | ||||||
|  |                 'key_yellow': '[scene] schlafzimmer_ganz_hell', | ||||||
|  |                 'key_blue': '[scene] schlafzimmer_blau', | ||||||
|  | 
 | ||||||
|  |                 'key_tv': '[timed_light_off] 30', | ||||||
|  |                 'key_video': '[timed_light_off] 15', | ||||||
|  |                 'key_music': '[timed_light_off] 10', | ||||||
|  |                 'key_pictures': '[timed_light_off] 5', | ||||||
|  | 
 | ||||||
|  |                 'key_power': [  # Music & Lights off | ||||||
|  |                     service('media_player.media_pause', 'media_player.bedroompi'), | ||||||
|  |                     service('light.turn_off', 'group.bedroom'), | ||||||
|  |                 ], | ||||||
|  |                 'key_ok': [  # Grosser Rollo zu, kleiner halb zu | ||||||
|  |                     service('cover.close_cover', 'cover.schlafzimmer_rollo_gross'), | ||||||
|  |                     service('cover_half.set_half', 'cover.schlafzimmer_rollo_klein'), | ||||||
|  |                 ], | ||||||
|  |                 'key_mute': [service('light.turn_off', 'group.all_downstairs_but_bedroom_and_outside')], | ||||||
|  |                 'key_channel': [service('light.turn_off', 'group.all_downstairs_but_bedroom')], | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         'living_area': { | ||||||
|  |             'ir_host': 'kitchenpi', | ||||||
|  |             'media_player': 'media_player.kitchenpi', | ||||||
|  |             'group': 'group.living_area', | ||||||
|  | 
 | ||||||
|  |             'mapping': { | ||||||
|  |                 'key_4': '[playlist] Bar Classics', | ||||||
|  |                 'key_5': '[playlist] Sentimental Moods', | ||||||
|  |                 'key_6': '[playlist] Pop', | ||||||
|  | 
 | ||||||
|  |                 'key_7': '[radio] B 5 aktuell', | ||||||
|  |                 'key_8': '[radio] BR-Klassik', | ||||||
|  |                 'key_9': '[playlist] http://opml.radiotime.com/Tune.ashx?id=s25028',  # Klassik Radio | ||||||
|  | 
 | ||||||
|  |                 'key_numeric_star': '[radio] Antenne Bayern', | ||||||
|  |                 'key_0': '[radio] Bayern 3', | ||||||
|  |                 'key_numeric_pound': '[radio] Bayern 2', | ||||||
|  | 
 | ||||||
|  |                 'key_red': '[scene] wohnbereich_orange', | ||||||
|  |                 'key_green': '[scene] wohnbereich_grun', | ||||||
|  |                 'key_yellow': '[scene] wohnbereich_hell', | ||||||
|  |                 'key_blue': '[scene] wohnbereich_blau_grun', | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # ---------------------------------------------------------------------------------------------------------------------- | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | description_regex = re.compile(r'\[\s*(.*)\s*\](.*)') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def split_description(d): | ||||||
|  |     res = description_regex.match(d) | ||||||
|  |     return res.group(1).strip(), res.group(2).strip() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def automation_from_config(ir_description): | ||||||
|  |     ir_host = ir_description['ir_host'] | ||||||
|  |     media_player = ir_description['media_player'] | ||||||
|  |     group = ir_description['group'] | ||||||
|  | 
 | ||||||
|  |     result = [] | ||||||
|  |     for key, description in ir_description['mapping'].items(): | ||||||
|  |         automation = {'alias': f'IR {ir_host} {key}', | ||||||
|  |                       'trigger': ir_trigger(ir_host, key)} | ||||||
|  |         if isinstance(description, list): | ||||||
|  |             action = description | ||||||
|  |         elif isinstance(description, str): | ||||||
|  |             function, value = split_description(description) | ||||||
|  |             if function == 'playlist': | ||||||
|  |                 action = service('media_player.play_media', media_player, media_content_id=value) | ||||||
|  |             elif function == 'radio': | ||||||
|  |                 action = service('media_player.play_media', media_player, | ||||||
|  |                                  media_content_id=value, media_content_type='channel') | ||||||
|  |             elif function == 'scene': | ||||||
|  |                 action = service('scene.turn_on', 'scene.' + value) | ||||||
|  |             elif function == 'timed_light_off': | ||||||
|  |                 action = service('light.turn_off', group, transition=str(60 * int(value))) | ||||||
|  |             else: | ||||||
|  |                 raise ValueError("Invalid prefix " + function) | ||||||
|  |         else: | ||||||
|  |             raise ValueError("Invalid type for entry " + key) | ||||||
|  | 
 | ||||||
|  |         automation['action'] = action | ||||||
|  |         result.append(automation) | ||||||
|  |     return result | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def ir_trigger(ir_host, button_name): | ||||||
|  |     return { | ||||||
|  |         'platform': 'event', | ||||||
|  |         'event_type': 'ir_command_received', | ||||||
|  |         'button_name': button_name, | ||||||
|  |         'repeat_counter': 0, | ||||||
|  |         'host': ir_host, | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def service(service_name, entity_id, **kwargs): | ||||||
|  |     kwargs['entity_id'] = entity_id | ||||||
|  |     return { | ||||||
|  |         'service': service_name, | ||||||
|  |         'data': kwargs | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def default_shutter_controls(device_group, ir_host): | ||||||
|  |     """Default rules for Hauppauge IR for Shutter control with up, down, left, right buttons""" | ||||||
|  |     return [ | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Rollo auf', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_up'), | ||||||
|  |             'action': service('cover.open_cover', device_group), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Rollo zu', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_down'), | ||||||
|  |             'action': service('cover.close_cover', device_group), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Rollo halb', | ||||||
|  |             'trigger': [ir_trigger(ir_host, 'key_left'), ir_trigger(ir_host, 'key_right')], | ||||||
|  |             'action': service('cover_half.set_half', device_group), | ||||||
|  |         }, | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def default_light_controls(device_group, ir_host): | ||||||
|  |     """Default light rules for Hauppauge IR for light dimming with channel up/down and light off with stop button""" | ||||||
|  |     return [ | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Licht heller', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_channelup'), | ||||||
|  |             'action': service('dimmer.dim', device_group, offset=30), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Licht dunkler', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_channeldown'), | ||||||
|  |             'action': service('dimmer.dim', device_group, offset=-30), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Licht viel heller', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_menu'), | ||||||
|  |             'action': service('dimmer.dim', device_group, offset=130), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Licht viel dunkler', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_stop'), | ||||||
|  |             'action': service('dimmer.dim', device_group, offset=-130), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Licht aus', | ||||||
|  |             'trigger': ir_trigger(ir_host, 'key_goto'), | ||||||
|  |             'action': service('light.turn_off', device_group), | ||||||
|  |         }, | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def default_music_controls(device_group, ir_host): | ||||||
|  |     """Default music control (play, pause, next) for Hauppauge IR""" | ||||||
|  |     return [ | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Musik Play/Pause', | ||||||
|  |             'trigger': [ir_trigger(ir_host, 'key_play'), ir_trigger(ir_host, 'key_pause')], | ||||||
|  |             'action': service('media_player.media_play_pause', device_group), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Musik Next', | ||||||
|  |             'trigger': [ir_trigger(ir_host, 'key_forward'), ir_trigger(ir_host, 'key_fastforward')], | ||||||
|  |             'action': service('media_player.media_next_track', device_group), | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             'alias': f'IR {ir_host} Musik Prev', | ||||||
|  |             'trigger': [ir_trigger(ir_host, 'key_previous'), ir_trigger(ir_host, 'key_rewind')], | ||||||
|  |             'action': service('media_player.media_next_track', device_group), | ||||||
|  |         }, | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def create_rules(folder): | ||||||
|  |     for name, data in get_config().items(): | ||||||
|  |         rules = automation_from_config(data) | ||||||
|  |         rules += default_light_controls(data['group'], data['ir_host']) | ||||||
|  |         rules += default_music_controls(data['media_player'], data['ir_host']) | ||||||
|  |         rules += default_shutter_controls(data['group'], data['ir_host']) | ||||||
|  |         file_name = os.path.join(folder, name + '.yaml') | ||||||
|  |         with open(file_name, 'w') as f: | ||||||
|  |             f.write("# Dont' edit manually! this is generated!\n\n") | ||||||
|  |             yaml.dump(rules, f) | ||||||
|  | @ -123,7 +123,9 @@ def create_lights(device_info: List[DeviceInfo], | ||||||
|     result = [] |     result = [] | ||||||
|     for entry in device_info: |     for entry in device_info: | ||||||
|         try: |         try: | ||||||
|             on_off_write_addr = csv_contents[entry.csv_name + postfix_on_off_write] |             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) |             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_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) |             brightness_read_addr = csv_contents.get(entry.csv_name + postfix_brightness_read, None) | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ import argparse | ||||||
| from util import DeviceInfo, add_to_group, name_to_id | from util import DeviceInfo, add_to_group, name_to_id | ||||||
| from ruamel.yaml import YAML | from ruamel.yaml import YAML | ||||||
| import knx_conf as knx | import knx_conf as knx | ||||||
|  | from ir_automations import create_rules as create_automation_rules | ||||||
| 
 | 
 | ||||||
| script_path = os.path.dirname(os.path.realpath(__file__)) | script_path = os.path.dirname(os.path.realpath(__file__)) | ||||||
| yaml = YAML() | yaml = YAML() | ||||||
|  | @ -48,10 +49,14 @@ def add_knx_devices(devices, groups): | ||||||
|         DeviceInfo("LichtWaschküche", "Waschküche Licht", 'hallway'), |         DeviceInfo("LichtWaschküche", "Waschküche Licht", 'hallway'), | ||||||
|         # Normal lights |         # Normal lights | ||||||
|         DeviceInfo('AussenleuchteHaustüren', 'Haustür Licht', 'outside'), |         DeviceInfo('AussenleuchteHaustüren', 'Haustür Licht', 'outside'), | ||||||
|         DeviceInfo('AussenleuchteObenNW', 'Haustür Licht NW', 'outside'), |         DeviceInfo('AussenleuchteObenNW', 'Haustür Licht NW', 'first_floor'), | ||||||
|         DeviceInfo('TreppenhausLicht', "Treppenhaus Licht", 'first_floor'), |         DeviceInfo('TreppenhausLicht', "Treppenhaus Licht", 'first_floor'), | ||||||
|         DeviceInfo('WCLicht', "WC Licht", 'other'), |         DeviceInfo('WCLicht', "WC Licht", 'other'), | ||||||
|         DeviceInfo('LampeVorratsraum', "Vorratsraum Licht", 'other'), |         DeviceInfo('LampeVorratsraum', "Vorratsraum Licht", 'other'), | ||||||
|  |         # Bewegungsmelder LEDs | ||||||
|  |         DeviceInfo("BewegungsmelderMitte LED", "Bewegungsmelder Mitte LED", 'hallway'), | ||||||
|  |         DeviceInfo("BewegungsmelderWest LED", "Bewegungsmelder West LED", 'hallway'), | ||||||
|  |         DeviceInfo("BewegungsmelderOst LED", "Bewegungsmelder Ost LED", 'hallway'), | ||||||
|     ] |     ] | ||||||
| 
 | 
 | ||||||
|     shutters = [ |     shutters = [ | ||||||
|  | @ -66,10 +71,6 @@ def add_knx_devices(devices, groups): | ||||||
|         DeviceInfo("KlingelOben", "Klingel Oben", 'first_floor'), |         DeviceInfo("KlingelOben", "Klingel Oben", 'first_floor'), | ||||||
|         DeviceInfo("Klingel Innen", "Klingel Innentür", 'other'), |         DeviceInfo("Klingel Innen", "Klingel Innentür", 'other'), | ||||||
|         DeviceInfo("Klingel Aussen", "Klingen Außentür", 'other'), |         DeviceInfo("Klingel Aussen", "Klingen Außentür", 'other'), | ||||||
|         # Bewegungsmelder LEDs |  | ||||||
|         DeviceInfo("BewegungsmelderMitte LED", "Bewegungsmelder Mitte LED", 'hallway'), |  | ||||||
|         DeviceInfo("BewegungsmelderWest LED", "Bewegungsmelder West LED", 'hallway'), |  | ||||||
|         DeviceInfo("BewegungsmelderOst LED", "Bewegungsmelder Ost LED", 'hallway'), |  | ||||||
|     ] |     ] | ||||||
|     scene_button_names = ['ObenLinks', 'ObenRechts', 'MitteLinks', 'MitteRechts', 'UntenLinks', 'UntenRechts'] |     scene_button_names = ['ObenLinks', 'ObenRechts', 'MitteLinks', 'MitteRechts', 'UntenLinks', 'UntenRechts'] | ||||||
|     scene_button_names = [(i, e) for i, e in enumerate(scene_button_names)] |     scene_button_names = [(i, e) for i, e in enumerate(scene_button_names)] | ||||||
|  | @ -174,15 +175,33 @@ def add_fhem_devices(devices, groups): | ||||||
|             devices[device_type].append(device) |             devices[device_type].append(device) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def add_light_groups(groups): | def add_meta_groups(groups): | ||||||
|     light_groups = { |     all_devices = set() | ||||||
|         f"light_{group_id}": { |     for group in groups.values(): | ||||||
|             'name': content['name'] + " Lichter", |         all_devices.update(group['entities']) | ||||||
|             'entities': [e for e in content['entities'] if e.startswith('light.')], |     first_floor = set(groups['first_floor']['entities']) | ||||||
|         } |     bedroom = set(groups['bedroom']['entities']) | ||||||
|         for group_id, content in groups.items() if 'name' in content |     outside = set(groups['outside']['entities']) | ||||||
|  | 
 | ||||||
|  |     groups['all_downstairs'] = { | ||||||
|  |         'name': 'Unten Alles', | ||||||
|  |         'entities': [e for e in all_devices - first_floor] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     groups['all_downstairs_but_outside'] = { | ||||||
|  |         'name': 'Unten Alles Ausser Draussen', | ||||||
|  |         'entities': [e for e in all_devices - first_floor - outside] | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     groups['all_downstairs_but_bedroom'] = { | ||||||
|  |         'name': 'Unten Alles Ausser Schlafzimmer', | ||||||
|  |         'entities': [e for e in all_devices - first_floor - bedroom], | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     groups['all_downstairs_but_bedroom_and_outside'] = { | ||||||
|  |         'name': 'Unten Alles Ausser Schlafzimmer und Draussen', | ||||||
|  |         'entities': [e for e in all_devices - first_floor - bedroom - outside], | ||||||
|     } |     } | ||||||
|     groups.update(light_groups) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def make_sensor_exclude_list(all_devices, name_fragments): | def make_sensor_exclude_list(all_devices, name_fragments): | ||||||
|  | @ -256,8 +275,9 @@ def create_config(target_directory, development=False): | ||||||
|         yaml.dump(all_devices, output) |         yaml.dump(all_devices, output) | ||||||
|         yaml.dump(logbook_config(all_devices), output) |         yaml.dump(logbook_config(all_devices), output) | ||||||
|         yaml.dump(recorder_config(all_devices), output) |         yaml.dump(recorder_config(all_devices), output) | ||||||
|  |         output.write("automation manual: !include_dir_merge_list automations\n") | ||||||
| 
 | 
 | ||||||
|     add_light_groups(group_dict) |     add_meta_groups(group_dict) | ||||||
| 
 | 
 | ||||||
|     with open(os.path.join(target_directory, 'groups.yaml'), 'w') as output: |     with open(os.path.join(target_directory, 'groups.yaml'), 'w') as output: | ||||||
|         output.write("# Dont' edit manually! this is generated!\n\n") |         output.write("# Dont' edit manually! this is generated!\n\n") | ||||||
|  | @ -270,6 +290,8 @@ def create_config(target_directory, development=False): | ||||||
|         additional_file = 'secrets_development.yaml' if development else 'secrets_deploy.yaml' |         additional_file = 'secrets_development.yaml' if development else 'secrets_deploy.yaml' | ||||||
|         output.write(open(os.path.join(script_path, additional_file), 'r').read()) |         output.write(open(os.path.join(script_path, additional_file), 'r').read()) | ||||||
| 
 | 
 | ||||||
|  |     create_automation_rules(os.path.join(target_directory, 'automations')) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     parser = argparse.ArgumentParser() |     parser = argparse.ArgumentParser() | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ import sys | ||||||
| from typing import List, Tuple | from typing import List, Tuple | ||||||
| import voluptuous as vol | import voluptuous as vol | ||||||
| from ..reconnecting_client import ReconnectingClient | from ..reconnecting_client import ReconnectingClient | ||||||
|  | from .radio import find_local_radio_url_by_name | ||||||
| 
 | 
 | ||||||
| from homeassistant.components.media_player import ( | from homeassistant.components.media_player import ( | ||||||
|     MediaPlayerDevice, PLATFORM_SCHEMA) |     MediaPlayerDevice, PLATFORM_SCHEMA) | ||||||
|  | @ -485,6 +486,9 @@ class SqueezeBoxDevice(MediaPlayerDevice): | ||||||
|         If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the current playlist. |         If ATTR_MEDIA_ENQUEUE is True, add `media_id` to the current playlist. | ||||||
|         This method must be run in the event loop and returns a coroutine. |         This method must be run in the event loop and returns a coroutine. | ||||||
|         """ |         """ | ||||||
|  |         if media_type == 'channel': | ||||||
|  |             media_id = find_local_radio_url_by_name(media_id) | ||||||
|  | 
 | ||||||
|         if kwargs.get(ATTR_MEDIA_ENQUEUE): |         if kwargs.get(ATTR_MEDIA_ENQUEUE): | ||||||
|             return self._add_uri_to_playlist(media_id) |             return self._add_uri_to_playlist(media_id) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,68 @@ | ||||||
|  | import xml.etree.ElementTree as ET | ||||||
|  | from urllib.request import urlopen | ||||||
|  | 
 | ||||||
|  | ompl_radio_browse_url = 'http://opml.radiotime.com/Browse.ashx' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def radio_name_cleanup(radio_name): | ||||||
|  |     """Removes tokens with brackets or points | ||||||
|  |      "Radio Bamberg 106.1 (Top 40/Pop)" -> "Radio Bamberg 106.1" | ||||||
|  |     """ | ||||||
|  |     radio_name = radio_name.split() | ||||||
|  |     res = [] | ||||||
|  |     for token in radio_name: | ||||||
|  |         if '(' in token or ')' in token: | ||||||
|  |             continue | ||||||
|  |         res.append(token) | ||||||
|  |     return " ".join(res) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_sender_information(queryURL): | ||||||
|  |     """ | ||||||
|  |         Example Query: GET http://opml.radiotime.com/Browse.ashx?partnerId=<partnerid>&serial=<serial> | ||||||
|  |                        partnerid and serial does not seem to be necessary - so we do not use it here, | ||||||
|  |     """ | ||||||
|  |     xmlfile = urlopen(queryURL) | ||||||
|  |     tree = ET.ElementTree(file=xmlfile) | ||||||
|  |     rootnode = tree.getroot() | ||||||
|  | 
 | ||||||
|  |     result = dict() | ||||||
|  |     for node in rootnode.iter('outline'): | ||||||
|  |         if 'type' not in node.attrib or node.attrib['type'] != "audio": | ||||||
|  |             continue | ||||||
|  |         station_name = radio_name_cleanup(node.attrib['text']) | ||||||
|  |         station_url = node.attrib['URL'] | ||||||
|  |         station_id = node.attrib['guide_id'] | ||||||
|  |         print(station_name) | ||||||
|  |         result[station_id] = {'name': station_name, 'url': station_url} | ||||||
|  | 
 | ||||||
|  |     return result | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_related_radio_stations(stationID): | ||||||
|  |     query_url = ompl_radio_browse_url + '?id=' + stationID | ||||||
|  |     return get_sender_information(query_url) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def get_local_radio_stations(): | ||||||
|  |     # goto ompl.radiotime with parameter ?c=local and look for your city there then paste id here | ||||||
|  |     query_url = ompl_radio_browse_url + '?id=r100765' | ||||||
|  |     result = get_sender_information(query_url) | ||||||
|  |     print(result) | ||||||
|  |     return result | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def find_local_radio_url_by_name(search_name): | ||||||
|  |     """Searches at the Radiotime database for a local radiostation which contains the searchName """ | ||||||
|  |     search_name = search_name.lower().strip() | ||||||
|  |     if search_name.startswith('http'): | ||||||
|  |         return search_name | ||||||
|  | 
 | ||||||
|  |     for radioId, radio in find_local_radio_url_by_name.stations.items(): | ||||||
|  |         if search_name in radio['name'].lower(): | ||||||
|  |             return radio['url'] | ||||||
|  | 
 | ||||||
|  |     raise ValueError("Could not find radio station " + search_name) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | find_local_radio_url_by_name.stations = get_local_radio_stations() | ||||||
							
								
								
									
										57
									
								
								scenes.yaml
								
								
								
								
							
							
						
						
									
										57
									
								
								scenes.yaml
								
								
								
								
							|  | @ -202,6 +202,51 @@ | ||||||
|       xy_color: [0.2075, 0.6584] |       xy_color: [0.2075, 0.6584] | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | - name: Wohnbereich Hell | ||||||
|  |   entities: | ||||||
|  |     light.esszimmer_deckenlampe_west: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |     light.wohnzimmer_deckenlampe: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |     light.kuche_deckenlampe: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |     light.wohnzimmer_regal_links: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       xy_color: [0.527, 0.447] | ||||||
|  |     light.kuche_links: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       xy_color: [0.537, 0.438] | ||||||
|  |     light.kuche_rechts: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       xy_color: [0.557, 0.403] | ||||||
|  |     light.wohnzimmer_regal_rechts: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       xy_color: [0.616, 0.371] | ||||||
|  |     light.wohnzimmer_stehlampe_oben: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       color_temp: 492 | ||||||
|  |     light.wohnzimmer_stehlampe: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       color_temp: 492 | ||||||
|  |     light.wohnzimmer_kugel: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       color_temp: 492 | ||||||
|  |     light.kuche_vorne: | ||||||
|  |       state: on | ||||||
|  |       brightness: 255 | ||||||
|  |       color_temp: 492 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| - name: Wohnbereich Meditation | - name: Wohnbereich Meditation | ||||||
|   entities: |   entities: | ||||||
|     light.kuche_deckenlampe: |     light.kuche_deckenlampe: | ||||||
|  | @ -330,12 +375,20 @@ | ||||||
| 
 | 
 | ||||||
| - name: Schlafzimmer Bettlicht dunkel | - name: Schlafzimmer Bettlicht dunkel | ||||||
|   entities: |   entities: | ||||||
|  |     light.schlafzimmer_deckenlampe: | ||||||
|  |       state: off | ||||||
|  |     light.schlafzimmer_schrank: | ||||||
|  |       state: off | ||||||
|     light.bett_martin: |     light.bett_martin: | ||||||
|       state: on |       state: on | ||||||
|       brightness: 2 |       brightness: 5 | ||||||
|  |       xy_color: [0.502, 0.414] | ||||||
|     light.bett_rebecca: |     light.bett_rebecca: | ||||||
|       state: on |       state: on | ||||||
|       brightness: 2 |       brightness: 5 | ||||||
|  |       xy_color: [0.502, 0.414] | ||||||
|  |     light.schlafzimmer_fluter: | ||||||
|  |       state: off | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| - name: Schlafzimmer Orange | - name: Schlafzimmer Orange | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue