bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

HDMI CEC - Status per Bash abfragen

Fri Jan 23, 2015 5:45 pm

Hallo!

Ich möchte mit meinem Raspberry überwachen, ob mein Fernseher eingeschaltet ist. Dafür habe ich mir den cec-client bereits installiert. Mit

Code: Select all

echo pow 0 | cec-client -s -d 1
lässt sich der Status des Fernsehers abfragen. Jetzt habe ich mir ein Script gebastelt:

Code: Select all

#!/bin/sh

while :; do
    command="echo pow 0 | cec-client -s -d 1 | grep 'power status' | awk '{split(\$0,a,\":\");print a[2]}' | sed 's/ //'"
    status=$(eval $command)

echo $status
done
exit 0
Jetzt wird dauerhaft der Status abgefragt. Soweit kein Problem. Allerdings habe ich laufend ca. 5% CPU-Auslastung, da cec-client sich immer wieder neu verbindet.

Starte ich den cec-client und gebe hier mehrfach "pow 0" ein, bekomme ich sofort den Status ausggegeben.
Daher war meine Idee, dass ich nur den cec-client 1x starte und per Bash nur den Status mittels "pow 0" abfrage. Ohne jedes mal neu Verbinden zu müssen. Geht das irgendwie? Wie?
Mein Versuch war folgender:

Code: Select all

#!/bin/sh
cec-client &

while :; do
 sleep 5
 echo pow 0

done
exit 0
Hier wird jetzt sogar der Befehl "pow 0" geschrieben. Aber nicht ausgeführt. Warum?

Gruß
Bismosa

User avatar
mline
Posts: 1271
Joined: Sun Jan 27, 2013 1:47 pm
Location: Austria, Vienna

Re: HDMI CEC - Status per Bash abfragen

Fri Jan 23, 2015 5:56 pm

Du gibst quasi nur nen String aus.
Für Ausführen und Rückgabe ausgeben nutzt man die Pipe http://de.wikipedia.org/wiki/Pipe_%28Informatik%29
<~~>

bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

Re: HDMI CEC - Status per Bash abfragen

Fri Jan 23, 2015 6:04 pm

Hallo,

ja...eine pipe benutze ich ja hier:

Code: Select all

echo pow 0 | cec-client -s -d 1
Aber ich baue jedes mal die Verbindung neu auf....und das möchte ich umgehen...oder habe ich etwas übersehen?

Gruß
Bismosa

cdo
Posts: 9
Joined: Tue Nov 19, 2013 5:13 pm

Re: HDMI CEC - Status per Bash abfragen

Fri Jan 23, 2015 6:26 pm

Hallo,

mit

Code: Select all

(while true ; do sleep 5 ; echo "pow 0" ; done) | cec-client -d 1
geht es bei mir. Der Befehl schiebt die Ausgabe der while-Schleife in die Eingabgepipe von cec-client. Ausgabe:

Code: Select all

log level set to 1
No device type given. Using 'recording device'
CEC Parser created - libCEC version 2.2.0
no serial port given. trying autodetect: 
 path:     Raspberry Pi
 com port: RPI

opening a connection to the CEC adapter...
waiting for input
power status: standby
power status: standby
(und so weiter)
Ich habe das -s beim Aufruf von cec-client weggelassen, da dieses nur eine einzige Abfrage erlaubt (single-command).

Viele Grüße

bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

Re: HDMI CEC - Status per Bash abfragen

Fri Jan 23, 2015 6:54 pm

Hallo,

das ist ja genial! Ich wäre nie darauf gekommen, die Schleife vor der pipe zu setzen. Vermutlich weil ich es doch bisher noch nicht richtig verstanden habe/hatte.

Dann sollte ich den Rest problemlos hinbekommen:
- Einschalten eines zweiten Raspberry (mit Openelec) über ein Relais
- Ausschalten, wenn TV ausgeschaltet wird

Sehr praktisch, da mein TV zwar einen USB-Anschluss hat der aber vermutlich nicht genug Strom abgibt um einen Raspberry zu betreiben. Der USB-Anschluss wird auch erst aktiviert, wenn der TV komplett hochgefahren ist...das ist mir zu spät ;) Per HDMI bekomme ich nach 2sek. den Status das der TV gestartet wird.

