[gelöst] Vertretungsapp API - für FHEM nutzbar? Indiware Stundenplan24

Begonnen von matze1999, 02 September 2025, 14:33:19

Vorheriges Thema - Nächstes Thema

matze1999

Hallo,

kann man diese API für FHEM nutzen, wenn ja, wie?

https://github.com/Vertretungsapp/indiware-api

matze1999

DennisFL

Wenn du gerade erst anfängst, kannst du versuchen, die Daten über Perl/HTTP-GET in FHEM abzurufen und sie anschließend mit Internal-Command weiterzuverarbeiten. So hat man einen relativ einfachen Einstieg, bevor man einen eigenen Modulbau oder komplexere Skripte angeht.

matze1999

Hallo,

das habe ich schon versucht aber ist https, und http://name:passwort@... funktioniert nicht zum einloggen.

matze1999

passibe

Wenn das nur basic auth ist, kannst du einfach den Authorization-Header benutzen.

matze1999

Hallo, ich bin schon einen Schritt weiter, das login klappt, und ich habe auch eine xml die ich auslesen kann, dafür gibt es ein Beispile bei indieware:

https://www.stundenplan24.de/10000000/vplan/vdaten/VplanKl.xml

mit ....VplanKLYYYYMMDD.xml kann ich auch den gewünschten Tag angeben. allerdings komme ich hier nicht weiter.

Wie kann ich bei HTTPMOD das Datum für die Abfrage mit übergeben, Mir schwebt vor, immer zu einer bestimmten Zeit für den nächsten Tag die xml abrufe, nach der Klasse 6d suche <Kurz>6d</Kurz> und nach dem Wort "Ausfall" und dann readings habe, die mir anzeigen, da ist ein Ausfall der Stunde X  <St>X</St> ist. Hier mal eine Teil aus der xml:

<Pl>
<Std>
<St>1</St>
<Beginn>08:05</Beginn>
<Ende>08:50</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>48</Nr>
<If>KU Lehrer Ausfall</If>
</Std>
<Std>
<St>2</St>
<Beginn>08:55</Beginn>
<Ende>09:40</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>48</Nr>
<If>KU Lehrer Ausfall</If>
</Std>
<Std>
<St>3</St>
<Beginn>10:10</Beginn>
<Ende>10:55</Ende>
<Fa>SP M</Fa>
<Ku2>SP M</Ku2>
<Le>RW</Le>
<Ra>A-TH3</Ra>
<Nr>33</Nr>
<If/>
</Std>
<Std>
<St>3</St>
<Beginn>10:10</Beginn>
<Ende>10:55</Ende>
<Fa>SP J</Fa>
<Ku2>SP J</Ku2>
<Le>CL</Le>
<Ra>A-TH2</Ra>
<Nr>46</Nr>
<If/>
</Std>
<Std>
<St>4</St>
<Beginn>11:00</Beginn>
<Ende>11:45</Ende>
<Fa>SP M</Fa>
<Ku2>SP M</Ku2>
<Le>RW</Le>
<Ra>A-TH3</Ra>
<Nr>33</Nr>
<If/>
</Std>
<Std>
<St>4</St>
<Beginn>11:00</Beginn>
<Ende>11:45</Ende>
<Fa>SP J</Fa>
<Ku2>SP J</Ku2>
<Le>CL</Le>
<Ra>A-TH2</Ra>
<Nr>46</Nr>
<If/>
</Std>
<Std>
<St>5</St>
<Beginn>11:50</Beginn>
<Ende>12:35</Ende>
<Fa FaAe="FaGeaendert">EN</Fa>
<Le>IK</Le>
<Ra>H-221</Ra>
<Nr>402</Nr>
<If/>
</Std>
<Std>
<St>6</St>
<Beginn>13:25</Beginn>
<Ende>14:10</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>402</Nr>
<If>FD Lehrer Ausfall</If>
</Std>
<Std>
<St>7</St>
<Beginn>14:15</Beginn>
<Ende>15:00</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>402</Nr>
<If>FD Leher Ausfall</If>
</Std>


