Zeitansage-Script + Datumsansage-Script

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Habe zwei kleine Scripte geschrieben, die für manch einen ganz nützlich sein könnten. Vor allem, wenn man an einem RPi-Radiowecker oder ähnlichem arbeitet. Sollte jemand Lust haben ein Zeitansage- oder Datumsansage-Shellscript für eine andere Sprache (Englisch, Französisch, Spanisch...) zu schreiben, könnte man ja eine kleine Sammlung daraus machen. Ich habe selbst nur wenig Ahnung vom Programmieren und das ganze einfach mal zusammengehackt. Eignet sich also gut für Anfänger.

  • Hehe... Das is ja witzig.
    Genau sowas hatte ich noch gebraucht.
    Bisher hatte ich für Zeit und Datum einzelne Soundfiles erstellt und die mithilfe einer kleinen Routine zusammengesetzt. Mir war klar, das es eine Sprachausgabe geben müsste, hatte bisher aber noch nicht danach gesucht. Denn mit meinem jetzigem System kann ich die Stimme auch selber einsprechen.

    Die Stimme von dem Onkel ist zwar nicht so angenehm wie meine Google-Tante, lässt sich aber wunderbar für ungeplante Sprachausgabe nutzen (neue Radiosender oder vorlesen von Radiotext z.B.).

    Echt geil! Danke dafür!:danke_ATDE:

    Vllt. sollte man für Anfänger noch erwähnen das man espeak installieren und die Datei ausführbar machen muss.

    Code
    sudo apt-get install espeak
    sudo chmod +x tts_date_de1.sh
    ./tts_date_de1.sh

    ...and write down with pencil&paper...
    Where can i download "pencil&paper" ?

  • Hi...
    ist ja ne lustige Idee, aber wäre eine case-Anweisung in diesem Fall nicht effizienter als die ganzen if-Anweisungen?
    Also:


    Einmal editiert, zuletzt von BooStar (5. März 2014 um 23:44)

  • LieberScholli: Danke für deine Ergänzungen zur Scriptausführung. Freut mich ja, dass dir das Script nützt.
    BooStar: Habe mir eben mal angeschaut, wie das mit case-Anweisungen funktioniert und das ganze gleich mal ausprobiert. Ist wirklich deutlich übersichtlicher!

    Falls sich jemand wundert, warum die eSpeak-Ausgabe in eine wave-Datei umgeleitet wird, welche dann vom omxplayer wiedergegeben und am Ende gelöscht wird: Die direkte eSpeak-Ausgabe läuft manchmal nicht ganz optimal.

    Code
    espeak -vde "Es ist $hours Uhr $minutes." -w tts_time_de1
    omxplayer tts_time_de1
    rm tts_time_de1


    Es würde aber theoretisch auch so funktionieren:

    Code
    espeak -vde "Es ist $hours Uhr $minutes."

    Die neue Version von tts_date_de1.sh mit case-Anweisungen hab ich an den Beitrag drangehängt.

  • Ich versteh nicht ganz wieso in der tts_time_de1.sh date +%k genutzt wird?

    Wieso wird das überhaupt teilweise in Worte verändert aber teilweise bleibt es bei Zahlen :huh:

    Anfängerfreundlich wäre es wenn in den Scripts Kommentare stünden wieso etwas gemacht wird... :D


    Aber wirklich super und vorbildlich das du deinen Code der Community ungefragt bereitstellst :thumbs1:

    das ist leider keine Selbstverständlichkeit mehr, sondern nimmt sogar leider immer weiter ab :( Fragen wie was umgesetzt werden kann gibts zu hauf aber letzlich die Umsetzung oder das Ergebnis wird für sich behalten :baeh2: :no_sad:

  • Zitat


    Ich versteh nicht ganz wieso in der tts_time_de1.sh date +%k genutzt wird?

    Ich auch nicht. ;) Wie gesagt, ich hab das einfach mal so zusammengehackt und es funktioniert auch ohne Fehler, aber dass einiges logisch nicht ganz konsistent ist, war mir gleich klar. Ich hab vorher so gut wie nichts selbst programmiert.

    Code
    if [ "`date +%k`" = "1" ]; then
     hours=ein
    else
     hours=`date +%k`
    fi


    Aber der Hinweis ist, glaube ich ganz gut. Es gibt bei date 4 Varianten für Stundenangaben:

    %H Stunde (00..23).
    %I Stunde (01..12).
    %k Stunde, mit Leerzeichen auf zwei Stellen aufgefüllt ( 0..23).
    %l Stunde, mit Leerzeichen auf zwei Stellen aufgefüllt ( 1..12).

    und dann gibt es ja noch = und ==.

    Ich hab generell %k benutzt, weil hier 1,2,3,4 gezählt wird und nicht 01,02,03,04 wie beispielsweise bei %H. eSpeak würde im Fall von

    Code
    hours=`date +%H`

    nicht "Es ist zwei Uhr..." lesen, sondern es ist "Es ist null zwei Uhr..." ausgeben.


    Zitat


    Wieso wird das überhaupt teilweise in Worte verändert aber teilweise bleibt es bei Zahlen icon_question2.gif

    Also Worte werden immer dann verwendet wenn eSpeak das sonst falsch aussprechen würde.

    Zitat


    Anfängerfreundlich wäre es wenn in den Scripts Kommentare stünden wieso etwas gemacht wird... icon_biggrin2.gif

    Mach ich vielleicht noch. Wollte mir erst einmal anschauen, wie andere ihre Scripte so durchkommentieren. Ich bin ja selbst Anfänger und da ich es hinbekommen habe, es zu schreiben, sollte eigentlich jeder der die manpages von date und espeak lesen kann, und sich kurz mit Shellscripten beschäftigt, nach einer Weile eine nette Stimme aus seinen Lautsprechern hören. :D
    Man könnte nämlich noch weitere Varianten schreiben, wie z.B. "Es ist viertel nach acht.".
    Deshalb die Namensgebung:

    tts Text-to-Speech
    time ist klar, aber ich hab auch noch ein halbfertiges Script für "Guten morgen." "Guten Abend"... für die jeweilige Tageszeit. Deswegen könnte man auch hier noch greetings-Scripte und ähnliches basteln.
    de1
    weitere Varianten wären dann en, es, fr, --> Englisch, Spanisch, Französisch
    oder de2 für die "Es ist viertel nach acht."-Version und so weiter.

    Einmal editiert, zuletzt von belvsdragon (6. März 2014 um 13:32)

  • Wenn ihr das für Multilanguage umschreiben wollt kann ich euch eine einfache Vorlage geben mit der ihr nur ein Script benötigen würdet :) hoffe nur das ich das verständlich genug Beschreiben kann :D


    Also was man nur bräuchte wäre ein Script was die Ausgabe macht und in dem die Sprache festgelegt wird - optional könnte man aber auch zusätzlich eine Konfigurationsdatei anlegen in der die Sprache festgelegt wird..

    Dann erstellt man Language Files in denen die Sätze hinterlegt sind aber mit einheitlichen Variablen, also zum Beispiel:

    lang_de.sh

    Code
    TodayIs="Heute ist"
    The="der"
    ItIs="Es ist"
    Clock="Uhr"

    lang_en.sh

    Code
    TodayIs="Today is"
    The="the"
    ItIs="It is"
    Clock="clock"

    Und im eigentlichen Script prüft man dann welche Language eingestellt wurde und inkludiert dann das entsprechende Language-File:

    tts_time.sh


    Die Schreibweise der for Schleife ist Absicht, also insbesondere der Punkt und das Leerzeichen ist hierbei wichtig, da wir das Script nicht ausführen sondern einlesen, also dessen Variablen inkludieren, wollen

    Auf diese Art braucht ihr quasi nur lang_X.sh zu erstellen ;)

  • Prinzipiell finde ich die Idee ziemlich gut. Das hätte den Vorteil, dass man relativ einfach andere Sprachen hinzufügen könnte. Ich bin mir nur nicht sicher ob das so funktioniert. Aus dem Bauch heraus würde ich jetzt darauf tippen, dass einem an irgendeiner Stelle die Syntax irgendeiner Sprach einen Strich durch die Rechnung macht und man am Ende dann doch wieder diese Zeile hier anders schreiben muss:

    Code
    espeak -vde "${ItIs} $hours ${Clock} $minutes." -w tts_time_1

    Deswegen würde ich jetzt eher dazu tendieren, die Scripte einzeln zu lassen. Aber ich muss auch zugeben, dass ich die for-Schleife nicht wirklich kapiere. Muss ich mir mal genauer anschauen. Kann also auch sein, dass es am Verständnis liegt.


  • Aus dem Bauch heraus würde ich jetzt darauf tippen, dass einem an irgendeiner Stelle die Syntax irgendeiner Sprach einen Strich durch die Rechnung macht und man am Ende dann doch wieder diese Zeile hier anders schreiben muss:

    Code
    espeak -vde "${ItIs} $hours ${Clock} $minutes." -w tts_time_1

    Das versteh ich jetzt irgendwie nich :huh:
    Selbst wenn der Satzbau in einer anderen Sprache anders wäre, könnte man das flexibel regeln - habe mir die Mühe jetzt nur nicht gemacht ums nicht allzu kompliziert wirken zu lassen ;)

    Man kann mit 'Platzhalter'n arbeiten und in den lang_X.sh Dateien die vollständigen Sätze mit Platzhalter einfügen. Im Script wird dann der Platzhalter mit der entsprechenden Variablen ersetzt und friedefreudeeierkuchen :D


    lang_de.sh

    Code
    TIME="Es ist %HOUR% %CLOCK% %MINUTE%"
    DATE="Heute ist %DAYNAME% %THE% %DAY% %MONNAME% %YEAR%."
    THE="der"
    CLOCK="Uhr"

    lang_en.sh

    Code
    TIME="It is %HOUR% %CLOCK% %MINUTE%"
    DATE="Today is %DAYNAME% %THE% %DAY% %MONNAME% %YEAR%."
    THE="the"
    CLOCK="clock"

    tts_time.sh

    Spoiler anzeigen

    tts_date.sh

    Spoiler anzeigen
  • Zitat


    Das versteh ich jetzt irgendwie nich icon_question2.gif
    Selbst wenn der Satzbau in einer anderen Sprache anders wäre, könnte man das flexibel regeln - habe mir die Mühe jetzt nur nicht gemacht ums nicht allzu kompliziert wirken zu lassen icon_wink.gif

    Man kann mit 'Platzhalter'n arbeiten und in den lang_X.sh Dateien die vollständigen Sätze mit Platzhalter einfügen. Im Script wird dann der Platzhalter mit der entsprechenden Variablen ersetzt und friedefreudeeierkuchen icon_biggrin2.gif

    Also ich glaube, das ist jetzt alles nicht mehr so ganz mein Level. Aber ich würd mich freuen, wenn du das ganze weiterentwickelst.

    Ich finde, man könnte ja mal eine Shell-Scripte Sammlung für den Raspberry Pi machen. Es gibt ja einige nützliche Sachen, die nur ziemlich verstreut im Netz herumliegen. Und da das meiste unter CC oder ähnlichen Lizensen steht wäre es ja ganz praktisch das alles mal zu einem Paket zu verschnüren. Mir fällt da zum Beispiel Bashpodder ein (http://lincgeek.org/bashpodder/)...

    Einmal editiert, zuletzt von belvsdragon (8. März 2014 um 23:15)

  • Was nicht ist kann ja noch werden ;)

    Eigentlich ist das nicht sooo schwer, ich versuchs mal zu erklärn was das alles so macht:

    Code
    for l in $(ls lang_*); do
        lang=$(echo $l | sed 's/lang_//g')
        if [ "$DEFAULTlanguage" == "$(basename $lang .sh)" ]; then
            . $l
            break
        fi
    done

    Die for Schleife dreht sich halt für den "in" Inhalt im Kreis, arbeitet das also ab.

    $(ls lang_*) ... enthält die Rückgabe des Befehls ls lang_* , es werden also im aktuellen Verzeichnis alle Dateien gelistet die auf lang_* zutreffen: lang_de.sh lang_en.sh usw
    $( ) ist vergleichbar mit ``man könnte das also auch so schreiben: `ls lang_*` ... nur finde ich meine gewählte Schreibweise übersichtlicher, als würde man eben eine Variable nutzen ;)

    lang=$(echo $l | sed 's/lang_//g') ... dort wird von der for Schleife $l ausgegeben und an den sed Befehl gepiped (übergeben). Der sed Befehl ersetzt alle Vorkommen von lang_ und ersetzt es mit <nichts>, es wird also rausgelöscht -> lang_de.sh wird dadurch zu de.sh

    if [ "$DEFAULTlanguage" == "$(basename $lang .sh)" ]; then ... if-Bedingungsvergleich kennste ja scho..
    'The Magic' hierbei ist denk ich $(basename $lang .sh) -> basename ist ein allgemeiner Befehl (wie auch dirname) welcher aus einer Pfadangabe nur den Dateinamen ausgibt und der 2.Parameter .sh sorgt dafür dass die Dateiendung .sh ebenfalls rausgeschnitten wird. Würde man zum Beispiel basename /var/log/auth.log in die Konsole eingeben würde er nur auth.log zurück geben. Würde man basename /var/log/auth.log .log eingeben käme nur auth zurück..
    Dadurch erreicht man also das aus der zuvor bearbeiteten $l -> lang_de.sh -> de.sh und dann nur noch -> de wird, und somit für den if Vergleich erst brauchbar wäre ;)
    Ist die if Bedingung erfüllt wird . $l geladen -> lang_de.sh ... Das ist hierbei wie gesagt kein Ausführen sondern Inkludieren, wir fügen also den Inhalt der Datei in das aktuelle Script mit ein. Die Dateien könnten auch ohne Dateiendung sein das würde keine Rolle spielen.
    Anschließend unterbrechen und beenden wir die for Schleife mithilfe von break , da wir ja eine passende Datei gefunden haben brauchen wir auch nicht noch mehr Zeit/CPU-last verschwenden :)
    (man könnte auch continue nutzen dann würde er weiter unten stehenden Code nicht mehr beachten und zum nächsten for-Durchlauf springen - aber das nur nebenbei)


    Das nächste was denk ich unklar ist wären dann diese Platzhalter:

    Code
    TIME=${TIME//%HOUR%/$hours}

    Dies ist eine allgemeine bash Funktion, sh kann das noch nicht (bash ist neuer als sh), und ist ein spezieller Umgang mit Variablen - das macht im Prinzip das selbe wie beim zuvor behandelten sed Befehl -> Es ersetzt ein Vorkommen:
    Der Inhalt der Variable $TIME wird nach %HOUR% durchsucht und alle Vorkommen werden durch den Inhalt der Variablen $hours ersetzt
    Wenn $hour=12 und TIME="Es ist %HOUR% %CLOCK% %MINUTE%" ist dann durchsucht er "Es ist %HOUR% %CLOCK% %MINUTE%" nach %HOUR% und ersetzt dies durch den Variablen-Inhalt von $hours -> "Es ist 12 %CLOCK% %MINUTE%"


    Verstanden? :huh:

  • Das ist wirklich mal eine super Erklärung! Die for-Schleife, sed, basename und das mit dem Inkludieren hab ich soweit verstanden. Das mit

    Code
    TIME=${TIME//%HOUR%/$hours}


    muss ich mir nochmal näher anschauen. Trotzdem: Wieder was gelernt! :)
    Ich hab mal ein paar Fragen/Aussagen versammelt, die dafür Sprechen würden doch Einzelscripte zu verwenden. So ganz will mir dieser Ansatz nämlich nicht aus dem Kopf gehen. :D


    Was ist, wenn ich verschiedene Cronjobs anlegen will und zu verschiedenen Tageszeiten unterschiedliche Sprachen bei der Zeitansage nehmen will?
    Ist das dann nicht flexibler für jede Sprache ein einzelnes Script zu nehmen?

    Würde das nicht auch mehr dem KISS-Prinzip entsprechen?
    Wenn ich mich schon schwer mit der Auslagerung in verschiedene Sprachdateien tue... Wäre bestimmt anfängerfreundlicher.

    Ich sehe die Hackability des ganzen auch größer, wenn jedes Script für sich funktioniert und einfach in ein anderes Script reinkopiert werden kann.

    Verständnisfrage: Wenn die ganzen If-Anweisungen für sprachliche Unregelmäßigkeiten wie das "Es ist ein(s) Uhr"-Problem auch in die Sprachdateien wandern, ist dann das Hauptscript sowieso nicht ziemlich leer?

    Wird das nicht ziemlich unübersichtlich, wenn man für eine Sprache 3 verschiedene Versionen macht und alles einer Datei versammelt?

    Einmal editiert, zuletzt von belvsdragon (12. März 2014 um 17:00)

  • Wie auch an Befehle kannst du auch an Scripte sog. Parameter (oder Argumente) übergeben. Wie zum Beispiel beim Befehl ls mit dem Zusatz -la --> ls -la ... dann wäre -la ein Parameter für ls

    Parameter werden durch Leerzeichen getrennt, also jedes Leerzeichen zwischen den Parametern kennzeichnet ein weiteren Parameter, nur mal als Beispiel: befehl a b c d
    Dann ist a der erste Parameter, b der 2.Parameter, c der 3.Parameter usw

    Beim bash Script wird das anhand von $1 fürs 1. Parameter, $2 fürs 2. Parameter, $3 fürs dritte usw - oder $* bzw $@ für alle...

    Nur nebenbei erwähnt: Wenn man nicht das erste aber flexibel alle weiteren Parameter weiter nutzen will kann man folgendes nutzen:

    Code
    echo $@ | cut -d' ' -f2-

    cut "schneidet" etwas aus, erkennt das anhand eines Leerzeichens (-d ' ' ) und gibt dann nur die Felder 2 bis Ende aus ( -f 2- )


    Man könnte das Script also so gestalten dass wenn ein Parameter übergeben wird eine bestimmte Aktion auszuführen:

    Bash
    #!/bin/bash
    
    
    if [ ! -z "$1" ]; then
      echo $1
      exit 0
    fi
    
    
    ...other code...

    wenn also ein 1.Parameter übergeben wurde, also $1 nicht leer ist (anstatt ! -z könnte man auch -n nutzen), wird das echo ausgeführt und danach das Script beendet.. Wenn $1 aber leer oder nicht gesetzt (also nicht übergeben) wurde, wird der nachfolgende Code ausgeführt


    Bezüglich "Es ist ein(s) Uhr"-Problem: Die if Schleife auch noch in die Sprachdateien auszulagern würde in diesem Fall nichts bringen, also nicht die if schleifen ansich, da an die lang_de.sh Dateien keine Parameter übergeben werden sondern nur der Inhalt der Datei ausgelesen wird


    Eigentlich programmiert man modular bzw mit Templates. Sprachen kann man so einfacher hinzufügen als jedesmal den Quellcode des "Programms" duplizieren zu müssen. Ausserdem will man nicht 20x den eigentlichen Code bearbeiten/verändern/optimieren sondern eben nur ein mal ;) Immer wiederkehrende Abläufe packet man zB auch in sog. Functions (Anweisungen), damit man diese nicht 20x bearbeiten muss wenns dort nen Fehler gab oder man diese erweitern möchte sondern eben nur ein mal und der Aufruf bleibt gleich..
    Also zum Beispiel:

    Bash
    #!/bin/bash
    
    
    free_() {
      df -h
      free -m
    }
    
    
    echo "Freie Resourcen:"; free_
  • Ich finde, man könnte ja mal eine Shell-Scripte Sammlung für den Raspberry Pi machen. Es gibt ja einige nützliche Sachen, die nur ziemlich verstreut im Netz herumliegen.

    Das würde ich auch begrüßen. Hätte auch das ein oder andere Skript zum einstellen :thumbs1:

  • Zitat

    Eigentlich programmiert man modular bzw mit Templates. Sprachen kann man so einfacher hinzufügen als jedesmal den Quellcode des "Programms" duplizieren zu müssen. Ausserdem will man nicht 20x den eigentlichen Code bearbeiten/verändern/optimieren sondern eben nur ein mal Icon_wink Immer wiederkehrende Abläufe packet man zB auch in sog. Functions (Anweisungen), damit man diese nicht 20x bearbeiten muss wenns dort nen Fehler gab oder man diese erweitern möchte sondern eben nur ein mal und der Aufruf bleibt gleich..

    Also ich hatte mich vor kurzem mal an einer Zeitansage auf Spanisch versucht und da stößt man auf ganz andere Probleme als im Deutschen. Aber vielleicht lässt sich das ja trotzdem so modular, wie du das vorschlägst, vereinfachen. Das wäre natürlich professioneller. :thumbs1:

    Zitat

    Das würde ich auch begrüßen. Hätte auch das ein oder andere Skript zum einstellen

    Hab mal ein Thread dazu aufgemacht: Raspberry Pi-Shell-Scripte-Sammlung

    Einmal editiert, zuletzt von belvsdragon (23. März 2014 um 14:39)

  • Hab ich glaub ich schon mal erwähnt: Linux mag Umlaute nicht besonders, am besten wärs diese anders zu schreiben:
    ä -> ae
    ö -> oe
    ü -> ue
    ß -> ss

    Das sieht man leider auch an deinem Code auf Github von Datumsansage.sh :

    Code
    " 5") Tag=fünfte


    usw ... da ist der Zeichensatz also schon bei dir kaputt

    Und Btw: Manche Monate haben mehr als 30 Tage :D

  • Das mit den Umlauten hab ich selbst grad schon bemerkt. Ich hatte über putty ins Webinterface von Github rüberkopiert und putty mag Umlaute nicht. Dabei ist mir wohl auch die Zeile mit der 31 abhanden gekommen. :D Habs korrigiert!

    Einmal editiert, zuletzt von belvsdragon (1. April 2014 um 18:22)

  • Doch, auch PuTTY zeigt Umlaute wenn mans entsprechend einstellt :D Aber kaum einer macht das und Linux hat wie gesagt allgemein Probleme mit Umlauten oder nicht-englisch-typischen-zeichen

    -> [Tutorial] Wie stelle ich in Putty den richtigen Zeichensatz ein?

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!