########################################################################################################################
# Group.pm
#-----------------------------------------------------------------------------------------------------------------------
#
# Steuerung von Philips Hue Gruppen
#
# Bei Gruppen mit Farbdarstellung, welche Bauart bedingt keine Einstellung der Farbtemperatur zulassen kann trozdem die
# Farbtemperatur eingestellt werden. hierzu wurde ein Mapping der Temperaturangabe auf die xy-Farbskala integriert.
#
#
# Aufruf           : use TSS::Philips::Hue::Group;
#                    my $gobjDevice = TSS::Philips::Hue::Group->new( gateway => <Gateway>, deviceid => <Geräte-ID>, devicedata => <Gerätedaten> );
#                    my $gprtarrDevices=$gobjGateway->getDeviceInfo("phl65544"); # phl65544=Geräte-ID-Lampen
#                    print $gprtarrDevices."\n";
#                      > <datapoint deviceid='phg1' name='Wohnzimmer' type='Room' state_all='0' status='0' brightness='120' ct='153' xyY='0.4574,0.41,120' hsv='8418,140,254' />
#                      > <datapoint deviceid='phg2' name='Essplatz' type='Zone' state_all='0' status='0' brightness='131' ct='153' xyY='0.458,0.41,131' hsv='8418,140,254' />
#
#                    Version ausgeben:
#                    -----------------
#                    print "Version: ".$TSS::Philips::Hue::Group::VERSION."\n";
#                      > Version: v1.0.0
#
#                    Name der Gruppe ausgeben:
#                    -------------------------
#                    print $gobjDevice->name()."\n";
#                      > <datapoint deviceid='phg1' name='Wohnzimmer' />
#
#                    Adresse der Gruppe ausgeben:
#                    ----------------------------
#                    print $gobjDevice->deviceid()."\n";
#                      > <datapoint deviceid='phg1' />
#
#                    Typ der Gruppe ausgeben:
#                    ------------------------
#                    print $gobjDevice->devicetype()."\n";
#                      > <datapoint deviceid='phg1' devicetype='group' />
#
#                    Status aller Lampen der Gruppe ausgeben:
#                    ----------------------------------------
#                    print $gobjDevice->status_all()."\n";
#                      > <datapoint deviceid='phg1' state_all='0' />
#
#                    Power-Status der Gruppe ausgeben:
#                    ---------------------------------
#                    print $gobjDevice->status()."\n";
#                      > <datapoint deviceid='phg1' status='0' />
#
#                    Helligkeit der Gruppe ausgeben:
#                    -------------------------------
#                    print $gobjDevice->brightness()."\n";
#                      > <datapoint deviceid='phg1' brightness='120' />
#
#                    Farbemperatur der Gruppe ausgeben:
#                    ----------------------------------
#                    print $gobjDevice->ct()."\n";
#                      > <datapoint deviceid='phg1' ct='153' />
#
#                    Farbe über xyY-Wert der Gruppe ausgeben:
#                    ----------------------------------------
#                    print $gobjDevice->xyy()."\n";
#                      > <datapoint deviceid='phg1' xyY='0.4574,0.41,120' />
#
#                    Farbe über HSV-Wert der Gruppe ausgeben:
#                    ----------------------------------------
#                    print $gobjDevice->hsv()."\n";
#                      > <datapoint deviceid='phg1' hsv='8418,140,254' />
#
#                    Gesamtstatus der Gruppe ausgeben:
#                    ----------------------------------
#                    print $gobjDevice->devicestate()."\n";
#                      >  <datapoint deviceid='phg1' name='Wohnzimmer' type='Room' state_all='0' status='0' brightness='120' ct='153' xyY='0.4574,0.41,120' hsv='8418,140,254' />
#
#                    Alle Gruppeninformationen neu einlesen:
#                    ---------------------------------------
#                    my $gintResult=$gobjDevice->readDeviceInfo();
#                    if (! defined($gintResult)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    print $gobjDevice->devicestate()."\n";
#                      > <datapoint deviceid='phg1' name='Wohnzimmer' type='Room' state_all='2' status='1' brightness='254' ct='153' xyY='0.4573,0.41,254' hsv='8418,140,254' />
#
#                    Die Gruppe aus-/einschalten:
#                    ----------------------------
#                    my $gstrResult=$gobjDevice->setPower(x); # 0=aus, 1=ein
#                    if (! defined($gstrResult)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gstrResult\n"; }
#                      > <datapoint deviceid='phg1' status='1' />
#
#                    Helligkeit der Gruppe ändern:
#                    -----------------------------
#                    my $gstrResult=$gobjDevice->setBrightness(x); # 0-254
#                    if (! defined($gstrResult)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gstrResult\n"; }
#                      > <datapoint deviceid='phg1' brightness='131' />
#
#                    Farbemperatur der Gruppe ändern:
#                    --------------------------------
#                    my $gstrResult=$gobjDevice->setCT(x); # 153 - 500
#                    if (! defined($gstrResult)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gstrResult\n"; }
#                      > <datapoint deviceid='phg1' xyY='0.4444,0.4065,131' />
#
#                    Farbe der Gruppe über xyY-Wert ändern:
#                    --------------------------------------
#                    my $gstrResult=$gobjDevice->setXYY(x); # 0 - 1,0 - 1,0 - 254
#                    if (! defined($gstrResult)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gstrResult\n"; }
#                      > <datapoint deviceid='phg1' xyY='0.4452,0.4068,131' />
#
#                    Farbe der Gruppe über HSV-Wert ändern:
#                    --------------------------------------
#                    my $gstrResult=$gobjDevice->setHsv(x); # 0 - 65535,0 - 254,0 - 254
#                    if (! defined($gstrResult)) { print "Befehl nicht erfolgreich! Fehler:\"".$gobjGateway->{"error"}."\"\n"; exit(1); }
#                    else { print "$gstrResult\n"; }
#                      > <datapoint deviceid='phg1' hsv='21845,254,120' />
#
# Attribute        : Allgemein
#                      Fehlertext                = $lobjSelf->{"error"}
#                      Gateway                   = $lobjSelf->{"gateway"} (Übergeordnetes Objekt)
#                    Gruppeninformationen
#                      Gruppenname               = $lobjSelf->{"name"}
#                      Gerätetyp                 = $lobjSelf->{"devicetype"}
#                      Gruppentyp                = $lobjSelf->{"type"} (0, Luminaire, Lightsource, LightGroup, Room, Entertainment, Zone)
#                      Hersteller                = $lobjSelf->{"manufacturername"} (immer Leer)
#                      Automatisches löschen     = $lobjSelf->{"recycle"} (0=wird nicht glöscht, 1=wird automatisch gelöscht)
#                      Gruppenklasse (Icon)      = $lobjSelf->{"class"} (Living room,Kitchen,Dining,Bedroom,Kids bedroom,Bathroom,Nursery,Recreation,Office,Gym,Hallway,Toilet,Front door,Garage,Terrace,Garden,Driveway,Carport,Other,Home,Downstairs,Upstairs,Top floor,Attic,Guest room,Staircase,Lounge,Man cave,Computer,Studio,Music,TV,Reading,Closet,Storage,Laundry room,Balcony,Porch,Barbecue,Pool)
#                      Zugeordnete Lampen        = $lobjSelf->{"lights"} (Array mit Lampen-ID)
#                      Zugeordnete Sensoren      = $lobjSelf->{"sensors"} (Array mit Sensoren-ID)
#                    Gerätestatus
#                      Status aller Lampen       = $lobjSelf->{"state_all"} (0=alle aus, 1=einige an, 2=alle an)
#                      Power-Status              = $lobjSelf->{"status"} (0=off, 1=on)
#                      Helligkeit                = $lobjSelf->{"brightness"} (Optional, 0 - 254)
#                      Farbton                   = $lobjSelf->{"hue" (Optional, 0 - 65535, nur Zusammen mit Sättigung und Helligkeit - wird nicht verwendet)
#                      Sättigung                 = $lobjSelf->{"saturation"} (Optional, 0 - 254, nur Zusammen mit Farbton und Helligkeit - wird nicht verwendet)
#                      Effekt                    = $lobjSelf->{"effect"} (Optional, none, colorloop)
#                      Alarm                     = $lobjSelf->{"alert"} (Optional, none, select, lselect)
#                      Letzte Farbeinstellung    = $lobjSelf->{"colormode"} (Optional, hs, xy, ct)
#                      Farbtemperatur            = $lobjSelf->{"ct"} (153 - 500)
#                      Farbe X                   = $lobjSelf->{"colorx"} (Optional, 0 - 1, 4 Stellen hinter dem Komma, nur zusammen mit Farbe Y)
#                      Farbe Y                   = $lobjSelf->{"colory"} (0 - 1, 4 Stellen hinter dem Komma,nur zusammen mit Farbe X)
#
# Methoden         : Name ausgeben                                 = $gobjDevice->name()
#                    Adresse ausgeben                              = $gobjDevice->deviceid()
#                    Typ ausgeben                                  = $gobjDevice->devicetype()
#                    Power-Status aller Geräte der Gruppe ausgeben = $gobjDevice->status_all()
#                    Power-Status ausgeben                         = $gobjDevice->status()
#                    Helligkeit ausgeben                           = $gobjDevice->brightness()
#                    Farbemperatur über ct-Wert ausgeben           = $gobjDevice->ct()
#                    Farbe über xyY-Wert ausgeben                  = $gobjDevice->xyy()
#                    Farbe über HSV-Wert ausgeben                  = $gobjDevice->hsv()
#                    Gesamtstatus ausgeben                         = $gobjDevice->devicestate()
#                    Geräteinformationen neu einlesen              = $gobjDevice->readDeviceInfo()
#                    Aus-/einschalten                              = $gobjDevice->setPower(<Status>)           -> <Status>     : 0=aus, 1=ein
#                    Helligkeit ändern                             = $gobjDevice->setBrightness(<Helligkeit>)  -> <Helligkeit> : 0-254=Helligkeit
#                    Farbemperatur über ct-Wert ändern             = $gobjDevice->setCT(<Temperatur>)          -> <Temperatur> : 153-500=Temperatur
#                    Farbe über xyY-Wert ändern                    = $gobjDevice->setXYY(<Farbe>)              -> <Farbe>      : 0-1,0-1,0-254=x,y,Y
#                    Farbe über HSV-Wert ändern                    = $gobjDevice->setHsv(<Farbe>)              -> <Farbe>      : 0-65535,0-254,0-254=H,S,V
#
# Präfixe Device-ID: phl Leuchten   (l=light)
#                    php Steckdosen (p=Plug)
#                    phg Gruppen    (g=group)
#
# Version          : 17.12.2019 v1.0.0 Initiale Version
#                    20.12.2019 v1.0.1 Namensangelichungen mit anderen Modulen
#                    07.01.2020 v1.0.2 Erweiterung um Steckdosen
#                    29.01.2020 v1.0.2 Neues Attribut $lobjSelf->{"manufacturername"}
#                    04.02.2020 v1.0.3 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::Philips::Hue::Group;

