Wetter vorlesen lassen

Begonnen von hexenmeister, 09 November 2014, 23:04:52

Vorheriges Thema - Nächstes Thema

hexenmeister

Als ich Text2Speech Modul gesehen habe, hatte ich gleich einige Ideen, was man damit alles anfangen kann. :)
Eine davor war, die aktuellen Wetterdaten und die Vorhersage vorlesen zu lassen. Funktioniert wunderbar. Die entsprechenden Codefragmente habe ich in dem Modul-Thread zwar bereits gepostet, da jedoch diese dort kaum jemand später finden wird, habe ich mich entschlossen, das ganz noch mal hier zu wiederholen. Vielleicht findet noch jemand nützlich... ;)

Also der Reihe nach...

Zuerst die notwendigen FHEM-Devices:
1. Das Text2Speak-Device heißt bei mir 'tts'
2. Mein Temperatur/Feuchte-Sensor heißt 'GSD_1.4'
3. Das Weather-Modul heißt 'Wetter'
(Die Namen könnt ihr natürlich leicht anpassen. s. weiter...)

Jetzt der Code, packt den in irgendein Modul, 99_myUtils.pm ist ok.

Die Konstanten, die die Geräte-Namen festlegen:
use constant {
  DEVICE_NAME_TTS    => "tts",
  DEVICE_NAME_TH      => "GSD_1.4",
  DEVICE_NAME_WEATHER => "Wetter",
};


Die zwei Methoden, die die eigentliche Sprachausgabe auslösen: speakWetterDaten(;$) und speakWetterVorhersage(;$).
Zum Testen kann man sie (wenn alles fertig eingetragen ist) direkt in der FHEM-Console (oder eben in der Commandline des Webinterfaces) eingeben:
{speakWetterDaten()}
und
{speakWetterVorhersage()}
Beide haben optionale Parameter, diese sind im Quellcode beschrieben.
###############################################################################
# Sagt Wetterdaten an
#  Param: Art: Variante der Aussage:
#         0: Kurzansage, 1: Normal
###############################################################################
sub speakWetterDaten(;$) {
my($art)=@_;
if(!defined($art)){$art=1;}
# TODO: Sauber / Abstraktionslayer erstellen
my $temp = prepareNumToSpeak(rundeZahl0(ReadingsVal(+DEVICE_NAME_TH,"temperature","unbekannt")));
my $humi = prepareNumToSpeak(rundeZahl0(ReadingsVal(+DEVICE_NAME_TH,"humidity","unbekannt")));
if($art==0) {
    #speak("Aussentemperatur ".$temp." Grad. Feuchtigkeit ".$humi." Prozent.",0);
    speak($temp." Grad. Feuchtigkeit ".$humi." Prozent.",0);
  }
  if($art==1) {
    #speak("Die Aussentemperatur betraegt ".$temp." Grad. Die Luftfeuchtigkeit liegt bei ".$humi." Prozent.",0);
    speak("Temperatur ".$temp." Grad. Luftfeuchtigkeit ".$humi." Prozent.",0);
  }
}

###############################################################################
# Sagt Wettervorhersage an.
#  Parameter: Tag: Zahl 1-5 (1-heute, 2-morgen,...) Defaul=2
###############################################################################
sub speakWetterVorhersage(;$) {
my ($day) = @_;
if(!defined($day)) {$day=2;}

# TODO: Sauber / Abstraktionslayer erstellen
my $t1= ReadingsVal(+DEVICE_NAME_WEATHER,"fc".$day."_condition",undef);
my $t2= ReadingsVal(+DEVICE_NAME_WEATHER,"fc".$day."_low_c",undef);
my $t3= ReadingsVal(+DEVICE_NAME_WEATHER,"fc".$day."_high_c",undef);

my $text = "";
if($day==1) {
#$text = "Wetter heute ";
$text = "Heute ";
}
if($day==2) {
$text = "Morgen ";
}
if($day==3) {
$text = "Uebermorgen ";
}
if($day>3) {
$text = "Wetter in ".($day-1)." Tagen ";
}
if(defined($t1) && defined($t2) && defined($t3)) {
  $text.=$t1.". ";
  $text.="Temperatur von ".$t2." bis ".$t3." Grad.";
  if($day==1) {
  # gefuehlte Temperatur
  my $tg= ReadingsVal(+DEVICE_NAME_WEATHER,"wind_chill",undef);
  #$text.="Gefuehlte Temperatur aktuell ".$tg." Grad.";
  $text.="Gefuehlte ".$tg." Grad.";
  my $tw= ReadingsVal(+DEVICE_NAME_WEATHER,"wind_speed",undef);
  #$text.="Windgeschwindigkeit ".$tw." Kilometer pro Stunde.";
  $text.="Wind ".$tw." Kilometer pro Stunde.";
  }
} else {
$text="Leider keine Vorhersage verfuegbar.";
}

speak($text,0);
}


