########################################################################################################################
# Tradfri.pm
#-----------------------------------------------------------------------------------------------------------------------
#
# Kommunikation mit dem Ikea Tradfri Gateway
#
# Bei farbige Lampen kann die Farbtemperatur zusätzlich über ct-Werte eingestellt werden. Hierzu wurde ein Mapping der
# Temperaturangabe auf die xyY-Farbraum integriert.
#
# Fehlt noch:
# - Implementierung Sensoren
# - Implementierung Rollos
# - Implementierung Szenen
#
#
# Getestete Geräte:
# TRADFRI bulb E27 CWS opal 600lm (Color)
# TRADFRI bulb E14 CWS opal 600lm (Color)
# TRADFRI bulb E14 W op/ch 400lm (Fix White)
# FLAIR VIYU-C35-470-CCT-10011722 (Tunable White) 
# TRADFRI remote control
# TRADFRI on/off switch
#
#
# Aufruf           : use TSS::Ikea::Tradfri;
#
#                    Neuen Öffentlicher Schlüssel erzeugen:
#                    --------------------------------------
#                    my $gobjGateway = TSS::Ikea::Tradfri->new( host => "192.168.178.107", username => "MurrKatza", gatewaycode => "w9MuuMCkD1XQ3qYD" );
#
#                    Genereller Aufruf:
#                    ------------------
#                    my $gobjGateway = TSS::Ikea::Tradfri->new( host => "192.168.178.107", username => "MurrKatza", presharedkey => "3yeMwVrsSKohcYUm" );
#
#                    Version ausgeben:
#                    -----------------
#                    print "Version: ".$TSS::Ikea::Tradfri::VERSION."\n";
#         
#                    Alle Geräte auflisten:
#                    ----------------------
#                    my $gprtarrDevices=$gobjGateway->listObjects();
#                    if (! defined($gprtarrDevices)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    foreach my $tobjDevice ( @{$gprtarrDevices} ) { print $tobjDevice."\n"; }
#                      > <datapoint deviceid='itfr65543' name='TRADFRI remote control' devicetype='fernbedienung' online='1' batterylevel='16' />
#                      > <datapoint deviceid='itfr65546' name='TRADFRI on/off switch' devicetype='on/off-switch' online='1' batterylevel='47' />
#                      > <datapoint deviceid='itfp12345' name='Steckdose' devicetype='plug' online='1' status='1' batterylevel='87' brightness='254' />
#                      > <datapoint deviceid='itfl65542' name='Hobbyraum-Fenster' devicetype='bulb:fixed_white,dimmable' online='1' status='0' brightness='9' />
#                      > <datapoint deviceid='itfl65541' name='Hobbyraum-Türe' devicetype='bulb:fixed_white,dimmable' online='1' status='0' brightness='10' />
#                      > <datapoint deviceid='itfl65537' name='Sideboard' devicetype='bulb:color,tunable_white,dimmable' online='1' status='1' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='1' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#
#                    Geräteinformationen ausgeben:
#                    -----------------------------
#                    my $gobjDevice=$gobjGateway->getDeviceInfo("itfl65544"); # itfl65544=Device-ID;
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='1' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#
#                    Alle Geräte aus-/einschalten:
#                    -----------------------------
#                    my $gstrResult=$gobjGateway->setPowerAll(0); # 0=aus, 1=ein
#                    if (! $gstrResult) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "Befehl erfolgreich!\n"; }
#                    print $gstrResult."\n";
#                      > <datapoint deviceid='' status='0' />
#
#                    Alle Lampen aus-/einschalten:
#                    -----------------------------
#                    my $gstrResult=$gobjGateway->setPowerAllLights(0); # 0=aus, 1=ein
#                    if (! $gstrResult) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "Befehl erfolgreich!\n"; }
#                    print $gstrResult."\n";
#                      > <datapoint deviceid='' status='0' />
#
#                    Alle Steckdosen aus-/einschalten:
#                    -----------------------------
#                    my $gstrResult=$gobjGateway->setPowerAllPlugs(0); # 0=aus, 1=ein
#                    if (! $gstrResult) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "Befehl erfolgreich!\n"; }
#                    print $gstrResult."\n";
#                      > <datapoint deviceid='' status='0' />
#
#                    Alle Gruppen aus-/einschalten:
#                    ------------------------------
#                    my $gstrResult=$gobjGateway->setPowerAllGroups(0); # 0=aus, 1=ein
#                    if (! $gstrResult) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "Befehl erfolgreich!\n"; }
#                    print $gstrResult."\n";
#                      > <datapoint deviceid='' status='0' />
#         
#                    Ein Gerät aus-/einschalten:
#                    ---------------------------
#                    my $gobjDevice=$gobjGateway->setPower("itfl65544",0); # itfl65544=Device-ID; 0=aus, 1=ein
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='0' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#                    print $gobjDevice->status()."\n";
#                      > <datapoint deviceid='itfl65544' status='0' />
#
#                    Helligkeit eines Gerätes steuern:
#                    ---------------------------------
#                    my $gobjDevice=$gobjGateway->setBrightness("itfl65544",100); # itfl65544=Device-ID; 0-254=Helligkeit
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='0' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#                    print $gobjDevice->brightness()."\n";
#                      > <datapoint deviceid='itfl65544' brightness='66' />
#
#                    Farbtemperatur eines Gerätes steuern:
#                    -------------------------------------
#                    my $gobjDevice=$gobjGateway->setTemperature("itfl65544",1); # itfl65544=Device-ID; 1-3=Farbtemperatur
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                         else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='1' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#                    print $gobjDevice->temperature()."\n";
#                      > <datapoint deviceid='itfl65544' temperature='3' />
#
#                    Farbe eines Gerätes über Farbwert steuern:
#                    ------------------------------------------
#                    my $gobjDevice=$gobjGateway->setColor("itfl65544",1); # itfl65544=Device-ID; 1-20=Farbe
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='1' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#                    print $gobjDevice->color()."\n";
#                      > <datapoint deviceid='itfl65544' color='19' />
#
#                    Farbtemperatur eines Gerätes über ct-Wert steuern:
#                    --------------------------------------------------
#                    my $gobjDevice=$gobjGateway->setCT("phl2",1); # phl2=Device-ID; 153-500=Farbtemperatur
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                         else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='phl2' name='Hue color lamp 1' devicetype='LCA001' online='1' status='1' brightness='120' temperaturect='366' xyY='0.4572,0.4099,120' hsv='65535,65279,75' />
#                    print $gobjDevice->temperaturect()."\n";
#                      > <datapoint deviceid='phl2' temperaturect='3' />
#
#                    Farbe eines Gerätes über xyY-Wert ändern:
#                    -----------------------------------------
#                    my $gobjDevice=$gobjGateway->setXYY("itfl65544","9830,3932,133"); # itfl65544=Device-ID; "0-65535,0-65535,0-254"=xyY-Wert
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65544' name='Stehlampe' devicetype='bulb:color,tunable_white,dimmable' online='1' status='1' brightness='66' temperature='2' color='5' xyY='9830,3932,133' hsv='65535,65279,75' />
#                    print $gobjDevice->colorxyY()."\n";
#                      > <datapoint deviceid='itfl65544' xyY='9830,3932,133' />
#
#                    Farbe eines Gerätes über HSV-Wert ändern:
#                    -----------------------------------------
#                    my $gobjDevice=$gobjGateway->setHsv("itfl65544","21845,65279,75"); # itfl65544=Device-ID; "0-65535,0-65279,0-254"=hsv-Wert
#                    if (! defined($gobjDevice)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gobjDevice\n"; }
#                      > <datapoint deviceid='itfl65552' name='Stehlampe' devicetype='TRADFRI bulb E27 CWS opal 600lm' online='1' status='1' brightness='75' temperature='0' color='0' ct='153' xyY='19583,39167,75' hsv='21845,65279,75' />
#                    print $gobjDevice->colorxyY()."\n";
#                      > <datapoint deviceid='itfl65552' xyY='19583,39167,75' />
#
# Attribute        : Fehlertext   = $lobjSelf->{"error"}
#                    IP-Adresse   = $lobjSelf->{"host"}
#                    Benutzername = $lobjSelf->{"username"}
#                    Gateway-Code = $lobjSelf->{"gatewaycode"}
#                    Gateway-Key  = $lobjSelf->{"presharedkey"}
#                    Geräteliste  = $lobjSelf->{"devices"}             = Hash mit allen Tradfri-IDs (Key) und Typ (Value), Keine Gruppen, Tradfri-Id's ohne Präfix (it[x])
#
# Methoden         : Alle Geräte ausgeben                              = $objGateway->listObjects()
#                    Geräteinformationen ausgeben                      = $objGateway->getDeviceInfo(<Geräte-ID>)
#                    Alle Geräte schalten                              = $objGateway->setPowerAll(<Status>)              -> <Status>     : 0=aus, 1=ein
#                    Alle Lampen schalten                              = $objGateway->setPowerAllLights(<Status>)              -> <Status>     : 0=aus, 1=ein
#                    Alle Steckdosen schalten                          = $objGateway->setPowerAllPlugs(<Status>)              -> <Status>     : 0=aus, 1=ein
#                    Alle Gruppen schalten                             = $objGateway->setPowerAllGroups(<Status>)              -> <Status>     : 0=aus, 1=ein
#                    Ein Gerät schalten                                = $objGateway->setPower(<Geräte-ID>,<Status>)           -> <Status>     : 0=aus, 1=ein
#                    Helligkeit eines Gerätes steuern                  = $objGateway->setBrightness(<Geräte-ID>,<Helligkeit>)  -> <Helligkeit> : 0-254=Helligkeit
#                    Farbtemperatur eines Gerätes steuern              = $objGateway->setTemperature(<Geräte-ID>,<Temperatur>) -> <Temperatur> : 1-3=Temperatur
#                    Farbe eines Gerätes über Farbwert ändern          = $objGateway->setColor(<Geräte-ID>,<Farbe>)            -> <Farbe>      : 1-20=Farbe
#                    Farbtemperatur eines Gerätes über ct-Wert steuern = $objGateway->setCT(<Geräte-ID>,<Temperatur>)          -> <Temperatur> : 153-500=Temperatur
#                    Farbe eines Gerätes über xyY-Wert ändern          = $objGateway->setXYY(<Geräte-ID>,<Farbe>)              -> <Farbe>      : 0-65535,0-65535,0-254=x,y,Y
#                    Farbe eines Gerätes über HSV-Wert ändern          = $objGateway->setHsv(<Geräte-ID>,<Farbe>)              -> <Farbe>      : 0-65535,0-65279,0-254=H,S,V
#
# Präfixe Device-ID: itfb Rollos (b=blind)
#                    itfg Gruppen (g=group)
#                    itfl Leuchten (l=light)
#                    itfm Bewegungsmelder (m=motion)
#                    itfp Steckdosen (p=plug)
#                    itfr Fernbedienungen (r=Remote)
#                    itfs Szenen (s=scene)
#
# Farben           : 1             = "dcf0f8"
#                    2             = "eaf6fb"
#                    3             = "f5faf6" (coldwhite)
#                    4             = "f2eccf"
#                    5             = "f1e0b5" (normalwhite)
#                    6             = "efd275" (warmwhite)
#                    7             = "ebb63e"
#                    8             = "e78834"
#                    9             = "e57345"
#                    10             = "da5d41"
#                    11            = "dc4b31"
#                    12            = "e491af"
#                    13            = "e8bedd"
#                    14            = "d9337c"
#                    15            = "c984bb"
#                    16            = "8f2686"
#                    17            = "4a418a"
#                    18            = "6c83ba"
#                    19            = "a9d62b"
#                    20            = "d6e44b"
#
# Weißtöne         : 1 = "f5faf6" (coldwhite)
#                    2 = "f1e0b5" (normalwhite)
#                    3 = "efd275" (warmwhite)
#
# Gerätetypen      : "TRADFRI bulb E14 W op/ch 400lm"  = Lampe weiß fix, dimmbar
#                    "TRADFRI bulb E27 CWS opal 600lm" = Lampe farbe steuerbar, weiß steuerbar, dimmbar
#                    "TRADFRI bulb E14 CWS opal 600lm" = Lampe farbe steuerbar, weiß steuerbar, dimmbar
#                    "TRADFRI remote control"          = Fernbedinung rund 5 Tasten
#                    "TRADFRI on/off switch"           = Fernbedinung quadradisch 2 Tasten
#
# Zugriffstyp      : 0=Fernbedienung
#                    1=Slave Fernbedienung
#                    2=Lampe
#                    3=Steckdose
#                    4=Bewegungsmelder
#                    6=Repeater
#                    7=Rollo
#
# Stromquellen     : 0=Unbekannt
#                    1=Netzteil
#                    2=Externe Batterie
#                    3=Batterie
#                    4=PowerOverEthernet
#                    5=USB
#                    6=AC_Power
#                    7=Solar
#
# Version          : 01.11.2019 v1.0.0 Initiale Version
#                    25.11.2019 v1.0.1 HSB-Farbsteuerung hinzugefügt
#                    16.11.2019 v2.0.0 HSB-Farbsteuerung entfernt
#                    19.12.2019 v3.0.0 Neue Version
#                    20.12.2019 v3.0.1 Namensangelichungen mit anderen Modulen
#                    08.01.2020 v3.0.2 Implementierung Steckdosen, Farbsteuerung über HSV
#                    13.01.2020 v3.0.3 Korrektur der Funktion _xy2ct
#                    20.01.2020 v3.0.4 Neues Attribut Geräteliste - Hash mit allen Tradfri-IDs (Key) und Typ (Value), Keine Gruppen, Tradfri-Id's ohne Präfix (it[x])
#                    21.01.2020 v3.0.5 Workaround für fehlerhafte Gruppensati
#                    21.01.2020 v3.0.6 Farbsteuerung für Gruppen
#                    06.02.2020 v3.0.7 Copyright und Warranty hinzugefügt
#
#
# Copyright & Warranty:
# =====================
#
# Copyright (C) 2019 Thomas Schütz-Schneider 
#
# This program 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 3 of the License, or (at your option) any later version. 
#
# This program 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 this program; if not, see <http://www.gnu.org/licenses/>. 
#
########################################################################################################################