# ========================
#  Definition der Pragmas
# ========================
use strict;
use warnings;
use JSON::Parse 'parse_json';
use TSS::Philips::Hue::Common;

# ===============
#  Vererbung aus
# ===============
our @ISA = qw( TSS::Philips::Hue::Common );

# ==================================
#  Definition der Versions-Variable
# ==================================
our $VERSION = "v1.0.3";

# ================================================
#  Überladung: Klassenattribute als Text ausgeben
# ================================================
use overload '""' => '_stringify';

########################################################################################################################
# Interne Variable
#-----------------------------------------------------------------------------------------------------------------------
########################################################################################################################


########################################################################################################################
# Gruppendaten aus JSON-String auswerten 
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $objSelf->_decodeDevicedata();
#
# Übergabe: -
#
# Rückgabe: -
#
#-----------------------------------------------------------------------------------------------------------------------
sub _decodeDevicedata {
  my $lobjSelf=shift;    # Klasse-Name abfangen
  my $lptrResult="";     # Zeiger auf ein Array, Hash oder Sclar eines dekodierten JSON-Strings
  
  # Json-String dekodieren
  $lptrResult=parse_json($lobjSelf->{'devicedata'});
  
  # Unerwaretetes Ergebnis?
  if (ref($lptrResult) ne "HASH") { $lobjSelf->{"error"}="_decodeDevicedata: Unerwartetes Ergebnisformat (".ref($lptrResult).") !"; return; }

  # Gruppeninformationen
  # Gruppenname
  if (defined($lptrResult->{"name"})) { $lobjSelf->{"name"}=$lptrResult->{"name"}; } else { $lobjSelf->{"name"}=""; }
  # Gruppentyp (0, Luminaire, Lightsource, LightGroup, Room, Entertainment, Zone)
  if (defined($lptrResult->{"type"})) { $lobjSelf->{"type"}=$lptrResult->{"type"}; } else { $lobjSelf->{"type"}=""; }
  # Automatisches löschen (0=wird nicht glöscht, 1=wird automatisch gelöscht)
  if (defined($lptrResult->{"recycle"})) {
    if ($lptrResult->{"recycle"} == 1) { $lobjSelf->{"recycle"}=1; }
    else  { $lobjSelf->{"recycle"}=0; }
  }
  else { $lobjSelf->{"recycle"}=0; }
  # Gruppenklasse (Icon) (Living room,Kitchen,Dining,Bedroom,Kids bedroom,Bathroom,Nursery,Recreation,Office,Gym,Hallway,Toilet,Front door,Garage,Terrace,Garden,Driveway,Carport,Other,Home,Downstairs,Upstairs,Top floor,Attic,Guest room,Staircase,Lounge,Man cave,Computer,Studio,Music,TV,Reading,Closet,Storage,Laundry room,Balcony,Porch,Barbecue,Pool)
  if (defined($lptrResult->{"class"})) { $lobjSelf->{"class"}=$lptrResult->{"class"}; } else { $lobjSelf->{"class"}=""; }
  # Zugeordnete Lampen (Array mit Lampen-ID)
  if (defined($lptrResult->{"lights"})) { $lobjSelf->{"lights"}=$lptrResult->{"lights"}; } else { $lobjSelf->{"lights"}=(); }
  # Zugeordnete Sensoren (Array mit Sensoren-ID)
  if (defined($lptrResult->{"sensors"})) { $lobjSelf->{"sensors"}=$lptrResult->{"sensors"}; } else { $lobjSelf->{"sensors"}=(); }
  # Hersteller
  $lobjSelf->{"manufacturername"}="";

  # Gerätestatus
  # Status aller Lampen der Gruppe (0=alle aus, 1=einige an, 2=alle an)
  if ((defined($lptrResult->{"state"}{"all_on"})) && (defined($lptrResult->{"state"}{"any_on"}))) {
    if ($lptrResult->{"state"}{"all_on"} == 1) { $lobjSelf->{"state_all"}=2; }
    elsif ($lptrResult->{"state"}{"any_on"} == 1) { $lobjSelf->{"state_all"}=1; }
    else  { $lobjSelf->{"state_all"}=0; }
  }
  else  { $lobjSelf->{"state_all"}=0; }
  # Power-Status (0=off, 1=on)
  if (defined($lptrResult->{"action"}{"on"})) {
    if ($lptrResult->{"action"}{"on"} == 1) { $lobjSelf->{"status"}=1; }
    else  { $lobjSelf->{"status"}=0; }
  }
  else { $lobjSelf->{"status"}=0; }
  
  # Helligkeit (Optional, 0 - 254)
  if (defined($lptrResult->{"action"}{"bri"})) { $lobjSelf->{"brightness"}=$lptrResult->{"action"}{"bri"}; }
  # Farbton (Optional, 0 - 65535, nur Zusammen mit Sättigung und Helligkeit - wird nicht verwendet)
  if (defined($lptrResult->{"action"}{"hue"})) { $lobjSelf->{"hue"}=$lptrResult->{"action"}{"hue"}; }
  # Sättigung (Optional, 0 - 254, nur Zusammen mit Farbton und Helligkeit - wird nicht verwendet)
  if (defined($lptrResult->{"action"}{"sat"})) { $lobjSelf->{"saturation"}=$lptrResult->{"action"}{"sat"}; }
  # Effekt (Optional, none, colorloop)
  if (defined($lptrResult->{"action"}{"effect"})) { $lobjSelf->{"effect"}=$lptrResult->{"action"}{"effect"}; }
  # Alarm (Optional, none, select, lselect)
  if (defined($lptrResult->{"action"}{"alert"})) { $lobjSelf->{"alert"}=$lptrResult->{"action"}{"alert"}; }
  # Letzte Farbeinstellung (Optional, hs, xy, ct)
  if (defined($lptrResult->{"action"}{"colormode"})) { $lobjSelf->{"colormode"}=$lptrResult->{"action"}{"colormode"}; }
  # Farbtemperatur (153 - 500)
  if (defined($lptrResult->{"action"}{"ct"})) { $lobjSelf->{"ct"}=$lptrResult->{"action"}{"ct"}; }
  # Farbe X (0 - 1, 4 Stellen hinter dem Komma, nur zusammen mit Farbe Y)
  if (defined($lptrResult->{"action"}{"xy"}[0])) { $lobjSelf->{"colorx"}=$lptrResult->{"action"}{"xy"}[0]; }
  # Farbe Y (0 - 1, 4 Stellen hinter dem Komma,nur zusammen mit Farbe X)
  if (defined($lptrResult->{"action"}{"xy"}[1])) { $lobjSelf->{"colory"}=$lptrResult->{"action"}{"xy"}[1]; }
   
  # Gerätetyp
  $lobjSelf->{"devicetype"}="group";
 
  # Erfolgreiche Rückmeldung
  return(0);
}
########################################################################################################################


