Autor Thema: Sammelthread: Steuerung von Webradios mit ListenLive Firmware  (Gelesen 19569 mal)

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Um die in verschiedenen Threads angefangene Diskussion zur Steuerung von Webradios mit ListenLive Firmware zusammenzuführen, habe ich diesen Thread eröffnet.

Grundlagen zum Thema sind die Beiträge aus diesen Threads:

Radiowecker via FHEM steuern
Neues Modul schreiben für ein Radio
Class Programmierung und FHEM

Ich würde mich freuen, wenn die gesamte Diskussion zu dem Thema nun gesammelt hier in diesem Thread erfolgen würde, damit man den Suchaufwand reduzieren kann (was stand denn nun in welchem Thread)


Ausdrücklich möchte ich darauf hinweisen, dass hier nicht nur der Lösungsansatz "Modul für ListenLive Geräte", sondern auch die von herrmannj entwickelte Idee, eigene Software auf dem Gerät zu installieren, um eine bidirektionale Kommunikation zu ermöglichen, diskutiert werden soll. Vielleicht lassen sich beide Ansätze ja sinnvoll verknüpfen. Zu diesem Thema gleich noch ein Hinweis von mir:

Zitat von: herrmannj
Sourcecode:
Soweit ich das verstanden habe hat er das selbst geschrieben, Basis war reverse engineering der original firmware und Studium der Chips. Wenn Du die FW auspackst (war glaub ich tar oder sowas) findest Du ein busybox linux. Die Apps sind kleine C progs. Du bräuchtest die busybox toolchain um da was zu schreiben. Ist imho machbar, aber mit hohem Zeiteinsatz.


Zitat von: ritchie
Aber auf dem Testsystem müsste man vorher die App auch selber testen, daher müsste man auch selber kompilieren.
Das wäre für mich kein Problem, da mein Desktop selber eine Linux System ist und ich bereits eine Toolchain für einen Arm am laufen habe.
Wenn das Zielsystem auch ein ARM Prozessor ist und ich z.B. ein Beispielprogm einer App haette, könnte man hier langsam was aufbauen.


Zitat von: ritchie
Eine Entwicklungsumgebung auf dem System konnte ich nicht finden (gcc).
[...]
Zudem hat er auch in der Linux-Version den Ursprung gelöscht (uname -a) zeigt keinen Ursprung.


Alles was man für die Entwicklung braucht, gibt es hier: http://en.ingenic.cn/product.aspx?ID=62

-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline herrmannj

  • Global Moderator
  • Hero Member
  • ****
  • Beiträge: 6130
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #1 am: 15 Juli 2013, 12:39:41 »
Prima Zusammenfassung, ergänzend dazu:

Eine passend Toolchain konnte ich aufsetzen und erfolgreich testen. Die Hardware (kmp510, 511 -> Archos Webradio, Xoro HMT350, 370) verstehe ich mittlerweile ausreichend um alle Schlüsselfunktionen (Radio Display, Audio- und Videowiedergabe, Remotecontrol, Bildschirmhelligkeit) verwenden zu können.

Zum Verständniss: die Firmware besteht aus zwei Schlüsselkomponenten:

 * eine speziell angepassten Linux Version mit den erforderlichen Treiber für die verbauten Hardwarekomponenten.
 * die "Apps" der Listenlive Firmware werden von einem einzelnen Programm geformt. (jz-media-app)

Es ist ohne Nebenwirkungen möglich diese Anwendung zu schließen (telnet pkill) und an ihrer Stelle eine eigene Anwendung (zB von der SD Karte) zu starten die dann die Bildschirmausgabe + Mediensteuerung übernimmt. Daran arbeite ich im Augenblick mit dem Ziel diese Anwendung direkt für FHEM verfügbar zu machen.

Grüße,
Jörg
smartVisu mit fronthem, einiges an HM, RFXTRX, Oregon, CUL, Homeeasy, ganz viele LED + Diverse

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #2 am: 15 Juli 2013, 23:21:18 »
Nicht dass jemand meint, ich hätte hier was vergessen anzuhängen: eine aktualisierte Version des Moduls zum Testen kommt hier in den nächsten Tagen. Bin grade noch an einer Codebereinigung und an einer Vereinheitlichung der readings.