Vielen Dank für die Hilfe!

Gruß
Bismosa

cdo
Posts: 9
Joined: Tue Nov 19, 2013 5:13 pm

Re: HDMI CEC - Status per Bash abfragen

Fri Jan 23, 2015 7:35 pm

Immer schön, wenn man helfen kann :D
Der Unterschied ist der: wenn man das cec-client in die Schleife reinschreibt, wird es bei jedem Schleifendurchlauf neu gestartet. Wenn man die Schleife vor die Pipe schreibt, funktioniert sie wie ein eigener Befehl (das machen die Klammern drumherum) und jede Zeile, die sie ausgibt, wird als Eingabe für das cec-client verwendet (das nur einmal gestartet wird).
Viel Spaß!

bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

Re: HDMI CEC - Status per Bash abfragen

Sat Jan 24, 2015 9:20 am

Hallo!

Jetzt muss ich doch noch einmal fragen...
Ich habe mein Script jetzt mal zusammengebastelt. Allerdings habe ich nicht herausbekommen, wie ich die Ausgabe vom cec-client in eine Variable packen kann:

Code: Select all

#!/bin/sh

SleepTime=1
TimePowerOff=5 #Zeit bis zum wirklichen ausschalten, wenn der TV nicht wieder eingeschaltet wurde
TimeRunterfahren=3 #Zeit bis der Raspberry heruntergefahren wurde (und das Relais abfallen kann)
TimeStarten=5 #Zeit bis XMBC gestartet ist (solange muss bis zum nächsten runterfahren gewartet werden!)

TimerPowerOff=0

(
while true
do
	sleep $SleepTime
	echo "pow 0"
    read Ausgabe
	if [ "$Ausgabe" = "power status: standby" ] || [ "$Ausgabe" = "power status: unknown" ]; then

		powerstateGPIO=`gpio read 1`
		if [ "$powerstateGPIO" = 0 ] ; then
			echo "Berreits abgeschaltet"
			continue
		fi

		TimerPowerOff=$(expr $TimerPowerOff + $SleepTime)
		
		if [ "$TimerPowerOff" -gt "$TimePowerOff" ]; then
			#Ausschalten
			#curl -i -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0", "method": "System.Shutdown", "params": { }, "id": 1}' http://xbmc/jsonrpc
			echo "Ausschalten"
			#Hier jetzt die Zeit bis zum ausschalten abwaren, da eh nicht mehr eingegriffen werden kann:
			sleep $TimeRunterfahren
			echo "Relais ausschalten"
			gpio mode 1 out
			gpio write 1 0
				
			TimerPowerOff=0
		fi
	
    elif [ "$Ausgabe" = "power status: on" ] || [ "$Ausgabe" = "power status: in transition from standby to on" ]; then
        #Falls der Timer zum Ausschalten gesetzt war zurücksetzen:
		TimerPowerOff=0
		
		#GPIO Status abfragen, ob bereits eingeschaltet
		powerstateGPIO=`gpio read 1`
		if [ "$powerstateGPIO" = 0 ] ; then
			#Einschalten
			gpio mode 1 out
			gpio write 1 1
			sleep $TimeStarten
		fi
		
    fi

done
 ) | cec-client -d 1 #| grep 'power status'

 
 exit 0

In der Trockenübung (wenn ich nur meine Eingaben lese) scheint das schon zu klappen.
- Wird der TV eingeschaltet, schaltet sich das Relais sofort ein. Das Script wartet dann bis zur nächsten Ausführung, bis XBMC auch wirklich gestartet ist
- Sollte der TV schon wieder aus sein oder wird irgendwann abgeschaltet, wird per JSON XBMC heruntergefahren und nach einer einstellbaren Zeit das Relais ebenfalls abgeschaltet.
- Es wird erst nach einer bestimmten Zeit abgeschaltet. Falls man gleich nach dem Abschalten doch noch mal eben was nachschauen wollte...

Aber wie kann ich die Ausgabe vom cec-client einlesen?

Danke und Gruß
Bismosa

User avatar
Hiswif
Posts: 664
Joined: Sat Oct 13, 2012 11:54 am
Contact: Website