Die größte Hürde für mich ist die automatische HTTPMOD Abfrage mit Datum des nächsten Tages.

matze1999

matze1999

hier noch mal der vollständige Block für eine Klasse (5e):

<Kl>
<Kurz>5e</Kurz>
<Hash/>
<KlStunden>
<KlSt ZeitVon="07:15" ZeitBis="08:00">0</KlSt>
<KlSt ZeitVon="08:05" ZeitBis="08:50">1</KlSt>
<KlSt ZeitVon="08:55" ZeitBis="09:40">2</KlSt>
<KlSt ZeitVon="10:10" ZeitBis="10:55">3</KlSt>
<KlSt ZeitVon="11:00" ZeitBis="11:45">4</KlSt>
<KlSt ZeitVon="11:50" ZeitBis="12:35">5</KlSt>
<KlSt ZeitVon="13:25" ZeitBis="14:10">6</KlSt>
<KlSt ZeitVon="14:15" ZeitBis="15:00">7</KlSt>
<KlSt ZeitVon="15:05" ZeitBis="15:50">8</KlSt>
</KlStunden>
<Kurse>
<Ku>
<KKz KLe="CL">SP J</KKz>
</Ku>
<Ku>
<KKz KLe="RW">SP M</KKz>
</Ku>
</Kurse>
<Unterricht>
<Ue>
<UeNr UeLe="RW" UeFa="SPO" UeGr="SP M">33</UeNr>
</Ue>
<Ue>
<UeNr UeLe="MaL" UeFa="DeuFö">38</UeNr>
</Ue>
<Ue>
<UeNr UeLe="HeH" UeFa="MaFö">39</UeNr>
</Ue>
<Ue>
<UeNr UeLe="MS" UeFa="DE">40</UeNr>
</Ue>
<Ue>
<UeNr UeLe="IK" UeFa="EN">41</UeNr>
</Ue>
<Ue>
<UeNr UeLe="HeH" UeFa="MA">42</UeNr>
</Ue>
<Ue>
<UeNr UeLe="MK" UeFa="BIO">43</UeNr>
</Ue>
<Ue>
<UeNr UeLe="MH" UeFa="GE">44</UeNr>
</Ue>
<Ue>
<UeNr UeLe="NW" UeFa="GEO">45</UeNr>
</Ue>
<Ue>
<UeNr UeLe="CL" UeFa="SPO" UeGr="SP J">46</UeNr>
</Ue>
<Ue>
<UeNr UeLe="CS" UeFa="REV">47</UeNr>
</Ue>
<Ue>
<UeNr UeLe="AgK" UeFa="KU">48</UeNr>
</Ue>
<Ue>
<UeNr UeLe="StS" UeFa="MU">49</UeNr>
</Ue>
<Ue>
<UeNr UeLe="UB" UeFa="TC">50</UeNr>
</Ue>
<Ue>
<UeNr UeLe="IK" UeFa="FD">402</UeNr>
</Ue>
<Ue>
<UeNr UeLe="JN" UeFa="TC">371</UeNr>
</Ue>
</Unterricht>
<Pl>
<Std>
<St>1</St>
<Beginn>08:05</Beginn>
<Ende>08:50</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>48</Nr>
<If>KU Lehrer Ausfall</If>
</Std>
<Std>
<St>2</St>
<Beginn>08:55</Beginn>
<Ende>09:40</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>48</Nr>
<If>KU Lehrer Ausfall</If>
</Std>
<Std>
<St>3</St>
<Beginn>10:10</Beginn>
<Ende>10:55</Ende>
<Fa>SP M</Fa>
<Ku2>SP M</Ku2>
<Le>RW</Le>
<Ra>A-TH3</Ra>
<Nr>33</Nr>
<If/>
</Std>
<Std>
<St>3</St>
<Beginn>10:10</Beginn>
<Ende>10:55</Ende>
<Fa>SP J</Fa>
<Ku2>SP J</Ku2>
<Le>CL</Le>
<Ra>A-TH2</Ra>
<Nr>46</Nr>
<If/>
</Std>
<Std>
<St>4</St>
<Beginn>11:00</Beginn>
<Ende>11:45</Ende>
<Fa>SP M</Fa>
<Ku2>SP M</Ku2>
<Le>RW</Le>
<Ra>A-TH3</Ra>
<Nr>33</Nr>
<If/>
</Std>
<Std>
<St>4</St>
<Beginn>11:00</Beginn>
<Ende>11:45</Ende>
<Fa>SP J</Fa>
<Ku2>SP J</Ku2>
<Le>CL</Le>
<Ra>A-TH2</Ra>
<Nr>46</Nr>
<If/>
</Std>
<Std>
<St>5</St>
<Beginn>11:50</Beginn>
<Ende>12:35</Ende>
<Fa FaAe="FaGeaendert">EN</Fa>
<Le>IK</Le>
<Ra>H-221</Ra>
<Nr>402</Nr>
<If/>
</Std>
<Std>
<St>6</St>
<Beginn>13:25</Beginn>
<Ende>14:10</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>402</Nr>
<If>FD Lehrer Ausfall</If>
</Std>
<Std>
<St>7</St>
<Beginn>14:15</Beginn>
<Ende>15:00</Ende>
<Fa FaAe="FaGeaendert">---</Fa>
<Le LeAe="LeGeaendert"/>
<Ra RaAe="RaGeaendert"/>
<Nr>402</Nr>
<If>FD Lehrer Ausfall</If>
</Std>
</Pl>
</Kl>