# ========================
#  Package-Name
# ========================
package TSS::Ikea::Tradfri;

# ========================
#  Definition der Pragmas
# ========================
use strict;
use warnings;
use JSON::Parse 'parse_json';
use TSS::Ikea::Tradfri::Light;
use TSS::Ikea::Tradfri::Plug;
use TSS::Ikea::Tradfri::Remote;
use TSS::Ikea::Tradfri::Group;

# ==================================
#  Definition der Versions-Variable
# ==================================
our $VERSION = "v3.0.7";


########################################################################################################################
# Konstruktur
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : use TSS::Ikea::Tradfri;
#           $objGateway = TSS::Ikea::Tradfri->new( host => <IP-Adresse>, username => <Benutzername>, gatewaycode => <Gateway-Code> | presharedkey => <Öffentlicher Schlüssel> );
#
# Übergabe: <IP-Adresse>             = IP-Adrese des Tradfri Gateways
#           <Benutzername>           = Benutzername des öffentlichen Schlüssels
#           <Gateway-Code>           = Sicherheitscode des Tradfri Gateways (Nur wenn noch kein öffentlicher Schlüssel vorhanden ist)
#           <Öffentlicher Schlüssel> = Öffentlicher Schlüssel zur Kommunikation mit dem Tradfri Gateway
#
# Rückgabe: $objGateway              = Tradfri Gateway
#
#-----------------------------------------------------------------------------------------------------------------------
sub new {
  my $lobjClass=shift; # Klasse-Name abfangen
  my $lobjSelf={};     # Klassen-Attribute
  my $lptrResult="";   # Zeiger auf Objekt mit dekdierten JSON-Sting

  # Korrekte Referenzierung auf den Klasse-Name
  $lobjClass = ref($lobjClass) || $lobjClass;
  
  # Parameter übernemen
  my %lhshParameter = (@_);
  
  # Attribute der Klasse erzeugen
  # Enthält im Fehlerfall in einer Subroutine die Fehlerbeschreibung
  $lobjSelf->{"error"}="";
  # IP-Adresse des Lightifiy Gateways
  $lobjSelf->{"host"} = $lhshParameter{'host'} || die "Fehlender Parameter \"host\"!";
  # Benutzername des Lightifiy Gateways
  $lobjSelf->{"username"} = $lhshParameter{'username'} || die "Fehlender Parameter \"username\"!";
  # Gateway-Code des Lightifiy Gateways
  $lobjSelf->{"gatewaycode"} = $lhshParameter{'gatewaycode'};
  # Öffentlicher Schlüssel des Lightifiy Gateways
  $lobjSelf->{"presharedkey"} = $lhshParameter{'presharedkey'};
  # Geräteliste - Hash mit allen Tradfri-IDs (Key) und Typ (Value), Keine Gruppen, Tradfri-Id's ohne Präfix (it[x])
  $lobjSelf->{"devices"}=();

  # Prüfen ob Gateway-Code oder Öffentlicher Schlüssel vorhanden ist
  if (($lobjSelf->{'gatewaycode'} eq "") && ($lobjSelf->{'presharedkey'} eq "")) { die "Fehlender Parameter \"gatewaycode/presharedkey\"!"; }
  if (($lobjSelf->{'username'} eq "") && ($lobjSelf->{'gatewaycode'} eq "")) { die "Fehlender Parameter \"username/gatewaycode\"!"; }
  
  # Klasse erzeugen
  bless( $lobjSelf, $lobjClass );

  # Prüfen ob kein Öffentlicher Schlüssel vorhanden ist
  if ($lobjSelf->{'presharedkey'} eq "") {
    # Öffentlicher Schlüssel Anfragen
    my $tstrResponse=$lobjSelf->_requestPresharedKey(); 
    # Fehlerüberprüfung
    if (!defined($tstrResponse)) { die "NIX!".$lobjSelf->{"error"}; }
    # JSON-String dekodieren
    $lptrResult=parse_json($tstrResponse);
    # Unerwaretetes Ergebnis?
    if (ref($lptrResult) ne "HASH") { die "Unerwartetes Ergebnisformat (".ref($lptrResult).") !"; }
    if (!defined($lptrResult->{"9091"})) { die "Keinen Öffentlicher Schlüssel erhalten!"; }
    # Öffentlicher Schlüssel des Tradfri Gateways
    $lobjSelf->{"presharedkey"}=$lptrResult->{"9091"};
  }    

  # Klasse zurück geben
  return($lobjSelf);
}
########################################################################################################################