Re: HDMI CEC - Status per Bash abfragen

Sun Jan 25, 2015 9:47 am

Es ist jetzt nicht böse gemeint, sondern wirklich Interesse. Was ist der Sinn des ganzen? Du nutzt einen pi der scheinbar 24/7 läuft um einen mit dem mediacenter zu starten und beenden zu können. HDMI ist aber an dem ersten dran? Ich verstehe noch nicht so ganz was du bezweckst. Sonnst könnte ich dir da eventuell mit Netz Schaltung weiterhelfen.
http://technikegge.blogspot.de

bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

Re: HDMI CEC - Status per Bash abfragen

Sun Jan 25, 2015 12:08 pm

Hallo,

ja...ich kann verstehen das es ungewöhnlich klingt.
Ich nutze derzeit 2 Raspberry. Einen nur für XBMC(Kodi) und den anderen (schon länger) als Musikserver für unsere Squeezeboxen. Ausserdem nutze ich diesen noch zusätzlich als Druckserver, Fileserver, Scanserver, IR-Empfänger (um mit der TV Fernbedienung die Anlage zu bedienen) usw. Der muss also 24/7 laufen. Der XBMC allerdings muss wirklich nur laufen, wenn der Fernseher auch eingeschaltet ist.
Durch die bisherigen Basteleien habe ich schon sehr viel gelernt, was die Programmierung betrifft. Macht mir auch einfach Spaß...vor allem wenn es dann auch funktioniert!

Daher ist mein Vorhaben jetzt mit dem 1. RPi der ja eh immer läuft über ein Relais den zweiten RPi zu starten, wenn der Fernseher läuft. Beide RPi´s hängen per HDMI am Fernseher (Brauche ich bei dem Musikserver nur selten...aber wenn er mal nicht starten möchte kann ich immer gleich prüfen warum). Daher sehe ich hier einen geeigneten Weg um mein vorhaben umzusetzen. Ich habe eh noch 3 Relais (230V direkt in eine Steckdosenleiste verbaut) frei.

Ich glaube fast, das ich es so nicht schaffe die Verbindung vernünftig zu halten und kontinuierlich den Status abzufragen. Manchmal hat sich bei meinen bisherigen versuchen der cec-client mit voller Prozessorauslastung aufgehangen. Gibt es vielleicht bessere Möglichkeiten, wenn ich es mit python probiere? Oder eine andere Programmiersprache? Oder bin ich mal wieder mit einem völlig falschen Ansatz dabei? Eigentlich sollte ein Bash-Script für mein vorhaben genügen...

Bin für jeden Tipp dankbar :)

Gruß
Bismosa

bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

Re: HDMI CEC - Status per Bash abfragen

Mon Jan 26, 2015 9:45 pm

So....ich habe jetzt noch ein paar Stunden gegoogelt und probiert. Ich bin auf folgende Seite gestossen:
http://www.whizzy.org/2012/11/device-co ... ibcec-ftw/
Dort wurden zwei Scripte verwendet. Ein Server und ein Client. Der Server sorgt dafür, dass die Verbindung zum cec-client immer aufrecht gehalten wird. Der Client dient in dem Beispiel nur zum senden der Befehle.

Ich habe mich an den Scripten versucht. Ich habe noch eine zweite "named Pipe" hinzugefügt (die kannte ich bisher noch gar nicht) und bekomme beim Client auch eine Ausgabe mit "cat $CECFIFOBACK":

cecserver.sh

Code: Select all

#!/bin/bash
#
# Set up a fifo and connect cec-client to it
#
# By Will Cooke.  http://www.whizzy.org
# It's a very hacky solution, but it seems to just about work.
#
# Version 1.  Does the job.  November 2012
# Modified by Bismosa 26.01.2015

CECLOG=/tmp/cec.log
CECDEV=/dev/ttyACM0
CECFIFO=/tmp/cec.fifo
CECFIFOBACK=/tmp/cecback.fifo
CECCLIENT="/usr/local/bin/cec-client " #-d 8 -p 1 -b 5 -t p -o MythTV -f $CECLOG $CECDEV"