matze1999

Hallo,

mit diesen Readings bekomme ich die Ausfallstunde und den Text angezeigt, allerdings geht das in die nächste klasse über, ich weiss nicht wie ich das auf den Bereich der Klasse 5e begrenze:

attr Stundenplan reading01Name Ausfall_1
attr Stundenplan reading01Regex (?s)<Kl\b[^>]*>.*?<Kurz>\s*5e\s*</Kurz>.*?(?:.*?<Std\b[^>]*>.*?<If>[^<]*Ausfall[^<]*</If>.*?</Std>){0}.*?<Std\b[^>]*>.*?<St>\s*(\d+)\s*</St>.*?<If>\s*([^<]*Ausfall[^<]*)\s*</If>.*?</Std>
attr Stundenplan reading02Name Ausfall_2
attr Stundenplan reading02Regex (?s)<Kl\b[^>]*>.*?<Kurz>\s*5e\s*</Kurz>.*?(?:.*?<Std\b[^>]*>.*?<If>[^<]*Ausfall[^<]*</If>.*?</Std>){1}.*?<Std\b[^>]*>.*?<St>\s*(\d+)\s*</St>.*?<If>\s*([^<]*Ausfall[^<]*)\s*</If>.*?</Std>
attr Stundenplan reading03Name Ausfall_3
attr Stundenplan reading03Regex (?s)<Kl\b[^>]*>.*?<Kurz>\s*5e\s*</Kurz>.*?(?:.*?<Std\b[^>]*>.*?<If>[^<]*Ausfall[^<]*</If>.*?</Std>){2}.*?<Std\b[^>]*>.*?<St>\s*(\d+)\s*</St>.*?<If>\s*([^<]*Ausfall[^<]*)\s*</If>.*?</Std>
attr Stundenplan reading04Name Ausfall_4
attr Stundenplan reading04Regex (?s)<Kl\b[^>]*>.*?<Kurz>\s*5e\s*</Kurz>.*?(?:.*?<Std\b[^>]*>.*?<If>[^<]*Ausfall[^<]*</If>.*?</Std>){3}.*?<Std\b[^>]*>.*?<St>\s*(\d+)\s*</St>.*?<If>\s*([^<]*Ausfall[^<]*)\s*</If>.*?</Std>
attr Stundenplan reading05Name Ausfall_5
attr Stundenplan reading05Regex (?s)<Kl\b[^>]*>.*?<Kurz>\s*5e\s*</Kurz>.*?(?:.*?<Std\b[^>]*>.*?<If>[^<]*Ausfall[^<]*</If>.*?</Std>){4}.*?<Std\b[^>]*>.*?<St>\s*(\d+)\s*</St>.*?<If>\s*([^<]*Ausfall[^<]*)\s*</If>.*?</Std>

