From 5c22c571f4ad9fd6d77463f34aa3f62c60e7d207 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Wed, 29 Nov 2017 21:16:39 +0000 Subject: [PATCH 01/30] Auto Discovery of TPLinkDevices on network Changes to TPLinkManager to better handle discovered devices --- composer.json | 3 ++- src/TPLinkManager.php | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 6ea9fe3..2a3bc04 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,8 @@ } ], "require": { - "tightenco/collect": "^5.3" + "tightenco/collect": "^5.3", + "s1lentium/iptools": "^1.1" }, "require-dev": { "phpunit/phpunit": "^5.7" diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 6410084..439e161 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -3,13 +3,14 @@ namespace Williamson\TPLinkSmartplug; use InvalidArgumentException; +use IPTools\Range; class TPLinkManager { protected $config; protected $devices; - public function __construct(array $config) + public function __construct(array $config = []) { $this->config = $config; } @@ -20,11 +21,33 @@ public function device($name = 'default') throw new InvalidArgumentException('You have not setup the details for a device named ' . $name); } - return $this->newTPLinkDevice($this->config[$name], $name); + return new TPLinkDevice($this->config[$name], $name); } protected function newTPLinkDevice($config, $name) { + $this->config[$name] = $config; return new TPLinkDevice($config, $name); } + + public function deviceList() + { + return $this->config; + } + + public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) + { + $ips = Range::parse($ipRange); + foreach($ips AS $ip){ + $device = new TPLinkDevice(['ip' => $ip, 'port' => 9999, 'timeout' => $timeout], 'autodiscovery'); + try{ + $systemInfo = json_decode($device->sendCommand(TPLinkCommand::systemInfo())); + $this->newTPLinkDevice([ + 'ip' => (string)$ip, + 'port' => 9999, + 'systemInfo' => $systemInfo->system->get_sysinfo + ], $systemInfo->system->get_sysinfo->alias); + } catch(\UnexpectedValueException $e) {} + } + } } \ No newline at end of file From 43a40be79044e9842005d13e932b26d6401189d1 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Wed, 29 Nov 2017 21:19:37 +0000 Subject: [PATCH 02/30] Stopped stream_socket_client from giving off warning messages Added a configurable timeout setting to device config Exposed getConfig to public to allow easy querying of a devices config Added powerOn, powerOff and powerStatus direct methods --- src/TPLinkDevice.php | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index a63fdbe..f062eaf 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -24,6 +24,16 @@ public function __construct(array $config, $deviceName) $this->deviceName = $deviceName; } + /** + * Return current power status + * + * @return boolean + */ + public function powerStatus() + { + return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->relay_state; + } + /** * Toggle the current status of the switch on/off * @@ -31,9 +41,27 @@ public function __construct(array $config, $deviceName) */ public function togglePower() { - $status = (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->relay_state; + return $this->powerStatus() ? $this->sendCommand(TPLinkCommand::powerOff()) : $this->sendCommand(TPLinkCommand::powerOn()); + } - return $status ? $this->sendCommand(TPLinkCommand::powerOff()) : $this->sendCommand(TPLinkCommand::powerOn()); + /** + * Change the current status of the switch to on + * + * @return string + */ + public function powerOn() + { + return $this->sendCommand(TPLinkCommand::powerOn()); + } + + /** + * Change the current status of the switch off + * + * @return string + */ + public function powerOff() + { + return $this->sendCommand(TPLinkCommand::powerOff()); } /** @@ -62,11 +90,11 @@ public function sendCommand(array $command) */ protected function connectToDevice() { - $this->client = stream_socket_client( + $this->client = @stream_socket_client( "tcp://" . $this->getConfig("ip") . ":" . $this->getConfig("port"), $errorNumber, $errorMessage, - 5 + $this->getConfig('timeout', 5) ); if ($this->client === false) { @@ -80,7 +108,7 @@ protected function connectToDevice() * * @return mixed */ - protected function getConfig($key, $default = null) + public function getConfig($key, $default = null) { if (is_array($this->config) && isset($this->config[$key])) { return $this->config[$key]; From c2ea0ee95011ed85b35fe75cd0034ac091f92939 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 30 Nov 2017 18:20:22 +0000 Subject: [PATCH 03/30] Faster querying of network devices by allowing config to support a timeout setting Stopped stream_socket_client from generating warnings --- src/TPLinkDevice.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index a63fdbe..d51b124 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -62,11 +62,11 @@ public function sendCommand(array $command) */ protected function connectToDevice() { - $this->client = stream_socket_client( + $this->client = @stream_socket_client( "tcp://" . $this->getConfig("ip") . ":" . $this->getConfig("port"), $errorNumber, $errorMessage, - 5 + $this->getConfig('timeout') ); if ($this->client === false) { From dab8bcb0ae69609a7143c13c3d36f8009b562edd Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 30 Nov 2017 18:26:02 +0000 Subject: [PATCH 04/30] Expose devices config via getConfig --- src/TPLinkDevice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index d51b124..155d85e 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -80,7 +80,7 @@ protected function connectToDevice() * * @return mixed */ - protected function getConfig($key, $default = null) + public function getConfig($key, $default = null) { if (is_array($this->config) && isset($this->config[$key])) { return $this->config[$key]; From 9efbc7fda3bb984dc71569a8d6e7ced2c6f70081 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 30 Nov 2017 18:42:36 +0000 Subject: [PATCH 05/30] Checking auto discovery for empty responses and null json_decodes --- src/TPLinkManager.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 439e161..acaeaa2 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -39,14 +39,26 @@ public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) { $ips = Range::parse($ipRange); foreach($ips AS $ip){ + // Try to connect to a IP and port $device = new TPLinkDevice(['ip' => $ip, 'port' => 9999, 'timeout' => $timeout], 'autodiscovery'); try{ - $systemInfo = json_decode($device->sendCommand(TPLinkCommand::systemInfo())); - $this->newTPLinkDevice([ - 'ip' => (string)$ip, - 'port' => 9999, - 'systemInfo' => $systemInfo->system->get_sysinfo - ], $systemInfo->system->get_sysinfo->alias); + // Try sending systemInfo command + // Possible we may get a blank response, if querying another device which uses these ports + $response = $device->sendCommand(TPLinkCommand::systemInfo()); + if(!empty($response)){ + // Check the returned data JSON decodes + // Make sure is not NULL, some devices may return a single character + // LB100 Series seems to respond on port 9999, however return a bad string + // TODO:: investigate LB100 support + $jsonResponse = json_decode($response); + if(!is_null($jsonResponse)){ + $this->newTPLinkDevice([ + 'ip' => (string)$ip, + 'port' => 9999, + 'systemInfo' => $jsonResponse->system->get_sysinfo + ], $jsonResponse->system->get_sysinfo->alias); + } + } } catch(\UnexpectedValueException $e) {} } } From ac1c5072ef2490c9137373dc8a5df6d48e590d3b Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 08:22:17 +0000 Subject: [PATCH 06/30] PSR-2 compliance changes --- src/Laravel/TPLinkServiceProvider.php | 11 ++++------- src/Laravel/config/TPLink.php | 2 +- src/TPLinkCommand.php | 21 ++++++++++----------- src/TPLinkDevice.php | 18 ++++++++++-------- src/TPLinkManager.php | 14 ++++++++------ 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/Laravel/TPLinkServiceProvider.php b/src/Laravel/TPLinkServiceProvider.php index 197f01f..028f877 100644 --- a/src/Laravel/TPLinkServiceProvider.php +++ b/src/Laravel/TPLinkServiceProvider.php @@ -27,20 +27,17 @@ public function boot() */ public function register() { - $this->app->singleton(TPLinkManager::class, - function ($app) { - $config = (array)$app['config']['TPLink']; + $this->app->singleton(TPLinkManager::class, function ($app) { + $config = (array)$app['config']['TPLink']; - return new TPLinkManager($config); - }); + return new TPLinkManager($config); + }); $this->app->alias(TPLinkManager::class, 'tplink'); - //Auto-register the TPLink facade if the user hasn't already //assigned it to another class. if (class_exists(AliasLoader::class)) { - $loader = AliasLoader::getInstance(); if (!array_key_exists('TPLink', $loader->getAliases())) { diff --git a/src/Laravel/config/TPLink.php b/src/Laravel/config/TPLink.php index 7d9cb2b..b6d85ab 100644 --- a/src/Laravel/config/TPLink.php +++ b/src/Laravel/config/TPLink.php @@ -15,4 +15,4 @@ // 'port' => '9999', // ], -]; \ No newline at end of file +]; diff --git a/src/TPLinkCommand.php b/src/TPLinkCommand.php index f76e407..f144117 100644 --- a/src/TPLinkCommand.php +++ b/src/TPLinkCommand.php @@ -7,7 +7,6 @@ use InvalidArgumentException; use Illuminate\Support\Collection; - /** * Class TPLinkCommands * @@ -114,7 +113,7 @@ public static function setDeviceAlias($name) public static function setMacAddress($macAddress) { if (filter_var($macAddress, FILTER_VALIDATE_MAC) === false) { - throw new InvalidArgumentException('The supplied MAC address is not valid. Try again using hyphens between each group of characters.'); + throw new InvalidArgumentException('MAC address invalid. Try hyphens between each group of characters.'); } return [ @@ -241,7 +240,7 @@ public static function flashFirmware($confirm = false) ]; } - throw new InvalidArgumentException('You must set the confirm flag to true before flashing firmware is allowed.'); + throw new InvalidArgumentException('Confirm flag to true before flashing firmware is allowed.'); } /** @@ -402,7 +401,7 @@ public static function cloudUnregisterDevice($confirm = false) ]; } - throw new InvalidArgumentException('You must set the confirm flag to true before un-registering the device is allowed.'); + throw new InvalidArgumentException('Confirm flag to true before un-registering the device is allowed.'); } /** @@ -662,7 +661,7 @@ public static function scheduleRuleList() * @param DateTime $dateAndTime The actual Date and Time for this event. * @param bool $turnOn Should the event turn on or off the timer. * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional). An array of days of the week this event should repeat. Use normal english like Tues, Saturday etc. + * @param array $daysOfWeekToRepeat (Optional). Days of week event should repeat. Use EN like Tues, Saturday etc. * * @return array */ @@ -690,7 +689,7 @@ public static function scheduleRuleCreate(DateTime $dateAndTime, $turnOn, $name, * @param DateTime $dateAndTime The actual Date and Time for this event. * @param bool $turnOn Should the event turn on or off the timer. * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional). An array of days of the week this event should repeat. Use normal english like Tues, Saturday etc. + * @param array $daysOfWeekToRepeat (Optional). Days of week event should repeat. Use EN like Tues, Saturday etc. * * @return array */ @@ -856,7 +855,7 @@ public static function antitheftRuleList() * @param DateTime $startTime The start date/time for the event to begin * @param DateTime $endTime The end date/time for the event to finish. * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional). An array of days of the week this event should repeat. Use normal english like Tues, Saturday etc. + * @param array $daysOfWeekToRepeat (Optional). Days of week event should repeat. Use EN like Tues, Saturday etc. * * @return array */ @@ -884,7 +883,7 @@ public static function antitheftRuleCreate(DateTime $startTime, DateTime $endTim * @param DateTime $startTime The start date/time for the event to begin * @param DateTime $endTime The end date/time for the event to finish. * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional). An array of days of the week this event should repeat. Use normal english like Tues, Saturday etc. + * @param array $daysOfWeekToRepeat (Optional). Days of week event should repeat. Use EN like Tues, Saturday etc. * * @return array */ @@ -1035,7 +1034,7 @@ protected static function calculateMinutes(DateTime $dateAndTime) * @param DateTime $dateAndTime The actual Date and Time for this event. * @param bool $turnOn Should the event turn on or off the timer. * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional). An array of days of the week this event should repeat. Use normal english like Tues, Saturday etc. + * @param array $daysOfWeekToRepeat (Optional) Day of week event should repeat. Use EN like Tues, Saturday etc. * @param Collection $data specific information depending on if the event is repeating or not. * @param string $ruleId The ID of the rule to be edited. * @@ -1103,7 +1102,7 @@ protected static function countdownCommonData($type, $delay, $turnOn, $name, $ru * @param DateTime $startTime The start date/time for the event to begin * @param DateTime $endTime The end date/time for the event to finish. * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional). An array of days of the week this event should repeat. Use normal english like Tues, Saturday etc. + * @param array $daysOfWeekToRepeat (Optional) Day of week event should repeat. Use EN like Tues, Saturday etc. * @param Collection $data specific information depending on if the event is repeating or not. * @param string $ruleId The ID of the rule to be edited. * @@ -1144,4 +1143,4 @@ protected static function antitheftCommonData( ], ]; } -} \ No newline at end of file +} diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index 155d85e..7d6f861 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -70,7 +70,7 @@ protected function connectToDevice() ); if ($this->client === false) { - throw new UnexpectedValueException("Failed to connect to {$this->deviceName}: $errorMessage ($errorNumber)"); + throw new UnexpectedValueException("Failed connect to {$this->deviceName}: $errorMessage ($errorNumber)"); } } @@ -101,12 +101,14 @@ protected function encrypt($string) $key = 171; return collect(str_split($string)) - ->reduce(function ($result, $character) use (&$key) { - $key = $key ^ ord($character); - - return $result .= chr($key); - }, - "\0\0\0\0"); + ->reduce( + function ($result, $character) use (&$key) { + $key = $key ^ ord($character); + + return $result .= chr($key); + }, + "\0\0\0\0" + ); } /** @@ -117,7 +119,7 @@ protected function connectionError() { return json_encode([ 'success' => false, - 'message' => "When sending the command to the smartplug {$this->deviceName}, the connection terminated before the command was sent.", + 'message' => "{$this->deviceName} : connection terminated before the command was sent.", ]); } diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index acaeaa2..3b10987 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -38,20 +38,20 @@ public function deviceList() public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) { $ips = Range::parse($ipRange); - foreach($ips AS $ip){ + foreach ($ips as $ip) { // Try to connect to a IP and port $device = new TPLinkDevice(['ip' => $ip, 'port' => 9999, 'timeout' => $timeout], 'autodiscovery'); - try{ + try { // Try sending systemInfo command // Possible we may get a blank response, if querying another device which uses these ports $response = $device->sendCommand(TPLinkCommand::systemInfo()); - if(!empty($response)){ + if (!empty($response)) { // Check the returned data JSON decodes // Make sure is not NULL, some devices may return a single character // LB100 Series seems to respond on port 9999, however return a bad string // TODO:: investigate LB100 support $jsonResponse = json_decode($response); - if(!is_null($jsonResponse)){ + if (!is_null($jsonResponse)) { $this->newTPLinkDevice([ 'ip' => (string)$ip, 'port' => 9999, @@ -59,7 +59,9 @@ public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) ], $jsonResponse->system->get_sysinfo->alias); } } - } catch(\UnexpectedValueException $e) {} + } catch (\UnexpectedValueException $e) { + // Lets not do anything here + } } } -} \ No newline at end of file +} From 7a897f8c89b03889d5c6a0d9d470d83588a33e80 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 08:25:18 +0000 Subject: [PATCH 07/30] Exclude .idea dev folder --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 189d7da..7c239d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ composer.phar composer.lock vendor/ -build/ \ No newline at end of file +build/ +.idea/ \ No newline at end of file From b7d3d573e548849ac6167840475679ca4f274c7f Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 08:42:28 +0000 Subject: [PATCH 08/30] Updated readme.md --- README.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 836f732..c31a8f4 100644 --- a/README.md +++ b/README.md @@ -59,11 +59,14 @@ return [ 'lamp' => [ 'ip' => '192.168.1.100', //Or hostname eg: home.example.com 'port' => '9999', + 'timeout' => 5 // Optional, timeout setting (how long we will try communicate with device before giving up) ], ]; ``` -You may add as many devices as you wish, as long as you specify the IP address (or host address if required) and port number to access each one. Giving each device a name makes it easy to identify them when coding later. _(Please note that the name you give here does NOT have to match the actual name you might have assigned the device using an official app like Kasa. They do NOT have to match)_ +You may add as many devices as you wish, as long as you specify the IP address (or host address if required) and port number to access each one. Giving each device a name makes it easy to identify them when coding later. _(Please note that the name you give here does NOT have to match the actual name you might have assigned the device using an official app like Kasa. They do NOT have to match) + +You can use the `autoDiscoverTPLinkDevices` method to automatically find networked devices. ## Usage You can access your device either through the `TPLinkManager` class (especially useful if you have multiple devices), or directly using the `TPLinkDevice` class. @@ -130,6 +133,27 @@ If a command requires a parameter, provide that as well: $tpDevice->sendCommand(TPLinkCommand::setLED(false)); ``` + +####Auto Discovery +You can search your local network for devices using `TPLinkManager`, using the method `autoDiscoverTPLinkDevices` +all found devices will be added to the 'TPLinkManager' config automatically, exposed using `deviceList()`. + +You must provide the IP range you wish to scan, use it as follows: +```php +//Non laravel + $tpLinkManager->autoDiscoverTPLinkDevices('192.168.0.*'); + +//Laravel + // with facade + TPLink::autoDiscoverTPLinkDevices('192.168.0.*'); + + // without facade + app(TPLinkManager::class)->autoDiscoverTPLinkDevices('192.168.0.*'); +``` + +The auto discovery command will take a while to scan, once completed you can use `deviceList()` method to view the new configuration and any found devices. + + ####Toggle Power There is one command that is called directly on the `TPLinkDevice` and that is the `togglePower()` method. From 64b4fa245363950af1e89be341851b4b0e480064 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 08:42:28 +0000 Subject: [PATCH 09/30] Updated readme.md --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 836f732..2a81d16 100644 --- a/README.md +++ b/README.md @@ -59,11 +59,14 @@ return [ 'lamp' => [ 'ip' => '192.168.1.100', //Or hostname eg: home.example.com 'port' => '9999', + 'timeout' => 5 // Optional, timeout setting (how long we will try communicate with device before giving up) ], ]; ``` -You may add as many devices as you wish, as long as you specify the IP address (or host address if required) and port number to access each one. Giving each device a name makes it easy to identify them when coding later. _(Please note that the name you give here does NOT have to match the actual name you might have assigned the device using an official app like Kasa. They do NOT have to match)_ +You may add as many devices as you wish, as long as you specify the IP address (or host address if required) and port number to access each one. Giving each device a name makes it easy to identify them when coding later. _(Please note that the name you give here does NOT have to match the actual name you might have assigned the device using an official app like Kasa. They do NOT have to match) + +You can use the `autoDiscoverTPLinkDevices` method to automatically find networked devices. ## Usage You can access your device either through the `TPLinkManager` class (especially useful if you have multiple devices), or directly using the `TPLinkDevice` class. @@ -130,6 +133,27 @@ If a command requires a parameter, provide that as well: $tpDevice->sendCommand(TPLinkCommand::setLED(false)); ``` + +####Auto Discovery +You can search your local network for devices using `TPLinkManager`, using the method `autoDiscoverTPLinkDevices` +all found devices will be added to the 'TPLinkManager' config automatically, exposed using `deviceList()`. + +You must provide the IP range you wish to scan, use it as follows: +```php +//Non laravel + $tpLinkManager->autoDiscoverTPLinkDevices('192.168.0.*'); + +//Laravel + // with facade + TPLink::autoDiscoverTPLinkDevices('192.168.0.*'); + + // without facade + app(TPLinkManager::class)->autoDiscoverTPLinkDevices('192.168.0.*'); +``` + +The auto discovery command will take a while to scan, once completed you can use `deviceList()` method to view the new configuration and any found devices. + + ####Toggle Power There is one command that is called directly on the `TPLinkDevice` and that is the `togglePower()` method. @@ -216,6 +240,7 @@ Any issues, feedback, suggestions or questions please use issue tracker [here][l - [softScheck](https://github.com/softScheck/tplink-smartplug) (Who did the reverse engineering and provided the secrets on how to talk to the Smartplug.) - [Jonathan Williamson][link-author] - [Syed Irfaq R.](https://github.com/irazasyed) For the idea behind how to manage multiple devices. +- [Shane Rutter](https://shanerutter.co.uk) Auto-Discovery feature ## Disclaimer From bfb0fe38d5caec827a46f7dcbb28edd997e8ad0a Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 08:52:22 +0000 Subject: [PATCH 10/30] Laravel config updated with timeout setting --- src/Laravel/config/TPLink.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Laravel/config/TPLink.php b/src/Laravel/config/TPLink.php index b6d85ab..36cd483 100644 --- a/src/Laravel/config/TPLink.php +++ b/src/Laravel/config/TPLink.php @@ -8,11 +8,13 @@ // 'bedroom' => [ // 'ip' => '192.168.1.100', //Or hostname // 'port' => '9999', +// 'timeout' => 5 // ], // 'livingroom' => [ // 'ip' => '192.168.1.101', //Or hostname // 'port' => '9999', +// 'timeout' => 10 // ], ]; From a9c457c1c3f6ef421b3cad67dc4f872c361fb0ef Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 09:14:43 +0000 Subject: [PATCH 11/30] Added missing bit from readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2a81d16..1045e6d 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ You must provide the IP range you wish to scan, use it as follows: TPLink::autoDiscoverTPLinkDevices('192.168.0.*'); // without facade + app('tplink')->autoDiscoverTPLinkDevices('192.168.0.*'); app(TPLinkManager::class)->autoDiscoverTPLinkDevices('192.168.0.*'); ``` From d7d3efe81db1e1b43c2089980fe9fe83c4163340 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 09:14:43 +0000 Subject: [PATCH 12/30] Added missing bit from readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2a81d16..a10684c 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,6 @@ If a command requires a parameter, provide that as well: $tpDevice->sendCommand(TPLinkCommand::setLED(false)); ``` - ####Auto Discovery You can search your local network for devices using `TPLinkManager`, using the method `autoDiscoverTPLinkDevices` all found devices will be added to the 'TPLinkManager' config automatically, exposed using `deviceList()`. @@ -148,12 +147,12 @@ You must provide the IP range you wish to scan, use it as follows: TPLink::autoDiscoverTPLinkDevices('192.168.0.*'); // without facade + app('tplink')->autoDiscoverTPLinkDevices('192.168.0.*'); app(TPLinkManager::class)->autoDiscoverTPLinkDevices('192.168.0.*'); ``` The auto discovery command will take a while to scan, once completed you can use `deviceList()` method to view the new configuration and any found devices. - ####Toggle Power There is one command that is called directly on the `TPLinkDevice` and that is the `togglePower()` method. From f0ed9dea14e93372b2758f645f97f5c856ad2b68 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 1 Dec 2017 09:25:22 +0000 Subject: [PATCH 13/30] Read me edit for deviceList --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 8ca91ee..c84290a 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,19 @@ You must provide the IP range you wish to scan, use it as follows: The auto discovery command will take a while to scan, once completed you can use `deviceList()` method to view the new configuration and any found devices. +```php +//Non laravel + $tpLinkManager->deviceList(); + +//Laravel + // with facade + $devices = TPLink::deviceList(); + + // without facade + $devices = app('tplink')->deviceList(); + $devices = app(TPLinkManager::class)->deviceList(); +``` + #### Toggle Power There is one command that is called directly on the `TPLinkDevice` and that is the `togglePower()` method. From 8b750c7491ebcf7af09f72f1e4715b8237c3aa5a Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Wed, 19 Jun 2019 18:19:52 +0100 Subject: [PATCH 14/30] Added jonnywilliamson changes with some bug fixes Removed supression of stream_socker_client errors --- src/TPLinkDevice.php | 2 +- src/TPLinkManager.php | 102 ++++++++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 25 deletions(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index 7d6f861..5746d66 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -62,7 +62,7 @@ public function sendCommand(array $command) */ protected function connectToDevice() { - $this->client = @stream_socket_client( + $this->client = stream_socket_client( "tcp://" . $this->getConfig("ip") . ":" . $this->getConfig("port"), $errorNumber, $errorMessage, diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 3b10987..f1702e0 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -4,6 +4,7 @@ use InvalidArgumentException; use IPTools\Range; +use Tightenco\Collect\Support\Collection; class TPLinkManager { @@ -35,33 +36,86 @@ public function deviceList() return $this->config; } + /** + * Will return a collection of all TPLink devices auto discovered + * on the IP Range given. + * + * These will already have been added to the global config during + * discovery. + * + * @param $ipRange + * @param int $timeout + * + * @return Collection + */ public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) { - $ips = Range::parse($ipRange); - foreach ($ips as $ip) { - // Try to connect to a IP and port + return collect(Range::parse($ipRange)) + ->map(function ($ip) use ($timeout) { + $response = $this->deviceResponse($ip, $timeout); + + return is_null($response) ? $response : $this->validTPLinkResponse($response, $ip); + }) + ->filter(); + } + + /** + * Try sending systemInfo command to an ip. + * Possible we may get a blank response, if querying another device which uses these ports + * + * @param $ip + * @param $timeout + * + * @return null + */ + protected function deviceResponse($ip, $timeout) + { + try { $device = new TPLinkDevice(['ip' => $ip, 'port' => 9999, 'timeout' => $timeout], 'autodiscovery'); - try { - // Try sending systemInfo command - // Possible we may get a blank response, if querying another device which uses these ports - $response = $device->sendCommand(TPLinkCommand::systemInfo()); - if (!empty($response)) { - // Check the returned data JSON decodes - // Make sure is not NULL, some devices may return a single character - // LB100 Series seems to respond on port 9999, however return a bad string - // TODO:: investigate LB100 support - $jsonResponse = json_decode($response); - if (!is_null($jsonResponse)) { - $this->newTPLinkDevice([ - 'ip' => (string)$ip, - 'port' => 9999, - 'systemInfo' => $jsonResponse->system->get_sysinfo - ], $jsonResponse->system->get_sysinfo->alias); - } - } - } catch (\UnexpectedValueException $e) { - // Lets not do anything here - } + + return $device->sendCommand(TPLinkCommand::systemInfo()); + } catch (\Exception $exception) { + return null; } } + + /** + * Check the returned data JSON decodes + * Make sure is not NULL, some devices may return a single character + * LB100 Series seems to respond on port 9999, however return a bad string + * TODO:: investigate LB100 support + * + * @param $response + * @param $ip + * + * @return mixed|TPLinkDevice + */ + protected function validTPLinkResponse($response, $ip) + { + $jsonResponse = json_decode($response); + + return is_null($jsonResponse) ? $jsonResponse : $this->discoveredDevice($jsonResponse, $ip); + } + + /** + * Create a new discovered device instance and update config to contain new device + * + * @param $jsonResponse + * @param $ip + * + * @return TPLinkDevice + */ + protected function discoveredDevice($jsonResponse, $ip) + { + return $this->newTPLinkDevice([ + 'ip' => (string)$ip, + 'port' => 9999, + 'systemInfo' => $jsonResponse->system->get_sysinfo, + ], $jsonResponse->system->get_sysinfo->alias); + } + + + + + } From 0030c64ad086d0efb10d8df29a79ae3ccfeca1a9 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 20 Jun 2019 09:22:13 +0100 Subject: [PATCH 15/30] Removed error supression --- src/TPLinkDevice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index fe408f6..ee9f052 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -90,7 +90,7 @@ public function sendCommand(array $command) */ protected function connectToDevice() { - $this->client = @stream_socket_client( + $this->client = stream_socket_client( "tcp://" . $this->getConfig("ip") . ":" . $this->getConfig("port"), $errorNumber, $errorMessage, From 4f300333685ff1be1dceaa9a11ff5871cc709251 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 20 Jun 2019 12:56:54 +0100 Subject: [PATCH 16/30] Changed requirement for ip lib to use latest --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2a3bc04..ede6c1a 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ ], "require": { "tightenco/collect": "^5.3", - "s1lentium/iptools": "^1.1" + "s1lentium/iptools": "*" }, "require-dev": { "phpunit/phpunit": "^5.7" From d3f2f2b564cc15eb937674065d9d1f395ffc88e3 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 20 Jun 2019 12:59:14 +0100 Subject: [PATCH 17/30] Made newDevice public to allow manually adding new items to existing config Renamed newTPLinkDevice to newDevice to simplify Added various missing comment text Fixed bug where IP where not resolving to string --- src/TPLinkManager.php | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 3c624c7..fc74b87 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -16,6 +16,13 @@ public function __construct(array $config = []) $this->config = $config; } + /** + * Get a device object pre-configured in config + * + * @param string $name + * + * @return TPLinkDevice + */ public function device($name = 'default') { if (!isset($this->config[$name]) || !is_array($this->config[$name]) || empty($this->config[$name]['ip'])) { @@ -25,12 +32,25 @@ public function device($name = 'default') return new TPLinkDevice($this->config[$name], $name); } - protected function newTPLinkDevice($config, $name) + /** + * Add a new device to the config setup + * + * @param $config + * @param $name + * + * @return TPLinkDevice + */ + public function newDevice($config, $name) { $this->config[$name] = $config; return new TPLinkDevice($config, $name); } + /** + * Return current config + * + * @return array + */ public function deviceList() { return $this->config; @@ -51,12 +71,11 @@ public function deviceList() public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) { return collect(Range::parse($ipRange)) - ->map(function ($ip) use ($timeout) { - $response = $this->deviceResponse($ip, $timeout); + ->filter(function ($ip) use ($timeout) { + $response = $this->deviceResponse((string)$ip, $timeout); - return is_null($response) ? $response : $this->validTPLinkResponse($response, $ip); - }) - ->filter(); + return is_null($response) ? $response : $this->validTPLinkResponse($response, (string)$ip); + }); } /** @@ -107,7 +126,7 @@ protected function validTPLinkResponse($response, $ip) */ protected function discoveredDevice($jsonResponse, $ip) { - return $this->newTPLinkDevice([ + return $this->newDevice([ 'ip' => (string)$ip, 'port' => 9999, 'systemInfo' => $jsonResponse->system->get_sysinfo, From ca5a794e835f42a32eb7e83411c249dab27fa9b4 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 20 Jun 2019 12:59:42 +0100 Subject: [PATCH 18/30] Ability to set TPLinkDevice encryption key on construct --- src/TPLinkDevice.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index ee9f052..c2358a9 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -10,6 +10,7 @@ class TPLinkDevice protected $config; protected $deviceName; protected $client; + protected $encryptionKey; /** @@ -18,10 +19,11 @@ class TPLinkDevice * @param array $config * @param string $deviceName */ - public function __construct(array $config, $deviceName) + public function __construct(array $config, $deviceName, $encryptionKey = 171) { $this->config = $config; $this->deviceName = $deviceName; + $this->encryptionKey = $encryptionKey; } /** @@ -126,7 +128,7 @@ public function getConfig($key, $default = null) */ protected function encrypt($string) { - $key = 171; + $key = $this->encryptionKey; return collect(str_split($string)) ->reduce( @@ -162,7 +164,7 @@ protected function connectionError() */ protected function decrypt($data) { - $key = 171; + $key = $this->encryptionKey; return collect(str_split(substr($data, 4))) ->reduce(function ($result, $character) use (&$key) { From ba2f25391b4d916afbb9e4db1951f1836f7693dd Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Thu, 20 Jun 2019 13:51:10 +0100 Subject: [PATCH 19/30] Fix for hs105 --- src/TPLinkDevice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index c2358a9..1364649 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -137,7 +137,7 @@ function ($result, $character) use (&$key) { return $result .= chr($key); }, - "\0\0\0\0" + strrev(pack('I', strlen($string))) ); } From 8485ca97533bcbe125cda66df34bea3b03c87c3b Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 11:05:46 +0100 Subject: [PATCH 20/30] - Added stream timeout capabilities as some devices cause the stream function to halt for a long period of time - Fixed bug with the auto discovery function --- src/Laravel/config/TPLink.php | 6 ++++-- src/TPLinkDevice.php | 17 ++++++++++++----- src/TPLinkManager.php | 16 ++++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Laravel/config/TPLink.php b/src/Laravel/config/TPLink.php index 36cd483..9769f07 100644 --- a/src/Laravel/config/TPLink.php +++ b/src/Laravel/config/TPLink.php @@ -8,13 +8,15 @@ // 'bedroom' => [ // 'ip' => '192.168.1.100', //Or hostname // 'port' => '9999', -// 'timeout' => 5 +// 'timeout' => 5, +// 'timeout_stream' => 5 // ], // 'livingroom' => [ // 'ip' => '192.168.1.101', //Or hostname // 'port' => '9999', -// 'timeout' => 10 +// 'timeout' => 10, +// 'timeout_stream' => 5 // ], ]; diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index 1364649..a338079 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -16,8 +16,9 @@ class TPLinkDevice /** * TPLinkDevice constructor. * - * @param array $config + * @param array $config * @param string $deviceName + * @param int $encryptionKey */ public function __construct(array $config, $deviceName, $encryptionKey = 171) { @@ -82,6 +83,7 @@ public function sendCommand(array $command) } $response = $this->decrypt(stream_get_contents($this->client)); + $this->disconnect(); return $response; @@ -99,6 +101,9 @@ protected function connectToDevice() $this->getConfig('timeout', 5) ); + // Set stream timeout (important or some devices will cause the stream read function to hang for a period) + stream_set_timeout($this->client, $this->getConfig('timeout_stream', 1)); + if ($this->client === false) { throw new UnexpectedValueException("Failed connect to {$this->deviceName}: $errorMessage ($errorNumber)"); } @@ -133,7 +138,7 @@ protected function encrypt($string) return collect(str_split($string)) ->reduce( function ($result, $character) use (&$key) { - $key = $key ^ ord($character); + $key = ord($character) ^ $key; return $result .= chr($key); }, @@ -160,15 +165,17 @@ protected function connectionError() * * @param $data * + * @param bool $stripHeader + * * @return mixed */ - protected function decrypt($data) + protected function decrypt($data, $stripHeader = true) { $key = $this->encryptionKey; - return collect(str_split(substr($data, 4))) + return collect(str_split(substr($data, ($stripHeader) ? 4 : 0))) ->reduce(function ($result, $character) use (&$key) { - $a = $key ^ ord($character); + $a = ord($character) ^ $key; $key = ord($character); return $result .= chr($a); diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index fc74b87..697a4f3 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -65,17 +65,18 @@ public function deviceList() * * @param $ipRange * @param int $timeout + * @param int $timeoutStream * * @return Collection */ - public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) + public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1, $timeoutStream = 1) { return collect(Range::parse($ipRange)) - ->filter(function ($ip) use ($timeout) { - $response = $this->deviceResponse((string)$ip, $timeout); + ->map(function ($ip) use ($timeout, $timeoutStream) { + $response = $this->deviceResponse((string)$ip, $timeout, $timeoutStream); return is_null($response) ? $response : $this->validTPLinkResponse($response, (string)$ip); - }); + })->filter(); } /** @@ -84,13 +85,14 @@ public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1) * * @param $ip * @param $timeout + * @param $timeoutStream * * @return null */ - protected function deviceResponse($ip, $timeout) + protected function deviceResponse($ip, $timeout, $timeoutStream) { try { - $device = new TPLinkDevice(['ip' => $ip, 'port' => 9999, 'timeout' => $timeout], 'autodiscovery'); + $device = new TPLinkDevice(['ip' => $ip, 'port' => 9999, 'timeout' => $timeout, 'timeout_stream' => $timeoutStream], 'autodiscovery'); return $device->sendCommand(TPLinkCommand::systemInfo()); } catch (\Exception $exception) { @@ -101,8 +103,6 @@ protected function deviceResponse($ip, $timeout) /** * Check the returned data JSON decodes * Make sure is not NULL, some devices may return a single character - * LB100 Series seems to respond on port 9999, however return a bad string - * TODO:: investigate LB100 support * * @param $response * @param $ip From 63487bf247def4c4c26e4b96d7d21a9bde625ff1 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 11:14:16 +0100 Subject: [PATCH 21/30] Updated readme --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c84290a..1897467 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,8 @@ return [ 'lamp' => [ 'ip' => '192.168.1.100', //Or hostname eg: home.example.com 'port' => '9999', - 'timeout' => 5 // Optional, timeout setting (how long we will try communicate with device before giving up) + 'timeout' => 5, // Optional, timeout setting (how long we will try communicate with device before giving up) + 'timeout_stream' => 5, // Optional, timeout setting for stream (how long to wait for the response stream) ], ]; ``` @@ -252,7 +253,7 @@ Any issues, feedback, suggestions or questions please use issue tracker [here][l - [softScheck](https://github.com/softScheck/tplink-smartplug) (Who did the reverse engineering and provided the secrets on how to talk to the Smartplug.) - [Jonathan Williamson][link-author] - [Syed Irfaq R.](https://github.com/irazasyed) For the idea behind how to manage multiple devices. -- [Shane Rutter](https://shanerutter.co.uk) Auto-Discovery feature +- [Shane Rutter](https://shanerutter.co.uk) Various features such as Auto-Discovery ## Disclaimer From 830c016da965670624fc2e6c275be3ac4b7bfb76 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 11:40:10 +0100 Subject: [PATCH 22/30] Auto discovery added callback function when a new device is discovered --- src/TPLinkManager.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 697a4f3..b90c84c 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -66,16 +66,17 @@ public function deviceList() * @param $ipRange * @param int $timeout * @param int $timeoutStream + * @param null $callbackFunction * * @return Collection */ - public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1, $timeoutStream = 1) + public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1, $timeoutStream = 1, $callbackFunction = null) { return collect(Range::parse($ipRange)) - ->map(function ($ip) use ($timeout, $timeoutStream) { + ->map(function ($ip) use ($timeout, $timeoutStream, $callbackFunction) { $response = $this->deviceResponse((string)$ip, $timeout, $timeoutStream); - return is_null($response) ? $response : $this->validTPLinkResponse($response, (string)$ip); + return is_null($response) ? $response : $this->validTPLinkResponse($response, (string)$ip, $callbackFunction); })->filter(); } @@ -106,14 +107,15 @@ protected function deviceResponse($ip, $timeout, $timeoutStream) * * @param $response * @param $ip + * @param null $callbackFunction * * @return mixed|TPLinkDevice */ - protected function validTPLinkResponse($response, $ip) + protected function validTPLinkResponse($response, $ip, $callbackFunction = null) { $jsonResponse = json_decode($response); - return is_null($jsonResponse) ? $jsonResponse : $this->discoveredDevice($jsonResponse, $ip); + return is_null($jsonResponse) ? $jsonResponse : $this->discoveredDevice($jsonResponse, $ip, $callbackFunction); } /** @@ -121,16 +123,24 @@ protected function validTPLinkResponse($response, $ip) * * @param $jsonResponse * @param $ip + * @param null $callbackFunction * * @return TPLinkDevice */ - protected function discoveredDevice($jsonResponse, $ip) + protected function discoveredDevice($jsonResponse, $ip, $callbackFunction = null) { - return $this->newDevice([ + $device = $this->newDevice([ 'ip' => (string)$ip, 'port' => 9999, 'systemInfo' => $jsonResponse->system->get_sysinfo, ], $jsonResponse->system->get_sysinfo->alias); + + // Callback function during discovery + if (!is_null($callbackFunction)) { + call_user_func($callbackFunction, $device); + } + + return $device; } } From aa9f2cddb00d4291d26f021c1e246c6de926d8ef Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 12:08:54 +0100 Subject: [PATCH 23/30] Added laravel 5.5 auto package discovery support --- README.md | 2 ++ composer.json | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/README.md b/README.md index 1897467..b283eb4 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ composer require williamson/tplinksmartplug ### Laravel Installation/Integration +###### Now Supports Laravel 5.5 auto package discovery (you do not need to do the below step if you have Laravel 5.5+) + Once the TPLink Smartplug library is installed, you need to register the library's service provider, in `config/app.php`: ```php diff --git a/composer.json b/composer.json index ede6c1a..4185be5 100644 --- a/composer.json +++ b/composer.json @@ -20,5 +20,12 @@ "psr-4": { "Williamson\\TPLinkSmartplug\\": "src" } + }, + "extra": { + "laravel": { + "providers": [ + "Williamson\\TPLinkSmartplug\\Laravel\\TPLinkServiceProvider" + ] + } } } From 8bad2b351e454a25fa0b011d2b5dcffd87e7bdef Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 12:28:44 +0100 Subject: [PATCH 24/30] Added alias to auto package discovery --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4185be5..cf92543 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,10 @@ "laravel": { "providers": [ "Williamson\\TPLinkSmartplug\\Laravel\\TPLinkServiceProvider" - ] + ], + "aliases": { + "TPLink": "Williamson\\TPLinkSmartplug\\Laravel\\Facades\\TPLinkFacade" + } } } } From e20c416def346c32028b162a1b56bb24eccf0a64 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 12:32:53 +0100 Subject: [PATCH 25/30] Added support for a "deviceType" field against the device to allow different commands based on device type E.G plug / bulb --- src/Laravel/config/TPLink.php | 7 +++++-- src/TPLinkDevice.php | 15 ++++++++++++++- src/TPLinkManager.php | 9 +++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Laravel/config/TPLink.php b/src/Laravel/config/TPLink.php index 9769f07..eae6b94 100644 --- a/src/Laravel/config/TPLink.php +++ b/src/Laravel/config/TPLink.php @@ -3,20 +3,23 @@ 'heater' => [ 'ip' => '192.168.1.100', //Or hostname eg: home.example.com 'port' => '9999', + 'deviceType' => 'IOT.SMARTPLUGSWITCH', ], // 'bedroom' => [ // 'ip' => '192.168.1.100', //Or hostname // 'port' => '9999', // 'timeout' => 5, -// 'timeout_stream' => 5 +// 'timeout_stream' => 5, +// 'deviceType' => 'IOT.SMARTPLUGSWITCH', // ], // 'livingroom' => [ // 'ip' => '192.168.1.101', //Or hostname // 'port' => '9999', // 'timeout' => 10, -// 'timeout_stream' => 5 +// 'timeout_stream' => 5, +// 'deviceType' => 'IOT.SMARTBULB', // ], ]; diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index a338079..5aeb13e 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -11,6 +11,7 @@ class TPLinkDevice protected $deviceName; protected $client; protected $encryptionKey; + protected $deviceType; /** @@ -18,12 +19,14 @@ class TPLinkDevice * * @param array $config * @param string $deviceName + * @param $deviceType * @param int $encryptionKey */ - public function __construct(array $config, $deviceName, $encryptionKey = 171) + public function __construct(array $config, $deviceName, $deviceType = "IOT.SMARTPLUGSWITCH", $encryptionKey = 171) { $this->config = $config; $this->deviceName = $deviceName; + $this->deviceType = $deviceType; $this->encryptionKey = $encryptionKey; } @@ -67,6 +70,16 @@ public function powerOff() return $this->sendCommand(TPLinkCommand::powerOff()); } + /** + * What type of device is this? + * + * @return string + */ + public function deviceType() + { + return $this->deviceType; + } + /** * Send a command to the connected device. * diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index b90c84c..56bca43 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -29,7 +29,7 @@ public function device($name = 'default') throw new InvalidArgumentException('You have not setup the details for a device named ' . $name); } - return new TPLinkDevice($this->config[$name], $name); + return new TPLinkDevice($this->config[$name], $name, $this->config[$name]->deviceType); } /** @@ -37,13 +37,14 @@ public function device($name = 'default') * * @param $config * @param $name + * @param $deviceType * * @return TPLinkDevice */ - public function newDevice($config, $name) + public function newDevice($config, $name, $deviceType) { $this->config[$name] = $config; - return new TPLinkDevice($config, $name); + return new TPLinkDevice($config, $name, $deviceType); } /** @@ -133,7 +134,7 @@ protected function discoveredDevice($jsonResponse, $ip, $callbackFunction = null 'ip' => (string)$ip, 'port' => 9999, 'systemInfo' => $jsonResponse->system->get_sysinfo, - ], $jsonResponse->system->get_sysinfo->alias); + ], $jsonResponse->system->get_sysinfo->alias, (isset($jsonResponse->system->get_sysinfo->type)) ? $jsonResponse->system->get_sysinfo->type : $jsonResponse->system->get_sysinfo->mic_type); // Callback function during discovery if (!is_null($callbackFunction)) { From fc2c5e61fd7b9bfc5004007463bee656dd367f02 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Tue, 9 Jul 2019 12:51:25 +0100 Subject: [PATCH 26/30] Added max discover limit to the autoDiscoverTPLinkDevices function, this allows auto discovery and if you know you have x devices, no point in scanning the rest of the IP range if you have discovered all x devices already --- src/TPLinkManager.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 56bca43..cb257e8 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -71,13 +71,26 @@ public function deviceList() * * @return Collection */ - public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1, $timeoutStream = 1, $callbackFunction = null) + public function autoDiscoverTPLinkDevices($ipRange, $timeout = 1, $timeoutStream = 1, $callbackFunction = null, $maxDiscoveredDevices = 0) { + $discoveredCount = 0; + return collect(Range::parse($ipRange)) - ->map(function ($ip) use ($timeout, $timeoutStream, $callbackFunction) { + ->map(function ($ip) use ($timeout, $timeoutStream, $callbackFunction, $maxDiscoveredDevices, &$discoveredCount) { + // Discovered max devices, do not do checks for further devices + if ($maxDiscoveredDevices > 0 && $discoveredCount >= $maxDiscoveredDevices) { + return null; + } + $response = $this->deviceResponse((string)$ip, $timeout, $timeoutStream); + $device = $this->validTPLinkResponse($response, (string)$ip, $callbackFunction); + + if (!is_null($device)) { + $discoveredCount++; + return $device; + } - return is_null($response) ? $response : $this->validTPLinkResponse($response, (string)$ip, $callbackFunction); + return $response; })->filter(); } From e0c165e09c8c5046595f6b32c7605769d70150dd Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Fri, 9 Aug 2019 17:52:48 +0100 Subject: [PATCH 27/30] Added ability to control smart light bulbs on / off with colour controls / brightness control --- src/TPLinkCommand.php | 54 +++++++++++++++++++++++++++++++++++++++++++ src/TPLinkDevice.php | 32 +++++++++++++++++++++---- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/src/TPLinkCommand.php b/src/TPLinkCommand.php index f144117..a83d605 100644 --- a/src/TPLinkCommand.php +++ b/src/TPLinkCommand.php @@ -1143,4 +1143,58 @@ protected static function antitheftCommonData( ], ]; } + + /** + * @param int $brightness + * @param int $transPeriod + * @param int $hue + * @param int $saturation + * @param int $color_temp + * @param string $mode + * + * @return array + */ + public static function lightControlValues($brightness = 100, $transPeriod = 100, $hue = 120, $saturation = 150, $color_temp = 2700, $mode = 'normal') + { + return [ + "transition_period" => $transPeriod, + "mode" => $mode, + "hue" => $hue, + "saturation" => $saturation, + "color_temp" => $color_temp, + "brightness" => $brightness, + ]; + } + + /** + * @param array $params + * + * @return array + */ + public static function lightOn($params = []) + { + $cmd = array_merge(["ignore_default" => 1, "on_off" => 1], $params); + + return [ + 'smartlife.iot.smartbulb.lightingservice' => [ + 'transition_light_state' => $cmd + ] + ]; + } + + /** + * @return array + */ + public static function lightOff() + { + return [ + 'smartlife.iot.smartbulb.lightingservice' => [ + 'transition_light_state' => [ + "ignore_default" => 1, + "on_off" => 0, + ], + ] + ]; + } + } diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index 5aeb13e..47d15f8 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -37,7 +37,15 @@ public function __construct(array $config, $deviceName, $deviceType = "IOT.SMART */ public function powerStatus() { - return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->relay_state; + if ($this->deviceType() == "IOT.SMARTBULB") { + return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->light_state->on_off; + } + + if ($this->deviceType() == "IOT.SMARTPLUGSWITCH") { + return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->relay_state; + } + + return false; } /** @@ -47,7 +55,7 @@ public function powerStatus() */ public function togglePower() { - return $this->powerStatus() ? $this->sendCommand(TPLinkCommand::powerOff()) : $this->sendCommand(TPLinkCommand::powerOn()); + return $this->powerStatus() ? $this->powerOff() : $this->powerOn(); } /** @@ -57,7 +65,15 @@ public function togglePower() */ public function powerOn() { - return $this->sendCommand(TPLinkCommand::powerOn()); + if ($this->deviceType() == "IOT.SMARTBULB") { + return $this->sendCommand(TPLinkCommand::lightOn()); + } + + if ($this->deviceType() == "IOT.SMARTPLUGSWITCH") { + return $this->sendCommand(TPLinkCommand::powerOn()); + } + + return ''; } /** @@ -67,7 +83,15 @@ public function powerOn() */ public function powerOff() { - return $this->sendCommand(TPLinkCommand::powerOff()); + if ($this->deviceType() == "IOT.SMARTBULB") { + return $this->sendCommand(TPLinkCommand::lightOff()); + } + + if ($this->deviceType() == "IOT.SMARTPLUGSWITCH") { + return $this->sendCommand(TPLinkCommand::powerOff()); + } + + return ''; } /** From fb8252ca65e3d0be658f16027cc8efb5b61b2ad4 Mon Sep 17 00:00:00 2001 From: Jonathan Williamson Date: Tue, 20 Aug 2019 12:13:59 +0100 Subject: [PATCH 28/30] Code re-formatted and some extra info added to readme. --- .travis.yml | 1 + README.md | 17 +- composer.json | 2 +- src/Laravel/TPLinkServiceProvider.php | 4 +- src/Laravel/config/TPLink.php | 32 +- src/TPLinkCommand.php | 411 +++++++++++++------------- src/TPLinkDevice.php | 45 +-- src/TPLinkManager.php | 33 ++- 8 files changed, 279 insertions(+), 266 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1410252..dd27797 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: php php: + - 7.2 - 7.1 - 7.0 - 5.6 diff --git a/README.md b/README.md index c30c963..8bf7865 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -PHP Library to Control and Access a TP-Link Smartplug! +PHP Library to Control and Access a TP-Link Smartplug OR TP Smart Bulbs! ========= -

+

Smart Plug
Build Status Total Downloads @@ -69,7 +69,7 @@ return [ You may add as many devices as you wish, as long as you specify the IP address (or host address if required) and port number to access each one. Giving each device a name makes it easy to identify them when coding later. _(Please note that the name you give here does NOT have to match the actual name you might have assigned the device using an official app like Kasa. They do NOT have to match) -You can use the `autoDiscoverTPLinkDevices` method to automatically find networked devices. +If you do not know the IP address of your devices, you can use the `autoDiscoverTPLinkDevices` method to automatically scan and find devices on your network for you to save into your config file. ## Usage You can access your device either through the `TPLinkManager` class (especially useful if you have multiple devices), or directly using the `TPLinkDevice` class. @@ -140,6 +140,8 @@ If a command requires a parameter, provide that as well: You can search your local network for devices using `TPLinkManager`, using the method `autoDiscoverTPLinkDevices` all found devices will be added to the 'TPLinkManager' config automatically, exposed using `deviceList()`. +However this information will not automatically be persisted. You must save the details into your config file if you wish to avoid having to keep scanning your network. + You must provide the IP range you wish to scan, examples of usage are as follows: ```php //Non laravel @@ -175,9 +177,12 @@ The auto discovery command will take a while to scan, once completed you can use ``` #### Toggle Power -There is one command that is called directly on the `TPLinkDevice` and that is the `togglePower()` method. +There are a few convenience commands that can be called directly on the `TPLinkDevice`. Those methods are + `togglePower()` + `powerOn()` + `powerOff()` -If you only wish to toggle the current power state of the plug, use it as follows: +Eg. if you only wish to toggle the current power state of the plug, use it as follows: ```php //Non laravel @@ -271,7 +276,7 @@ See License section for more details. This project is released under the [MIT][link-license] License. -© 2017 [Jonathan Williamson][link-author], All rights reserved. +© 2019 [Jonathan Williamson][link-author], All rights reserved. [link-author]: https://github.com/jonnywilliamson [link-repo]: https://github.com/jonnywilliamson/tplinksmartplug diff --git a/composer.json b/composer.json index 4e2542c..afeb764 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "williamson/tplinksmartplug", "description": "A PHP library to control and receive information from a TP-Link smartplug.", "license": "MIT", - "keywords": ["TPLink", "PHP", "HS110", "HS100", "Timer", "SmartPlug", "Laravel"], + "keywords": ["TPLink", "PHP", "HS110", "HS100", "Timer", "SmartPlug", "Laravel", "SmartBulbs", "Bulbs"], "authors": [ { "name": "Jonathan Williamson", diff --git a/src/Laravel/TPLinkServiceProvider.php b/src/Laravel/TPLinkServiceProvider.php index d137e87..372afc0 100644 --- a/src/Laravel/TPLinkServiceProvider.php +++ b/src/Laravel/TPLinkServiceProvider.php @@ -33,8 +33,8 @@ public function register() $this->app->alias(TPLinkManager::class, 'tplink'); - //Auto-register the TPLink facade if the user hasn't already - //assigned it to another class. Takes care of Laravel <5.5 users. + // Auto-register the TPLink facade if the user hasn't already + // assigned it to another class. Takes care of Laravel <5.5 users. if (class_exists(AliasLoader::class)) { $loader = AliasLoader::getInstance(); diff --git a/src/Laravel/config/TPLink.php b/src/Laravel/config/TPLink.php index 98d3577..dbc476b 100644 --- a/src/Laravel/config/TPLink.php +++ b/src/Laravel/config/TPLink.php @@ -1,27 +1,27 @@ [ - 'ip' => '192.168.1.100', //Or hostname eg: home.example.com - 'port' => '9999', - 'timeout' => 5, - 'timeout_stream' => 5, - 'deviceType' => 'IOT.SMARTPLUGSWITCH', + 'ip' => '192.168.1.100', //Or hostname eg: home.example.com + 'port' => '9999', + 'timeout' => 5, // Optional, timeout setting (how long we will try communicate with device before giving up) + 'timeout_stream' => 3, // Optional, timeout setting for stream (how long to wait for the response from the device) + 'deviceType' => 'IOT.SMARTPLUGSWITCH', // Smart Bulbs are also supported: 'IOT.SMARTBULB' ], // 'bedroom' => [ -// 'ip' => '192.168.1.101', //Or hostname -// 'port' => '9999', -// 'timeout' => 5, -// 'timeout_stream' => 5, -// 'deviceType' => 'IOT.SMARTPLUGSWITCH', +// 'ip' => '192.168.1.101', +// 'port' => '9999', +// 'timeout' => 5, +// 'timeout_stream' => 3, +// 'deviceType' => 'IOT.SMARTPLUGSWITCH', // ], // 'livingroom' => [ -// 'ip' => '192.168.1.102', //Or hostname -// 'port' => '9999', -// 'timeout' => 10, -// 'timeout_stream' => 5, -// 'deviceType' => 'IOT.SMARTBULB', +// 'ip' => '192.168.1.102', +// 'port' => '9999', +// 'timeout' => 10, +// 'timeout_stream' => 3, +// 'deviceType' => 'IOT.SMARTBULB', // ], -]; +]; \ No newline at end of file diff --git a/src/TPLinkCommand.php b/src/TPLinkCommand.php index c8ba18a..6199ff2 100644 --- a/src/TPLinkCommand.php +++ b/src/TPLinkCommand.php @@ -4,6 +4,7 @@ use DateTime; use stdClass; +use Exception; use InvalidArgumentException; use Illuminate\Support\Collection; @@ -682,6 +683,144 @@ public static function scheduleRuleCreate(DateTime $dateAndTime, $turnOn, $name, ]; } + /** + * Depending on if the event is to be repeated during the week or not return the + * data needed to create the event. + * + * @param DateTime $dateAndTime + * @param $weekDaysToRepeat + * + * @return Collection + */ + protected static function formatDates(DateTime $dateAndTime, $weekDaysToRepeat) + { + if (empty($weekDaysToRepeat)) { + $data = collect([ + 'year' => $dateAndTime->format('Y'), + 'month' => $dateAndTime->format('n'), + 'day' => $dateAndTime->format('j'), + 'wday' => self::createDayMatrix($dateAndTime), + ]); + } else { + $data = collect(['wday' => self::createRepeatingDayMatrix($weekDaysToRepeat)]); + } + + return $data; + } + + /** + * Create the array/matrix required for single events + * + * @param DateTime $dateAndTime + * + * @return array + */ + protected static function createDayMatrix(DateTime $dateAndTime) + { + $weekMatrix = self::emptyMatrix(); + $weekMatrix[$dateAndTime->format('w')] = 1; + + return $weekMatrix; + } + + /** + * Create an empty matrix. + * + * @return array + */ + protected static function emptyMatrix() + { + return [0, 0, 0, 0, 0, 0, 0]; + } + + /** + * Create the array/matrix required for repeating/reoccuring events + * + * @param array $daysToReoccur + * + * @return array + */ + protected static function createRepeatingDayMatrix(array $daysToReoccur) + { + $weekMatrix = self::emptyMatrix(); + + foreach ($daysToReoccur as $dayString) { + try { + $weekMatrix[(new DateTime($dayString))->format('w')] = 1; + } catch (Exception $e) { + throw new InvalidArgumentException("Invalid date string provided. {$e->getMessage()}"); + } + } + + return $weekMatrix; + } + + /** + * @param string $type The type of action that should be performed, add or edit. + * @param DateTime $dateAndTime The actual Date and Time for this event. + * @param bool $turnOn Should the event turn on or off the timer. + * @param string $name An event name. On some clients this isn't even seen. + * @param array $daysOfWeekToRepeat (Optional) Day of week event should repeat. Use EN like Tues, Saturday etc. + * @param Collection $data specific information depending on if the event is repeating or not. + * @param string $ruleId The ID of the rule to be edited. + * + * @return array + */ + protected static function ruleCommonData( + $type, + DateTime $dateAndTime, + $turnOn, + $name, + $daysOfWeekToRepeat, + $data, + $ruleId + ) { + return [ + $type => [ + 'id' => $ruleId, + 'enable' => 1, + 'name' => "$name", + 'sact' => (int)$turnOn, + 'repeat' => (int)!empty($daysOfWeekToRepeat), + 'smin' => self::calculateMinutes($dateAndTime), + 'emin' => 0, + 'wday' => (array)$data->get('wday'), + 'day' => (int)$data->get('day', 0), + 'month' => (int)$data->get('month', 0), + 'year' => (int)$data->get('year', 0), + 'etime_opt' => -1, + 'eact' => -1, + 'stime_opt' => 0, + 'force' => 0, + 'longitude' => 0, + 'latitude' => 0, + ], + 'set_overall_enable' => [ + 'enable' => 1, + ], + ]; + } + + /** + * All start/end times on the device are recorded as minutes from midnight. + * + * Return the required minute value from the supplied DateTime object + * + * @param DateTime $dateAndTime + * + * @return int + */ + protected static function calculateMinutes(DateTime $dateAndTime) + { + $datetime2 = clone $dateAndTime; + $datetime2->setTime(00, 00, 00); + + $interval = $dateAndTime->diff($datetime2); + + //Timer needs minutes since midnight + return ($interval->h * 60 + $interval->i); + } + /** * Edit Schedule Rule with given ID * @@ -786,6 +925,28 @@ public static function countdownRuleCreate($delay, $turnOn, $name = 'countdown') ]; } + /** + * @param string $type The type of action that should be performed, add or edit. + * @param int $delay The number of secs until the event should fire. + * @param bool $turnOn Should the event turn on or off the timer. + * @param string $name An event name. On some clients this isn't even seen. + * @param string $ruleId The id of the rule to edit. + * + * @return array + */ + protected static function countdownCommonData($type, $delay, $turnOn, $name, $ruleId) + { + return [ + $type => [ + 'id' => $ruleId, + 'enable' => 1, + 'delay' => (int)$delay, + 'act' => (int)$turnOn, + 'name' => $name, + ], + ]; + } + /** * Edit Countdown Rule with specified ID * @@ -876,6 +1037,53 @@ public static function antitheftRuleCreate(DateTime $startTime, DateTime $endTim ]; } + /** + * @param string $type The type of action that should be performed, add or edit. + * @param DateTime $startTime The start date/time for the event to begin + * @param DateTime $endTime The end date/time for the event to finish. + * @param string $name An event name. On some clients this isn't even seen. + * @param array $daysOfWeekToRepeat (Optional) Day of week event should repeat. Use EN like Tues, Saturday etc. + * @param Collection $data specific information depending on if the event is repeating or not. + * @param string $ruleId The ID of the rule to be edited. + * + * @return array + */ + protected static function antitheftCommonData( + $type, + DateTime $startTime, + DateTime $endTime, + $name, + $daysOfWeekToRepeat, + $data, + $ruleId + ) { + return [ + $type => [ + 'id' => $ruleId, + 'enable' => 1, + 'frequency' => 5, + 'name' => "$name", + 'repeat' => (int)!empty($daysOfWeekToRepeat), + 'smin' => self::calculateMinutes($startTime), + 'emin' => self::calculateMinutes($endTime), + 'wday' => (array)$data->get('wday'), + 'day' => (int)$data->get('day', 0), + 'month' => (int)$data->get('month', 0), + 'year' => (int)$data->get('year', 0), + 'stime_opt' => 0, + 'etime_opt' => 0, + 'duration' => 2, + 'lastfor' => 1, + 'force' => 0, + 'longitude' => 0, + 'latitude' => 0, + ], + 'set_overall_enable' => [ + 'enable' => 1, + ], + ]; + } + /** * Edit Anti theft Rule with given ID * @@ -941,209 +1149,6 @@ public static function antitheftRuleWipeAll() ]; } - /** - * Depending on if the event is to be repeated during the week or not return the - * data needed to create the event. - * - * @param DateTime $dateAndTime - * @param $weekDaysToRepeat - * - * @return Collection - */ - protected static function formatDates(DateTime $dateAndTime, $weekDaysToRepeat) - { - if (empty($weekDaysToRepeat)) { - $data = collect([ - 'year' => $dateAndTime->format('Y'), - 'month' => $dateAndTime->format('n'), - 'day' => $dateAndTime->format('j'), - 'wday' => self::createDayMatrix($dateAndTime), - ]); - } else { - $data = collect(['wday' => self::createRepeatingDayMatrix($weekDaysToRepeat)]); - } - - return $data; - } - - /** - * Create the array/matrix required for single events - * - * @param DateTime $dateAndTime - * - * @return array - */ - protected static function createDayMatrix(DateTime $dateAndTime) - { - $weekMatrix = self::emptyMatrix(); - $weekMatrix[$dateAndTime->format('w')] = 1; - - return $weekMatrix; - } - - /** - * Create an empty matrix. - * - * @return array - */ - protected static function emptyMatrix() - { - return [0, 0, 0, 0, 0, 0, 0]; - } - - /** - * Create the array/matrix required for repeating/reoccuring events - * - * @param array $daysToReoccur - * - * @return array - */ - protected static function createRepeatingDayMatrix(array $daysToReoccur) - { - $weekMatrix = self::emptyMatrix(); - - foreach ($daysToReoccur as $dayString) { - $weekMatrix[(new DateTime($dayString))->format('w')] = 1; - } - - return $weekMatrix; - } - - /** - * All start/end times on the device are recorded as minutes from midnight. - * - * Return the required minute value from the supplied DateTime object - * - * @param DateTime $dateAndTime - * - * @return int - */ - protected static function calculateMinutes(DateTime $dateAndTime) - { - $datetime2 = clone $dateAndTime; - $datetime2->setTime(00, 00, 00); - - $interval = $dateAndTime->diff($datetime2); - - //Timer needs minutes since midnight - return ($interval->h * 60 + $interval->i); - } - - /** - * @param string $type The type of action that should be performed, add or edit. - * @param DateTime $dateAndTime The actual Date and Time for this event. - * @param bool $turnOn Should the event turn on or off the timer. - * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional) Day of week event should repeat. Use EN like Tues, Saturday etc. - * @param Collection $data specific information depending on if the event is repeating or not. - * @param string $ruleId The ID of the rule to be edited. - * - * @return array - */ - protected static function ruleCommonData( - $type, - DateTime $dateAndTime, - $turnOn, - $name, - $daysOfWeekToRepeat, - $data, - $ruleId - ) { - return [ - $type => [ - 'id' => $ruleId, - 'enable' => 1, - 'name' => "$name", - 'sact' => (int)$turnOn, - 'repeat' => (int)!empty($daysOfWeekToRepeat), - 'smin' => self::calculateMinutes($dateAndTime), - 'emin' => 0, - 'wday' => (array)$data->get('wday'), - 'day' => (int)$data->get('day', 0), - 'month' => (int)$data->get('month', 0), - 'year' => (int)$data->get('year', 0), - 'etime_opt' => -1, - 'eact' => -1, - 'stime_opt' => 0, - 'force' => 0, - 'longitude' => 0, - 'latitude' => 0, - ], - 'set_overall_enable' => [ - 'enable' => 1, - ], - ]; - } - - /** - * @param string $type The type of action that should be performed, add or edit. - * @param int $delay The number of secs until the event should fire. - * @param bool $turnOn Should the event turn on or off the timer. - * @param string $name An event name. On some clients this isn't even seen. - * @param string $ruleId The id of the rule to edit. - * - * @return array - */ - protected static function countdownCommonData($type, $delay, $turnOn, $name, $ruleId) - { - return [ - $type => [ - 'id' => $ruleId, - 'enable' => 1, - 'delay' => (int)$delay, - 'act' => (int)$turnOn, - 'name' => $name, - ], - ]; - } - - /** - * @param string $type The type of action that should be performed, add or edit. - * @param DateTime $startTime The start date/time for the event to begin - * @param DateTime $endTime The end date/time for the event to finish. - * @param string $name An event name. On some clients this isn't even seen. - * @param array $daysOfWeekToRepeat (Optional) Day of week event should repeat. Use EN like Tues, Saturday etc. - * @param Collection $data specific information depending on if the event is repeating or not. - * @param string $ruleId The ID of the rule to be edited. - * - * @return array - */ - protected static function antitheftCommonData( - $type, - DateTime $startTime, - DateTime $endTime, - $name, - $daysOfWeekToRepeat, - $data, - $ruleId - ) { - return [ - $type => [ - 'id' => $ruleId, - 'enable' => 1, - 'frequency' => 5, - 'name' => "$name", - 'repeat' => (int)!empty($daysOfWeekToRepeat), - 'smin' => self::calculateMinutes($startTime), - 'emin' => self::calculateMinutes($endTime), - 'wday' => (array)$data->get('wday'), - 'day' => (int)$data->get('day', 0), - 'month' => (int)$data->get('month', 0), - 'year' => (int)$data->get('year', 0), - 'stime_opt' => 0, - 'etime_opt' => 0, - 'duration' => 2, - 'lastfor' => 1, - 'force' => 0, - 'longitude' => 0, - 'latitude' => 0, - ], - 'set_overall_enable' => [ - 'enable' => 1, - ], - ]; - } - /** * @param int $brightness * @param int $transPeriod diff --git a/src/TPLinkDevice.php b/src/TPLinkDevice.php index c0e5239..439211f 100644 --- a/src/TPLinkDevice.php +++ b/src/TPLinkDevice.php @@ -25,36 +25,37 @@ public function __construct(array $config, $deviceName, $encryptionKey = 171) { $this->config = $config; $this->deviceName = $deviceName; - $this->deviceType = $config['deviceType'] ?? "IOT.SMARTPLUGSWITCH"; + $this->deviceType = isset($config['deviceType']) ? $config['deviceType'] : "IOT.SMARTPLUGSWITCH"; $this->encryptionKey = $encryptionKey; } /** - * Return current power status + * Toggle the current status of the switch on/off * - * @return boolean + * @return string */ - public function powerStatus() + public function togglePower() { - if ($this->deviceType() == "IOT.SMARTBULB") { - return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->light_state->on_off; - } - - if ($this->deviceType() == "IOT.SMARTPLUGSWITCH") { - return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->relay_state; - } - - return false; + return $this->powerStatus() ? $this->powerOff() : $this->powerOn(); } + /** - * Toggle the current status of the switch on/off + * Change the current status of the switch off * * @return string */ - public function togglePower() + public function powerOff() { - return $this->powerStatus() ? $this->powerOff() : $this->powerOn(); + if ($this->deviceType() == "IOT.SMARTBULB") { + return $this->sendCommand(TPLinkCommand::lightOff()); + } + + if ($this->deviceType() == "IOT.SMARTPLUGSWITCH") { + return $this->sendCommand(TPLinkCommand::powerOff()); + } + + return ''; } /** @@ -76,21 +77,21 @@ public function powerOn() } /** - * Change the current status of the switch off + * Return current power status * - * @return string + * @return boolean */ - public function powerOff() + public function powerStatus() { if ($this->deviceType() == "IOT.SMARTBULB") { - return $this->sendCommand(TPLinkCommand::lightOff()); + return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->light_state->on_off; } if ($this->deviceType() == "IOT.SMARTPLUGSWITCH") { - return $this->sendCommand(TPLinkCommand::powerOff()); + return (bool)json_decode($this->sendCommand(TPLinkCommand::systemInfo()))->system->get_sysinfo->relay_state; } - return ''; + return false; } /** diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index b56e725..3ee845c 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -2,6 +2,7 @@ namespace Williamson\TPLinkSmartplug; +use Exception; use IPTools\Range; use InvalidArgumentException; use Tightenco\Collect\Support\Collection; @@ -32,21 +33,6 @@ public function device($name = 'default') return new TPLinkDevice($this->config[$name], $name); } - /** - * Add a new device to the config setup - * - * @param $config - * @param $name - * - * @return TPLinkDevice - */ - public function newDevice($config, $name) - { - $this->config[$name] = $config; - - return new TPLinkDevice($config, $name); - } - /** * Return current config * @@ -130,7 +116,7 @@ protected function deviceResponse($ip, $timeout, $timeoutStream) ], 'autodiscovery'); return $device->sendCommand(TPLinkCommand::systemInfo()); - } catch (\Exception $exception) { + } catch (Exception $exception) { return null; } } @@ -180,6 +166,21 @@ protected function discoveredDevice($jsonResponse, $ip, $callbackFunction = null return $device; } + /** + * Add a new device to the config setup + * + * @param $config + * @param $name + * + * @return TPLinkDevice + */ + public function newDevice($config, $name) + { + $this->config[$name] = $config; + + return new TPLinkDevice($config, $name); + } + private function detectDeviceType($jsonResponse) { return (isset($jsonResponse->system->get_sysinfo->type)) ? $jsonResponse->system->get_sysinfo->type : $jsonResponse->system->get_sysinfo->mic_type; From 0545c3959f1444612fb7f86a4548adc8c597660c Mon Sep 17 00:00:00 2001 From: Jonathan Williamson Date: Tue, 20 Aug 2019 12:15:28 +0100 Subject: [PATCH 29/30] Fix center paragraph --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bf7865..c549bea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ PHP Library to Control and Access a TP-Link Smartplug OR TP Smart Bulbs! ========= -

+

Smart Plug
Build Status Total Downloads From be391a8dd09b0d5aa0656fa0d8b30f53b4964c3c Mon Sep 17 00:00:00 2001 From: Jonathan Williamson Date: Mon, 26 Dec 2022 17:53:40 +0000 Subject: [PATCH 30/30] Use original laravel collections package --- composer.json | 2 +- src/TPLinkManager.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index afeb764..79c0476 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "tightenco/collect": "^5.3", + "illuminate/collections": ">5.0", "s1lentium/iptools": "^1.1" }, "require-dev": { diff --git a/src/TPLinkManager.php b/src/TPLinkManager.php index 3ee845c..e53b7f8 100644 --- a/src/TPLinkManager.php +++ b/src/TPLinkManager.php @@ -3,9 +3,9 @@ namespace Williamson\TPLinkSmartplug; use Exception; +use Illuminate\Support\Collection; use IPTools\Range; use InvalidArgumentException; -use Tightenco\Collect\Support\Collection; class TPLinkManager {