From 5c22c571f4ad9fd6d77463f34aa3f62c60e7d207 Mon Sep 17 00:00:00 2001 From: Shane Rutter Date: Wed, 29 Nov 2017 21:16:39 +0000 Subject: [PATCH 01/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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,