Die Idee, den LightManager über eine HID-Instanz anzusteuern, ist wirklich super :)!
Ich habe mir das USB-Protokoll auch mal angeschaut und die Funktionalität in einer Klasse gekapselt. Die Erkenntnisse von macgyver dienten als Basis, bis auf Feinheiten (das 2. und 3. Steuerzeichen bei FS20 ist nicht fix, sondern entspricht dem Hauscode) sind die diese absolut korrekt.
Neben normalen InterTechno-Aktoren können mit der Klasse auch lernfähige, prozentual dimmbare wie das Dimmer-Micromodul angesprochen werden. Die Uniroll-Rollladen-Steuerung ist rudimentär (könnte man noch mit dem Shutter Control-Skript verzahnen), ebenso die zur Schaltung von FS20-Aktoren. Letztere sollte man ohnehin besser über eine FHZ 1x00 laufen lassen und die entsprechenden FS20_*-Funktionen von IPS nutzen; ich verwende die implementierte Methode lediglich für das Senden von Befehlen an „virtuelle“ Geräte per FS20 IRF (etwa: TV leiser/lauter), die ich nicht extra in IP-Symcon anlegen möchte.
Hier nun der Code der LightManager-Klasse (einfach per C&P in ein neues Skript namens LightManager.ips.php übertragen und die Konfiguration am Ende anpassen, wobei nur die ID der HID-Instanz essentiell ist):
<?php
/**
* Klasse zur Ansteuerung des jbmedia Light-Manager Pro per HID-Instanz
* Beinhaltet aus Gründen der IPS-Konformität und Wumpus-Widmung ausschließlich statische Methoden
* Unterstützte Systeme: InterTechno, Uniroll, FS20 (rudimentär)
*
* @author tpmaerk
*/
class LightManager
{
const INTERTECHNO_OFF = 0x00;
const INTERTECHNO_ON = 0x01;
const INTERTECHNO_TOGGLE = 0x02;
const INTERTECHNO_TURN_LEFT = 0x03;
const INTERTECHNO_TURN_RIGHT = 0x04;
const UNIROLL_UP = 0x01;
const UNIROLL_STOP = 0x02;
const UNIROLL_DOWN = 0x04;
const FS20_OFF = 0x00;
const FS20_ON = 0x11;
const FS20_TOGGLE = 0x12;
private static $FS20_Housecode;
private static $instanceId;
/**
* Konfiguration: ID der LightManager-Instanz setzen
*
* @param string $instanceId ID der LightManager-Instanz
* @return void
*/
public static function setInstanceId($instanceId)
{
self::$instanceId = $instanceId;
}
/**
* Befehl an LightManager senden (Wrapper für HID_SendEvent())
*
* @param mixed $command Abzusetzender Befehl
* @return boolean Rückgabe von HID_SendEvent()
*/
private static function _sendCommand($command)
{
return HID_SendEvent(self::$instanceId, 0, $command);
}
/**
* InterTechno-Adressen (A1 - P16) in internes Hex-Format übersetzen
*
* @param string $actor Adresse des Aktors (etwa 'A1')
* @return string Adresse im internen Hex-Format
*/
public static function InterTechno_TranslateAddress($actor)
{
$group = ord(strtoupper(substr($actor, 0, 1))) - 65;
$channel = intval(substr($actor, 1)) - 1;
return '0x'.dechex($group).dechex($channel);
}
/**
* InterTechno-Aktor schalten
*
* @param string $actor Adresse des Aktors (etwa 'A1')
* @param int $mode Schaltmodus (vordefinierte Konstante angeben)
* @param int $statusID ID der Status-Variable (etwa 12345)
* @param boolean $isAdaptable true, falls Aktor lernfähig, ansonsten false (Default)
* @return void
*/
public static function InterTechno_SwitchMode($actor, $mode, $statusID, $isAdaptable = false)
{
$address = self::InterTechno_TranslateAddress($actor);
$type = !$isAdaptable ? chr(0x06).chr(0x00) : chr(0x07).chr(0x01);
self::_sendCommand(chr(0x05).chr($address).chr($mode).$type.chr(0x00).chr(0x00).chr(0x00));
$msg = ($mode == self::INTERTECHNO_ON) ? true : false;
$msg = ($mode == self::INTERTECHNO_TOGGLE) ? !GetValueBoolean($statusID) : $msg;
SetValueBoolean($statusID, $msg);
}
/**
* Lernfähigen InterTechno-Aktor dimmen
*
* @param string $actor Adresse des Aktors (etwa 'A1')
* @param int $value Intensität (0 bis 100)
* @param int $statusID ID der Status-Variable (etwa 12345)
* @param int $intensityID ID der Intensitäts-Variable (etwa 12345)
* @return void
*/
public static function InterTechno_SetIntensity($actor, $value, $statusID, $intensityID)
{
$address = self::InterTechno_TranslateAddress($actor);
$scale = array(0x00, 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8);
$level = ceil($value / 6.25);
self::_sendCommand(chr(0x05).chr($address).chr($scale[$level]).chr(0x04).chr(0x01).chr(0x00).chr(0x00).chr(0x00));
SetValueBoolean($statusID, ($value == 0) ? false : true);
SetValueInteger($intensityID, floor($level * 6.25));
}
/*
* Uniroll-Rollladen steuern
*
* @param string $actor Adresse des Aktors (etwa 1)
* @param int $mode Schaltmodus (vordefinierte Konstante angeben)
* @param int $statusID Optional: ID der Status-Variable (etwa 12345)
* @return void
*/
public static function Uniroll_SwitchMode($actor, $mode, $statusID = null)
{
$address = dechex(intval($actor) - 1);
self::_sendCommand(chr(0x15).chr($address).chr(0x74).chr($mode).chr(0x00).chr(0x00).chr(0x00).chr(0x00));
if(!empty($statusID)) {
$msg = ($mode == self::UNIROLL_UP) ? 'Geöffnet' : 'Geschlossen';
$msg = ($mode == self::UNIROLL_STOP) ? 'Angehalten' : $msg;
SetValue($statusID, $msg);
}
}
/**
* FS20-Adressen (1111 - 4444) in internes Hex-Format übersetzen
*
* @param string $actor Adresse des Aktors (etwa '1111')
* @return string Adresse im internen Hex-Format
*/
public static function FS20_TranslateAddress($actor)
{
$trans = array(11 => '0', 12 => '1', 13 => '2', 14 => '3', 21 => '4', 22 => '5', 23 => '6', 24 => '7',
31 => '8', 32 => '9', 33 => 'a', 34 => 'b', 41 => 'c', 42 => 'd', 43 => 'e', 44 => 'f');
return '0x'.$trans[substr($actor, 0, 2)].$trans[substr($actor, 2, 2)];
}
/**
* Konfiguration: FS20-Hauscode setzen
*
* @param string $code FS20-Hauscodes (etwa '11111111')
* @return void
*/
public static function setFS20Housecode($code)
{
$part1 = self::FS20_TranslateAddress(substr($code, 0, 4));
$part2 = self::FS20_TranslateAddress(substr($code, 4, 4));
self::$FS20_Housecode = chr($part1).chr($part2);
}
/*
* FS20-Aktor schalten
*
* @param string $actor Adresse des Aktors (etwa '1111')
* @param int $mode Schaltmodus (vordefinierte Konstante angeben)
* @param int $statusID Optional: ID der Status-Variable (etwa 12345)
* @return void
*/
public static function FS20_SwitchMode($actor, $mode, $statusID = null)
{
$address = self::FS20_TranslateAddress($actor);
self::_sendCommand(chr(0x01).self::$FS20_Housecode.chr($address).chr($mode).chr(0x00).chr(0x03).chr(0x00));
if(!empty($statusID)) {
$msg = ($mode == self::FS20_ON) ? true : false;
$msg = ($mode == self::FS20_TOGGLE) ? !GetValueBoolean($statusID) : $msg;
SetValueBoolean($statusID, $msg);
}
}
}
// Konfiguration hier vornehmen
LightManager::setInstanceId(12345 /*[Light-Manager Pro (HID)]*/);
LightManager::setFS20Housecode('12341234');
?>
Ein beispielhaftes Aktionsskript zum Schalten eines InterTechno-Aktors mit der Adresse A1 (an/aus abhängig vom aktuellen Status):
<?php
include('LightManager.ips.php');
$mode = GetValueBoolean($IPS_VARIABLE) ? LightManager::INTERTECHNO_OFF : LightManager::INTERTECHNO_ON;
LightManager::InterTechno_SwitchMode('A1', $mode, $IPS_VARIABLE, true);
?>
Ein Aktionsskript zum Dimmen eines lernfähigen InterTechno-Dimmers mit der Adresse A1 sieht wie folgt aus:
<?php
include('LightManager.ips.php');
$status = 48788 /*[Zimmer\Deckenleuchten\Status]*/;
LightManager::InterTechno_SetIntensity('A1', $IPS_VALUE, $status, $IPS_VARIABLE);
?>
FS20-Aktor mit der Adresse 1122 einschalten (ohne eine Status-Variable zu aktualisieren):
<?php
include('LightManager.ips.php');
LightManager::FS20_SwitchMode('1122', LightManager::FS20_ON);
?>
Runterlassen des Uniroll-Rollladens Nr. 1:
<?php
include('LightManager.ips.php');
$status = 18015 /*[Zimmer\Rollladen\Status]*/;
LightManager::Uniroll_SwitchMode('1', LightManager::UNIROLL_DOWN, $status);
?>
Die Methoden sind ausführlich dokumentiert; falls trotzdem Fragen auftreten, einfach hier stellen :).