########################################################################################################################
# Einen neuen Gateway-Code erzeugen
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objGateway->_requestPresharedKey();
#
# Übergabe: -
#
# Rückgabe: $strResponse = Json-String=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub _requestPresharedKey {
  my $lobjSelf=shift;        # Klasse-Name abfangen
  my $lstrResponse="";    # Antwort des Tradfri Gateways
  my $lstrRequest="";     # Anfrage an den Tradfri Gateway
  # Abfrage erzeugen
  $lstrRequest="coap-client -m post -u \"Client_identity\" -k ".$lobjSelf->{"gatewaycode"}." -e '{\"9090\":\"".$lobjSelf->{"username"}."\"}' \"coaps://".$lobjSelf->{"host"}.":5684/15011/9063\"";
  # Abfrage senden
  $lstrResponse=`$lstrRequest`;
  # Abfrage nicht erfolgreich?
  if ($? != 0) { $lobjSelf->{"error"}="Tradfri Gateway: Abfrage nicht erfolgreich!"; return; }
  chomp($lstrResponse);
  # Rückmeldung
  return($lstrResponse);
}
########################################################################################################################


########################################################################################################################
# Kommunikation mit dem Tradfri Gateway
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objGateway->_requestGateway($intMethod,$strExecute,$strCoapsCmd);
#
# Übergabe: $intMethod   = Methode (0=get, 1=put, 2=post)
#           $strExecute  = Auszuführende Aufgabe
#           $strCoapsCmd = Coap-Befehl
#
# Rückgabe: $strResponse = JSON-String=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub _requestGateway {
  my $lobjSelf=shift;     # Klasse-Name abfangen
  my $lintMethod=shift;   # Methode (0=get, 1=put, 2=post)
  my $lstrExecute=shift;  # Auszuführende Aufgabe
  my $lstrCoapsCmd=shift; # Coap-Befehl
  my $lstrMethod="";      # Methode
  my $lstrRequest="";     # Anfrage an den Tradfri Gateway
  my $lstrResponse="";    # Antwort des Tradfri Gateways
  # Methode dekodieren
  if ($lintMethod == 0) { $lstrMethod="get"; }
  elsif ($lintMethod == 1) { $lstrMethod="put"; }
  else { $lstrMethod="post"; }
  # Auszuführende Aufgabe erstellen
  if ($lstrExecute ne "") { $lstrExecute= " -e '".$lstrExecute."'"; }
  # Anfrage an den Tradfri Gateway erstellen
  $lstrRequest="coap-client -B 1 -m $lstrMethod -u \"".$lobjSelf->{"username"}."\" -k \"".$lobjSelf->{"presharedkey"}."\"".$lstrExecute." \"coaps://".$lobjSelf->{"host"}.":$lstrCoapsCmd\" 2>/dev/null";
  # Abfrage senden
  $lstrResponse=`$lstrRequest`;
  # Abfrage nicht erfolgreich?
  if ($? != 0) { $lobjSelf->{"error"}="Tradfri Gateway: Abfrage nicht erfolgreich!"; return; }
  chomp($lstrResponse);
  # Rückmeldung
  return($lstrResponse);
}
########################################################################################################################


