<?php
#---------------------------------------------------------------------------------------------------------------
# PHP-Script control_lk35.php                        NN/06/2016
#-----------------------------------------------------------------
#
#-----------------------------------------------------------------
# Voraussetzung "nmap" muss auf dem Linux System Installiert sein.
#-----------------------------------------------------------------
#
#---------------------------------------------------------------------------------------------------------------
# Aufrufmöglichkeiten mit POST oder Commandline-Parametern 
#---------------------------------------------------------------------------------------------------------------
#
# Ping, prüfen ob RGBW-Controller erreichbar ist
#
# control_lk35.php ip port param1
#
#                ip     = ip-Adresse des RGBW-Controllers
#                port   = Port des RGBW-Controllers
#
#                param1 = ping
#
#        z.B.  php control_lk35.php 192.168.2.200 ping
#
#---------------------------------------------------------------------------------------------------------------
#
# Einzelne Farben steuern
#
# control_lk35.php ip port param1 [param2]
#
#                ip   = ip-Adresse des RGBW-Controllers
#                port = Port des RGBW-Controllers
#
#                param1 = Steuerbefehl:Intensität/Helligkeit/State        
#
#                Steuerbefehle : r:X , g:X , b:X , w:X , h:X , all:X , d:X  
#
#                X .. für Befehle 'r','g','b','w','h' ist X der Einstellwert der Intensität bzw. Helligkeit
#                X .. für Befehl 'd' ist X die Pausenlänge in Sekunden
#                X .. für Befehl 'all' ist ist X 'on' oder 'off'     
#
#		 Beispiele:
#
#                r:30     .. Rot  auf 30% Intensität
#                g:40     .. Grün auf 40% Intensität
#                b:50     .. Blau auf 50% Intensität
#                w:60     .. Weiß auf 60% Intensität
#
#		 h:7      .. Helligkeit auf Maximum (mögliche Helligkeits Werte 0,1,2,3,4,5,6,7)
#
#                all:on   .. LED (r+g+b+w) einschalten  (r,g,b,w,h Einstellungen werden nicht verändert)
#                all:ein  .. LED (r+g+b+w) einschalten  (r,g,b,w,h Einstellungen werden nicht verändert)
#
#                all:off  .. LED (r+g+b+w) ausschalten  (r,g,b,w,h Einstellungen können im "off"-Zustand nicht verändert werden)
#                all:aus  .. LED (r+g+b+w) ausschalten  (r,g,b,w,h Einstellungen können im "off"-Zustand nicht verändert werden)
#
#                d:5      .. Pause (zwischen Befehlen in Sekunden)
#
#	  Die maximale Helligkeit einer Farbe wird erreicht, wenn eine Farbe (z.B. rot) auf 100% eingestellt ist und
#	  die Helligkeit auf 7 eingestellt wird !!! Die Helligkeitseinstellung wirkt sich immer auf alle Farben (r,g,b,w) aus .
#
#         z.B. rote LED auf 60% einstellen :        php control_lk35.php ip port r:60
#
#         z.B. rote LED auf 60% einstellen , 
#              5 Sekunden warten
#              dann rote LED auf 30% einstellen:    php control_lk35.php ip port r:60,d:5,r:30
#
#        im 'all:off' Zustand werden Befehle der Intensität (z.B. b:80%) nicht ausgeführt
#
#        !! Wurden alle Farben auf 0% Intensität (r:0,g:0,b:0) gesetzt, ist keine LED-Farbe sichtbar, d.h. die LED sind dunkel.
#           Wird nun ein Befehl 'all:off' gesendet passiert nichts. Schaltet man die LED wieder ein 'all:on'
#           passiert wieder nichts, da die Intensität immer noch auf 0% eingestellt ist. !!
#
#	 Beispiele ...
#
#                r:30     .. Rot  auf 30% Intensität
#                g:60     .. Grün auf 60% Intensität
#                b:60     .. Blau auf 80% Intensität
#                h:7      .. max. Helligkeit (r,g,b,w)
#                led:on   .. LED (r+g+b) generell einschalten
#                led:ein  .. LED (r+g+b) generell einschalten
#                led:aus  .. LED (r+g+b) generell ausschalten
#                led:off  .. LED (r+g+b) generell einschalten
#
#                d:5      .. Pause (zwischen Befehlen in Sekunden)
#
#         z.B. rote LED auf 60% einstellen :        php control_lk35.php ip port r:60
#
#         z.B. rote LED auf 60% einstellen , 
#              5 Sekunden warten
#              dann rote LED auf 30% einstellen:    php control_lk35.php ip port r:60,d:5,r:30
#
#        im 'led:aus' Zustand werden Befehle der Intensität (z.B. b:80%) nicht ausgeführt
#
#        !! Wurden alle Farbe auf 0% Intensität (r:0,g:0,b:0) gesetzt ist keine LED-Farbe sichtbar.
#           Wird nun ein Befehl 'led:aus' gesendet passiert nichts. Schaltet man die LED wieder ein 'led:ein'
#           passiert wieder nichts, da die Intensität aller Farben noch auf 0 eingestellt sind. !!
#
#---------------------------------------------------------------------------------------------------------------
#
# mehrere Farben steuern (Reihenfolge und Anzahl der Farben beliebig)
#
# control_lk35.php ip port param1 
#
#                ip   = ip-Adresse des RGBW-Controllers
#                port = Port des RGBW-Controllers
#
#                param1 = Steuerbefehl:Intensity,Steuerbefehl:Intensity,Steuerbefehl:Intensity, ......
#
#         z.B. rote LED auf 30%, blaue LED auf 40%, grüne LED auf 50%, weiße LED auf 60%
#      
#               php control_lk35.php 10.0.0.10 8899 r:30,g:40,b:50,w:60
#
#         z.B. grüne LED auf 18%, blaue LED auf 22%
#
#               php control_lk35.php 10.0.0.10 8899 g:18,b:22        
#
#        mit Pause (hier 5 Sekunden) zwischen den Einstellungen:  
#
#                 php control_lk35.php 10.0.0.10 8899 g:18,d:5;b:22
#
#---------------------------------------------------------------------------------------------------------------
#
# LED generell aus- oder einschalten
#
#         ein , aus   off , on
#
#         z.B. LED ein
#
#                  php control_lk35.php 10.0.0.10 8899 led:ein
#
#         z.B. LED aus
#
#                  php control_lk35.php 10.0.0.10 8899 led:aus
#
#---------------------------------------------------------------------------------------------------------------
#
# wird der Script von einem Web-Server (HTTP POST) aufgerufen, erfolgt eine Rückmeldung (Text)
#
#        Rückmeldung bei 
#
#                Ablauf ohne Fehler                     	: LK35 OK
#                Ablauf LK 35 nicht erreichbar          	: LK35 nicht erreichbar (IP-Adresse xxx.xxx.xxx.xxx)
#                Ablauf bei Fehler im Ã‡obergabeparameter 	: LK35 Aufruf, Parameter-Fehler"
#
#---------------------------------------------------------------------------------------------------------------

