From d253b55d41c5b8b42214a500b5c47e729124c56a Mon Sep 17 00:00:00 2001 From: Teemu R Date: Mon, 20 Mar 2017 19:03:19 +0100 Subject: [PATCH] Add new client tool (#42) * Add new client tool After installing the package pyhs100 command-line tool can be used to control the plug. See --help for its usage, most of the features for plugs are implemented, some of the shared functionality works for bulbs too. * Add discover command * Delete old examples, the cli works as an example well enough --- examples/cli.py | 24 --------- examples/discover.py | 9 ---- pyHS100/cli.py | 126 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 2 + setup.py | 7 ++- 5 files changed, 134 insertions(+), 34 deletions(-) delete mode 100644 examples/cli.py delete mode 100644 examples/discover.py create mode 100644 pyHS100/cli.py create mode 100644 requirements.txt diff --git a/examples/cli.py b/examples/cli.py deleted file mode 100644 index 20063dd..0000000 --- a/examples/cli.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys -import logging -from pprint import pformat as pf - -from pyHS100 import SmartPlug - -logging.basicConfig(level=logging.DEBUG) - -if len(sys.argv) < 2: - print("%s " % sys.argv[0]) - sys.exit(1) - -hs = SmartPlug(sys.argv[1]) - -logging.info("Identify: %s", hs.identify()) -logging.info("Sysinfo: %s", pf(hs.get_sysinfo())) -has_emeter = hs.has_emeter -if has_emeter: - logging.info("== Emeter ==") - logging.info("- Current: %s", hs.get_emeter_realtime()) - logging.info("== Monthly ==") - logging.info(hs.get_emeter_monthly()) - logging.info("== Daily ==") - logging.info(hs.get_emeter_daily(month=11, year=2016)) diff --git a/examples/discover.py b/examples/discover.py deleted file mode 100644 index a1d6ce0..0000000 --- a/examples/discover.py +++ /dev/null @@ -1,9 +0,0 @@ -import logging -from pprint import pprint as pp - -from pyHS100 import TPLinkSmartHomeProtocol -logging.basicConfig(level=logging.DEBUG) - -for dev in TPLinkSmartHomeProtocol.discover(): - print("Found device!") - pp(dev) diff --git a/pyHS100/cli.py b/pyHS100/cli.py new file mode 100644 index 0000000..acdcc5c --- /dev/null +++ b/pyHS100/cli.py @@ -0,0 +1,126 @@ +import click +import logging +from click_datetime import Datetime +from pprint import pformat + +from pyHS100 import SmartPlug, TPLinkSmartHomeProtocol + +pass_dev = click.make_pass_decorator(SmartPlug) + + +@click.group(invoke_without_command=True) +@click.option('--ip', envvar="PYHS100_IP", required=False) +@click.option('--debug/--normal', default=False) +@click.pass_context +def cli(ctx, ip, debug): + """A cli tool for controlling TP-Link smart home plugs.""" + if debug: + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) + + if ctx.invoked_subcommand == "discover": + return + + plug = SmartPlug(ip) + ctx.obj = plug + + if ctx.invoked_subcommand is None: + ctx.invoke(state) + + +@cli.command() +@click.option('--timeout', default=5, required=False) +def discover(timeout): + """Discover devices in the network.""" + click.echo("Discovering devices for %s seconds" % timeout) + for dev in TPLinkSmartHomeProtocol.discover(timeout=timeout): + print("Found device: %s" % pformat(dev)) + + +@cli.command() +@pass_dev +def sysinfo(plug): + """Print out full system information.""" + click.echo(click.style("== System info ==", bold=True)) + click.echo(pformat(plug.sys_info)) + + +@cli.command() +@pass_dev +@click.pass_context +def state(ctx, plug): + """Print out device state and versions.""" + click.echo(click.style("== %s - %s ==" % (plug.alias, plug.model), + bold=True)) + + click.echo(click.style("Device state: %s" % plug.state, + fg="green" if plug.is_on else "red")) + click.echo("LED state: %s" % plug.led) + click.echo("Time: %s" % plug.time) + click.echo("On since: %s" % plug.on_since) + click.echo("Hardware: %s" % plug.hw_info["hw_ver"]) + click.echo("Software: %s" % plug.hw_info["sw_ver"]) + click.echo("MAC (rssi): %s (%s)" % (plug.mac, plug.rssi)) + click.echo("Location: %s" % plug.location) + ctx.invoke(emeter) + + +@cli.command() +@pass_dev +@click.option('--year', type=Datetime(format='%Y'), + default=None, required=False) +@click.option('--month', type=Datetime(format='%Y-%m'), + default=None, required=False) +@click.option('--erase', is_flag=True) +def emeter(plug, year, month, erase): + """Query emeter for historical consumption.""" + click.echo(click.style("== Emeter ==", bold=True)) + if not plug.has_emeter: + click.echo("Device has no emeter") + return + + if erase: + click.echo("Erasing emeter statistics..") + plug.erase_emeter_stats() + return + + click.echo("Current state: %s" % plug.get_emeter_realtime()) + if year: + click.echo("== For year %s ==" % year.year) + click.echo(plug.get_emeter_monthly(year.year)) + elif month: + click.echo("== For month %s of %s ==" % (month.month, month.year)) + plug.get_emeter_daily(year=month.year, month=month.month) + + +@cli.command() +@click.argument('state', type=bool, required=False) +@pass_dev +def led(plug, state): + """Get or set led state.""" + if state is not None: + click.echo("Turning led to %s" % state) + plug.led = state + else: + click.echo("LED state: %s" % plug.led) + + +@cli.command() +@pass_dev +def on(plug): + """Turn the device on.""" + click.echo("Turning on..") + plug.turn_on() + + +@cli.command() +@pass_dev +def off(plug): + """Turn the device off.""" + click.echo("Turning off..") + plug.turn_off() + + +if __name__ == "__main__": + cli() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..09e8c8a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +click +click-datetime \ No newline at end of file diff --git a/setup.py b/setup.py index 4bdf032..ff86314 100644 --- a/setup.py +++ b/setup.py @@ -8,5 +8,10 @@ author_email='sean@gadgetreactor.com', license='GPLv3', packages=['pyHS100'], - install_requires=[], + install_requires=['click', 'click-datetime'], + entry_points={ + 'console_scripts': [ + 'pyhs100=pyHS100.cli:cli', + ], + }, zip_safe=False)