summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlassulus <lassulus@lassul.us>2020-11-23 11:33:23 +0100
committerlassulus <lassulus@lassul.us>2020-11-23 11:33:23 +0100
commit1b4d1c4aaba003f42a542ce1cf442a4983f50194 (patch)
treeef6e88ffcd5f036fa31086e119fa25b7a4c98874
parent801ea60c3a31db7600d004697d4520b636f3c0df (diff)
parentb26b6c4ccedfc6f92193dd7386e382d0bf88a293 (diff)
Merge remote-tracking branch 'gum/master' into master
-rw-r--r--makefu/1systems/omo/config.nix1
-rw-r--r--makefu/2configs/bgt/download.binaergewitter.de.nix19
-rw-r--r--makefu/2configs/bureautomation/automation/bureau-shutdown.nix157
-rw-r--r--makefu/2configs/bureautomation/automation/hass-restart.nix65
-rw-r--r--makefu/2configs/bureautomation/automation/nachtlicht.nix71
-rw-r--r--makefu/2configs/bureautomation/automation/schlechteluft.nix130
-rw-r--r--makefu/2configs/bureautomation/binary_sensor/buttons.nix9
-rw-r--r--makefu/2configs/bureautomation/binary_sensor/motion.nix27
-rw-r--r--makefu/2configs/bureautomation/camera/comic.nix23
-rw-r--r--makefu/2configs/bureautomation/camera/stuttgart.nix42
-rw-r--r--makefu/2configs/bureautomation/camera/verkehrskamera.nix31
-rw-r--r--makefu/2configs/bureautomation/default.nix92
-rw-r--r--makefu/2configs/bureautomation/device_tracker/openwrt.nix29
-rw-r--r--makefu/2configs/bureautomation/light/buzzer.nix12
-rw-r--r--makefu/2configs/bureautomation/light/statuslight.nix14
-rw-r--r--makefu/2configs/bureautomation/multi/10h_timers.nix16
-rw-r--r--makefu/2configs/bureautomation/multi/README.md3
-rw-r--r--makefu/2configs/bureautomation/multi/aramark.nix21
-rw-r--r--makefu/2configs/bureautomation/multi/daily-standup.nix83
-rw-r--r--makefu/2configs/bureautomation/multi/frosch.nix158
-rw-r--r--makefu/2configs/bureautomation/multi/matrix.nix106
-rw-r--r--makefu/2configs/bureautomation/multi/mittagessen.nix93
-rw-r--r--makefu/2configs/bureautomation/person/team.nix153
-rw-r--r--makefu/2configs/bureautomation/script/multi_blink.nix73
-rw-r--r--makefu/2configs/bureautomation/sensor/airquality.nix21
-rw-r--r--makefu/2configs/bureautomation/sensor/espeasy.nix12
-rw-r--r--makefu/2configs/bureautomation/sensor/influxdb.nix18
-rw-r--r--makefu/2configs/bureautomation/sensor/outside.nix54
-rw-r--r--makefu/2configs/bureautomation/sensor/tasmota_firmware.nix5
-rw-r--r--makefu/2configs/bureautomation/switch/rfbridge.nix16
-rw-r--r--makefu/2configs/bureautomation/switch/tasmota_switch.nix17
-rw-r--r--makefu/2configs/default.nix3
-rw-r--r--makefu/2configs/editor/vim.nix4
-rw-r--r--makefu/2configs/gui/base.nix6
-rw-r--r--makefu/2configs/ham/automation/firetv_restart.nix52
-rw-r--r--makefu/2configs/ham/calendar/nextcloud.nix11
-rw-r--r--makefu/2configs/ham/default.nix72
-rw-r--r--makefu/2configs/ham/device_tracker/openwrt.nix23
-rw-r--r--makefu/2configs/ham/light/groups.nix41
-rw-r--r--makefu/2configs/ham/multi/fliegen-couter.nix100
-rw-r--r--makefu/2configs/ham/multi/kurzzeitwecker.nix223
-rw-r--r--makefu/2configs/ham/multi/the_playlist.nix139
-rw-r--r--makefu/2configs/ham/multi/zigbee2mqtt.nix127
-rw-r--r--makefu/2configs/ham/sensor/outside.nix45
-rw-r--r--makefu/2configs/ham/zigbee2mqtt/default.nix31
-rw-r--r--makefu/2configs/ham/zigbee2mqtt/hass.nix130
-rw-r--r--makefu/2configs/ham/zigbee2mqtt/osram.nix14
-rw-r--r--makefu/2configs/hw/tp-x2x0.nix23
-rw-r--r--makefu/2configs/sickbeard/sickgear.nix6
-rw-r--r--makefu/2configs/wireguard/server.nix4
-rw-r--r--makefu/3modules/snapraid.nix2
-rw-r--r--makefu/5pkgs/hactool/default.nix30
52 files changed, 1365 insertions, 1292 deletions
diff --git a/makefu/1systems/omo/config.nix b/makefu/1systems/omo/config.nix
index cbe97e28..a9e307dd 100644
--- a/makefu/1systems/omo/config.nix
+++ b/makefu/1systems/omo/config.nix
@@ -92,7 +92,6 @@ in {
<stockholm/makefu/2configs/bluetooth-mpd.nix>
<stockholm/makefu/2configs/ham>
- <stockholm/makefu/2configs/ham/zigbee2mqtt>
{
makefu.ps3netsrv = {
enable = true;
diff --git a/makefu/2configs/bgt/download.binaergewitter.de.nix b/makefu/2configs/bgt/download.binaergewitter.de.nix
index 77c9ddc8..4abc7d34 100644
--- a/makefu/2configs/bgt/download.binaergewitter.de.nix
+++ b/makefu/2configs/bgt/download.binaergewitter.de.nix
@@ -17,12 +17,14 @@ in {
PasswordAuthentication no
'';
};
+
users.users.auphonic = {
uid = genid "auphonic";
group = "nginx";
useDefaultShell = true;
openssh.authorizedKeys.keys = [ ident config.krebs.users.makefu.pubkey ];
};
+
services.logrotate = {
enable = true;
config = ''
@@ -36,6 +38,12 @@ in {
}
'';
};
+
+ # 20.09 unharden nginx to write logs
+ systemd.services.nginx.serviceConfig.ReadWritePaths = [
+ "/var/spool/nginx/logs/"
+ ];
+
services.nginx = {
appendHttpConfig = ''
types {
@@ -55,15 +63,4 @@ in {
'';
};
};
- environment.etc."netdata/python.d/web_log.conf".text = ''
- nginx_log3:
- name: 'nginx'
- path: '/var/spool/nginx/logs/access.log'
- nginx_log4:
- name: 'bgt'
- path: '${bgtaccess}'
- '';
-
- users.users.netdata.extraGroups = [ "nginx" ];
-
}
diff --git a/makefu/2configs/bureautomation/automation/bureau-shutdown.nix b/makefu/2configs/bureautomation/automation/bureau-shutdown.nix
index b9aa710c..f4c10adc 100644
--- a/makefu/2configs/bureautomation/automation/bureau-shutdown.nix
+++ b/makefu/2configs/bureautomation/automation/bureau-shutdown.nix
@@ -1,84 +1,87 @@
-[
- { alias = "Turn on Fernseher on group home";
- trigger = {
- platform = "state";
- entity_id = "group.team";
- from = "not_home";
- to = "home";
- for.seconds = 30;
- };
- action = [
- {
- service = "homeassistant.turn_on";
- entity_id = [
- "switch.fernseher"
- "switch.feuer"
- ];
- }
- {
- service = "media_player.kodi_call_method";
- data = {
- entity_id = "media_player.kodi";
- method = "Player.Open";
- item.partymode = "music";
- };
- }
- {
- service = "notify.telegrambot";
- data = {
- title = "Bureau Startup";
- message = "Das Büro wurde eröffnet";
- };
- }
- ];
- }
- { alias = "Turn off Fernseher after last in group left";
- trigger = [
- { # trigger when movement was detected at the time
+{
+ services.home-assistant.config.automation =
+ [
+ { alias = "Turn on Fernseher on group home";
+ trigger = {
platform = "state";
entity_id = "group.team";
- from = "home";
- to = "not_home";
- }
- { # trigger at 18:00 no matter what
- # to avoid 'everybody left before 18:00:00'
- platform = "time";
- at = "18:00:00";
- }
- ];
- action = [
- {
- service = "homeassistant.turn_off";
- entity_id = [
- "switch.fernseher"
- "switch.feuer"
- "light.status_felix"
- "light.status_daniel"
- ];
- }
- {
- service = "notify.telegrambot";
- data_template = {
- title = "Bureau Shutdown";
- message = "All devices are turned off due to {{ trigger.platform }}";
- };
- }
- ];
- condition =
- { condition = "and";
- conditions = [
+ from = "not_home";
+ to = "home";
+ for.seconds = 30;
+ };
+ action = [
+ {
+ service = "homeassistant.turn_on";
+ entity_id = [
+ "switch.fernseher"
+ "switch.feuer"
+ ];
+ }
{
- condition = "time";
- before = "06:30:00"; #only turn off between 6:30 and 18:00
- after = "18:00:00";
- # weekday = [ "mon" "tue" "wed" "thu" "fri" ];
+ service = "media_player.kodi_call_method";
+ data = {
+ entity_id = "media_player.kodi";
+ method = "Player.Open";
+ item.partymode = "music";
+ };
}
- { # if anybody is still there
- condition = "state";
+ {
+ service = "notify.telegrambot";
+ data = {
+ title = "Bureau Startup";
+ message = "Das Büro wurde eröffnet";
+ };
+ }
+ ];
+ }
+ { alias = "Turn off Fernseher after last in group left";
+ trigger = [
+ { # trigger when movement was detected at the time
+ platform = "state";
entity_id = "group.team";
- state = "not_home";
+ from = "home";
+ to = "not_home";
+ }
+ { # trigger at 18:00 no matter what
+ # to avoid 'everybody left before 18:00:00'
+ platform = "time";
+ at = "18:00:00";
}
];
- };
- }
-]
+ action = [
+ {
+ service = "homeassistant.turn_off";
+ entity_id = [
+ "switch.fernseher"
+ "switch.feuer"
+ "light.status_felix"
+ "light.status_daniel"
+ ];
+ }
+ {
+ service = "notify.telegrambot";
+ data_template = {
+ title = "Bureau Shutdown";
+ message = "All devices are turned off due to {{ trigger.platform }}";
+ };
+ }
+ ];
+ condition =
+ { condition = "and";
+ conditions = [
+ {
+ condition = "time";
+ before = "06:30:00"; #only turn off between 6:30 and 18:00
+ after = "18:00:00";
+ # weekday = [ "mon" "tue" "wed" "thu" "fri" ];
+ }
+ { # if anybody is still there
+ condition = "state";
+ entity_id = "group.team";
+ state = "not_home";
+ }
+ ];
+ };
+ }
+ ];
+}
diff --git a/makefu/2configs/bureautomation/automation/hass-restart.nix b/makefu/2configs/bureautomation/automation/hass-restart.nix
index be16f696..3b3ce059 100644
--- a/makefu/2configs/bureautomation/automation/hass-restart.nix
+++ b/makefu/2configs/bureautomation/automation/hass-restart.nix
@@ -1,31 +1,34 @@
-[
- { alias = "State on HA start-up";
- trigger = {
- platform = "homeassistant";
- event = "start";
- };
- action = [
- # Startup State
- { service = "mqtt.publish";
- data = {
- topic = "/bam/sonoffs/cmnd/state";
- payload = "";
- };
- }
- # Firmware Version
- { service = "mqtt.publish";
- data = {
- topic = "/bam/sonoffs/cmnd/status";
- payload = "2";
- };
- }
- # Will trigger restart of all devices!
- #{ service = "mqtt.publish";
- # data = {
- # topic = "sonoffs/cmnd/SetOption59"; # configure sending state on power change
- # payload = "1";
- # };
- #}
- ];
- }
-]
+{
+ services.home-assistant.config.automation =
+ [
+ { alias = "State on HA start-up";
+ trigger = {
+ platform = "homeassistant";
+ event = "start";
+ };
+ action = [
+ # Startup State
+ { service = "mqtt.publish";
+ data = {
+ topic = "/bam/sonoffs/cmnd/state";
+ payload = "";
+ };
+ }
+ # Firmware Version
+ { service = "mqtt.publish";
+ data = {
+ topic = "/bam/sonoffs/cmnd/status";
+ payload = "2";
+ };
+ }
+ # Will trigger restart of all devices!
+ #{ service = "mqtt.publish";
+ # data = {
+ # topic = "sonoffs/cmnd/SetOption59"; # configure sending state on power change
+ # payload = "1";
+ # };
+ #}
+ ];
+ }
+ ];
+}
diff --git a/makefu/2configs/bureautomation/automation/nachtlicht.nix b/makefu/2configs/bureautomation/automation/nachtlicht.nix
index ec6fa20c..ade89418 100644
--- a/makefu/2configs/bureautomation/automation/nachtlicht.nix
+++ b/makefu/2configs/bureautomation/automation/nachtlicht.nix
@@ -1,35 +1,38 @@
-[
- # TODO: trigger if it is before dusk and somebody arives but nachtlichter are
- # off from last day
- # TODO: do not have nachtlicht turned on at night
- {
- alias = "Turn on Nachtlicht at dusk"; # when it gets dim
- trigger =
- { platform = "numeric_state";
- entity_id = "sun.sun";
- value_template = "{{ state.attributes.elevation }}";
- below = 10;
+{
+ services.home-assistant.config.automation =
+ [
+ # TODO: trigger if it is before dusk and somebody arives but nachtlichter are
+ # off from last day
+ # TODO: do not have nachtlicht turned on at night
+ {
+ alias = "Turn on Nachtlicht at dusk"; # when it gets dim
+ trigger =
+ { platform = "numeric_state";
+ entity_id = "sun.sun";
+ value_template = "{{ state.attributes.elevation }}";
+ below = 10;
- };
- action =
- { service = "homeassistant.turn_on";
- entity_id = [ "group.nachtlicht" ];
- };
- }
- {
- alias = "Turn off Nachtlicht at dawn";
- trigger =
- { platform = "sun";
- event = "sunrise";
- offset = "01:30:00"; # on dawn
- };
- # TODO: when somebody is still in the buero
- # condition =
- #{
- #};
- action =
- { service = "homeassistant.turn_off";
- entity_id = [ "group.nachtlicht" ];
- };
- }
-]
+ };
+ action =
+ { service = "homeassistant.turn_on";
+ entity_id = [ "group.nachtlicht" ];
+ };
+ }
+ {
+ alias = "Turn off Nachtlicht at dawn";
+ trigger =
+ { platform = "sun";
+ event = "sunrise";
+ offset = "01:30:00"; # on dawn
+ };
+ # TODO: when somebody is still in the buero
+ # condition =
+ #{
+ #};
+ action =
+ { service = "homeassistant.turn_off";
+ entity_id = [ "group.nachtlicht" ];
+ };
+ }
+ ];
+}
diff --git a/makefu/2configs/bureautomation/automation/schlechteluft.nix b/makefu/2configs/bureautomation/automation/schlechteluft.nix
index 37033474..ea1d4451 100644
--- a/makefu/2configs/bureautomation/automation/schlechteluft.nix
+++ b/makefu/2configs/bureautomation/automation/schlechteluft.nix
@@ -1,71 +1,75 @@
let
long_threshold = 30;
-in [
- {
- alias = "Bad Air Alarm 60 seconds";
- trigger =
- { platform = "numeric_state";
- entity_id = "sensor.air_quality";
- above = 1523;
- for.seconds = 60;
- };
- condition = {
- condition = "and";
- conditions = [
- { condition = "state";
- entity_id = "group.team";
- state = "home";
- }
- { condition = "time";
- after = "06:00:00";
- before = "20:00:00";
+in
+{
+ services.home-assistant.config.automation =
+ [
+ {
+ alias = "Bad Air Alarm 60 seconds";
+ trigger =
+ { platform = "numeric_state";
+ entity_id = "sensor.air_quality";
+ above = 1523;
+ for.seconds = 60;
+ };
+ condition = {
+ condition = "and";
+ conditions = [
+ { condition = "state";
+ entity_id = "group.team";
+ state = "home";
+ }
+ { condition = "time";
+ after = "06:00:00";
+ before = "20:00:00";
+ }
+ ];
+ };
+
+ action = [
+ { service = "homeassistant.turn_on";
+ entity_id = [
+ "script.schlechteluft"
+ ];
}
];
- };
-
- action = [
- { service = "homeassistant.turn_on";
- entity_id = [
- "script.schlechteluft"
+ }
+ {
+ alias = "Bad Air Alarm ${toString long_threshold} Minutes";
+ trigger =
+ { platform = "numeric_state";
+ entity_id = "sensor.air_quality";
+ above = 1523;
+ for.minutes = long_threshold;
+ };
+ condition = {
+ condition = "and";
+ conditions = [
+ { condition = "state";
+ entity_id = "group.team";
+ state = "home";
+ }
+ { condition = "time";
+ after = "06:00:00";
+ before = "20:00:00";
+ }
];
- }
- ];
- }
- {
- alias = "Bad Air Alarm ${toString long_threshold} Minutes";
- trigger =
- { platform = "numeric_state";
- entity_id = "sensor.air_quality";
- above = 1523;
- for.minutes = long_threshold;
- };
- condition = {
- condition = "and";
- conditions = [
- { condition = "state";
- entity_id = "group.team";
- state = "home";
+ };
+
+ action = [
+ { service = "homeassistant.turn_on";
+ entity_id = [
+ "script.schlechteluft"
+ ];
}
- { condition = "time";
- after = "06:00:00";
- before = "20:00:00";
+ { service = "tts.google_say";
+ entity_id = "media_player.mpd";
+ data_template = {
+ message = "BEEP BEEP - Die luft ist schon ${toString long_threshold} Minuten schlecht! Student Nummer {{ range(1,500) | random }}, öffne ein Fenster.";
+ language = "de";
+ };
}
];
- };
-
- action = [
- { service = "homeassistant.turn_on";
- entity_id = [
- "script.schlechteluft"
- ];
- }
- { service = "tts.google_say";
- entity_id = "media_player.mpd";
- data_template = {
- message = "BEEP BEEP - Die luft ist schon ${toString long_threshold} Minuten schlecht! Student Nummer {{ range(1,500) | random }}, öffne ein Fenster.";
- language = "de";
- };
- }
- ];
- }
-]
+ }
+ ];
+}
diff --git a/makefu/2configs/bureautomation/binary_sensor/buttons.nix b/makefu/2configs/bureautomation/binary_sensor/buttons.nix
index e23c4a36..20590a6b 100644
--- a/makefu/2configs/bureautomation/binary_sensor/buttons.nix
+++ b/makefu/2configs/bureautomation/binary_sensor/buttons.nix
@@ -12,6 +12,9 @@ let
# expire_after = "5"; #expire after 5 seconds
qos = 1;
};
-in [
- (tasmota_button "RedButton" "redbutton")
-]
+in {
+ services.home-assistant.config.binary_sensor =
+ [
+ (tasmota_button "RedButton" "redbutton")
+ ];
+}
diff --git a/makefu/2configs/bureautomation/binary_sensor/motion.nix b/makefu/2configs/bureautomation/binary_sensor/motion.nix
index ad8fab03..0c5a808e 100644
--- a/makefu/2configs/bureautomation/binary_sensor/motion.nix
+++ b/makefu/2configs/bureautomation/binary_sensor/motion.nix
@@ -1,12 +1,15 @@
-[
- { platform = "mqtt";
- device_class = "motion";
- name = "Motion";
- state_topic = "/bam/easy2/movement/Switch";
- payload_on = "1";
- payload_off = "0";
- availability_topic = "/bam/easy2/tele/LWT";
- payload_available = "Online";
- payload_not_available = "Offline";
- }
-]
+{
+ services.home-assistant.config.binary_sensor =
+ [
+ { platform = "mqtt";
+ device_class = "motion";
+ name = "Motion";
+ state_topic = "/bam/easy2/movement/Switch";
+ payload_on = "1";
+ payload_off = "0";
+ availability_topic = "/bam/easy2/tele/LWT";
+ payload_available = "Online";
+ payload_not_available = "Offline";
+ }
+ ];
+}
diff --git a/makefu/2configs/bureautomation/camera/comic.nix b/makefu/2configs/bureautomation/camera/comic.nix
index a523d032..ae24760e 100644
--- a/makefu/2configs/bureautomation/camera/comic.nix
+++ b/makefu/2configs/bureautomation/camera/comic.nix
@@ -1,10 +1,13 @@
-[
- { name = "Poorly Drawn Lines";
- platform = "generic";
- still_image_url = http://127.0.0.1:8123/local/lines.png ;
- }
- { name = "XKCD";
- platform = "generic";
- still_image_url = http://127.0.0.1:8123/local/xkcd.png ;
- }
-]
+{
+ services.home-assistant.config.camera =
+ [
+ { name = "Poorly Drawn Lines";
+ platform = "generic";
+ still_image_url = http://127.0.0.1:8123/local/lines.png ;
+ }
+ { name = "XKCD";
+ platform = "generic";
+ still_image_url = http://127.0.0.1:8123/local/xkcd.png ;
+ }
+ ];
+}
diff --git a/makefu/2configs/bureautomation/camera/stuttgart.nix b/makefu/2configs/bureautomation/camera/stuttgart.nix
index 78cbeb3e..0badcb28 100644
--- a/makefu/2configs/bureautomation/camera/stuttgart.nix
+++ b/makefu/2configs/bureautomation/camera/stuttgart.nix
@@ -5,22 +5,26 @@ let
inherit name still_image_url;
platform = "generic";
};
-in [
- ( cam "Max-Eyth-See" https://www.wav-stuttgart.de/webcam/_/webcam1.jpg )
- ( cam "Wilhelma" http://webcam.wilhelma.de/webcam02/webcam02.jpg )
- ( cam "Marktplatz" https://webcam.stuttgart.de/wcam007/current.jpg )
- ( cam "Schoch Areal" https://webcam.stuttgart.de/wcam004/current.jpg )
- ( cam "Leuze" https://webcam.stuttgart.de/wcam005/current.jpg )
- ( cam "Straße Wilhelma" https://webcam.stuttgart.de/wcam006/current.jpg )
- ( cam "Fernsehturm 1" http://webcam.fernsehturmstuttgart.com/current.jpg )
- ( cam "Fernsehturm 2" http://webcam.fernsehturmstuttgart.com/current2.jpg )
- ( cam "Feuerbach Lemberg" http://www.regio7.de/handy/current.jpg )
- ( cam "Flughafen Stuttgart 1" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam2.jpg )
- ( cam "Flughafen Stuttgart 2" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam5.jpg )
- ( cam "Flughafen Stuttgart 3" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam7.jpg )
- ( cam "S21 1" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Turm-03/s21-turm03.jpg )
- ( cam "S21 2" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Turm-02/s21-turm-02.jpg )
- ( cam "S21 3" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Turm-01/s21-turm-01.jpg )
- ( cam "S21 4" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Jaegerstrasse-Nordkopf/s21-jaegerstrassse-nordkopf.jpg )
- ( cam "S21 5" http://webcam-bahnprojekt-stuttgart-ulm.de/S21-Bahndirektion-Nord/S21-Bundesbahndirektion-Nord.jpg )
-]
+in
+{
+ services.home-assistant.config.camera =
+ [
+ ( cam "Max-Eyth-See" https://www.wav-stuttgart.de/webcam/_/webcam1.jpg )
+ ( cam "Wilhelma" http://webcam.wilhelma.de/webcam02/webcam02.jpg )
+ ( cam "Marktplatz" https://webcam.stuttgart.de/wcam007/current.jpg )
+ ( cam "Schoch Areal" https://webcam.stuttgart.de/wcam004/current.jpg )
+ ( cam "Leuze" https://webcam.stuttgart.de/wcam005/current.jpg )
+ ( cam "Straße Wilhelma" https://webcam.stuttgart.de/wcam006/current.jpg )
+ ( cam "Fernsehturm 1" http://webcam.fernsehturmstuttgart.com/current.jpg )
+ ( cam "Fernsehturm 2" http://webcam.fernsehturmstuttgart.com/current2.jpg )
+ ( cam "Feuerbach Lemberg" http://www.regio7.de/handy/current.jpg )
+ ( cam "Flughafen Stuttgart 1" http://webcam.flughafen-stuttgart.de/Flughafen_Stuttgart_Webcam2.jpg )
+ ( cam "Flughafen Stuttgart 2" http://webcam.flughafen-stuttgart.