global $debug;
global $header,$trailer;
global $intensity;

global $led_cmds;
global $ip,$port;
global $called_by;
global $verbose;

$debug = 0;


$ip    = "";      # IP und Port werden durch Commandline- oder POST Parameter  definiert
$port  = "";

#--------------------------------------------------------------------------
#
# Übergabe Parameter
# ------------------

$called_by = (count($_POST) > 0 ? "URL" : "Command Line");


# ARGV-Parameter bei Aufruf durch Command-Line

$ip            = (isset($argv[1]) ? $argv[1] : $ip);
$port          = (isset($argv[2]) ? $argv[2] : $ip);
$cmd           = (isset($argv[3]) ? $argv[3] : "" );
$verbose       = (isset($argv[4]) ?         1 : 0 );

# POST-Parameter bei Aufruf aus Webseite

if (isset($_POST["ip"     ])) { $ip      = $_POST["ip"]     ; }
if (isset($_POST["port"   ])) { $port    = $_POST["port"]   ; }
if (isset($_POST["cmd"    ])) { $cmd     = $_POST["cmd"]    ; }
if (isset($_POST["verbose"])) { $verbose = $_POST["verbose"]; }

$cmd = strtolower($cmd);		# immer Kleinbuchstaben
$cmd = str_replace("on" ,"ein",$cmd);	# 'on' --> 'ein'
$cmd = str_replace("off","aus",$cmd);	# 'off' -> 'aus'

#--------------------------------------------------------------------------