log(){
    echo "SERVER:  $1" >> $CECLOG
}


stop(){
    # Kill the right proceses
    log "Begin shutting down..."
    # Using this hacky grep so that we only match those tail processes looking 
    # at /dev/null rather than, say, syslog
    declare -a TAILPIDS=(`ps aux | grep 'tailf /dev/null' | egrep -v grep | awk '{print $2}'`)
    declare -a CATPIDS=(`ps aux | grep 'cat $CECFIFO' | egrep -v grep | awk '{print $2}'`)
    if [ ${#TAILPIDS[@]} -gt 0 ]
        then
            # Found some old tail processes to kill
            log "Found some tail processes..."
            for i in "${TAILPIDS[@]}"
            do
                log "Killing $i"
                kill $i
            done
    fi

    if [ ${#CATPIDS[@]} -gt 0 ]
        then
            # Found some old cat processes to kill
            # It's unlikely we will ever get in here, because the previous tail
            # processes have been killed and so shut down this end of the pipe
            # already.
            log "Found some cat processes..."
            for i in "${CATPIDS[@]}"
            do
                log "Killing $i"
                kill $i
            done
    fi

    log "Asking cec-client to stop if it's running..."
    # Using signal 2, the same as a ctrl-c
    killall -s 2 cec-client 2> $CECLOG
    log "Trying to remove FIFO..."
    rm $CECFIFO 2> $CECLOG
	rm $CECFIFOBACK #2> $CECLOG
	
    log "Done shutting down."
}

case "${1}" in
    start|restart)
        log "Starting server.  Since only one server can run at a time, stopping first."
        stop
        log "Done stopping, now starting..."
        log "Setting up FIFOs..."
        # We use a FIFO to pass in CEC commands to the cec-client which comes
        # with libcec.
        mkfifo $CECFIFO
		mkfifo $CECFIFOBACK
		
        log "Open pipe for writing..."
        # We use tailf /dev/null because it doesn't disconnect from stdin when
        # put in the background and it doesn't cause any load when running.
        tailf /dev/null > $CECFIFO &
        echo "Opening pipe for reading and start cec-client..."
        # Since we're writing to a log file anyway we don't need the output from
        # cec-client.  Put the whole thing in brackets to background the lot.
        #(cat $CECFIFO | $CECCLIENT &) > /dev/null
		(cat $CECFIFO | $CECCLIENT &) > $CECFIFOBACK &
        log "Start up complete."
    ;;
    
    stop)
        stop
    ;;

    *)
        echo $"Usage: $0 {start|stop|restart}"
        exit 1
esac

exit 0
cecsimple.sh

Code: Select all

#!/bin/bash
#
# Execute some fairly simple CEC commands
# Can use the "server" if its already running for faster execution
# or will fall back to starting the cec-client in "single pass" mode.
#
# Another terrible hack from Will Cooke.  http://www.whizzy.org
#
# Handy site: http://www.cec-o-matic.com/
# 
# Version 1.  Seems to work. Nov. 2012
# Modified by Bismosa 26.01.2015

CECLOG=/tmp/cec.log
CECDEV=/dev/ttyACM0
CECFIFO=/tmp/cec.fifo
CECCLIENT="/usr/local/bin/cec-client -s -d 8 -p 1 -b 5 -t p -o MythTV $CECDEV"
CECFIFOBACK=/tmp/cecback.fifo

log(){
    echo "SIMPLE CLIENT:  $1" >> $CECLOG
}

send_command(){
    if [ $CECCLIENTAVAIL == true ]
        then
            # We've tested for the "server", and it seems to be running
            # Basically we dont have to start cec-client from scratch which
            # saves about 4 seconds, so things like volume control are a bit
            # more responsive.
            log "Using server to send CEC packets $1 ..."
            echo $1 > $CECFIFO
			
			
			while read line 
				do
					echo $line
				done <$CECFIFOBACK
        	#echo `cat $CECFIFOBACK`
		else
            # Server wasn't found to be running, so start cec-client
            # just for this one command.
            # Why is this here?  Well, sometimes when you come out of suspend
            # the cec-client, and so the "server" drops the connection to the
            # USB CEC device and so quits.  This means that we can always send
            # commands regarless of the state of the server.
            log "Using single run cec-client to send packets ( $1 ) ..."
            echo $1 | $CECCLIENT
    fi
}

# We should check if the server is running, because if it is we should use it.
CECCLIENTPID=`pidof cec-client`
if [ $? -lt 1 ]
    then
        # cec-client is /probably/ running ok
        CECCLIENTAVAIL=true
        log "Main server seems to be alive.  We will use that instead."
    else
        CECCLIENTAVAIL=false
fi


# Here are the commands we know how to support

case "${1}" in
    tvon)
        # "on" is supported by cec-client, it's a kind of short cut to the
        # hex codes.  0 is always the destination address of the TV.
        send_command "on 0"
        # Make sure something appears on the TV we've just switched on
	    xscreensaver-command -deactivate
    ;;
    
    tvoff)
        # "standby" is also supported by cec-client
        send_command "standby 0"
    ;;

    ampon)
        #address 5 is the "audio system" in an HDMI network
        send_command "on 5"
    ;;

    ampoff)
        # My Sony Amp doesn't support "standby" for some reason, so instead
        # I poke it like this...
        send_command "tx 45 44 6C"
        # 45 means from 4 (me, the playback device) to 5(amp)
        # 44 6C means "the user pressed the power off button, nap time"
    ;;

    allon)
        # address f is the broadcast address.  Haven't actually tested this.
        send_command "on f"
    ;;

    alloff)
        # same
        send_command "standby f"
    ;;

    activesrc)
        # Me (4) to broadcast (f) -> I am now the active source, switch to me.
        # 82 "switch to", 1100 = address 1.1.0.0 the first device on dev 1 (amp)
        # 1.2.0.0 would be the 2nd sub device on device 1
        # 2.1.0.0 would be the 1st sub device on device 2
        send_command "tx 4F 82 11 00"
    ;;
	
    mute)
        # Me to TV -> user pressed mute
		send_command "tx 40 44 43"
	;;
	
    volup)
        # Me to TV -> user pressed vol up
		send_command "tx 40 44 41"
	;;
   
	voldown)
        # Me to TV -> user pressed vol down
		send_command "tx 40 44 42"
	;;

	status)
        # Me to TV -> user pressed vol down
		send_command "pow 0"
	;;
	
    *)
        echo $"Usage: $0 {tvon|tvoff|ampon|ampoff|allon|alloff|activesrc|mute|volup|voldown}"
        exit 1
    ;;