Aktuell wird mein llradio als Radiowecker über Google-Kalender und das Calendar-Modul von FHEM gesteuert. Der Kalendereintrag beinhaltet im "Betreff" den Befehl, der an das Radio geschickt wird und im "Ort" den Namen des zu steuernden Radios. Damit können über den gleichen Kalender mehrere Radiowecker gesteuert werden.

(http://up.picr.de/15192289xb.png)

Interpretation des Kalendereintrags:

- am 15.07.2013 um 0530 Uhr wird an das LL-device "llradio" der Befehl "user weckerswr3" geschickt
- um 0700 Uhr wird das Radio wieder abgeschaltet

Was verbirgt sich hinter "user weckerswr3" ?

Relativ einfach. Das ist der Befehl, der an das Radio geschickt wird. "Befehl" in diesem Sinne kann fast alles sein: Angefangen vom einfachen EInschaltbefehl "power on" bis hin zu einem kompletten SUB, das z.B. in einer 99_myUtils.pm definiert sein kann:

Im konkreten Beispiel verbirgt sich dahinter folgende Sequenz:


sub weckerswr3(){
 {fhem("set llradio power off")};
 select(undef,undef,undef,1);
 {fhem("set llradio power on")};
 select(undef,undef,undef,1);
 {fhem("set llradio audio unmute")};
 select(undef,undef,undef,0.5);
 {fhem("set llradio raw HOME")};
 select(undef,undef,undef,0.5);
 {fhem("set llradio raw OK")};
 select(undef,undef,undef,0.5);
 {fhem("set llradio raw OK")};
 select(undef,undef,undef,0.5);
 {fhem("set llradio raw OK")};
 select(undef,undef,undef,0.5);
 {fhem("set llradio raw MENU")};
 select(undef,undef,undef,0.5);
 {fhem("set llradio raw MENU")};
}


Ablauf der Befehlsfolge:

zuerst wird das Radio ausgeschaltet, falls es angeschaltet sein sollte.
danach wird es wieder eingeschaltet,
es wird ein MUTE Status deaktiviert, falls aktiv (ich habe noch nicht getestet, ob der beim Ausschalten automatisch gelöscht wird)
es wird ein HOME Befehl geschickt, um den Cursor an eine eindeutige Position zu schicken,
es wird per Cursor-Steuerung der erste Eintrag aus den Favoriten ausgewählt,
es wird die Wiedergabe gestartet,
es wird auf die Anzeige der aktuellen Wetterlage umgeschaltet

Die Prozedur mit dem Aus- und Einschalten wird so lange nötig sein, solange es keine Möglichkeit gibt, den aktuellen Gerätestatus zu ermitteln, um laufende andere Anwendungen (falls vorhanden) zu beenden und einen definierten Zustand herzustellen.

Das Ausschalten des Gerätes am Ende des Kalenderevents ist im zugehörigen notify fest hinterlegt.
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #3 am: 15 Juli 2013, 23:28:40 »
Hier ist das notify für das Einschalten:

define Wecker_an notify Kalender_Wecker:modeStarted.* { my $reading="%EVTPART0"; my $uid= "%EVTPART1"; my $actor= fhem("get Kalender_Wecker location $uid"); if(defined $actor) { my $action= fhem("get Kalender_Wecker summary $uid"); fhem("set $actor $action") } }

Hier ist das notify für das Ausschalten:
define Wecker_aus notify Kalender_Wecker:modeEnded.* { my $reading="%EVTPART0"; my $uid= "%EVTPART1"; my $actor= fhem("get Kalender_Wecker location $uid"); if(defined $actor) { fhem("set $actor power off") } }

Und so sieht das LISTENLIVE-device mitsamt seinen Readings derzeit aus:

(http://up.picr.de/15192369rt.png)

Ich harre gespannt der neuen Firmware, die ja für diese Woche angekündigt ist. Momentan fehlen in meinem Modul noch die Get() und GetUpdate() sowie die komplette Dokumentation. Die Get-Teile machen einfach noch keinen Sinn, weil es noch nichts aus dem Gerät zu lesen gibt. Mir wäre ja mit einem Power-Status und dem Mute-Status schonmal sehr weitergeholfen, da dies Toggle-Befehle sind. FHEM merkt sich zwar, wenn diese beiden Aktionen geschaltet werden, aber das ist einfach noch nicht zuverlässig genug.

-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #4 am: 18 Juli 2013, 10:01:45 »
Für das persönliche Entwicklungsnotizbuch: Ich muss noch den Fehlerfall abfangen, dass llradio überhaupt nicht erreichbar ist, sonst schießt der Versuch, einen Befehl dorthin zu schicken, das ganze fhem ab *grmpf*

Ansonsten funktioniert der ferngesteuerte Radiowecker bisher recht zufriedenstellend.
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #5 am: 19 Juli 2013, 21:51:42 »
"sowosamma" (Fredl Fesl)

Wie versprochen, hier der neueste Entwicklungsstand.

Syntax zum Anlegen einen ListenLive-Webradios:

define <name> LISTENLIVE <ip-adresse>[:port] [interval]

Beispiel 1:

define llradio1 LISTENLIVE 192.168.222.222

ergibt in FHEM folgendes listing:

Internals:
   CFGFN      
   DEF        192.168.222.222
   NAME       llradio1
   NR         1634
   STATE      online
   TYPE       LISTENLIVE
   Readings:
     2013-07-19 21:39:17   interval        60
     2013-07-19 21:39:17   ipaddr          192.168.222.222
     2013-07-19 21:39:17   lastCmd        
     2013-07-19 21:39:17   lastResult      
     2013-07-19 21:39:17   menuPos         11
     2013-07-19 21:39:17   mute            ???
     2013-07-19 21:39:17   port            8080
     2013-07-19 21:39:17   power           ???
     2013-07-19 21:39:17   state           online
   Helper:
     ADDRESS    192.168.222.222
     AVAILABLE  1
     INTERVAL   60
     PORT       8080
Attributes:
   eventMap   absent:offline present:online


Da bei der Definition die optionalen Parameter für Port und Intervall (Erklärung später) weggelassen wurden, werden die Standardwerte port=8080 und interval=60 Sekunden verwendet.

Beispiel 2:

define llradio2 LISTENLIVE 192.168.222.222:7070 300

ergibt


Internals:
   CFGFN      
   DEF        192.168.222.222:7070 300
   NAME       llradio2
   NR         1651
   STATE      online
   TYPE       LISTENLIVE
   Readings:
     2013-07-19 21:41:41   interval        300
     2013-07-19 21:41:41   ipaddr          192.168.222.222
     2013-07-19 21:41:41   lastCmd        
     2013-07-19 21:41:41   lastResult      
     2013-07-19 21:41:41   menuPos         11
     2013-07-19 21:41:41   mute            ???
     2013-07-19 21:41:41   port            7070
     2013-07-19 21:41:41   power           ???
     2013-07-19 21:41:41   state           online
   Helper:
     ADDRESS    192.168.222.222
     AVAILABLE  1
     INTERVAL   300
     PORT       7070
Attributes:
   eventMap   absent:offline present:online


und wie man sieht, wurden die Parameter 7070 und 300 entsprechend übernommen.

Der Parameter Intervall gibt an, in welchem Abstand der Gerätestatus gelesen und aktualisiert wird. Zum derzeitigen Zeitpunkt wird hier lediglich die Erreichbarkeit des Gerätes geprüft, weil es vom Gerät selbst noch nichts zu Lesen gibt.

Die Prüfung der Erreichbarkeit erfolgt mit Hilfe von PRESENCE

Falls vorhanden, wird eine vorhandene PRESENCE-entity die sich auf das Gerät bezieht, verwendet, um den Status online/offline zu aktualisieren. Die Definition von PRESENCE setzt voraus, dass der Name mit pres_ beginnt und dann den Namen des Gerätes angehängt wird. In den obigen Beispielen wären dies also pres_llradio1 bzw. pres_llradio2.

define pres_llradio1 PRESENCE lan-ping 192.168.222.222 60 300

Die genaue Beschreibung von PRESENCE ist der commandref zu entnehmen.

Diese Art der Prüfung wurde gewählt, da ich keinerlei Notwendigkeit sah, das Rad neu zu erfinden oder Coding aus dem PRESENCE-Modul zu kopieren und wiederzuverwenden.

Fehlt die entsprechende PRESENCE-Definition zum Gerät, wird immer "online" vermutet. Achtung: Dies kann zu unerwünschten Effekten führen!
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #6 am: 19 Juli 2013, 22:19:36 »
Beschreibung der derzeit unterstützten Befehle

Allgemeine Syntax:

set llradio <Befehlsgruppe> <Kommando>

Die einzelnen Kommandos sind in funktionsbezogene Gruppen zusammengefasst.

Es gibt im Moment folgende Gruppen und Befehle:


Befehlsgruppe "audio"
set llradio audio mute
set llradio audio unmute
set llradio audio volm
set llradio audio volp


Befehlsgruppe "cursor"
set llradio cursor down
set llradio cursor left
set llradio cursor up
set llradio cursor right

set llradio cursor enter
set llradio cursor exit
set llradio cursor home
set llradio cursor ok


Befehlsgruppe "power"
set llradio power off
set llradio power on


Befehlsgruppe "raw"
set llradio raw <command>


Befehlsgruppe "reset"
set llradio reset menupos
set llradio reset mute
set llradio reset power


Befehlsgruppe "user"  (experimentell!)
set llradio user <userDefFunction>


Befehlsgruppe "app"  (experimentell!)
set llradio app weather


Befehlsgruppe statusRequest
set llradio statusRequest


Die meisten Befehle sollten selbsterklärend sein.

Die "reset" Kommandos dienen dazu, klar definierte Zustände herstellen zu können, solange es noch keine Lesemöglichkeit direkt aus dem Gerät gibt. Diese Befehle werden eigentlich nur benötigt, wenn die in fhem gespeicherten Readings nicht mit den tatsächlichen Zuständen am Gerät übereinstimmen. Eine ausführliche Erklärung erfolgt ggf. später. Eventuell fällt diese Befehlsgruppe nach dem Erscheinen der neuen LL-Firmware komplett weg.

In der Befehlsgruppe "cursor" sind die Kommandos "enter" und "ok" absolut identisch (ich habe die nur aus Gründen der usability kopiert)

In der experimentellen Gruppe "app" wurde testweise die Auswahl der Wetter-Applikation mittels der Cursortasten abgebildet.

Die Befehlsgruppe "user" werde ich zu gegebener Zeit dokumentieren, diese Gruppe ist ebenfalls noch in einem Experimentierstadium. Es könnte sein, dass diese Gruppe aus Sicherheitsgründen auch wieder komplett wegfällt.

Bei statusRequest gibt es keinen zweiten Teil beim Aufruf.


Viel Spaß beim Testen!

Ich freue mich über jede Rückmeldung und habe auch ein offenes Ohr für Fragen, Änderungsvorschläge und Wünsche. Aber bitte nicht per email, sondern hier im Forum, da haben dann nämlich alle Tester etwas davon.
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline UliM

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2711
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #7 am: 19 Juli 2013, 22:35:06 »
Hiho,
cool dass es da weitergeht. Werd mir alsbald so'n Ding bestellen :)

Hast Du den fred gesehen: Link

Gruß, Uli
RPi4/Raspbian, CUL V3 (ca. 30 HomeMatic-devices), LAN (HarmonyHub, alexa etc.).  Fördermitglied des FHEM e.V.

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #8 am: 19 Juli 2013, 22:49:01 »
Hallo Uli,

ja, habe ich gelesen. Allerdings ist bei der ListenLive Firmware im Moment noch das Problem, dass niemand weiss, was in der nächsten (eigentlich für diese Woche) angekündigten Firmware kommen wird und die Steuerung aktuell noch sehr rudimentär erfolgt.

Die eigentlichen Wiedergabefunktionen habe ich ja noch gar nicht implementiert. Die WIedergabe kann aber auch jetzt schon mittels "set llradio raw <command>" gesteuert werden, wobei <command> einBefehl aus dieser Menge sein kann:UP LEFT DOWN RIGHT EXIT POWER OK VOLp VOLm STOP REPEAT PGUP PGDN RECORD HOME MENU MUTE FORWARD REWIND FMRADIO

Naja, und die meisten der im genannten "Einheitlichkeit"-Thread gemachten Vorschläge habe ich ja bereits umgesetzt bzw. vorbereitet.

Das Gerät selbst liefert mir noch überhaupt keine Rückmeldung (z.B. Lautstärke oder gar die Menüposition) sodass ich mir den Power-Status in FHEM in einem Reading merke. Das Schlimme ist, dass das Einschalten über ein Toggle erfolgt, da für PowerOn und PowerOff der gleiche Befehl "Power" verwendet wird. Identisches Verhalten beim Mute.

Naja, warten wir mal, was die nächste Firmware wirklich bringt - ich bin jedenfalls schonmal vorbereitet. Man soll ja dann z.B. auch Textnachrichten als Popup schicken können :)

Viele Grüße
Udo
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #9 am: 19 Juli 2013, 22:55:53 »
Im Moment ist das Ganze für mich noch im Status "Proof of Concept" - natürlich ist die Implementierung aller Steuerungsbefehle ebenso geplant, wie es schon ein "Gerüst" für weitere Funktionsgruppen gibt.


Gruppe "play"
play play
play pause
play stop
play forward
play rewind
play fforward
play frewind
play record

Gruppe "media"
media radio <inetRadioUrl>
media tv <inetTvUrl>
media file <fileName>

Gruppe "send"
send message <text>
send image <imagefile>


Diese (möglichst logisch gehaltene) Gruppenstruktur ermöglicht eine sehr einfache Erweiterung des LL-Moduls.
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #10 am: 19 Juli 2013, 23:01:25 »
Als nächstes wird ein

get llradio <list commands>|<help>

implementiert. Wobei mir "help" besser gefällt. Auf jeden Fall wird auch das GET in logischen Funktionsgruppen strukturiert sein.
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline UliM

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2711
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #11 am: 19 Juli 2013, 23:16:33 »
Zitat von: betateilchen schrieb am Fr, 19 Juli 2013 23:01
Als nächstes wird ein

get llradio <list commands>|<help>

implementiert.


Für "list commands" gibt's schon einen fhem-Standard:
set <device> ?
get <device> ?
Muss auch eine Antwort im vorgeschriebenen Format liefern, damit FHEMWEB das richtig darstellt.
=8-)
RPi4/Raspbian, CUL V3 (ca. 30 HomeMatic-devices), LAN (HarmonyHub, alexa etc.).  Fördermitglied des FHEM e.V.

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #12 am: 19 Juli 2013, 23:27:55 »
Ok, das mit dem Fragezeichen soll nicht das Problem sein. Auch wenn mir das bisher noch nirgends untergekommen ist. Wo finde ich das "vorgeschriebene Format"?