und dann noch etwas an notwendigen Hilfsroutinen:
###############################################################################
# Bereitet Zahlen zur Ansage auf.
# Ersetzt Kommas und Punkte durch das Wort 'Komma'.
###############################################################################
sub prepareNumToSpeak($) {
my($text) = @_;
$text =~ s/\./Komma/g;
  $text =~ s/,/Komma/g;
return $text;
}

# Rundet eine Zahl ohne Nachkommastellen
sub rundeZahl0($) {
my($val)=@_;
# Prüfen, ob numerisch
if(int($val)>0) {
$val = int($val+0.5);
}
return $val;
}

# Rundet eine Zahl mit 1-er Nachkommastelle
sub rundeZahl1($) {
my($val)=@_;
# Prüfen, ob numerisch
if(int($val)>0) {
$val = int(10*$val+0.5)/10;
}
return $val;
}

###############################################################################
# Bereitet Texte zur Ansage auf.
# Ersetzt Umlaute (ä=ae etc.)
###############################################################################
sub prepareTextToSpeak($) {
my($text) = @_;
# TODO: Ist halt noch nicht fertig geworden ;)
return $text;
}


ja, und dann die Methode, die den TTS-Modul anspricht. Die Lautstärke wird je nach Tageszeit geändert (also Nachts leiser etc.)
######################################################
# Sprachausgabe ueber Text2Speak Modul
#  Parameter:
#   - text: Auszugebender Text
#   - volume (optional) - Lautstaerke
#     (wenn nicht vorhaneden: wird aktuell gesetzte
#      Lautstaerke benutzt,
#      wenn 1 oder groesser: dieser Wert wird benutzt,
#      wenn 0: adaptiv gesetzt je nach Fageszeit
#              (also Nachts wesentlich leiser)
#       (ggf. spaeter adaptiv durch ermitteln der Zimmerlautstaerke)
######################################################
sub speak($;$) {
my($text,$volume)=@_;
if(defined ($volume)) {
if(int($volume) >=1) {
      fhem("set ".+DEVICE_NAME_TTS." volume ".$volume);
    } else {
    if(int($volume) == 0) {
    # Adaptiv
    my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime;
    # 5 - sehr leise
    # 10 - ok
    # 50 - gut hoerbar
    # 100 - default / gut laut
    #
    # 20:00 - 22:00 => 10
    # 22:00 - 05:00 =>  5
    # 05:00 - 07:00 => 10
    # 07:00 - 08:00 => 50
    # 08:00 - 20:00 => 100
    if ($hour>=20 && $hour<22) {$volume=18}
    if ($hour>=22 || $hour<5)  {$volume=8}
    if ($hour>=5  && $hour<7)  {$volume=15}
    if ($hour>=7  && $hour<8)  {$volume=40}
    if ($hour>=8  && $hour<20)  {$volume=100}
   
    fhem("set ".+DEVICE_NAME_TTS." volume ".$volume);
      }
    }
  }
fhem("set ".+DEVICE_NAME_TTS." tts ".prepareTextToSpeak($text));
}


Ich hoffe, ich habe nichts vergessen...


Wie kann man das Ganze sinnvoll einsetzen? Na zum Beispiel indem man die Methoden auf ein Funkbutton oder ein Bewegungsmelder legt und sich so jeden Morgen nach dem Aufstehen auf die Welt da draußen vorbereiten lässt  ;D

Was braucht man an Hardware? Außer Wettersensoren werden aktive Boxen oder etwas in der Art benötigt, die an den Line-Out Ausgang des Rechners angeschlossen werden. Und natürlich etwas zum Aktivieren der Ansage.
Ich nutze einen in der Wand installierten Lautsprecher (http://www.pollin.de/shop/dt/MDI2OTUzOTk-/HiFi_Car_HiFi_Video_TV/Lautsprecher/Lautsprecherboxen/Decken_Einbau_Lautsprecher.html, lässt sich in einer tiefen UP-Dose installieren) der über eine kleine 3Watt Verstärkerplatine an meinen Cubietruck angeschlossen ist.

In der Zwischenzeit habe ich ein anderes interessantes Modul zur Wettervorharsage gesehen (PROPLANTA). Muss ich mir später genauer ansehen und ggf. auch für die Sprachausgabe verwenden.

Weiterhin lasse ich mir den Status der Fenster (ob welche geöffnet/gekippt sind, wie viele und wo) bei Verlassen des Hauses vorlesen und die Dauer der Abwesenheit beim Zurückkommen, habe auch einige Sonderschaltungen (z.B. einen ganz anderen Ton der Türklingel zum Halloween), aber das ist schon ein weiteres Thema...


Grüße,

Alexander

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Markus

Raspberry Pi2 als FHEM-Plattform
HM, FS20, 1-Wire, PanStamp,LW12,Intertechno,ESPEasy,Alexa

hexenmeister

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Rince

Sehr schick :)
Wäre was für das Wiki, meinst nicht?
Wer zu meinen Posts eine Frage schreibt und auf eine Antwort wartet, ist hiermit herzlich eingeladen mich per PN darauf aufmerksam zu machen. (Bitte mit Link zum betreffenden Thread)