Und wie ich in der Abfrage das Datum neu setzen kann, weiss ich auch noch nicht:

defmod Stundenplan HTTPMOD https://user:pass@www.stundenplan24.de/10000111/mobil/mobdaten/PlanKlYYYYMMDD.xml
matze1999


matze1999

eine runde im Forum gesucht, einen Schritt weiter, abfrage automatisch für den nächsten Tag:

defmod Stundenplan HTTPMOD https://user:pass@www.stundenplan24.de/100000111/mobil/mobdaten/PlanKl%%DATE%%.xml 86400
attr Stundenplan replacement01Mode expression
attr Stundenplan replacement01Regex %%DATE%%
attr Stundenplan replacement01Value POSIX::strftime("%Y%m%d", localtime(time + 86400));;

So, jetzt nur noch das Problem, dass er im Bereich der Klasse 5e, nach "Ausfall" sucht und mir dann die Stunde und den Text <if> .. </if> als reading (oder zwei Readings) ausgibt, wenn vorhanden.

matze1999

#8
Hallo,

ich habe jetzt für mich, auch unter Einsatz von Chatgpt, eine Lösung gefunden. Ich habe ein script, dass ich den Stundenplan des nächsten Tages abrufen lasse und in ein dummy Device "Stundenplan" in FHEM als separate readings stundenweise schreiben lasse:

#!/bin/bash

# Konfiguration
FHEM_HOST="localhost"
FHEM_PORT="7072"
FHEM_DEVICE="Stundenplan"
INFO_READING_PREFIX="Stunde"

# Datum des nächsten Tages im Format YYYYMMDD
NEXT_DAY_DATE=$(date -d "+1 day" +"%Y%m%d")
URL="https://[user]:[pass]@www.stundenplan24.de/[Schulnummer]/mobil/mobdaten/PlanKl${NEXT_DAY_DATE}.xml"

# XML-Datei herunterladen
curl -s "${URL}" > /tmp/stundenplan.xml

# Überprüfen, ob die XML-Datei gültig ist
if [ ! -s /tmp/stundenplan.xml ]; then
  perl fhem.pl "${FHEM_HOST}:${FHEM_PORT}" "setreading ${FHEM_DEVICE} status Error: No XML file or empty"
  exit 1
fi

# >> NEUE LOGIK: Alle alten Readings löschen
perl fhem.pl "${FHEM_HOST}:${FHEM_PORT}" "deletereading ${FHEM_DEVICE} .*"

# Alle Stunden-Informationen für die Klasse mit xmlstarlet auslesen
AUSGABE=$(xmlstarlet sel -t -m "//Kl[Kurz='[Klasse]']/Pl/Std" \
-v "St" -o "|" -v "Fa" -o "|" -v "If" -n /tmp/stundenplan.xml)

# die neuen Kommandos in ein bash array schreiben
declare -a FHEM_COMMANDS