########################################################################################################################
# Gesamtstatus der Gruppe ausgeben
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objDevice->devicestate()
#
# Übergabe: -
#
# Rückgabe: $strResponse = Gesamtstatus des Gerätes
#
#-----------------------------------------------------------------------------------------------------------------------
sub devicestate {
  my $lobjSelf=shift; # Klasse-Name abfangen
  my $lstrReturn="";  # Rückgabestring
  # Rückgabestring einleiten
  $lstrReturn="<datapoint deviceid='".$lobjSelf->{"deviceid"}."'";
  # Name der Gruppe
  $lstrReturn=$lstrReturn." name='".$lobjSelf->{"name"}."'";
  # Gruppentyp
  $lstrReturn=$lstrReturn." type='".$lobjSelf->{"type"}."'";
  # Power-Status aller Lampen der der Gruppe
  if (defined($lobjSelf->{"state_all"})) { $lstrReturn=$lstrReturn." state_all='".$lobjSelf->{"state_all"}."'"; }
  # Power-Status der Gruppe
  if (defined($lobjSelf->{"status"})) { $lstrReturn=$lstrReturn." status='".$lobjSelf->{"status"}."'"; }
  # Helligkeit der Gruppe
  if (defined($lobjSelf->{"brightness"})) { $lstrReturn=$lstrReturn." brightness='".$lobjSelf->{"brightness"}."'"; }
  # Farbtemperatur der Gruppe
  if (defined($lobjSelf->{"ct"})) { $lstrReturn=$lstrReturn." ct='".$lobjSelf->{"ct"}."'"; }
  elsif (defined($lobjSelf->{"colorx"})) {
    my $tstrValueXy=$lobjSelf->{"colorx"}.",".$lobjSelf->{"colory"};
    my $tstrValueCt=$lobjSelf->{"gateway"}->_xy2ct($tstrValueXy);
    $lstrReturn=$lstrReturn." ct='".$tstrValueCt."'";
  }
  # Farbige Geräte xyY
  if (defined($lobjSelf->{"colorx"})) {
    my $lstrColorxyY=""; # xyY-Farbwert
    $lstrColorxyY=$lobjSelf->{"colorx"}.",".$lobjSelf->{"colory"}.",".$lobjSelf->{"brightness"};
    $lstrReturn=$lstrReturn." xyY='".$lstrColorxyY."'";
  }  
  # Farbige Geräte HSV
  if (defined($lobjSelf->{"colorx"})) {
    my $lstrColorHsv=""; # xyY-Farbwert
    $lstrColorHsv=$lobjSelf->{"hue"}.",".$lobjSelf->{"saturation"}.",".$lobjSelf->{"brightness"};
    $lstrReturn=$lstrReturn." hsv='".$lstrColorHsv."'";
  }  
  # Rückgabestring abschließen
  $lstrReturn=$lstrReturn." />";
  return($lstrReturn);
}
########################################################################################################################


########################################################################################################################
# Status aller Lampen der Gruppe ausgeben
#-----------------------------------------------------------------------------------------------------------------------
# Aufruf  : $strResponse=$objDevice->status_all()
#
# Übergabe: -
#
# Rückgabe: $strResponse = Status aller Lampen der Gruppe
#
#-----------------------------------------------------------------------------------------------------------------------
sub status_all {
  my $lobjSelf=shift; # Klasse-Name abfangen
  if (defined($lobjSelf->{"state_all"})) { return("<datapoint deviceid='".$lobjSelf->{"deviceid"}."' state_all='".$lobjSelf->{"state_all"}."' />"); }
  else { return("<datapoint deviceid='".$lobjSelf->{"deviceid"}."' state_all='-1' />"); }
}
########################################################################################################################


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