Im Moment funktioniert die Anzeige der Hilfetexte bei mir im WebFrontend problemlos :o)
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

Offline UliM

  • Developer
  • Hero Member
  • ****
  • Beiträge: 2711
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #13 am: 19 Juli 2013, 23:44:58 »
Zitat von: betateilchen schrieb am Fr, 19 Juli 2013 23:27
Wo finde ich das "vorgeschriebene Format"?

Leider nur in anderen Programmen :(

elsif ($arg eq "?") {
    return "Unknown argument $arg choose one of <liste der gültigen Kommandos>";


=8-)
RPi4/Raspbian, CUL V3 (ca. 30 HomeMatic-devices), LAN (HarmonyHub, alexa etc.).  Fördermitglied des FHEM e.V.

Offline betateilchen

  • Developer
  • Hero Member
  • ****
  • Beiträge: 18268
  • Stoppt den Unicode-Irrsinn!
Aw: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
« Antwort #14 am: 19 Juli 2013, 23:48:21 »
Ach, wenns weiter nix ist :) Dann habe ich das ja instinktiv richtig eingebaut.

get llradio ?

liefert

(http://up.picr.de/15230694du.png)

set llradio ?

liefert

(http://up.picr.de/15230705ep.png)

Zufrieden?

Übrigens, elseif finde ich gruslig...
-----------------------
Unaufgeforderte Anfragen per email werden von mir nicht beantwortet. Dafür ist das Forum da.
-----------------------
Lesen gefährdet die Unwissenheit!

 

decade-submarginal