Neues Modul schreiben für ein Radio ...

Begonnen von ritchie, 12 Juli 2013, 21:15:23

Vorheriges Thema - Nächstes Thema

ritchie

Hallo Zusammen,

gibt es eigentlich mittlerweile eine Art Basismodul für FHEM Module zu erstellen.

Ich konnte in der Dev-Wiki in den ToDo nachlesen, das solch ein Modul erstellt werden soll,
welche die Basis Methoden beinhaltet.

Gibt es das schon ?

Welches bestehende Modul wäre das beste als Basis zu nehmen, gibt es da ein bevorzugtes Modul ?

Gruss R.

IPU662  Ipfire & Fhem (Homematic + MAX) - Produktiv
Cubietruck (1Wire - USB) - Produktiv

rudolfkoenig

Solche Fragen haben wir oefters, siehe meine Antwort vor einem halben Jahr hier: Link

Ich habe gerade contrib/00_TAHR.pm (als Geruest gedacht) aktualisiert.

UliM

Hi,
da es um Fernsteuerung eines devices via http (?) geht, wäre vmtl eins der bestehenden Fernsteuerungs-Module die beste Vorlage:
- VIERA
- STV
- XBMC

o.ä.
Am besten mal schauen, wekches die gleiche Übertragungsvariante verwendet wie Du (http-request, telnet, ...) und das dann anpassen.

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

betateilchen

@ritchie ich habe gestern auch mal angefangen, über ein Modul für listenlive aufgrund Deiner bisherigen Aktivitäten zu sinnieren - vielleicht können wir uns da einfach zusammen austauschen. Für die Geschichte mit der http-Steuerung habe ich mir das Yamaha Modul als Grundlage ausgesucht.

Viele Grüße
Udo
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

ritchie

Hallo Zusammen,

das Teil wird über einen TCP/IP Socket gesteuert und ich habe bereits in dem allmeinen Thread
zum Webradio versucht eine erste Version einer möglichen Steuerung vorgestellt.

Leider ist eine vernünftige Steuerung des Radios erst mit der kommenden Firmware
möglich. Daher bin ich erstmal in der "Design - Phase", mit dem Wissen der
möglichen Funktionen der neuen Firmware natürlich.

Siehe hier:

Link

Hier kann man sich die Kommandos ansehen, welche ich mir so vorgestellt habe.

Gruss R.


IPU662  Ipfire & Fhem (Homematic + MAX) - Produktiv
Cubietruck (1Wire - USB) - Produktiv

betateilchen

Hallo ritchie,

mit dem untenstehenden Code kannst Du Dir zumindest schonmal ein Device vom Typ LISTENLIVE definieren :)

define llradio LISTENLIVE 192.168.123.100

Danach kannst Du mit

set llradio on

oder

set llradio off