########################################################################################################################
# Liste der vorhandenen realen Objekt-ID's (ohne führendes "itfX") ermitteln
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $ptrArray=$objGateway->_getAllRealObjectIds($strEndpoint);
#
# Übergabe: $strEndpoint = Endpoint ("5684/15001"=Geräte, "5684/15004"=Gruppen)
#
# Rückgabe: $ptrArray    = Zeiger auf Array=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub _getAllRealObjectIds {
  my $lobjSelf=shift;     # Klasse-Name abfangen
  my $lstrEndpoint=shift; # Endpoint ("5684/15001"=Geräte, "5684/15004"=Gruppen)
  my $lstrResponse="";    # Antwort des Tradfri Gateways
  my $lptrResult="";      # Zeiger auf ein Array, Hash oder Sclar eines dekodierten JSON-Strings
  
  # Kommunikation mit dem Tradfri Gateway ->Geräteliste ausgeben
  $lstrResponse=$lobjSelf->_requestGateway(0,"",$lstrEndpoint);

  # Ist ein Fehler aufgetreten?
  if (!defined($lstrResponse)) { return; }
  
  # JSON-String dekodieren
  $lptrResult=parse_json($lstrResponse);
  
  # Unerwaretetes Ergebnis?
  if (ref($lptrResult) ne "ARRAY") { $lobjSelf->{"error"}="_getAllRealObjectIds: Unerwartetes Ergebnisformat (".ref($lptrResult).") !"; return; }

  # Erfolgreicher Rückmeldung
  return($lptrResult);
}
########################################################################################################################


########################################################################################################################
# Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResult=$objGateway->_checkObject($strEndpoint,$strAddress);
#
# Übergabe: $strEndpoint = Endpoint ("5684/15001"=Geräte, "5684/15004"=Gruppen)
#           $strAddress  = Geräte-ID (itfl65544)
#
# Rückgabe: $strResult   = JSON-String mit Gerätedaten=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub _checkObject {
  my $lobjSelf=shift;     # Klasse-Name abfangen
  my $lstrEndpoint=shift; # Endpoint ("5684/15001"=Geräte, "5684/15004"=Gruppen)
  my $lstrAddress=shift;  # Geräte-ID (itfl65544)
  my $lptrResult="";      # Zeiger auf ein Array, Hash oder Sclar eines dekodierten JSON-Strings
  my $lstrRealAddr="";    # Geräte-ID ohne führendes "itfl" (65544)
  my %lhshDeviceIds=();   # Vorhandene reale Geräte-ID ohne führendes "itfl" (65544) 
  my $lstrResponse="";    # Antwort des Tradfri Gateways

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Liste der vorhandenen realen Geräte-ID's (ohne führendes "itfX") ermitteln
  $lptrResult=$lobjSelf->_getAllRealObjectIds($lstrEndpoint);
  if (! defined($lptrResult)) { return; }

  # Wurden keine Geräte/Gruppen gefunden?
  if (scalar(@{$lptrResult}) < 1) { return; }

  # Array in Hash umwandlen
  $lhshDeviceIds{$_}++ for (@{$lptrResult});
  
  # Geräte-ID in reale Geräte-ID umwandeln
  $lstrRealAddr=$lstrAddress;
  $lstrRealAddr=~s/^itf[bglmprs]//;
  
  # Überprüfen ob das gewünsche Gerät/Gruppe nicht vorhanden ist
  if (!defined($lhshDeviceIds{$lstrRealAddr})) { $lobjSelf->{"error"}="_checkObject: Gerät/Gruppe '$lstrAddress' ist nicht vorhanden!"; return; }

  # Alle Geräte-/Gruppeninformationen auslesen
  $lstrResponse=$lobjSelf->_requestGateway(0,"",$lstrEndpoint."/$lstrRealAddr");

  # Ist ein Fehler aufgetreten?
  if (!defined($lstrResponse)) { return; }

  # Erfolgreiche Rückmeldung
  return($lstrResponse);
}
########################################################################################################################


