Skip to content
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

Dev1 #1

Merged
merged 5 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions kasa/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,29 @@
"""
from importlib.metadata import version

from kasa.auth import AuthCredentials, TPLinkAuthProtocol
from kasa.discover import Discover
from kasa.emeterstatus import EmeterStatus
from kasa.exceptions import SmartDeviceException
from kasa.protocol import TPLinkSmartHomeProtocol
from kasa.klapprotocol import TPLinkKlap
from kasa.smartbulb import SmartBulb, SmartBulbPreset, TurnOnBehavior, TurnOnBehaviors
from kasa.smartdevice import DeviceType, SmartDevice
from kasa.smartdimmer import SmartDimmer
from kasa.smartlightstrip import SmartLightStrip
from kasa.smartplug import SmartPlug
from kasa.smartstrip import SmartStrip
from kasa.unauthenticateddevice import UnauthenticatedDevice

__version__ = version("python-kasa")


__all__ = [
"AuthCredentials",
"TPLinkAuthProtocol",
"Discover",
"TPLinkSmartHomeProtocol",
"TPLinkKlap",
"SmartBulb",
"SmartBulbPreset",
"TurnOnBehaviors",
Expand All @@ -42,4 +48,5 @@
"SmartStrip",
"SmartDimmer",
"SmartLightStrip",
"UnauthenticatedDevice",
]
36 changes: 36 additions & 0 deletions kasa/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Authentication class for username / passwords."""
from kasa.protocol import TPLinkProtocol


class AuthCredentials:
"""Authentication credentials for Kasa authentication."""

def __init__(self, username: str = "", password: str = ""):
self.username = username
self.password = password


class TPLinkAuthProtocol(TPLinkProtocol):
"""Base class for authenticating protocol"""

def __init__(
self,
host: str,
port: str,
auth_credentials: AuthCredentials = AuthCredentials(),
):
super().__init__(host=host, port=port)
if auth_credentials is None:
self.auth_credentials = AuthCredentials()
else:
self.auth_credentials = auth_credentials
self._authentication_failed = False

@property
def authentication_failed(self):
"""Will be true if authentication negotiated but failed, false otherwise"""
return self._authentication_failed

@authentication_failed.setter
def authentication_failed(self, value):
self._authentication_failed = value
49 changes: 45 additions & 4 deletions kasa/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def wrapper(message=None, *args, **kwargs):


from kasa import (
AuthCredentials,
Discover,
SmartBulb,
SmartDevice,
Expand Down Expand Up @@ -123,9 +124,29 @@ def _device_to_serializable(val: SmartDevice):
@click.option(
"--json", default=False, is_flag=True, help="Output raw device response as JSON."
)
@click.option(
"--username",
default="",
required=False,
help="Username/email address to authenticate to device.",
)
@click.option(
"--password",
default="",
required=False,
help="Password to use to authenticate to device.",
)
@click.option(
"--discoverytimeout",
default=3,
required=False,
help="Timeout for discovery.",
)
@click.version_option(package_name="python-kasa")
@click.pass_context
async def cli(ctx, host, alias, target, debug, type, json):
async def cli(
ctx, host, alias, target, debug, type, json, username, password, discoverytimeout
):
"""A tool for controlling TP-Link smart home devices.""" # noqa
# no need to perform any checks if we are just displaying the help
if sys.argv[-1] == "--help":
Expand Down Expand Up @@ -171,15 +192,24 @@ def _nop_echo(*args, **kwargs):
echo(f"No device with name {alias} found")
return

if password != "" and username == "":
click.echo("Using a password requires a username")
return

if username != "":
authentication = AuthCredentials(username=username, password=password)
else:
authentication = AuthCredentials()

if host is None:
echo("No host name given, trying discovery..")
return await ctx.invoke(discover)
return await ctx.invoke(discover, timeout=discoverytimeout)

if type is not None:
dev = TYPE_TO_CLASS[type](host)
else:
echo("No --type defined, discovering..")
dev = await Discover.discover_single(host)
dev = await Discover.discover_single(host, authentication)

await dev.update()
ctx.obj = dev
Expand Down Expand Up @@ -241,8 +271,19 @@ async def print_discovered(dev: SmartDevice):
await ctx.invoke(state)
echo()

username = ctx.parent.params["username"]
password = ctx.parent.params["password"]

if username:
auth = AuthCredentials(username=username, password=password)
else:
auth = AuthCredentials()

await Discover.discover(
target=target, timeout=timeout, on_discovered=print_discovered
targetip=target,
timeout=timeout,
on_discovered=print_discovered,
auth_credentials=auth,
)

return discovered
Expand Down
Loading