-
-
Notifications
You must be signed in to change notification settings - Fork 239
Move connect_single to SmartDevice.connect #538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
rytilahti
merged 30 commits into
python-kasa:master
from
bdraco:connect_single_device_type
Nov 21, 2023
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
e638c7b
Update connect_single to allow passing in the device type
bdraco 5e29063
fix test
bdraco a63e0be
match names to cli
bdraco 1dcb5e7
match names to cli
bdraco 6573ee0
Update smartdevice.py
bdraco bcdcd5f
adjust per review
bdraco 8ca6417
Merge branch 'master' into connect_single_device_type
bdraco 418e508
move method
bdraco 88d3b5e
tweaks
bdraco a9ae4f0
tweak
bdraco e135289
preen
bdraco c076bc7
typing
bdraco 542554e
typing
bdraco 9030a3e
relo
bdraco 0f46386
make sure its a thin wrapper
bdraco 0dfb322
make sure its a thin wrapper
bdraco f554285
tweaks
bdraco 5fdec8c
tweak
bdraco 541cd53
fixes
bdraco 1492e14
fix test
bdraco ff756a7
make sure it calls discover single without type
bdraco 6f82170
strip unused
bdraco 38f2194
strip unused
bdraco 911ea4e
strip unused
bdraco 624baa0
Merge branch 'master' into connect_single_device_type
bdraco f0e6ad6
manually merge changes
bdraco 38411cd
add initialization
bdraco eaed0f6
Merge branch 'master' into connect_single_device_type
bdraco db833da
Update docs/source/design.rst
bdraco 3bab4f6
tweaks
bdraco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| """Device creation by type.""" | ||
|
|
||
| import logging | ||
| import time | ||
| from typing import Any, Dict, Optional, Type | ||
|
|
||
| from .credentials import Credentials | ||
| from .device_type import DeviceType | ||
| from .exceptions import UnsupportedDeviceException | ||
| from .smartbulb import SmartBulb | ||
| from .smartdevice import SmartDevice, SmartDeviceException | ||
| from .smartdimmer import SmartDimmer | ||
| from .smartlightstrip import SmartLightStrip | ||
| from .smartplug import SmartPlug | ||
| from .smartstrip import SmartStrip | ||
|
|
||
| DEVICE_TYPE_TO_CLASS = { | ||
| DeviceType.Plug: SmartPlug, | ||
| DeviceType.Bulb: SmartBulb, | ||
| DeviceType.Strip: SmartStrip, | ||
| DeviceType.Dimmer: SmartDimmer, | ||
| DeviceType.LightStrip: SmartLightStrip, | ||
| } | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| async def connect( | ||
| host: str, | ||
| *, | ||
| port: Optional[int] = None, | ||
| timeout=5, | ||
| credentials: Optional[Credentials] = None, | ||
| device_type: Optional[DeviceType] = None, | ||
| ) -> "SmartDevice": | ||
| """Connect to a single device by the given IP address. | ||
|
|
||
| This method avoids the UDP based discovery process and | ||
| will connect directly to the device to query its type. | ||
|
|
||
| It is generally preferred to avoid :func:`discover_single()` and | ||
| use this function instead as it should perform better when | ||
| the WiFi network is congested or the device is not responding | ||
| to discovery requests. | ||
|
|
||
| The device type is discovered by querying the device. | ||
|
|
||
| :param host: Hostname of device to query | ||
| :param device_type: Device type to use for the device. | ||
| If not given, the device type is discovered by querying the device. | ||
| If the device type is already known, it is preferred to pass it | ||
| to avoid the extra query to the device to discover its type. | ||
| :rtype: SmartDevice | ||
| :return: Object for querying/controlling found device. | ||
| """ | ||
| debug_enabled = _LOGGER.isEnabledFor(logging.DEBUG) | ||
|
|
||
| if debug_enabled: | ||
| start_time = time.perf_counter() | ||
|
|
||
| if device_type and (klass := DEVICE_TYPE_TO_CLASS.get(device_type)): | ||
| dev: SmartDevice = klass( | ||
| host=host, port=port, credentials=credentials, timeout=timeout | ||
| ) | ||
| await dev.update() | ||
| if debug_enabled: | ||
| end_time = time.perf_counter() | ||
| _LOGGER.debug( | ||
| "Device %s with known type (%s) took %.2f seconds to connect", | ||
| host, | ||
| device_type.value, | ||
| end_time - start_time, | ||
| ) | ||
| return dev | ||
|
|
||
| unknown_dev = SmartDevice( | ||
| host=host, port=port, credentials=credentials, timeout=timeout | ||
| ) | ||
| await unknown_dev.update() | ||
| device_class = get_device_class_from_info(unknown_dev.internal_state) | ||
| dev = device_class(host=host, port=port, credentials=credentials, timeout=timeout) | ||
| # Reuse the connection from the unknown device | ||
| # so we don't have to reconnect | ||
| dev.protocol = unknown_dev.protocol | ||
| await dev.update() | ||
| if debug_enabled: | ||
| end_time = time.perf_counter() | ||
| _LOGGER.debug( | ||
| "Device %s with unknown type (%s) took %.2f seconds to connect", | ||
| host, | ||
| dev.device_type.value, | ||
| end_time - start_time, | ||
| ) | ||
| return dev | ||
|
|
||
|
|
||
| def get_device_class_from_info(info: Dict[str, Any]) -> Type[SmartDevice]: | ||
| """Find SmartDevice subclass for device described by passed data.""" | ||
| if "system" not in info or "get_sysinfo" not in info["system"]: | ||
| raise SmartDeviceException("No 'system' or 'get_sysinfo' in response") | ||
|
|
||
| sysinfo: Dict[str, Any] = info["system"]["get_sysinfo"] | ||
| type_: Optional[str] = sysinfo.get("type", sysinfo.get("mic_type")) | ||
| if type_ is None: | ||
| raise SmartDeviceException("Unable to find the device type field!") | ||
|
|
||
| if "dev_name" in sysinfo and "Dimmer" in sysinfo["dev_name"]: | ||
| return SmartDimmer | ||
|
|
||
| if "smartplug" in type_.lower(): | ||
| if "children" in sysinfo: | ||
| return SmartStrip | ||
|
|
||
| return SmartPlug | ||
|
|
||
| if "smartbulb" in type_.lower(): | ||
| if "length" in sysinfo: # strips have length | ||
| return SmartLightStrip | ||
|
|
||
| return SmartBulb | ||
| raise UnsupportedDeviceException("Unknown device type: %s" % type_) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """TP-Link device types.""" | ||
|
|
||
|
|
||
| from enum import Enum | ||
|
|
||
|
|
||
| class DeviceType(Enum): | ||
| """Device type enum.""" | ||
|
|
||
| # The values match what the cli has historically used | ||
| Plug = "plug" | ||
| Bulb = "bulb" | ||
| Strip = "strip" | ||
| StripSocket = "stripsocket" | ||
| Dimmer = "dimmer" | ||
| LightStrip = "lightstrip" | ||
| Unknown = "unknown" | ||
|
|
||
| @staticmethod | ||
| def from_value(name: str) -> "DeviceType": | ||
| """Return device type from string value.""" | ||
| for device_type in DeviceType: | ||
| if device_type.value == name: | ||
| return device_type | ||
| return DeviceType.Unknown |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.