debug_msg("ip   : $ip");
debug_msg("port : $port");
debug_msg("cmd  : $cmd");

#--------------------------------------------------------------------------

init_vars();

if (! check_lk35() ) { exit;}        # Check : ist LK35 via Netzwerk erreichbar ?
if (isPingCmd($cmd)) { exit;}        # ? nur ping, keine RGBW-Befehle

execute_cmds($cmd);

if ($called_by == "URL") {echo "LK35 OK"; }

#--------------------------------------------------------------------------
function execute_cmds($cmd_param) {
#--------------------------------------------------------------------------

	$cmd_list = explode(",",$cmd_param);

        if (sizeof($cmd_list) == 0) {

                show_info("keine Steuerparameter definiert ...");
        }

        foreach ($cmd_list as $cmd) {

		debug_msg("cmd : $cmd");

                if (strpos($cmd,":")) {

                        list($c,$i) = explode(":",$cmd);
                }
                
                check_params($c,$i);

		debug_msg("command : $c   param : $i");

                switch ($c) {

                        case "d" : // Pause zwischen Befehlen

                                   debug_msg("Pause ".$i." Sekunden\n");

                                   sleep ($i);
                                   break;

                        default  : // Befehl ausführen

				   debug_msg("execute command ...");

                                   $lk_data = build_cmd($c,$i);

                                   $err     = send_to_lk35($lk_data);
                                   if (sizeof($err) > 0) {

                                           foreach ($err as $e) {
                                                debug_msg($e);
                                        }
                                   }
                                   break;
                }
        }
}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function send_to_lk35($data) {
#--------------------------------------------------------------------------
global $debug;
global $ip,$port;
global $verbose;

        $e = array();

        if ($verbose) {
                echo "LK35 IP-Adresse : $ip\n";
                echo "LK35 IP-Port    : $port\n";
        }

        $socket = fsockopen($ip,$port,$errno, $errstr); 

        if ($socket) { 

                if ($verbose) {

                        for ($i=0;$i<strlen($data); $i++) {
                                echo dec2hex(ord(substr($data,$i,1)))." ";
                        }
                        echo "\n";
                }

                

                fputs($socket, $data); 
                fclose($socket); 

        } else { 

                $e = array("keine Netzwerkverbindung ...",$errno, $errstr);
        } 

        return $e;
}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function build_cmd($c,$i) {
#--------------------------------------------------------------------------
global $debug;
global $header,$trailer;
global $led_cmds;

switch ($c) {

	case "r"	:
	case "g"	:
	case "b"	:
	case "w"	: $data   = $header . $led_cmds[$c] . $trailer;		# LK-35 Command (12 Bytes)
                          $intens = percent2intensity($i);                      # Prozentwert --> Intensitätswert
			  $data   = substr_replace($data,chr($intens),8,1);     # Intensitätswert einsetzen
			  break;

	case "h"	: $data   = $header . $led_cmds[$c] . $trailer;		# LK-35 Command (12 Bytes)
                          $intens = ($i < 0 ? 0 : $i);				# Minimalwert 0
			  $intens = ($i > 7 ? 7 : $i);				# Maximalwert 7
			  $data   = substr_replace($data,chr($intens),8,1);     # Intensitätswert einsetzen
			  break;

	case "led"	: $data   = $header . $led_cmds[$c.":".$i] . $trailer;  # LK-35 Command (12 Bytes)
			  break;
}


$cs     = check_sum($data);                                   # Checksum Byte 4 ... Byte 8
$data   = substr_replace($data,chr($cs),9,1);                 # Checksum einsetzen

if ($debug) { for ($i=0;$i<strlen($data); $i++) {
              		echo dec2hex(ord(substr($data,$i,1)))." ";
            }
	    echo "\n";
}

return $data;

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function extract_params($c) {
#--------------------------------------------------------------------------
global $header,$trailer;
global $led_cmds;

$cmd_list = array();
$clc      = 0;				# Command-List Counter

$c = str_replace("on" ,"ein",$c);	# deutsch oder englisch, egal --> deutsch
$c = str_replace("off","aus",$c);	# deutsch oder englisch, egal --> deutsch

if (strpos($c,":")) {

        $cmd_list = explode(",",$c);

}

return $cmd_list;
}


#--------------------------------------------------------------------------
function init_vars() {
#--------------------------------------------------------------------------
global $header,$trailer;
global $led_cmds;
global $intensity;

$intensity['min'] =   0;                # min. Intensität Wert (dezimal)  entspricht   0%
$intensity['max'] = 140;                # max. Intensität Wert (dezimal)  entspricht 100%

# ----------------------------------------
# Header : 5 Byte (Position Byte  0 ..  4)
# ----------------------------------------

# --------------------------------------------
#         Byte  # : | 0  | 1  | 2  | 3  | 4  |
# --------------------------------------------
$header  = pack("C*",0x55,0x33,0x61,0x39,0x02);        

# ---------------------------------------------------------------
# Steuerbefehle bestehend aus 5 Byte (Position Byte 5 bis Byte 9)
# ---------------------------------------------------------------
#
# Byte 5 (Zone Byte) immer 0, da nur ein LK35 eingesetz wird.
# Byte 8 Einstellwert bei Farben (wird zum Einstellzeitpunkt eingesetzt), 
# Byte 9 Checksum wird zum Einstellzeitpunkt berechnet und eingesetzt.

# ------------------------------------------------------------
#                         Byte  # : | 5  | 6  | 7  | 8  | 9  |
# ------------------------------------------------------------
$led_cmds['r'          ] = pack("C*",0x00,0x08,0x18,0x00,0x00);  # rot
$led_cmds['g'          ] = pack("C*",0x00,0x08,0x19,0x00,0x00);  # grün 
$led_cmds['b'          ] = pack("C*",0x00,0x08,0x20,0x00,0x00);  # blau
$led_cmds['w'          ] = pack("C*",0x00,0x08,0x21,0x00,0x00);  # weiss
$led_cmds['h'          ] = pack("C*",0x00,0x08,0x23,0x00,0x00);  # Helligkeit

$led_cmds['led:ein'    ] = pack("C*",0x00,0x02,0x12,0xab,0x00);  # alles ein
$led_cmds['led:aus'    ] = pack("C*",0x00,0x02,0x12,0xa9,0x00);  # alles aus

# ------------------------------------------
# Trailer : 2 Byte ( Position Byte 10 .. 11)
# ------------------------------------------
#
# -----------------------------
#         Byte  # : | 10 | 11 |
# -----------------------------
$trailer = pack("C*",0xaa,0xaa);        

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function percent2intensity($perc) {
#--------------------------------------------------------------------------
global $intensity;

        $p = ($perc <   0.0 ?   0.0 : floatval($perc));
        $p = ($perc > 100.0 ? 100.0 : floatval($perc));

        $p = $p / 100.0;

        $i = $intensity['min'] + ($intensity['max'] - $intensity['min']) * $p;
        

        return intval($i);                
}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function check_sum($data) {
#--------------------------------------------------------------------------

$cs = 0;

# Checksum Bytes 4 .. 8  

for ($i=4;$i<=8;$i++) {

        $cs = $cs + ord(substr($data,$i,1));
}

return $cs;

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function check_params($c,$i) {
#--------------------------------------------------------------------------
global $led_cmds;

$info="";
$err =0;

if ($c == "-h") {

        $info = "Programm-Aufrufe ...";

} else {

	switch($c) {

		case  "r" 	:
		case  "g" 	:
		case  "b" 	:
		case  "w" 	: if (! isset($led_cmds[$c])) { 

					# Befehl unbekannt 

					$info .= "Steuer-Parameter $c unbekannt ..."; 

				  } else {

                        		# Befehl ist bekannt ... ist Parameter 2 ok (Intensity oder Delay)

					if ($i == "")             { $info .= "Farbe $c -- Parameter Intensity nicht definiert ...";}
					if ($i <   0 || $i > 100) { $info .= "Farbe $c ---Parameter Intensity ($i) außerhalb Bereich 0- 100% ...";}
				  }
			     	  break;

		case  "h" 	: if (! isset($led_cmds[$c])) { 

					# Befehl unbekannt 

					$info .= "Steuer-Parameter $c unbekannt ..."; 

				  } else {

                        		# Befehl ist bekannt ... ist Parameter 2 ok (Helligkeit 0 .. 7)

					if ($i == "")             { $info .= "Farbe $c -- Parameter Helligkeit nicht definiert ...";}
					if ($i <   0 || $i > 7)   { $info .= "Farbe $c ---Parameter Helligkeit ($i) außerhalb Bereich 0- 100% ...";}
				  }
			     	  break;

		case  "led:on" 	:
		case  "led:ein" :
		case  "led:off"	:
		case  "led:aus" : if (! isset($led_cmds[$c.":".$i])) 

					# Befehl unbekannt

					{ $info = "Steuer-Parameter $c:$i unbekannt ..."; 
				  } else {

					# Befehl ist bekannt ... ist Parameter 2 ok (ein/aus oder on/off)

					if (strpos("einausonoff",$i) > -1)   { $info .= "LED Steuerung -- Befehl \"$i\" unbekannt ..."; }

					
				 }
				 break;

		case "d"	: # Befehle ist d (Delay)
				  # Befehl ist bekannt ... ist Parameter 2 (zwischen 1 und 3600 Sekunden )

				  if ($i < 1 || $i > 3600) { $info .= "Pausenzeit außerhalb Bereich 1 - 3600 Sekunden ...";}
				  break;
	}	

}

show_info($info,1);
}

#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function show_info($info,$detail=1) {
#--------------------------------------------------------------------------
global $led_cmds;
global $called_by;

if ($info == "" ) {return;}

system ("clear"); 
echo "RGBW-Controller LK35 Steuer-Program\n";
echo "-----------------------------------\n\n";

echo "$info\n"; 

echo "\n";

if (! $detail) { return;}

echo "zuläßige Aufrufe mit Commandline Parametern :\n";
echo "---------------------------------------------\n\n";

foreach ($led_cmds as $key => $v) {        
        echo "php control_lk35.php $key";
        if (strpos("r,g,b,w,h",$key) > -1)  {echo ":NN         \t\tNN --> Intensity in % (0 - 100)";}
        if (strpos("d",$key)         > -1)  {echo ":NN          \t\tNN --> Delay zwischen der Ausführung der Befehle (Sekunden)";}
        echo "\n";
}
echo "\n";
echo "mehrere Farben mit einem Aufruf steuern :\n";
echo "------------------------------------------------------------------------------\n\n";
echo "(Reihenfolge und Anzahl der Farben beliebig)\n\n";
echo "z.B. rote LED auf 30%, blaue LED auf 40%, grüne LED auf 50%, weiße LED auf 60%\n\n";
echo "        php control_lk35.php ip port r;30,b:40,g:50,w:60\n\n";
echo "z.B. grüne LED auf 18%, blaue LED auf 22%\n\n";
echo "        php control_lk35.php ip port g:18,b:22\n\n";
echo "z.B. weisse LED auf 100%, Delay 5 Sekunden,blaue LED auf 100% \n\n";
echo "        php control_lk35.php ip port w:100;d:5,b:100\n\n";
echo "------------------------------------------------------------------------------\n\n";


if ($called_by == "URL") { echo "LK35 Aufruf, Parameter-Fehler";};
exit;

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function check_lk35() {
#--------------------------------------------------------------------------
global $ip,$port;
global $called_by;

        $ans   = "";
        $cmd   = "nmap -sPn $ip | grep 'is up'";

        debug_msg("Ping LK35 $ip\n");
        debug_msg("cmd  --> $cmd\n");

        exec($cmd, $ans, $return);

        if (sizeof($ans)) { return 1;}

        if ($called_by == "URL") { echo "LK35 nicht erreichbar (IP-Adresse $ip)"; }

        return 0;

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function isPingCmd($c) {
#--------------------------------------------------------------------------

return (strpos($c,"ping") > -1 );

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function dec2hex($d,$l=2) {
#--------------------------------------------------------------------------

$h = dechex($d);
$l = $l - strlen($h);

if ($l > 0) { $h = str_repeat("0",$l).$h; }

return $h;

}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function pause ($t="") {
#--------------------------------------------------------------------------
# !! for troubleshooting only !!

                echo $t;
                $x = fgets(STDIN);
}
#--------------------------------------------------------------------------

#--------------------------------------------------------------------------
function debug_msg($t) {
#--------------------------------------------------------------------------
# !! for troubleshooting only !!

global $debug;

if (! $debug) { return; }

echo $t."\n";
}
#---------------------------------------------------------------------------
?>