hexenmeister

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Rince

Erst mal Danke :)

Zitat{speakWetterDaten()}

Da war mal was...
Ich muss mich nur wieder erinnern wie ich es damals gemacht hatte:
Mit einem Dummy und einem Notify dazu könntest du es einfach mit einem
Zitatset TTS_Wetter heute
aufrufen

(hoffe das war jetzt kein kompletter Unsinn; wenn ich Zeit finde, probiere ich das mal aus)
Wer zu meinen Posts eine Frage schreibt und auf eine Antwort wartet, ist hiermit herzlich eingeladen mich per PN darauf aufmerksam zu machen. (Bitte mit Link zum betreffenden Thread)

Rince

#6
Ungetestet:

Wir brauchen einen Dummy:
define TTS_Wetter_Heute dummy

Ein Notify welches auf den Dummy reagiert
define TTS_Wetter_Heute_Vorlesen notify TTS_Wetter_Heute {speakWetterDaten($EVENT)}


Dann müsste es so gehen:
set TTS_Wetter_Heute
set TTS_Wetter_Heute 0
set TTS_Wetter_Heute 1


Wie gesagt, ungetestet, habe das noch nicht am laufen. Vielleicht testet es mal wer?

Solange man nicht auf SAVE klickt, ist nach einem Neustart alles wieder weg ;)
Wer zu meinen Posts eine Frage schreibt und auf eine Antwort wartet, ist hiermit herzlich eingeladen mich per PN darauf aufmerksam zu machen. (Bitte mit Link zum betreffenden Thread)

hexenmeister

Auf den ersten Blick muss das so gehen, aber was ist die Anwendung dafür? Irgendwas mit WebCMD in Webinterface? Oder wo ist es nicht einfacher, direkt eine Perl-Funktion aufzurufen?

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Rince

Soll ich das Posting wieder löschen?
Wer zu meinen Posts eine Frage schreibt und auf eine Antwort wartet, ist hiermit herzlich eingeladen mich per PN darauf aufmerksam zu machen. (Bitte mit Link zum betreffenden Thread)

hexenmeister

Nein, wieso?
Das war überhaupt keine Kritik. Ich war nur neugierig. ;) Villeicht habe ich eine nützliche Möglichkeit der Verwendung übersehen (passiert mir gat nicht so selten, betriebsblind ;D )
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Rince

Dann bitte ich um Entschuldigung. Hatte es tatsächlich als Kritik aufgefasst und war deshalb ziemlich erstaunt, da ich dies nicht erwartet hatte.

Was den Einsatz angeht:
Viele Beispiele in der Commandref sind z.B. fhem-Syntax, nicht Perl.

Gerade für Anfänger dürfte es so leichter sein, denke ich wenigstens.


Hast du mal ausprobiert ob es so überhaupt stimmt? Würde mich interessieren :)
(Ich kann leider im Moment nicht)

Wer zu meinen Posts eine Frage schreibt und auf eine Antwort wartet, ist hiermit herzlich eingeladen mich per PN darauf aufmerksam zu machen. (Bitte mit Link zum betreffenden Thread)

hexenmeister

So entstehen Missverständnisse :o
Tut mir leid, wenn meine Antwort unhöflich klang. :(

Die Anweisungen habe ich gerade getestet.
set TTS_Wetter_Heute funktioniert so natürlich nicht, das FHEM an dieser stelle ein Wert erwartet (no set value specified), aber mit 0 oder 1 tut das wie gewünscht. Ich denke, damit könnte man z.B. ein Button auf der Weboberfläche herzaubern.

Grüße,

Alexander
Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Rince

Schwamm drüber :)


Danke fürs ausprobieren :)

Du hast recht. Ohne Parameter ist Asche.


Magst den Dummy und das Notify noch ins Wiki dazuschreiben?

Oder wie bauen es schnell noch aus. Mit einem WebCmd und einer EventMap
Wer zu meinen Posts eine Frage schreibt und auf eine Antwort wartet, ist hiermit herzlich eingeladen mich per PN darauf aufmerksam zu machen. (Bitte mit Link zum betreffenden Thread)

hexenmeister

Ja, ich denke, mit WebCmd und EventMap wird sich das ganz gut im Wiki machen ;)

Maintainer: MQTT_GENERIC_BRIDGE, SYSMON, SMARTMON, systemd_watchdog, MQTT, MQTT_DEVICE, MQTT_BRIDGE
Contrib: dev_proxy

Elbgeist

#14
Hallo,

ich habe das so wie beschrieben eingebaut. Was mich irritiert ist diese Konstante "unbekannt".
my $temp = prepareNumToSpeak(rundeZahl0(ReadingsVal(+DEVICE_NAME_TH,"temperature","unbekannt")));
my $humi = prepareNumToSpeak(rundeZahl0(ReadingsVal(+DEVICE_NAME_TH,"humidity","unbekannt")));

Was muss dort stehen?
Denn vorgelesen wird das Wetter nicht.
Immer diese Anfängerfehler, sorry.

Danke
Thomas