Ich bin über die Google-Suche hierüber gestolpert, und wollte daher noch kurz etwas ergänzen:
Die Denon AVRs lassen sich per HTTP und Telnet über das Netzwerk steuern (so macht es das IP-Syncom einen drüber ja bspw auch).
Das IP-Syncom ist sicherlich der weit einfachere Weg für jemanden der "bei null beginnt", wer jedoch eh mit Smart Home, NodeRed und Co rumspielt, wird ggf die folgende Lösung eher gebrauchen können.
Protokolle für das Netzwerk kann man direkt bei Denon herunterladen, hier sind dann die entsprechenden Befehle alle aufgeführt. Zu beachten ist, das die Telnet-Session jedes mal geschlossen werden muss, wenn ein Befehl abgesendet wurde, einen zweiten nimmt der Verstärker nicht mehr.
Die Befehle lassen sich dann wunderbar mit einer Node Red-Installation auf einem Raspberri PI o.ä. absenden, hier kann dann auch Alexa eingebunden werden. Wer sich damit nicht auskennt wird wohl nicht sehr glücklich damit da es nicht unbedingt trivial ist, wer mit sowas schon mal was gemacht hat sollte aber wenig Probleme bekommen.
Ich lasse einige Befehle über Telnet laufen (vor allem die bei denen man genug Zeit dazwischen hat), wer sich dafür interessiert wird bspw
im NodeRed-Forenthread fündig, da hab ich mein Python-Script und die Node zur Ausführung mal gepostet.
Wenn man allerdings bspw die Lautstärke schnell ändern will, sind Telnet-Commands mit ihren ~250ms imo zu langsam. Genau so gab es bei mir Befehle, die zwar im Protokoll standen, der Verstärker aber nicht verstand. Unter
diesem Link findet man entsprechende http-befehle, die man auch einfach als GET in Nodered absenden kann. so lässt sich bspw die Lautstärke um einiges schneller regeln, da man die Befehle schneller hintereinander weg senden kann. Auch konnte ich per Telnet den Kanal nicht ändern, jedoch per http.
Ich hab mir dann komplette Befehlsketten geschrieben, die mit 20ms Versatz gesendet werden, und bspw den Audio-Eingang von HDMI auf analog ändern, Audissey-Flat zu manual EQ, dazu Loudness off usw mit einem (bei mir) Tastendruck. So kann man sich wunderbar komplizierte Presets schreiben.
Die Function Node in NodeRed sieht dann bspw so aus (kann sicherlich noch schöner geschieben werden^^):
Code: Alles auswählen
var statOfDenonModeChange = flow.get('statOfDenonModeChange')||0;
function setPayLoad(pldToSend){
msg.payload = pldToSend;
}
function checkPayLoadNotEqual(pldToCheck){
if (msg.payload !== pldToCheck) return 1;
else return 0;
}
function checkPayLoadIsEqual(pldToCheck){
if (msg.payload === pldToCheck) return 1;
else return 0;
}
if (statOfDenonModeChange === 0){
setPayLoad("SI?"); // check input source
}
if (statOfDenonModeChange === 1){
if (checkPayLoadNotEqual("SISAT/CBL")){ // falls die Source NICHT auf sat Cable steht (Befehle stehen in der Dokuentation der Netzwerkprotokolle auf der Denon-HP)
setPayLoad("SISAT/CBL"); // den Kanal den man haben möchte an die Python Node übergeben
statOfDenonModeChange = statOfDenonModeChange - 2; // den Helper zurücksetzen, so das beim nächsten Durchlauf noch mal geshcaut wiurd, ob die Kanaländerung auch stattgefunden hat
}
else ++statOfDenonModeChange; // falls der Kanal richtig eingestellt ist, direkt weiter mit dem nächsten Befehl
}
if (statOfDenonModeChange === 2){
setPayLoad("SD?"); // check input source
}
if (statOfDenonModeChange === 3){
if (checkPayLoadNotEqual("SDHDMI")) {
setPayLoad("SDHDMI");
statOfDenonModeChange = statOfDenonModeChange - 2;
}
else ++statOfDenonModeChange;
}
if (statOfDenonModeChange === 4){
setPayLoad("MS?"); // check input source
}
if (statOfDenonModeChange === 5){
if (checkPayLoadIsEqual("MSSTEREO")) { // hier check auf IsEqual statt auf Not Equal. ich schalte nur zwischen Stereo und Movie hin und her, und da Movie viele Modi zurück geben kann die ich nicht alle checken will (siehe Datenblatt Protokolle von Denon, da sind weiter hinten auch alle returns aufgelistet), schaue ich einfach ob es Stereo ist oder nicht, und wenn ja stelle ich wieder auf Movie.
setPayLoad("MSMOVIE");
statOfDenonModeChange = statOfDenonModeChange - 2;
}
else ++statOfDenonModeChange;
}
if (statOfDenonModeChange === 6){
setPayLoad("PSMULTEQ: ?"); // check input source
}
if (statOfDenonModeChange === 7){
if (checkPayLoadNotEqual("PSMULTEQ:FLAT")) {
setPayLoad("PSMULTEQ:FLAT");
statOfDenonModeChange = statOfDenonModeChange - 2;
}
else ++statOfDenonModeChange;
}
if (statOfDenonModeChange === 8){
setPayLoad("PSDYNEQ ?"); // check input source
}
if (statOfDenonModeChange === 9){
if (checkPayLoadNotEqual("PSDYNEQ ON")) {
setPayLoad("PSDYNEQ ON");
statOfDenonModeChange = statOfDenonModeChange - 2;
}
else ++statOfDenonModeChange;
}
if (statOfDenonModeChange === 10){
setPayLoad("PSDYNVOL ?"); // check input source
}
if (statOfDenonModeChange === 11){
if (checkPayLoadNotEqual("PSDYNVOL HEV")) {
setPayLoad("PSDYNVOL HEV");
statOfDenonModeChange = statOfDenonModeChange - 2;
}
else {
++statOfDenonModeChange;
msg.payload = "{ \"dtype\" : \"Display\", \"mode\" : \"scrollingText\", \"showText\" : \"PC abendmodus\", \"bright\" : 1 }" // funktioniert nur bei mir, ist das was am zweiten Ausgang der Node ausgegeben wird
return [null, msg]; // return am ersten Ausgang null, so wird nichts gesended und die Python-Node nicht mehr getriggert, das Skript bzw die Kette endet also. Früher wurde hier einfach weiter hoch gezählt, daher weiter unten auch noch die if-Anweisung vor dem return msg. Kann also schnell zurückgeschrieben werden.
}
}
flow.set('statOfDenonModeChange', ++statOfDenonModeChange); // hier das increment, so das immer einen Befehl weiter gegangen wird bei jedem Durchgang
if (statOfDenonModeChange <= 11) return [msg, null];
Damit sende ich einen Befehl den ich direkt (bzw mit 20ms delay node) in die Python-Node gebe, den Python-Node-Ausgang gebe ich dann wieder zurück in die Function node so das diese mit der Rückgabe arbeiten kann. Immer mit einer extra Überprüfung ob die Änderung auch übernommen wurde.
"statOfDenonModeChange" sollte nach dem Durchlauf noch einmal separat auf 0 gesetzt werden, damit die Node wieder starten kann (oder das halt oben im Skript ergänzen).
Bei dieser node sind jetzt auch zwei Ausgänge (Outputs) gesetzt, so lasse ich mir nochmal eine andere msg auf den zweiten Ausgang geben wenn das Script durch ist, ist bei mir eine Anzeige am ESP32. Wer das nicht hat den zweiten Ausgang einfach leer lassen oder aus return [msg, null] bzw return [null, msg] einfach return msg machen und die node auf nur einen output setzen

Dann nur den Ausgang der Alexa Node auf entsprechenden Befehl abklopfen, und bei true die oben gepostete Node einfach mit irgendeiner msg am Eingang starten. Natürlich muss man sich für jeden Befehl dann eine eigene function node erstellen und die passend triggern.
tn.read_some muss natürlich wie im NodeRed-Thread beschrieben im Pythonscript dann nach dem send noch eingefügt werden, um auch eine Antwort vom AVR zu erhalten und auswerten zu können.
Gruß
Inso