########################################################################################################################
# ct-Temperatur in xy-Wert umrechen
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strValuexy=$objGateway->_ct2xy($intValueCt);
#
# Übergabe: $intValueCt = ct-Wert der Farbtemperatur
#
# Rückgabe: $strValuexy = xy-Wert der Farbtemperatur=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub _ct2xy {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $tintValueCt=shift; # ct-Wert der Farbtemperatur
  my $tstrValuexy="";    # xy-Wert der Farbtemperatur
  if ($tintValueCt < 154) { $tstrValuexy="0.3122,0.3282"; }
  elsif ($tintValueCt < 164) { $tstrValuexy="0.3136,0.3295"; }
  elsif ($tintValueCt < 174) { $tstrValuexy="0.3206,0.3356"; }
  elsif ($tintValueCt < 184) { $tstrValuexy="0.3276,0.3417"; }
  elsif ($tintValueCt < 194) { $tstrValuexy="0.3347,0.3473"; }
  elsif ($tintValueCt < 204) { $tstrValuexy="0.3419,0.353"; }
  elsif ($tintValueCt < 214) { $tstrValuexy="0.349,0.3584"; }
  elsif ($tintValueCt < 224) { $tstrValuexy="0.3562,0.3633"; }
  elsif ($tintValueCt < 234) { $tstrValuexy="0.3634,0.3684"; }
  elsif ($tintValueCt < 244) { $tstrValuexy="0.3705,0.3728"; }
  elsif ($tintValueCt < 254) { $tstrValuexy="0.3776,0.3772"; }
  elsif ($tintValueCt < 264) { $tstrValuexy="0.3846,0.3812"; }
  elsif ($tintValueCt < 274) { $tstrValuexy="0.3916,0.385"; }
  elsif ($tintValueCt < 284) { $tstrValuexy="0.3986,0.3888"; }
  elsif ($tintValueCt < 294) { $tstrValuexy="0.4053,0.3918"; }
  elsif ($tintValueCt < 304) { $tstrValuexy="0.4121,0.3949"; }
  elsif ($tintValueCt < 314) { $tstrValuexy="0.4187,0.3977"; }
  elsif ($tintValueCt < 324) { $tstrValuexy="0.4252,0.4001"; }
  elsif ($tintValueCt < 334) { $tstrValuexy="0.4317,0.4026"; }
  elsif ($tintValueCt < 344) { $tstrValuexy="0.438,0.4045"; }
  elsif ($tintValueCt < 354) { $tstrValuexy="0.4444,0.4065"; }
  elsif ($tintValueCt < 364) { $tstrValuexy="0.4505,0.4083"; }
  elsif ($tintValueCt < 374) { $tstrValuexy="0.4565,0.4097"; }
  elsif ($tintValueCt < 384) { $tstrValuexy="0.4626,0.4112"; }
  elsif ($tintValueCt < 394) { $tstrValuexy="0.4684,0.4122"; }
  elsif ($tintValueCt < 404) { $tstrValuexy="0.4741,0.4132"; }
  elsif ($tintValueCt < 414) { $tstrValuexy="0.4797,0.4139"; }
  elsif ($tintValueCt < 424) { $tstrValuexy="0.4852,0.4145"; }
  elsif ($tintValueCt < 434) { $tstrValuexy="0.4906,0.415"; }
  elsif ($tintValueCt < 444) { $tstrValuexy="0.4957,0.4151"; }
  elsif ($tintValueCt < 454) { $tstrValuexy="0.5008,0.4152"; }
  elsif ($tintValueCt < 464) { $tstrValuexy="0.5058,0.4151"; }
  elsif ($tintValueCt < 474) { $tstrValuexy="0.5106,0.4149"; }
  elsif ($tintValueCt < 484) { $tstrValuexy="0.5154,0.4146"; }
  elsif ($tintValueCt < 492) { $tstrValuexy="0.5199,0.4141"; }
  elsif ($tintValueCt < 497) { $tstrValuexy="0.5245,0.4136"; }
  else { $tstrValuexy="0.5267,0.4133"; }
  return($tstrValuexy);
}
########################################################################################################################