das Ding schonmal ein- und ausschalten. (Im Moment muss natürlich noch die Abfrage eingebaut werden, ob das Gerät überhaupt an oder aus ist, da dummerweise für beide Aktionen das gleiche Kommando benutzt wird. Aber da bin ich grade dran.


Es ist natürlich noch SEHR VIEL zu tun, aber vielleicht hilft Dir das Grundgerüst schonmal weiter.

Viele Grüße
Udo



# $Id: 71_LISTENLIVE.pm  $
##############################################################################
#
#     71_LISTENLIVE.pm
#     An FHEM Perl module for controlling ListenLive-enabled Mediaplayers
#     via network connection.
#
#     This file is part of fhem.
#
#     Fhem is free software: you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation, either version 2 of the License, or
#     (at your option) any later version.
#
#     Fhem is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License
#     along with fhem.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

package main;

use strict;
use warnings;
use POSIX;
use CGI qw(:standard);
use IO::Socket;
use IO::Socket::INET;
use MIME::Base64;
use Time::HiRes qw(gettimeofday sleep usleep nanosleep);
use HttpUtils;
use feature qw/say switch/;


sub LISTENLIVE_Get($@);
sub LISTENLIVE_Define($$);
sub LISTENLIVE_GetStatus($;$);
sub LISTENLIVE_Undefine($$);

###################################
sub
LISTENLIVE_Initialize($)
{
  my ($hash) = @_;

  $hash->{GetFn}     = "LISTENLIVE_Get";
  $hash->{SetFn}     = "LISTENLIVE_Set";
  $hash->{DefFn}     = "LISTENLIVE_Define";
  $hash->{UndefFn}   = "LISTENLIVE_Undefine";

  $hash->{AttrList}  = "do_not_notify:0,1 loglevel:0,1,2,3,4,5 ".
                      $readingFnAttributes;
}

###################################
sub
LISTENLIVE_GetStatus($;$)
{

}

###################################
sub
LISTENLIVE_Get($@)
{

}

###################################
sub
LISTENLIVE_Set($@)
{
    my ($hash, @a) = @_;
    my $name = $hash->{NAME};
    my $address = $hash->{helper}{ADDRESS};
    my $result = "";
    my $command;
       
    return "No Argument given" if(!defined($a[1]));    
   
    my $what = $a[1];
    my $usage = "Unknown argument $what, choose one of on off up down left right ok exit home statusRequest";

    given ($what){

       when("on") {

$result = LISTENLIVE_SendCommand($hash, "POWER");

if($result =~  m/OK/)
{
   readingsBeginUpdate($hash);
   readingsBulkUpdate($hash, "power","on");
   readingsBulkUpdate($hash, "state","on");
   readingsEndUpdate($hash, 1);
   return undef;
}
else
{
   return "Could not set power to on";
}
        break;
      }

       when("off") {

        $result = LISTENLIVE_SendCommand($hash, "POWER");

        if($result =~  m/OK/)
        {
            readingsBeginUpdate($hash);
            readingsBulkUpdate($hash, "power","off");
            readingsBulkUpdate($hash, "state","off");
            readingsEndUpdate($hash, 1);
            return undef;
        }
        else
        {
            return "Could not set power to off";
        }
        break;
      }

      when("statusRequest") {
        # Will be executed on the end of this function anyway, so no need to call it specificly
        break;
      }

      default:
        { break; }
    }


   
#    # Call the GetStatus() Function to retrieve the new values after setting something (with local flag, so the internal timer is not getting interupted)
#    LISTENLIVE_GetStatus($hash, 1);
   
    return undef;    
}


#############################
sub
LISTENLIVE_Define($$)
{
    my ($hash, $def) = @_;
    my @a = split("[ \t][ \t]*", $def);
    my $name = $hash->{NAME};
   
    if(! @a >= 4)
    {
my $msg = "wrong syntax: define <name> LISTENLIVE <ip-or-hostname> [<port>] [<state>]";
Log 2, $msg;
return $msg;
    }


    my $address = $a[2];
 
    $hash->{helper}{ADDRESS} = $address;
       
    if(defined($a[3]))
    {
        $hash->{helper}{PORT} = $a[3];
    }
    else
    {
$hash->{helper}{PORT} = "8080";
    }
   
    if(defined($a[4]))
    {
$hash->{helper}{STATE}=$a[4];
    }
    else
    {
$hash->{helper}{STATE}="";
    }
   
    $hash->{helper}{AVAILABLE} = 1;
   
    InternalTimer(gettimeofday()+2, "LISTENLIVE_GetStatus", $hash, 0);
 
  return undef;
}

#############################
sub
LISTENLIVE_SendCommand($$;$)
{
    my ($hash, $command, $loglevel) = @_;
    my $name = $hash->{NAME};
    my $address = $hash->{helper}{ADDRESS};
    my $port = $hash->{helper}{PORT};
    my $response = "";
    my ($socket,$client_socket);
#  my $response ="";

$loglevel = GetLogLevel($hash->{NAME}, 3) unless(defined($loglevel));
Log GetLogLevel($name,3), "LISTENLIVE: address: $address port: $port";

#
# Create a socket object for the communication with the radio
#
  $socket = new IO::Socket::INET (
PeerHost => $address,
PeerPort => $port,
Proto => 'tcp',
  ) or die "ERROR in Socket Creation : $!\n";

Log GetLogLevel($name, 3), "LISTENLIVE: send command: $command";

#
# Send the given command into the socket
#
  $socket->send($command);

#
# get the radio some time to execute the command (300ms )
#
  usleep(30000);   ###### <- erhöhen, wenn das Radio Kommandos verschluckt

#
# get the answer of the radio
#
  $socket->recv($response, 2);

Log GetLogLevel($name, 3), "LISTENLIVE: response: $response";

  if($response !~  m/OK/)
    {
        Log 1, "Error from radio ! Response from Radio : $response" ;
    }

  $socket->close();

   
    $hash->{helper}{AVAILABLE} = (defined($response) ? 1 : 0);
   
    return $response;

}

#############################
sub
LISTENLIVE_Undefine($$)
{
  my($hash, $name) = @_;
 
  # Stop the internal GetStatus-Loop and exist
  RemoveInternalTimer($hash);
  return undef;
}

1;

=pod
=begin html

<a name="LISTENLIVE"></a>
<h3>LISTENLIVE</h3>
<ul>

  <a name="LISTENLIVEdefine"></a>
  <b>Define</b>
  <ul>
    <code>define &lt;name&gt; LISTENLIVE &lt;ip-address&gt; [&lt;port&gt;] [&lt;state&gt;]</code>
    <br><br>

    Example:<br><br>
    <ul><code>
       define llradio LISTENLIVE 192.168.0.10
       <br><br>
       define listenlife device llradio 192.168.0.10 port 8080
    </code></ul>
   
  </ul>
</ul>

=end html
=cut
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

ritchie

Hallo Udo,

na das nenne ich mal eine tolle Antwort.

Ich werde mir den Code ansehen und entsprechend versuchen zu erweitern (also auch mit Kommentaren).

Wenn Du nichts dagegen hast, können wir ja diesen Code gemeinsam ans rennen bringen.
(Ich bin da derzeit eher am Anfang, was das angeht.)

Jedoch sind einige Funktionen erst verfügbar, wenn man die neue Firmware von
Livelisten hat. Diese habe ich selber auch nicht, daher sind einige Funktionen
derzeit noch nicht möglich.

Gruss R.
IPU662  Ipfire & Fhem (Homematic + MAX) - Produktiv
Cubietruck (1Wire - USB) - Produktiv

betateilchen

Hallo,

ich bin inzwischen schon sehr viel weiter als oben angegeben.

Lass uns mal das weitere Vorgehen per email abstimmen, ich melde mich per email hier über das Forum bei Dir.

Viele Grüße
Udo
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

betateilchen

Da ritchie im Moment noch ein bisschen anderweitig beschäftigt ist, habe ich einfach mal weitergebastelt. Sobald er mehr Zeit und Muse hat, werden wir uns abstimmen, wer welche Parts weiterbaut.

Falls jemand testen möchte, im Anhang ist mein aktueller Lösungsansatz zur Steuerung von ListenLive Geräten auf Modulbasis.

Es stehen aktuell folgende Befehle zur Verfügung:


define llradio LISTENLIVE <ip-adresse> [<host>]

set llradio power on
set llradio power off

set llradio audio mute
set llradio audio unmute
set llradio audio volp
set llradio audio volm

set llradio cursor up
set llradio cursor down
set llradio cursor left
set llradio cursor right
set llradio cursor ok
set llradio cursor enter (identisch zu ok)
set llradio cursor home
set llradio cursor exit

set llradio app weather

set llradio raw <command> (schickt ohne weitere Kontrolle oder Rückmeldung einfach ein Kommando an das Gerät, die Rückmeldung des Gerätes wird in das Reading rawresult geschrieben)

set llradio reset power
set llradio reset mute
set llradio reset menupos

(diese drei Befehle dienen dazu, den Gerätestatus synchroniseren zu können)


Anmerkungen:

Die Befehle "power <on|off>" und "audio <mute|unmute>" sind mit Readings verbunden und werden geprüft. Steht das Reading auf on, wird kein neuer Einschaltbefehl geschickt.
Das war notwendig, da bei Power und Mute ein TOGGLE stattfindet und immer der gleiche Befehl geschickt wird.

Das Reading menupos enthält die aktuelle Position des Cursors auf dem Bildschirm. 11 = 1. Zeile, 1.Spalte, 23 = 2.Zeile, 3. Spalte usw. Das Ganze ist experimentell.

Wird im define der Port weggelassen, wird 8080 als default verwendet.


Viel Spaß damit - Rückmeldungen dazu bitte jederzeit hier im Forum schreiben.

PS: wie schreibt man eigentlich am einfachsten den Doku-Teil am Ende eines Moduls?
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

ritchie

Hallo Zusammen,

da ich derzeit "Land Unter" anzeigen muss, übernimmt betateilchen jetzt aktiv das Modul "ListenLive".

Gruss R.
IPU662  Ipfire & Fhem (Homematic + MAX) - Produktiv
Cubietruck (1Wire - USB) - Produktiv

betateilchen

Bitte weitere Diskussion zum Thema FHEM & ListenLive Geräte hier zentral führen: Sammelthread: Steuerung von Webradios mit ListenLive Firmware
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!