esac

exit 0
Mein Problem ist jetzt, dass ich es noch nicht geschafft habe die Rückgabe vom Server in eine Variable zu bekommen. Beim lesen mit der Schleife bzw über cat bleibt die Ausführung des Scriptes hängen. Was kann ich tun, um nach der Ausgabe mein Script weiter laufen zu lassen? Wie kann ich das Ende der Pipe erkennen?

Ich denke das ist schon ein vielversprechender Ansatz...und geht genau in die Richtung die ich haben wollte :)

Gruß
Bismosa

bismosa
Posts: 40
Joined: Sun Dec 23, 2012 11:43 am

Re: HDMI CEC - Status per Bash abfragen

Sun Feb 01, 2015 7:07 pm

Hallo!

Auch wenn es hier für mich zum monolog wird...ich möchte trotzdem das Ergebnis posten. Vielleicht gibt es ja noch andere verrückte die das mal brauchen.
Ich habe es hinbekommen! Zwar ganz anders als gedacht....aber es funktioniert endlich.

Nachdem alle versuche mit einem Bash-Skript fehlgeschlagen sind, habe ich mir die libcec genauer angeschaut. Da meine Erfahrungen mit C++ bei 0 liegen...habe ich versucht mich in das Thema einzuarbeiten.
Gefunden habe ich dann nach Stundenlangen versuchen und auch einigen frust folgende Seite:
https://github.com/DrGeoff/cec_simplest ... mplest.cpp
Das war auf jeden Fall ein sehr guter Ansatz. Das Beispiel habe ich dann in mühevoller Kleinarbeit auf meine Bedürfnisse angepasst.
Jetzt kann kontinuierlich der Status (fast) ohne reconnect abgefragt und verarbeitet werden.