########################################################################################################################
# xy-Temperatur in ct-Wert umrechen
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $intValueCt=$objGateway->_xy2ct($strValuexy);
#
# Übergabe: $strValuexy = xy-Wert der Farbtemperatur
#
# Rückgabe: $intValueCt = ct-Wert der Farbtemperatur=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub _xy2ct {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $tstrValuexy=shift; # xy-Wert der Farbtemperatur
  my $tintValueCt=153;   # ct-Wert der Farbtemperatur
  
  my ($tintColX,$tintColY)=split(/,/,$tstrValuexy);

  if (($tintColX <= 0.3122) && ($tintColY <= 0.3282)) { $tintValueCt=153; }
  elsif (($tintColX <= 0.3136) && ($tintColY <= 0.3295)) { $tintValueCt=155; }
  elsif (($tintColX <= 0.3206) && ($tintColY <= 0.3356)) { $tintValueCt=165; }
  elsif (($tintColX <= 0.3276) && ($tintColY <= 0.3417)) { $tintValueCt=175; }
  elsif (($tintColX <= 0.3347) && ($tintColY <= 0.3473)) { $tintValueCt=185; }
  elsif (($tintColX <= 0.3419) && ($tintColY <= 0.3530)) { $tintValueCt=195; }
  elsif (($tintColX <= 0.3490) && ($tintColY <= 0.3584)) { $tintValueCt=205; }
  elsif (($tintColX <= 0.3562) && ($tintColY <= 0.3633)) { $tintValueCt=215; }
  elsif (($tintColX <= 0.3634) && ($tintColY <= 0.3684)) { $tintValueCt=225; }
  elsif (($tintColX <= 0.3705) && ($tintColY <= 0.3728)) { $tintValueCt=235; }
  elsif (($tintColX <= 0.3776) && ($tintColY <= 0.3772)) { $tintValueCt=245; }
  elsif (($tintColX <= 0.3846) && ($tintColY <= 0.3812)) { $tintValueCt=255; }
  elsif (($tintColX <= 0.3916) && ($tintColY <= 0.3850)) { $tintValueCt=265; }
  elsif (($tintColX <= 0.3986) && ($tintColY <= 0.3888)) { $tintValueCt=275; }
  elsif (($tintColX <= 0.4053) && ($tintColY <= 0.3918)) { $tintValueCt=285; }
  elsif (($tintColX <= 0.4121) && ($tintColY <= 0.3949)) { $tintValueCt=295; }
  elsif (($tintColX <= 0.4187) && ($tintColY <= 0.3977)) { $tintValueCt=305; }
  elsif (($tintColX <= 0.4252) && ($tintColY <= 0.4001)) { $tintValueCt=315; }
  elsif (($tintColX <= 0.4317) && ($tintColY <= 0.4026)) { $tintValueCt=325; }
  elsif (($tintColX <= 0.4380) && ($tintColY <= 0.4045)) { $tintValueCt=335; }
  elsif (($tintColX <= 0.4444) && ($tintColY <= 0.4065)) { $tintValueCt=345; }
  elsif (($tintColX <= 0.4505) && ($tintColY <= 0.4083)) { $tintValueCt=355; }
  elsif (($tintColX <= 0.4565) && ($tintColY <= 0.4097)) { $tintValueCt=365; }
  elsif (($tintColX <= 0.4626) && ($tintColY <= 0.4112)) { $tintValueCt=375; }
  elsif (($tintColX <= 0.4684) && ($tintColY <= 0.4122)) { $tintValueCt=385; }
  elsif (($tintColX <= 0.4741) && ($tintColY <= 0.4132)) { $tintValueCt=395; }
  elsif (($tintColX <= 0.4797) && ($tintColY <= 0.4139)) { $tintValueCt=405; }
  elsif (($tintColX <= 0.4852) && ($tintColY <= 0.4145)) { $tintValueCt=415; }
  elsif (($tintColX <= 0.4906) && ($tintColY <= 0.4150)) { $tintValueCt=425; }
  elsif (($tintColX <= 0.4957) && ($tintColY <= 0.4151)) { $tintValueCt=435; }
  elsif (($tintColX <= 0.5008) && ($tintColY <= 0.4152)) { $tintValueCt=445; }
  elsif (($tintColX <= 0.5058) && ($tintColY <= 0.4151)) { $tintValueCt=455; }
  elsif (($tintColX <= 0.5106) && ($tintColY <= 0.4149)) { $tintValueCt=465; }
  elsif (($tintColX <= 0.5154) && ($tintColY <= 0.4146)) { $tintValueCt=475; }
  elsif (($tintColX <= 0.5199) && ($tintColY <= 0.4141)) { $tintValueCt=485; }
  elsif (($tintColX <= 0.5245) && ($tintColY <= 0.4136)) { $tintValueCt=495; }
  else { $tintValueCt=500; }

  return($tintValueCt);
}
########################################################################################################################


########################################################################################################################
# Alle Geräte einlesen
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $ptrarrResponse=$objGateway->listObjects();
#
# Übergabe: -
#
# Rückgabe: $ptrarrResponse = Zeiger auf Array=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub listObjects {
  my $lobjSelf=shift;  # Klasse-Name abfangen
  my $lstrResponse=""; # Antwort des Tradfri Gateways
  my $lptrResult="";   # Zeiger auf ein Array, Hash oder Sclar eines dekodierten JSON-Strings
  my @larrDevices=();  # Gefundene Geräte

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";

  # Liste der vorhandenen realen Geräte-ID's (ohne führendes "itfX") ermitteln
  $lptrResult=$lobjSelf->_getAllRealObjectIds("5684/15001");
  if (! defined($lptrResult)) { return; }
  
  # Alle ID's bearbeiten
  foreach my $tstrDeviceId (@{$lptrResult}) {
    
    # Alle Geräteinformationen auslesen
    $lstrResponse=$lobjSelf->_requestGateway(0,"","5684/15001/$tstrDeviceId");

    # Ist ein Fehler aufgetreten?
    if (!defined($lstrResponse)) { return; }

    # Verzweigung nach Geräteart - Lampe
    if ( $lstrResponse =~ /"3311"/) { push( @larrDevices,TSS::Ikea::Tradfri::Light->new( gateway => $lobjSelf, devicedata => $lstrResponse ) ); }
    # Steckdose
    elsif ( $lstrResponse =~ /"3312"/) { push( @larrDevices,TSS::Ikea::Tradfri::Plug->new( gateway => $lobjSelf, devicedata => $lstrResponse ) ); }
    # Fernbedienung
    elsif ( $lstrResponse =~ /"15009"/) { push( @larrDevices,TSS::Ikea::Tradfri::Remote->new( gateway => $lobjSelf, devicedata => $lstrResponse ) ); }
    # Unbekannt
    else {}
  }
  
  # Liste der vorhandenen realen Gruppen-ID's (ohne führendes "itfX") ermitteln
  $lptrResult=$lobjSelf->_getAllRealObjectIds("5684/15004");
  if (! defined($lptrResult)) { return; }
  
  # Alle ID's bearbeiten
  foreach my $tstrGroupId (@{$lptrResult}) {
    
    # Alle Gruppeninformationen auslesen
    $lstrResponse=$lobjSelf->_requestGateway(0,"","5684/15004/$tstrGroupId");

    # Ist ein Fehler aufgetreten?
    if (!defined($lstrResponse)) { return; }

    # Daten einer Gruppe ablegen
    push( @larrDevices,TSS::Ikea::Tradfri::Group->new( gateway => $lobjSelf, devicedata => $lstrResponse ) );
  }

  # Erfolgreiche Rückmeldung
  return(\@larrDevices);
 }
########################################################################################################################


