diff --git a/Tapo Discovery/module.php b/Tapo Discovery/module.php index 208ccb1..2de1417 100644 --- a/Tapo Discovery/module.php +++ b/Tapo Discovery/module.php @@ -48,6 +48,7 @@ public function GetConfigurationForm() if ($this->GetStatus() == IS_CREATING) { return json_encode($Form); } + if (IPS_GetOption('NATSupport') && strpos(IPS_GetKernelPlatform(), 'Docker')) { // not supported. Docker cannot forward Broadcast :( $Form['actions'][2]['visible'] = true; @@ -157,7 +158,7 @@ private function Discover(): array continue; } $Data = substr($response, 16); - $this->SendDebug('Receive (' . $IPAddress . ':' . ')', $Data, 0); + $this->SendDebug('Receive (' . $IPAddress . ')', $Data, 0); $JsonReceive = json_decode($Data, true); if (!$JsonReceive) { continue; diff --git a/Tapo Light Color/README.md b/Tapo Light Color/README.md new file mode 100644 index 0000000..33a3582 --- /dev/null +++ b/Tapo Light Color/README.md @@ -0,0 +1,121 @@ +[![SDK](https://img.shields.io/badge/Symcon-PHPModul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) +[![Version](https://img.shields.io/badge/Modul%20Version-1.60-blue.svg)](https://community.symcon.de/t/modul-tp-link-tapo-smarthome/131865) +[![Version](https://img.shields.io/badge/Symcon%20Version-6.1%20%3E-green.svg)](https://www.symcon.de/service/dokumentation/installation/migrationen/v60-v61-q1-2022/) +[![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) +[![Check Style](https://github.com/Nall-chan/SSHClient/workflows/Check%20Style/badge.svg)](https://github.com/Nall-chan/tapo-SmartHome/actions) +[![Run Tests](https://github.com/Nall-chan/SSHClient/workflows/Run%20Tests/badge.svg)](https://github.com/Nall-chan/tapo-SmartHome/actions) +[![Spenden](https://www.paypalobjects.com/de_DE/DE/i/btn/btn_donate_SM.gif)](#2-spenden) +[![Wunschliste](https://img.shields.io/badge/Wunschliste-Amazon-ff69fb.svg)](#2-spenden) +# tapo Light Color + +## Inhaltsverzeichnis + +- [1. Funktionsumfang](#1-funktionsumfang) +- [2. Voraussetzungen](#2-voraussetzungen) +- [3. Software-Installation](#3-software-installation) +- [4. Einrichten der Instanzen in IP-Symcon](#4-einrichten-der-instanzen-in-ip-symcon) +- [5. Statusvariablen und Profile](#5-statusvariablen-und-profile) + - [Statusvariablen](#statusvariablen) + - [Profile](#profile) +- [6. PHP-Befehlsreferenz](#6-php-befehlsreferenz) +- [7. Aktionen](#7-aktionen) +- [8. Anhang](#8-anhang) + - [1. Changelog](#1-changelog) + - [2. Spenden](#2-spenden) +- [9. Lizenz](#9-lizenz) + + +## 1. Funktionsumfang + + - Instanz für Lampen und LED-Stripes + +## 2. Voraussetzungen + +- IP-Symcon ab Version 6.1 + +## 3. Software-Installation + +* Dieses Modul ist Bestandteil der [tapo SmartHome-Library](../README.md#3-software-installation). + +## 4. Einrichten der Instanzen in IP-Symcon + +Eine einfache Einrichtung ist die [Discovery-Instanz](../Tapo%20Discovery/README.md) möglich. + +Bei der manuellen Einrichtung ist das Modul im Dialog `Instanz hinzufügen` unter den Hersteller `TP-Link` zu finden. +![Instanz hinzufügen](../imgs/module.png) + +Damit Symcon mit den Geräten kommunizieren können, müssen diese in der TP-Link Cloud angemeldet und registriert sein. +Die entsprechenden Cloud-Zugangsdaten, die MAC-Adresse und das genutzte Protokoll werden beim anlegen durch die [Discovery-Instanz](../Tapo%20Discovery/README.md) automatisch eingetragen. + + ### Konfigurationsseite + +![Config](../imgs/conf_device.png) + +**Benutzername und Passwort sind die Cloud/App Zugangsdaten!** + +| Name | Text | Beschreibung | +| ---------- | ------------------------------ | ---------------------------------------------------------------------- | +| Open | Aktiv | Verbindung zu Gerät herstellen | +| Host | Host | Adresse des Gerätes | +| Mac | MAC Adresse | MAC Adresse des Gerätes (benötigt die Discovery-Instanz zur Zuordnung) | +| Protocol | Protokoll | Genutztes Kommunikationsprotokoll (AES oder KLAP) | +| Username | Benutzername | Benutzername für die Anmeldung (TP-Cloud Benutzername: eMail-Adresse) | +| Password | Passwort | Passwort für die Anmeldung (TP-Cloud Passwort) | +| Interval | Leseintervall | Intervall der Abfrage von Status und Energiewerten (in Sekunden) | +| AutoRename | Instanz automatisch umbenennen | Instanz erhält den Namen, welcher in der App vergeben wurde | + +## 5. Statusvariablen und Profile + +Die Statusvariablen werden automatisch angelegt. Das Löschen einzelner kann zu Fehlfunktionen führen. + +### Statusvariablen +| Ident | Name | Typ | +| ---------- | -------------- | ------- | +| device_on | Status | boolean | +| rssi | Rssi | integer | +| overheated | Überhitzt | boolean | +| brightness | Helligkeit | integer | +| color_temp | Farbtemperatur | integer | +| color_rgb | Farbe | integer | + + +### Profile +| Name | Typ | genutzt von | +| --------------- | ------- | ----------- | +| Tapo.ColorTemp | integer | color_temp | +| Tapo.Brightness | integer | brightness | + +## 6. PHP-Befehlsreferenz + +``` php +boolean TAPOSH_RequestState(integer $InstanzID); +``` +--- +``` php +array|false TAPOSH_GetDeviceInfo(integer $InstanzID); +``` + +## 7. Aktionen + +Es gibt keine speziellen Aktionen für dieses Modul. + +## 8. Anhang + +### 1. Changelog + +[Changelog der Library](../README.md#1-changelog) + +### 2. Spenden + + Die Library ist für die nicht kommerzielle Nutzung kostenlos, Schenkungen als Unterstützung für den Autor werden hier akzeptiert: + + + +[![Wunschliste](https://img.shields.io/badge/Wunschliste-Amazon-ff69fb.svg)](https://www.amazon.de/hz/wishlist/ls/YU4AI9AQT9F?ref_=wl_share) + + +## 9. Lizenz + + IPS-Modul: + [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) + \ No newline at end of file diff --git a/Tapo Light Color/module.json b/Tapo Light Color/module.json new file mode 100644 index 0000000..22f9106 --- /dev/null +++ b/Tapo Light Color/module.json @@ -0,0 +1,12 @@ +{ + "id": "{3C59DCC3-4441-4E1C-A59C-9F8D26CE2E82}", + "name": "tapo Light Color", + "type": 3, + "vendor": "TP-Link", + "aliases": [], + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "TAPOSH", + "url": "https://github.com/Nall-chan/tapoSmartHome" +} \ No newline at end of file diff --git a/Tapo Light Color/module.php b/Tapo Light Color/module.php new file mode 100644 index 0000000..276e425 --- /dev/null +++ b/Tapo Light Color/module.php @@ -0,0 +1,157 @@ + + * @copyright 2024 Michael Tröger + * @license https://creativecommons.org/licenses/by-nc-sa/4.0/ CC BY-NC-SA 4.0 + * + * @version 1.60 + */ +class TapoLightColor extends \TpLink\Device +{ + protected static $ModuleIdents = [ + '\TpLink\VariableIdent', + '\TpLink\VariableIdentLightColor' + ]; + + public function ApplyChanges() + { + $this->RegisterProfileInteger(\TpLink\VariableProfile::Brightness, 'Intensity', '', '%', 1, 100, 1); + $this->RegisterProfileInteger(\TpLink\VariableProfile::ColorTemp, '', '', ' K', 2500, 6500, 1); + //Never delete this line! + parent::ApplyChanges(); + } + + /** + * HSVtoRGB + * + * not static, falls wir doch auf Statusvariablen zurückgreifen müssen + * + * @param array $Values + * @return int + */ + protected function HSVtoRGB(array $Values) + { + $color_temp = $Values[\TpLink\VariableIdentLightColor::color_temp]; + if ($color_temp > 0) { + list($red, $green, $blue) = \TpLink\KelvinTable::ToRGB($color_temp); + return ($red << 16) ^ ($green << 8) ^ $blue; + } + $hue = $Values[\TpLink\VariableIdentLightColor::hue] / 360; + $saturation = $Values[\TpLink\VariableIdentLightColor::saturation] / 100; + $value = $Values[\TpLink\VariableIdentLightColor::brightness] / 100; + if ($saturation == 0) { + $red = $value * 255; + $green = $value * 255; + $blue = $value * 255; + } else { + $var_h = $hue * 6; + $var_i = floor($var_h); + $var_1 = $value * (1 - $saturation); + $var_2 = $value * (1 - $saturation * ($var_h - $var_i)); + $var_3 = $value * (1 - $saturation * (1 - ($var_h - $var_i))); + + switch ($var_i) { + case 0: + $var_r = $value; + $var_g = $var_3; + $var_b = $var_1; + break; + case 1: + $var_r = $var_2; + $var_g = $value; + $var_b = $var_1; + break; + case 2: + $var_r = $var_1; + $var_g = $value; + $var_b = $var_3; + break; + case 3: + $var_r = $var_1; + $var_g = $var_2; + $var_b = $value; + break; + case 4: + $var_r = $var_3; + $var_g = $var_1; + $var_b = $value; + break; + default: + $var_r = $value; + $var_g = $var_1; + $var_b = $var_2; + break; + } + + $red = (int) round($var_r * 255); + $green = (int) round($var_g * 255); + $blue = (int) round($var_b * 255); + } + + return ($red << 16) ^ ($green << 8) ^ $blue; + } + + /** + * RGBtoHSV + * + * not static, falls wir doch auf Statusvariablen zurückgreifen müssen + * + * @param int $RGB + * @return array + */ + protected function RGBtoHSV(int $RGB) + { + $Values[\TpLink\VariableIdentLightColor::color_temp] = 0; + $Values[\TpLink\VariableIdentLightColor::hue] = 0; + $Values[\TpLink\VariableIdentLightColor::saturation] = 0; + + $red = ($RGB >> 16) / 255; + $green = (($RGB & 0x00FF00) >> 8) / 255; + $blue = ($RGB & 0x0000ff) / 255; + + $min = min($red, $green, $blue); + $max = max($red, $green, $blue); + + $value = $max; + $delta = $max - $min; + + if ($delta == 0) { + $Values[\TpLink\VariableIdentLightColor::brightness] = (int) ($value * 100); + return $Values; + } + + $saturation = 0; + + if ($max != 0) { + $saturation = ($delta / $max); + } else { + $Values[\TpLink\VariableIdentLightColor::brightness] = (int) ($value); + return $Values; + } + if ($red == $max) { + $hue = ($green - $blue) / $delta; + } else { + if ($green == $max) { + $hue = 2 + ($blue - $red) / $delta; + } else { + $hue = 4 + ($red - $green) / $delta; + } + } + $hue *= 60; + if ($hue < 0) { + $hue += 360; + } + $Values[\TpLink\VariableIdentLightColor::hue] = (int) $hue; + $Values[\TpLink\VariableIdentLightColor::saturation] = (int) ($saturation * 100); + $Values[\TpLink\VariableIdentLightColor::brightness] = (int) ($value * 100); + return $Values; + } +} diff --git a/Tapo Light/README.md b/Tapo Light/README.md index 0ea31d9..788b06d 100644 --- a/Tapo Light/README.md +++ b/Tapo Light/README.md @@ -27,7 +27,7 @@ ## 1. Funktionsumfang - - Instanz für Lampen und LED-Stripes + - Instanz für Lampen ohne Farbe ## 2. Voraussetzungen @@ -75,14 +75,12 @@ Die Statusvariablen werden automatisch angelegt. Das Löschen einzelner kann zu | rssi | Rssi | integer | | overheated | Überhitzt | boolean | | brightness | Helligkeit | integer | -| color_temp | Farbtemperatur | integer | -| color_rgb | Farbe | integer | + ### Profile | Name | Typ | genutzt von | | --------------- | ------- | ----------- | -| Tapo.ColorTemp | integer | color_temp | | Tapo.Brightness | integer | brightness | ## 6. PHP-Befehlsreferenz diff --git a/Tapo Light/module.json b/Tapo Light/module.json index 8b8910f..5fac97d 100644 --- a/Tapo Light/module.json +++ b/Tapo Light/module.json @@ -1,5 +1,5 @@ { - "id": "{3C59DCC3-4441-4E1C-A59C-9F8D26CE2E82}", + "id": "{1B9D73D6-853D-4E2E-9755-2273FD7A6123}", "name": "tapo Light", "type": 3, "vendor": "TP-Link", diff --git a/Tapo Light/module.php b/Tapo Light/module.php index bdbacd3..a7c0a5f 100644 --- a/Tapo Light/module.php +++ b/Tapo Light/module.php @@ -24,134 +24,7 @@ class TapoLight extends \TpLink\Device public function ApplyChanges() { $this->RegisterProfileInteger(\TpLink\VariableProfile::Brightness, 'Intensity', '', '%', 1, 100, 1); - $this->RegisterProfileInteger(\TpLink\VariableProfile::ColorTemp, '', '', ' K', 2500, 6500, 1); //Never delete this line! parent::ApplyChanges(); } - - /** - * HSVtoRGB - * - * not static, falls wir doch auf Statusvariablen zurückgreifen müssen - * - * @param array $Values - * @return int - */ - protected function HSVtoRGB(array $Values) - { - $color_temp = $Values[\TpLink\VariableIdentLight::color_temp]; - if ($color_temp > 0) { - list($red, $green, $blue) = \TpLink\KelvinTable::ToRGB($color_temp); - return ($red << 16) ^ ($green << 8) ^ $blue; - } - $hue = $Values[\TpLink\VariableIdentLight::hue] / 360; - $saturation = $Values[\TpLink\VariableIdentLight::saturation] / 100; - $value = $Values[\TpLink\VariableIdentLight::brightness] / 100; - if ($saturation == 0) { - $red = $value * 255; - $green = $value * 255; - $blue = $value * 255; - } else { - $var_h = $hue * 6; - $var_i = floor($var_h); - $var_1 = $value * (1 - $saturation); - $var_2 = $value * (1 - $saturation * ($var_h - $var_i)); - $var_3 = $value * (1 - $saturation * (1 - ($var_h - $var_i))); - - switch ($var_i) { - case 0: - $var_r = $value; - $var_g = $var_3; - $var_b = $var_1; - break; - case 1: - $var_r = $var_2; - $var_g = $value; - $var_b = $var_1; - break; - case 2: - $var_r = $var_1; - $var_g = $value; - $var_b = $var_3; - break; - case 3: - $var_r = $var_1; - $var_g = $var_2; - $var_b = $value; - break; - case 4: - $var_r = $var_3; - $var_g = $var_1; - $var_b = $value; - break; - default: - $var_r = $value; - $var_g = $var_1; - $var_b = $var_2; - break; - } - - $red = (int) round($var_r * 255); - $green = (int) round($var_g * 255); - $blue = (int) round($var_b * 255); - } - - return ($red << 16) ^ ($green << 8) ^ $blue; - } - - /** - * RGBtoHSV - * - * not static, falls wir doch auf Statusvariablen zurückgreifen müssen - * - * @param int $RGB - * @return array - */ - protected function RGBtoHSV(int $RGB) - { - $Values[\TpLink\VariableIdentLight::color_temp] = 0; - $Values[\TpLink\VariableIdentLight::hue] = 0; - $Values[\TpLink\VariableIdentLight::saturation] = 0; - - $red = ($RGB >> 16) / 255; - $green = (($RGB & 0x00FF00) >> 8) / 255; - $blue = ($RGB & 0x0000ff) / 255; - - $min = min($red, $green, $blue); - $max = max($red, $green, $blue); - - $value = $max; - $delta = $max - $min; - - if ($delta == 0) { - $Values[\TpLink\VariableIdentLight::brightness] = (int) ($value * 100); - return $Values; - } - - $saturation = 0; - - if ($max != 0) { - $saturation = ($delta / $max); - } else { - $Values[\TpLink\VariableIdentLight::brightness] = (int) ($value); - return $Values; - } - if ($red == $max) { - $hue = ($green - $blue) / $delta; - } else { - if ($green == $max) { - $hue = 2 + ($blue - $red) / $delta; - } else { - $hue = 4 + ($red - $green) / $delta; - } - } - $hue *= 60; - if ($hue < 0) { - $hue += 360; - } - $Values[\TpLink\VariableIdentLight::hue] = (int) $hue; - $Values[\TpLink\VariableIdentLight::saturation] = (int) ($saturation * 100); - $Values[\TpLink\VariableIdentLight::brightness] = (int) ($value * 100); - return $Values; - } } diff --git a/libs/TapoLib.php b/libs/TapoLib.php index c940ace..6767d6a 100644 --- a/libs/TapoLib.php +++ b/libs/TapoLib.php @@ -171,6 +171,7 @@ class DeviceModel public const PlugP100 = 'P100'; public const PlugP110 = 'P110'; public const BulbL530 = 'L530'; + public const BulbL610 = 'L610'; public const KH100 = 'KH100'; } @@ -179,14 +180,17 @@ class GUID public const Plug = '{AAD6F48D-C23F-4C59-8049-A9746DEB699B}'; public const PlugEnergy = '{B18B6CAA-AB46-495D-9A7A-85FA3A83113A}'; public const BulbL530 = '{3C59DCC3-4441-4E1C-A59C-9F8D26CE2E82}'; - public const KH100 = '{1EDD1EB2-6885-4D87-BA00-9328D74A85C4}'; + public const BulbL610 = '{1B9D73D6-853D-4E2E-9755-2273FD7A6123}'; + //public const KH100 = '{1EDD1EB2-6885-4D87-BA00-9328D74A85C4}'; public static $TapoDevices = [ DeviceModel::PlugP100 => self::Plug, DeviceModel::PlugP110 => self::PlugEnergy, DeviceModel::BulbL530 => self::BulbL530, - DeviceModel::KH100 => self::KH100, + DeviceModel::BulbL610 => self::BulbL610, + //DeviceModel::KH100 => self::KH100, ]; + public static function GetByModel(string $Model) { if (!array_key_exists($Model, self::$TapoDevices)) { @@ -252,6 +256,27 @@ class VariableIdentEnergySocket } class VariableIdentLight + { + public const overheated = 'overheated'; + public const brightness = 'brightness'; + + public static $Variables = [ + self::overheated=> [ + IPSVarName => 'Overheated', + IPSVarType => VARIABLETYPE_BOOLEAN, + IPSVarProfile=> '~Alert', + HasAction => false + ], + self::brightness=> [ + IPSVarName => 'Brightness', + IPSVarType => VARIABLETYPE_INTEGER, + IPSVarProfile=> VariableProfile::Brightness, + HasAction => true + ] + ]; + } + + class VariableIdentLightColor { public const overheated = 'overheated'; public const brightness = 'brightness'; @@ -290,7 +315,6 @@ class VariableIdentLight ], ]; } - class VariableIdentTrv { public const target_temp = 'target_temp'; diff --git a/tests/LibraryTest.php b/tests/LibraryTest.php index ec68d30..2274e2a 100644 --- a/tests/LibraryTest.php +++ b/tests/LibraryTest.php @@ -30,4 +30,9 @@ public function testValidateLight(): void { $this->validateModule(__DIR__ . '/../Tapo Light'); } + + public function testValidateLightColor(): void + { + $this->validateModule(__DIR__ . '/../Tapo Light Color'); + } } \ No newline at end of file