Das Abfragen vom Status erfolgt einfach mittels:

Code: Select all

CEC::cec_power_status power = cec_adapter->GetDevicePowerStatus((CEC::cec_logical_address)0);
std::cout << "Status:" << cec_adapter->ToString(power) << std::endl;
Wenn Interesse besteht gebe ich meinen kompletten spaghetti-code gerne weiter.

Gruß
Bismosa

u001747
Posts: 1
Joined: Sun May 08, 2016 8:33 am

Re: HDMI CEC - Status per Bash abfragen

Sun May 08, 2016 8:37 am

Hallo Bismosa,

könnte ich Deinen "Spagetti-Code" bekommen. Herzlichen Dank.

Gruß u001747

PacGyver
Posts: 2
Joined: Tue Feb 21, 2017 6:38 pm

Re: HDMI CEC - Status per Bash abfragen

Tue Feb 21, 2017 6:46 pm

Auch wenn das Thema schon etwas älter ist hatte ich das gleiche Bedürfnis und bin durch google auf diesen Beitrag gestoßen. Mit der C++-Lösung bin ich allerdings nicht klar gekommen, insbesondere was die weitere Verarbeitung in OpenRemote angeht. Ich habe die Idee mit der Pipe aufgegriffen und daraus folgendes gemacht:

Code: Select all

(while true ; do sleep 5 ; echo "pow 0" ; done) | cec-client -d 8 -p 1 -b 5 -t p | grep power  --line-buffered | while read x ; do       
        echo $x | awk '{split($0,a,":");print a[2]}' | sed 's/ //' | tee /var/state/tvpower
done
Bisher scheint es gut zu funktionieren, die Datei /var/state/tvpower enthält ein simples "on" oder "standby".

Edit 27.02.2017: Manchmal wird ein "unknown" zurückgeliefert, das bringt bei mir OpenRemote durcheinander. Außerdem habe ich den Code durch Variablen ergänzt. Die neueste Version ist bei github zu finden: https://github.com/PacGyver/ha-scripts/ ... v_power.sh
Mein Raspberry Pi mit OpenRemote: www.hobbykritiker.de

PacGyver
Posts: 2
Joined: Tue Feb 21, 2017 6:38 pm

Re: HDMI CEC - Status per Bash abfragen

Fri Mar 03, 2017 6:59 pm

Ok, jetzt aber!
Jetzt wird die Datei nur noch geschrieben wenn sich der Status ändert.

Code: Select all

#!/bin/bash
OUTPUT="/var/state/tvpower"
SLEEP=5
DEVICE=0
STATE=""

(while true; do sleep $SLEEP ; echo "pow $DEVICE"; done) | cec-client -d 8 -p 1 -b 5 -t p | grep power  --line-buffered | while read x ; do	
	STATE=`echo $x | awk '{split($0,a,":");print a[2]}' | sed 's/ //'`
	if [ $STATE == "on" -o $STATE == "standby" ] && [ ! "$STATE" == "$PREV_STATE" ]
	then
			echo $STATE | tee $OUTPUT
			PREV_STATE=$STATE
	fi
Mein Raspberry Pi mit OpenRemote: www.hobbykritiker.de

einfach112
Posts: 1
Joined: Thu May 23, 2019 7:15 am

Re: HDMI CEC - Status per Bash abfragen

Thu May 23, 2019 8:20 am

Hallo zusammen.
Bin seltsamerweise erst nach 2 Tagen auf diesen Thread gestoßen. Passt aber glaube ich ganz gut.

Ich würde gerne folgendes machen:
Auslesen welcher HDMI-Port am TV gerade gewählt ist.....
Per
echo "tx 4F:82:10:00" | cec-client -s
kann ich schon z.B. am TV auf hdmi 1 umstellen.

Es müsste doch auch möglich sein den aktuell eingestellten HDMI kanal am TV auszulesen oder?

Mein Ziel ist es später sagen zu können:
If -> am TV HDMI 1= aktiv then bla bla
if -> am TV HDMI 2= aktiv then xxx xxx

geht so etwas ?
Vielen dank im Voraus
einfach112

Return to “Deutsch”