########################################################################################################################
# Geräteinformationen ausgeben
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->getDeviceInfo($strAddress);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub getDeviceInfo {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjDevices=();    # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itf[lrp]/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setBrightness: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
  
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }

  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjDevices=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Steckdows
  elsif ( $lstrAddress =~ /^itfp/) { $lobjDevices=TSS::Ikea::Tradfri::Plug->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Fernbedienung
  elsif ( $lstrAddress =~ /^itfr/) { $lobjDevices=TSS::Ikea::Tradfri::Remote->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjDevices=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="getDeviceInfo: Gerät '$lstrAddress' ist ein unbekannter Typ!"; return; }
 
  #Erfolgreiche Rückmeldung  
  return($lobjDevices);
}
########################################################################################################################


########################################################################################################################
# Alle Geräte schalten
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objGateway->setPowerAll($intState);
#
# Übergabe: $intState    = Neuer Status (0=Aus, 1=Ein)
#
# Rückgabe: $strResponse = 1String=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setPowerAll {
  my $lobjSelf=shift;   # Klasse-Name abfangen
  my $lintState=shift;  # Neuer Status (0=Aus, 1=Ein)
  my $lprtarrLights=""; # Zeiger auf Array mit den Tradfri-Geräten

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";

  # Alle Geräte auflisten:
  $lprtarrLights=$lobjSelf->listObjects();
  if (! defined($lprtarrLights)) { return; }
  foreach my $tobjLight ( @{$lprtarrLights} ) {
    # Nur Lampen/Steckdosen
    if ($tobjLight->{"deviceid"} =~ /^itf[lp].*$/) {
      # Gerät schalten
      my $tstrResult=$tobjLight->setPower($lintState);
      if (! defined($tstrResult)) { return; }
    }
  }

  # Erfolgreiche Rückmeldung
  return("<datapoint deviceid='' status='".$lintState."' />");
}
########################################################################################################################


########################################################################################################################
# Alle Lampen schalten
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objGateway->setPowerAllLights($intState);
#
# Übergabe: $intState    = Neuer Status (0=Aus, 1=Ein)
#
# Rückgabe: $strResponse = String=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setPowerAllLights {
  my $lobjSelf=shift;   # Klasse-Name abfangen
  my $lintState=shift;  # Neuer Status (0=Aus, 1=Ein)
  my $lprtarrLights=""; # Zeiger auf Array mit den Tradfri-Geräten

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";

  # Alle Geräte auflisten:
  $lprtarrLights=$lobjSelf->listObjects();
  if (! defined($lprtarrLights)) { return; }
  foreach my $tobjLight ( @{$lprtarrLights} ) {
    # Nur Lampen
    if ($tobjLight->{"deviceid"} =~ /^itfl.*$/) {
      # Gerät schalten
      my $tstrResult=$tobjLight->setPower($lintState);
      if (! defined($tstrResult)) { return; }
    }
  }

  # Erfolgreiche Rückmeldung
  return("<datapoint deviceid='' status='".$lintState."' />");
}
########################################################################################################################


########################################################################################################################
# Alle Steckdosen schalten
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objGateway->setPowerAllPlugs($intState);
#
# Übergabe: $intState    = Neuer Status (0=Aus, 1=Ein)
#
# Rückgabe: $strResponse = String=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setPowerAllPlugs {
  my $lobjSelf=shift;   # Klasse-Name abfangen
  my $lintState=shift;  # Neuer Status (0=Aus, 1=Ein)
  my $lprtarrLights=""; # Zeiger auf Array mit den Tradfri-Geräten

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";

  # Alle Geräte auflisten:
  $lprtarrLights=$lobjSelf->listObjects();
  if (! defined($lprtarrLights)) { return; }
  foreach my $tobjLight ( @{$lprtarrLights} ) {
    # Nur Lampen
    if ($tobjLight->{"deviceid"} =~ /^itfp.*$/) {
      # Gerät schalten
      my $tstrResult=$tobjLight->setPower($lintState);
      if (! defined($tstrResult)) { return; }
    }
  }

  # Erfolgreiche Rückmeldung
  return("<datapoint deviceid='' status='".$lintState."' />");
}
########################################################################################################################


########################################################################################################################
# Alle Gruppen schalten
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objGateway->setPowerAllGroups($intState);
#
# Übergabe: $intState = Neuer Status (0=Aus, 1=Ein)
#
# Rückgabe: $strResponse = String=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setPowerAllGroups {
  my $lobjSelf=shift;   # Klasse-Name abfangen
  my $lintState=shift;  # Neuer Status (0=Aus, 1=Ein)
  my $lprtarrLights=""; # Zeiger auf Array mit den Tradfri-Geräten

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";

  # Alle Geräte auflisten:
  $lprtarrLights=$lobjSelf->listObjects();
  if (! defined($lprtarrLights)) { return; }
  foreach my $tobjLight ( @{$lprtarrLights} ) {
    # Nur Gruppen
    if ($tobjLight->{"deviceid"} =~ /^itfg.*$/) {
      # Gerät schalten
      my $tstrResult=$tobjLight->setPower($lintState);
      if (! defined($tstrResult)) { return; }
    }
  }

  # Erfolgreiche Rückmeldung
  return("<datapoint deviceid='' status='".$lintState."' />");
}
########################################################################################################################