# Für jede Stunde ausführen und die Daten speichern
COUNTER=0
while IFS='|' read -r STUNDE FA_INFO IF_INFO; do
 
  # LeereZeilen im xmlstarlet output ignorieren
  if [ -z "$STUNDE" ]; then
    continue
  fi
 
  # Zähler erhöhen
  COUNTER=$((COUNTER + 1))
 
  # Default für fehlende Inhalte setzen
  if [ -z "$FA_INFO" ]; then
    FA_INFO="$EMPTY_INFO_STRING"
  fi
 
  # Alle Readings Kommandos dem FHEM_COMMANDS array zufügen
  FHEM_COMMANDS+=("setreading ${FHEM_DEVICE} ${INFO_READING_PREFIX}${COUNTER}_Stunde ${STUNDE}")
  FHEM_COMMANDS+=("setreading ${FHEM_DEVICE} ${INFO_READING_PREFIX}${COUNTER}_Fa ${FA_INFO}")
 
  # ODas'If' reading hinzufügen, wenn es nicht leer ist
if [ -n "$IF_INFO" ]; then
    FHEM_COMMANDS+=("setreading ${FHEM_DEVICE} ${INFO_READING_PREFIX}${COUNTER}_If ${IF_INFO}")
  fi

done <<< "$AUSGABE"

# Wenn keine Stunden gefunden werden Status setzen
if [ "${COUNTER}" -eq 0 ]; then
  FHEM_COMMANDS+=("setreading ${FHEM_DEVICE} status_info Kein Stundenplan für Klasse 5d gefunden.")
fi

# Anzahl der Gesamtstunden setzen
FHEM_COMMANDS+=("setreading ${FHEM_DEVICE} Stundenanzahl ${COUNTER}")

# Dass array abarbeiten und jedes Kommando zu FHEM senden
for cmd in "${FHEM_COMMANDS[@]}"; do
  perl fhem.pl "${FHEM_HOST}:${FHEM_PORT}" "$cmd"
done

# das Hilfsfile löschen
rm /tmp/stundenplan.xml

exit 0

Das ganze lasse ich zu bestimmten Zeiten aus FHEM ausführen, und dann im Device Stundenplan anzeigen:

mit diesem stateFormat

{
  # Translation table for German weekdays and months
  my %weekdays = (
    "Mon" => "Montag",
    "Tue" => "Dienstag",
    "Wed" => "Mittwoch",
    "Thu" => "Donnerstag",
    "Fri" => "Freitag",
    "Sat" => "Samstag",
    "Sun" => "Sonntag"
  );
  my %months = (
    "Jan" => "Januar",
    "Feb" => "Februar",
    "Mar" => "März",
    "Apr" => "April",
    "May" => "Mai",
    "Jun" => "Juni",
    "Jul" => "Juli",
    "Aug" => "August",
    "Sep" => "September",
    "Oct" => "Oktober",
    "Nov" => "November",
    "Dec" => "Dezember"
  );
 
  # Calculate the date for tomorrow (current time + 86400 seconds)
  my $next_day_timestamp = time + 86400;
  my $date = localtime($next_day_timestamp);
  my ($weekday_en, $month_en, $day, $time, $year) = split(/\s+/, $date);

  # Translate the weekday and month to German
  my $weekday_de = $weekdays{$weekday_en};
  my $month_de = $months{$month_en};
 
  # Build the final output string
  my $output = "$weekday_de, $day. $month_de $year<br><br>";
 
  for (my $i=1; $i<=ReadingsVal($name,"Stundenanzahl",0); $i++) {
    my $stunde = ReadingsVal($name,"Stunde".$i."_Stunde","");
    my $fach = ReadingsVal($name,"Stunde".$i."_Fa","");
    my $info = ReadingsVal($name,"Stunde".$i."_If","");

    if ($stunde ne "") {
      $output .= "Stunde $stunde: $fach";
      if ($info ne "") {
        $output .= " ($info)";
      }
      $output .= "<br>";
    }
  }
  return $output;
}

Das sieht dann so aus:

matze1999

PS: das ist richtig dargestellt, die ersten beiden Stunden sind geteilt, deshalb werden sie doppelt dargestellt.