########################################################################################################################
# Ein Gerät schalten
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setPower($strAddress,$intState);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $intState   = Neuer Status (0=Aus, 1=Ein)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setPower {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lintState=shift;   # Neuer Status (0=Aus, 1=Ein)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itf[lp]/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Steckdose
  elsif ( $lstrAddress =~ /^itfp/) { $lobjLight=TSS::Ikea::Tradfri::Plug->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
  
  # Das Gerät aus-/einschalten
  my $lstrResult=$lobjLight->setPower($lintState);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Helligkeit eines Gerätes steuern
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setBrightness($strAddress,$intValue);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $intValue   = Neue Helligkeit (0-254)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setBrightness {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lintValue=shift;   # Neue Helligkeit (0-254)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itfl/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }

  # Helligkeit des Gerätes ändern
  my $lstrResult=$lobjLight->setBrightness($lintValue);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Farbtemperatur eines Gerätes steuern
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setTemperature($strAddress,$intValue);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $intValue   = Neue Farbtemperatur (1-3)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setTemperature {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lintValue=shift;   # Neue Farbtemperatur (1-3)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itfl/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setTemperature: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }

  # Kann an dem Gerät gar keine Farbtemeratur eingestellt werden? - Verzweigung nach Geräteart
  if ( $lstrAddress =~ /^itfl/) { if (!defined($lobjLight->{"colorhex"})) { $lobjSelf->{"error"}="setTemperature: Das Gerät unterstützt keine Farbtemperatur!"; return; } }
  else { if (!defined($lobjLight->{"color"})) { $lobjSelf->{"error"}="setTemperature: Das Gerät unterstützt keine Farbtemperatur!"; return; } }

  # Farbtemperatur des Gerätes ändern
  my $lstrResult=$lobjLight->setTemperature($lintValue);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Farbe eines Gerätes über Farbwert ändern
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setColor($strAddress,$intValue);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $intValue   = Neue Farbe (1-20)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setColor {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lintValue=shift;   # Neue Neue Farbe (1-20)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itfl/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setColor: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }

  # Kann an dem Gerät gar keine Farbe eingestellt werden? - Verzweigung nach Geräteart
  if ( $lstrAddress =~ /^itfl/) { if (!defined($lobjLight->{"colorhex"})) { $lobjSelf->{"error"}="setColor: Das Gerät unterstützt keine Farbeinstellung!"; return; } }
  else { if (!defined($lobjLight->{"color"})) { $lobjSelf->{"error"}="setColor: Das Gerät unterstützt keine Farbtemperatur!"; return; } }

  # Farbe des Gerätes ändern
  my $lstrResult=$lobjLight->setColor($lintValue);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Farbtemperatur eines Gerätes über ct-Wert steuern
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setCT($strAddress,$intValue);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $intValue   = Neue Farbtemperatur (153-500)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setCT {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lintValue=shift;   # Neue Farbtemperatur (1-3)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itfl/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setCT: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }

  # Kann an dem Gerät gar keine Farbe eingestellt werden? - Verzweigung nach Geräteart
  if ( $lstrAddress =~ /^itfl/) { if (!defined($lobjLight->{"colorx"})) { $lobjSelf->{"error"}="setCT: Das Gerät unterstützt keine Farbeinstellung!"; return; } }
  else { if (!defined($lobjLight->{"ct"})) { $lobjSelf->{"error"}="setCT: Das Gerät unterstützt keine Farbtemperatur!"; return; } }

  # Farbtemperatur des Gerätes ändern
  my $lstrResult=$lobjLight->setCT($lintValue);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Farbe eines Gerätes über xyY-Wert ändern
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setXYY($strAddress,$strValue);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $strValue   = Neue Farbe (0-65535,0-65535,0-254)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setXYY {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lstrValue=shift;   # Neue Neue Farbe (0-65535,0-65535,0-254)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itfl/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setXYY: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }

  # Kann an dem Gerät gar keine Farbe eingestellt werden? - Verzweigung nach Geräteart
  if ( $lstrAddress =~ /^itfl/) { if (!defined($lobjLight->{"colorx"})) { $lobjSelf->{"error"}="setXYY: Das Gerät unterstützt keine Farbeinstellung!"; return; } }
  else { if (!defined($lobjLight->{"xyy"})) { $lobjSelf->{"error"}="setXYY: Das Gerät unterstützt keine Farbtemperatur!"; return; } }

  # Farbe des Gerätes ändern
  my $lstrResult=$lobjLight->setXYY($lstrValue);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Farbe eines Gerätes über HSV-Wert ändern
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objDevice=$objGateway->setHsv($strAddress,$strValue);
#
# Übergabe: $strAddress = Geräte-ID (itfl65544)
#           $strValue   = Neue Farbe (0-65535,0-65279,0-254)
#
# Rückgabe: $objDevice  = Tradfri Gerät=Erfolgreich, undef=Ein Fehler ist aufgetreten (Beschreibung in $objSelf->{"error"})
#
#-----------------------------------------------------------------------------------------------------------------------
sub setHsv {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lstrAddress=shift; # Geräte-ID (itfl65544)
  my $lstrValue=shift;   # Neue Neue Farbe (0-65535,0-65279,0-254)
  my $lstrJsonSring="";  # Geräteinformationen als JSON-Sting
  my $lobjLight=();      # Tradfri Gerät

  # Fehlertext bereinigen
  $lobjSelf->{"error"}="";
  
  # Überprüfen ob ein Tradfri Gerät/Gruppe vorhanden ist
  if ( $lstrAddress =~ /^itfl/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15001",$lstrAddress); }
  elsif ( $lstrAddress =~ /^itfg/) { $lstrJsonSring=$lobjSelf->_checkObject("5684/15004",$lstrAddress); }
  else { $lobjSelf->{"error"}="setHsv: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }
 
  # Ist ein Fehler aufgetreten?
  if (! defined($lstrJsonSring)) { return; }
  
  # Verzweigung nach Geräteart - Lampe
  if ( $lstrAddress =~ /^itfl/) { $lobjLight=TSS::Ikea::Tradfri::Light->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Gruppe
  elsif ( $lstrAddress =~ /^itfg/) { $lobjLight=TSS::Ikea::Tradfri::Group->new(gateway => $lobjSelf, devicedata => $lstrJsonSring); }
  # Unbekannt
  else { $lobjSelf->{"error"}="setPower: Unbekannter Gerätetyp (".$lstrAddress.")!"; return; }

  # Kann an dem Gerät gar keine Farbe eingestellt werden? - Verzweigung nach Geräteart
  if ( $lstrAddress =~ /^itfl/) { if (!defined($lobjLight->{"hue"})) { $lobjSelf->{"error"}="setHsv: Das Gerät unterstützt keine Farbeinstellung!"; return; } }
  else { if (!defined($lobjLight->{"hsv"})) { $lobjSelf->{"error"}="setHsv: Das Gerät unterstützt keine Farbtemperatur!"; return; } }

  # Farbe des Gerätes ändern
  my $lstrResult=$lobjLight->setHsv($lstrValue);
  if (! defined($lstrResult)) { return; }
  
  #Erfolgreiche Rückmeldung  
  return($lobjLight);
}
########################################################################################################################


########################################################################################################################
# Modul Aufräumen
#-----------------------------------------------------------------------------------------------------------------------
1;
########################################################################################################################
