mirror of
				https://github.com/python-kasa/python-kasa.git
				synced 2025-11-04 06:32:07 +00:00 
			
		
		
		
	Convert to use poetry & pyproject.toml for dep & build management (#54)
* Convert to use poetry and pyproject.toml, update README * add some resources for contributors * minor adjustments * ci: separate tests from linting, run using poetry * add pytest-mock to dev requirements * combine running tests and reporting to codecov * generate both xml and html coverage reports * add codecov to dev dependencies
This commit is contained in:
		
							
								
								
									
										8
									
								
								.flake8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.flake8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
[flake8]
 | 
			
		||||
exclude = .git,.tox,__pycache__,kasa/tests/newfakes.py,kasa/tests/test_fixtures.py
 | 
			
		||||
max-line-length = 88
 | 
			
		||||
per-file-ignores =
 | 
			
		||||
  kasa/tests/*.py:D100,D101,D102,D103,D104
 | 
			
		||||
  setup.py:D100
 | 
			
		||||
ignore = D105, D107, E203, E501, W503
 | 
			
		||||
max-complexity = 18
 | 
			
		||||
@@ -26,11 +26,11 @@ repos:
 | 
			
		||||
  - id: flake8
 | 
			
		||||
    additional_dependencies: [flake8-docstrings]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
- repo: https://github.com/pre-commit/mirrors-isort
 | 
			
		||||
  rev: v4.3.21
 | 
			
		||||
  hooks:
 | 
			
		||||
  - id: isort
 | 
			
		||||
    additional_dependencies: [toml]
 | 
			
		||||
 | 
			
		||||
- repo: https://github.com/pre-commit/mirrors-mypy
 | 
			
		||||
  rev: v0.740
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -1,50 +0,0 @@
 | 
			
		||||
####################################################
 | 
			
		||||
# Use python 3.x and the latest version of alpine  #
 | 
			
		||||
####################################################
 | 
			
		||||
FROM python:3-alpine
 | 
			
		||||
 | 
			
		||||
LABEL maintainer=peter@grainger.xyz
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Add all system packages relied upon by python   #
 | 
			
		||||
###################################################
 | 
			
		||||
RUN apk update && \
 | 
			
		||||
    apk add --no-cache gcc \
 | 
			
		||||
                       libffi-dev \
 | 
			
		||||
                       openssl-dev \
 | 
			
		||||
                       libxslt-dev \
 | 
			
		||||
                       libxml2-dev \
 | 
			
		||||
                       musl-dev \
 | 
			
		||||
                       linux-headers
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Create somewhere to put the files               #
 | 
			
		||||
###################################################
 | 
			
		||||
RUN mkdir -p /opt/python-kasa
 | 
			
		||||
WORKDIR /opt/python-kasa
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Requirements file first to help cache           #
 | 
			
		||||
###################################################
 | 
			
		||||
COPY requirements.txt .
 | 
			
		||||
RUN pip install -r requirements.txt
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Install dev dependancies                        #
 | 
			
		||||
###################################################
 | 
			
		||||
RUN pip install pytest pytest-cov voluptuous typing
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Copy over the rest.                             #
 | 
			
		||||
###################################################
 | 
			
		||||
COPY ./ ./
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Install everything to the path                  #
 | 
			
		||||
###################################################
 | 
			
		||||
RUN python setup.py install
 | 
			
		||||
 | 
			
		||||
###################################################
 | 
			
		||||
# Run tests                                       #
 | 
			
		||||
###################################################
 | 
			
		||||
CMD pytest
 | 
			
		||||
							
								
								
									
										146
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								README.md
									
									
									
									
									
								
							@@ -3,9 +3,10 @@
 | 
			
		||||
[](https://badge.fury.io/py/python-kasa)
 | 
			
		||||
[](https://dev.azure.com/python-kasa/python-kasa/_build/latest?definitionId=2&branchName=master)
 | 
			
		||||
[](https://coveralls.io/github/python-kasa/python-kasa?branch=master)
 | 
			
		||||
[](https://houndci.com)
 | 
			
		||||
 | 
			
		||||
Python Library to control TPLink smart plugs/switches and smart bulbs.
 | 
			
		||||
python-kasa is a Python library to control TPLink smart home devices (plugs, wall switches, power strips, and bulbs) using asyncio.
 | 
			
		||||
This project is a maintainer-made fork of [pyHS100](https://github.com/GadgetReactor/pyHS100) project.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Supported devices**
 | 
			
		||||
 | 
			
		||||
@@ -13,6 +14,7 @@ Python Library to control TPLink smart plugs/switches and smart bulbs.
 | 
			
		||||
  * HS100
 | 
			
		||||
  * HS103
 | 
			
		||||
  * HS105
 | 
			
		||||
  * HS107
 | 
			
		||||
  * HS110
 | 
			
		||||
* Power Strips
 | 
			
		||||
  * HS300
 | 
			
		||||
@@ -32,6 +34,9 @@ Python Library to control TPLink smart plugs/switches and smart bulbs.
 | 
			
		||||
  * KL120
 | 
			
		||||
  * KL130
 | 
			
		||||
 | 
			
		||||
**Contributions (be it adding missing features, fixing bugs or improving documentation) are more than welcome, feel free to submit pull requests! See below for instructions for setting up a development environment.**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Usage
 | 
			
		||||
 | 
			
		||||
The package is shipped with a console tool named kasa, please refer to ```kasa --help``` for detailed usage.
 | 
			
		||||
@@ -82,7 +87,7 @@ All devices support a variety of common commands, including:
 | 
			
		||||
 * `state` which returns state information
 | 
			
		||||
 * `on` and `off` for turning the device on or off
 | 
			
		||||
 * `emeter` (where applicable) to return energy consumption information
 | 
			
		||||
 * `sysinfo` to return raw system information which is used by e.g. `state`, useful for debugging and when adding support for new device types
 | 
			
		||||
 * `sysinfo` to return raw system information
 | 
			
		||||
 | 
			
		||||
## Energy meter
 | 
			
		||||
 | 
			
		||||
@@ -96,128 +101,95 @@ $ kasa emeter
 | 
			
		||||
Current state: {'total': 133.105, 'power': 108.223577, 'current': 0.54463, 'voltage': 225.296283}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Plug-specific commands
 | 
			
		||||
 | 
			
		||||
At the moment only switching the state of the LED is implemented.
 | 
			
		||||
**Feel free to submit patches as pull requests for further features!**
 | 
			
		||||
### Controlling the LED
 | 
			
		||||
 | 
			
		||||
`led` command can be used to control whether the LED light on front of the plug is on or off.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ kasa --plug led
 | 
			
		||||
LED state: False
 | 
			
		||||
$ kasa --plug led 1
 | 
			
		||||
Turning led to True
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Bulb-specific commands
 | 
			
		||||
 | 
			
		||||
At the moment setting brightness, color temperature and color (in HSV) is supported.
 | 
			
		||||
At the moment setting brightness, color temperature and color (in HSV) are supported depending on the device.
 | 
			
		||||
The commands are straightforward, so feel free to check `--help` for instructions how to use them.
 | 
			
		||||
 | 
			
		||||
**Feel free to submit patches as pull requests to add more functionality (e.g. scenes)!**
 | 
			
		||||
 | 
			
		||||
# Library usage
 | 
			
		||||
 | 
			
		||||
The public API is well documented, but here are some examples to get you started.
 | 
			
		||||
For all available API functions run ```help(SmartPlug)``` or ```help(SmartBulb)```.
 | 
			
		||||
The property accesses use the data obtained before by awaiting `update()`.
 | 
			
		||||
The values are cached until the next update call.
 | 
			
		||||
Each method changing the state of the device will automatically update the cached state.
 | 
			
		||||
 | 
			
		||||
Errors are raised as `SmartDeviceException` instances for the user to handle.
 | 
			
		||||
 | 
			
		||||
## Discovering devices
 | 
			
		||||
 | 
			
		||||
`Discover` class' `discover()` can be used to discover supported devices,
 | 
			
		||||
which returns a dictionary keyed with the IP address whose value hold a ready-to-use instance of the detected device type.
 | 
			
		||||
`Discover.discover()` can be used to discover supported devices in the local network.
 | 
			
		||||
The return value is a dictionary keyed with the IP address and the value holds a ready-to-use instance of the detected device type.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
```python
 | 
			
		||||
import asyncio
 | 
			
		||||
from kasa import Discover
 | 
			
		||||
 | 
			
		||||
for dev in Discover.discover().values():
 | 
			
		||||
    print(dev)
 | 
			
		||||
devices = asyncio.run(Discover.discover())
 | 
			
		||||
for addr, dev in devices.items():
 | 
			
		||||
    asyncio.run(dev.update())
 | 
			
		||||
    print(f"{addr} >> {dev}")
 | 
			
		||||
```
 | 
			
		||||
```
 | 
			
		||||
$ python3 example.py
 | 
			
		||||
$ python example.py
 | 
			
		||||
<SmartPlug at 192.168.XXX.XXX (My Smart Plug), is_on: True - dev specific: {'LED state': True, 'On since': datetime.datetime(2017, 3, 26, 18, 29, 17, 52073)}>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Querying basic information
 | 
			
		||||
 | 
			
		||||
*Please note that most property getters do I/O (e.g. fetching the system information) on each call.
 | 
			
		||||
If you want to avoid unnecessary communication with the device please use `get_sysinfo` and handle parsing of information by yourself.*
 | 
			
		||||
 | 
			
		||||
```python
 | 
			
		||||
from kasa import SmartPlug, SmartBulb
 | 
			
		||||
import asyncio
 | 
			
		||||
from kasa import SmartPlug
 | 
			
		||||
from pprint import pformat as pf
 | 
			
		||||
 | 
			
		||||
plug = SmartPlug("192.168.XXX.XXX")
 | 
			
		||||
asyncio.run(plug.update())
 | 
			
		||||
print("Hardware: %s" % pf(plug.hw_info))
 | 
			
		||||
print("Full sysinfo: %s" % pf(plug.get_sysinfo())) # this prints lots of information about the device
 | 
			
		||||
print("Full sysinfo: %s" % pf(plug.sys_info))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The rest of the examples assume that you have initialized an instance.
 | 
			
		||||
 | 
			
		||||
## State & switching
 | 
			
		||||
 | 
			
		||||
Devices can be turned on and off by either calling appropriate methods on the device object,
 | 
			
		||||
or by assigning a new state to `state` property.
 | 
			
		||||
Devices can be turned on and off by either calling appropriate methods on the device object.
 | 
			
		||||
 | 
			
		||||
```python
 | 
			
		||||
print("Current state: %s" % plug.state)
 | 
			
		||||
plug.turn_off()
 | 
			
		||||
plug.turn_on()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```python
 | 
			
		||||
plug.state = "ON"
 | 
			
		||||
plug.state = "OFF"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Time information
 | 
			
		||||
```python
 | 
			
		||||
print("Current time: %s" % plug.time)
 | 
			
		||||
print("Timezone: %s" % plug.timezone)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Getting and setting the name
 | 
			
		||||
```python
 | 
			
		||||
print("Alias: %s" % plug.alias)
 | 
			
		||||
plug.alias = "My New Smartplug"
 | 
			
		||||
print("Current state: %s" % plug.is_on)
 | 
			
		||||
await plug.turn_off()
 | 
			
		||||
await plug.turn_on()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Getting emeter status (if applicable)
 | 
			
		||||
```python
 | 
			
		||||
print("Current consumption: %s" % plug.get_emeter_realtime())
 | 
			
		||||
print("Per day: %s" % plug.get_emeter_daily(year=2016, month=12))
 | 
			
		||||
print("Per month: %s" % plug.get_emeter_monthly(year=2016))
 | 
			
		||||
print("Current consumption: %s" % await plug.get_emeter_realtime())
 | 
			
		||||
print("Per day: %s" % await plug.get_emeter_daily(year=2016, month=12))
 | 
			
		||||
print("Per month: %s" % await plug.get_emeter_monthly(year=2016))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Plug-specific
 | 
			
		||||
 | 
			
		||||
### Switching the led (plugs only)
 | 
			
		||||
```python
 | 
			
		||||
print("Current LED state: %s" % plug.led)
 | 
			
		||||
plug.led = False # turn off led
 | 
			
		||||
print("New LED state: %s" % plug.led)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Bulb-specific API
 | 
			
		||||
## Bulb and dimmer-specific APIs
 | 
			
		||||
 | 
			
		||||
The bulb API is likewise straightforward, so please refer to its API documentation.
 | 
			
		||||
Information about supported features can be queried by using properties prefixed with `is_`, e.g. `is_dimmable`.
 | 
			
		||||
 | 
			
		||||
### Setting the brightness
 | 
			
		||||
 | 
			
		||||
The `brightness` property works in percentages.
 | 
			
		||||
 | 
			
		||||
```python
 | 
			
		||||
print(bulb.brightness)
 | 
			
		||||
import asyncio
 | 
			
		||||
from kasa import SmartBulb
 | 
			
		||||
 | 
			
		||||
bulb = SmartBulb("192.168.1.123")
 | 
			
		||||
asyncio.run(bulb.update())
 | 
			
		||||
 | 
			
		||||
if bulb.is_dimmable:
 | 
			
		||||
    bulb.brightness = 100
 | 
			
		||||
    asyncio.run(bulb.set_brightness(100))
 | 
			
		||||
    print(bulb.brightness)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Setting the color temperature
 | 
			
		||||
```python
 | 
			
		||||
print(bulb.color_temp)
 | 
			
		||||
if bulb.is_variable_color_temp:
 | 
			
		||||
    bulb.color_temp = 3000
 | 
			
		||||
    await bulb.set_color_temp(3000)
 | 
			
		||||
    print(bulb.color_temp)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Setting the color
 | 
			
		||||
@@ -225,19 +197,29 @@ if bulb.is_variable_color_temp:
 | 
			
		||||
Hue is given in degrees (0-360) and saturation and value in percentage.
 | 
			
		||||
 | 
			
		||||
```python
 | 
			
		||||
print(bulb.hsv)
 | 
			
		||||
if bulb.is_color:
 | 
			
		||||
   bulb.hsv = (180, 100, 100) # set to cyan
 | 
			
		||||
    await bulb.set_hsv(180, 100, 100) # set to cyan
 | 
			
		||||
    print(bulb.hsv)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Development Setup
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
### Docker
 | 
			
		||||
Contributions are very welcome! To simplify the process, we are leveraging automated checks and tests for contributions.
 | 
			
		||||
 | 
			
		||||
The following assumes you have a working installation of Docker.
 | 
			
		||||
### Resources
 | 
			
		||||
 | 
			
		||||
Set up the environment and run the tests on demand.
 | 
			
		||||
* [softScheck's github contains lot of information and wireshark dissector](https://github.com/softScheck/tplink-smartplug#wireshark-dissector)
 | 
			
		||||
* [https://github.com/plasticrake/tplink-smarthome-simulator](tplink-smarthome-simulator)
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
docker build . -t kasa && docker run -v $(PWD)/kasa/tests:/opt/python-kasa/kasa/tests kasa pytest
 | 
			
		||||
### Setting up development environment
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
poetry install
 | 
			
		||||
pre-commit install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Code-style checks
 | 
			
		||||
 | 
			
		||||
We use several tools to automatically check all contributions, which are run automatically when you commit your code.
 | 
			
		||||
 | 
			
		||||
If you want to manually execute the checks, you can run `tox -e lint` to do the linting checks or `tox` to also execute the tests.
 | 
			
		||||
 
 | 
			
		||||
@@ -3,93 +3,116 @@ trigger:
 | 
			
		||||
pr:
 | 
			
		||||
- master
 | 
			
		||||
 | 
			
		||||
strategy:
 | 
			
		||||
  matrix:
 | 
			
		||||
    Python 3.7 Ubuntu:
 | 
			
		||||
      python.version: '3.7'
 | 
			
		||||
      vmImage: 'ubuntu-latest'
 | 
			
		||||
    Python 3.8 Ubuntu:
 | 
			
		||||
      python.version: '3.8'
 | 
			
		||||
      vmImage: 'ubuntu-latest'
 | 
			
		||||
#    PyPy Ubuntu:
 | 
			
		||||
#      python.version: pypy3
 | 
			
		||||
#      vmImage: 'ubuntu-latest'
 | 
			
		||||
    Python 3.7 Windows:
 | 
			
		||||
      python.version: '3.7'
 | 
			
		||||
      vmImage: 'windows-latest'
 | 
			
		||||
    Python 3.8 Windows:
 | 
			
		||||
      python.version: '3.8'
 | 
			
		||||
      vmImage: 'windows-latest'
 | 
			
		||||
    Python 3.7 OSX:
 | 
			
		||||
      python.version: '3.7'
 | 
			
		||||
      vmImage: 'macOS-latest'
 | 
			
		||||
    Python 3.8 OSX:
 | 
			
		||||
      python.version: '3.8'
 | 
			
		||||
      vmImage: 'macOS-latest'
 | 
			
		||||
 | 
			
		||||
pool:
 | 
			
		||||
stages:
 | 
			
		||||
- stage: "Linting"
 | 
			
		||||
  jobs:
 | 
			
		||||
  - job: "LintChecks"
 | 
			
		||||
    pool:
 | 
			
		||||
      vmImage: "ubuntu-latest"
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        Python 3.8:
 | 
			
		||||
          python.version: '3.8'
 | 
			
		||||
    steps:
 | 
			
		||||
    - task: UsePythonVersion@0
 | 
			
		||||
      inputs:
 | 
			
		||||
        versionSpec: '$(python.version)'
 | 
			
		||||
      displayName: 'Use Python $(python.version)'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        python -m pip install --upgrade pip poetry
 | 
			
		||||
        poetry install
 | 
			
		||||
      displayName: 'Install dependencies'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run black --all-files
 | 
			
		||||
      displayName: 'Code formating (black)'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run flake8 --all-files
 | 
			
		||||
      displayName: 'Code formating (flake8)'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run mypy --all-files
 | 
			
		||||
      displayName: 'Typing checks (mypy)'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run isort --all-files
 | 
			
		||||
      displayName: 'Order of imports (isort)'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run trailing-whitespace --all-files
 | 
			
		||||
      displayName: 'Run trailing-whitespace'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run end-of-file-fixer --all-files
 | 
			
		||||
      displayName: 'Run end-of-file-fixer'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run check-docstring-first --all-files
 | 
			
		||||
      displayName: 'Run check-docstring-first'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run check-yaml --all-files
 | 
			
		||||
      displayName: 'Run check-yaml'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run debug-statements --all-files
 | 
			
		||||
      displayName: 'Run debug-statements'
 | 
			
		||||
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pre-commit run check-ast --all-files
 | 
			
		||||
      displayName: 'Run check-ast'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
- stage: "Tests"
 | 
			
		||||
  jobs:
 | 
			
		||||
  - job: "Tests"
 | 
			
		||||
    strategy:
 | 
			
		||||
      matrix:
 | 
			
		||||
        Python 3.7 Ubuntu:
 | 
			
		||||
          python.version: '3.7'
 | 
			
		||||
          vmImage: 'ubuntu-latest'
 | 
			
		||||
 | 
			
		||||
        Python 3.8 Ubuntu:
 | 
			
		||||
          python.version: '3.8'
 | 
			
		||||
          vmImage: 'ubuntu-latest'
 | 
			
		||||
 | 
			
		||||
        Python 3.7 Windows:
 | 
			
		||||
          python.version: '3.7'
 | 
			
		||||
          vmImage: 'windows-latest'
 | 
			
		||||
 | 
			
		||||
        Python 3.8 Windows:
 | 
			
		||||
          python.version: '3.8'
 | 
			
		||||
          vmImage: 'windows-latest'
 | 
			
		||||
 | 
			
		||||
        Python 3.7 OSX:
 | 
			
		||||
          python.version: '3.7'
 | 
			
		||||
          vmImage: 'macOS-latest'
 | 
			
		||||
 | 
			
		||||
        Python 3.8 OSX:
 | 
			
		||||
          python.version: '3.8'
 | 
			
		||||
          vmImage: 'macOS-latest'
 | 
			
		||||
 | 
			
		||||
    pool:
 | 
			
		||||
      vmImage: $(vmImage)
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
- task: UsePythonVersion@0
 | 
			
		||||
  inputs:
 | 
			
		||||
    versionSpec: '$(python.version)'
 | 
			
		||||
  displayName: 'Use Python $(python.version)'
 | 
			
		||||
    steps:
 | 
			
		||||
    - task: UsePythonVersion@0
 | 
			
		||||
      inputs:
 | 
			
		||||
        versionSpec: '$(python.version)'
 | 
			
		||||
      displayName: 'Use Python $(python.version)'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    python -m pip install --upgrade pip
 | 
			
		||||
    pip install -r requirements.txt
 | 
			
		||||
    pip install -r requirements_test.txt
 | 
			
		||||
  displayName: 'Install dependencies'
 | 
			
		||||
    - script: |
 | 
			
		||||
        python -m pip install --upgrade pip poetry
 | 
			
		||||
        poetry install
 | 
			
		||||
      displayName: 'Install dependencies'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run black --all-files
 | 
			
		||||
  displayName: 'Code formating (black)'
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run pytest --cov kasa --cov-report=xml --cov-report=html
 | 
			
		||||
      displayName: 'Run tests'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run flake8 --all-files
 | 
			
		||||
  displayName: 'Code formating (flake8)'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run mypy --all-files
 | 
			
		||||
  displayName: 'Typing checks (mypy)'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run isort --all-files
 | 
			
		||||
  displayName: 'Order of imports (isort)'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run trailing-whitespace --all-files
 | 
			
		||||
  displayName: 'Run trailing-whitespace'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run end-of-file-fixer --all-files
 | 
			
		||||
  displayName: 'Run end-of-file-fixer'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run check-docstring-first --all-files
 | 
			
		||||
  displayName: 'Run check-docstring-first'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run check-yaml --all-files
 | 
			
		||||
  displayName: 'Run check-yaml'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run debug-statements --all-files
 | 
			
		||||
  displayName: 'Run debug-statements'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run check-ast --all-files
 | 
			
		||||
  displayName: 'Run check-ast'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pre-commit run isort --all-files
 | 
			
		||||
  displayName: 'Order of imports (isort)'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    pytest --cov kasa --cov-report xml
 | 
			
		||||
  displayName: 'Tests'
 | 
			
		||||
 | 
			
		||||
- script: |
 | 
			
		||||
    codecov -t $(codecov.token)
 | 
			
		||||
  displayName: Report Coverage to codecov
 | 
			
		||||
    - script: |
 | 
			
		||||
        poetry run codecov -t $(codecov.token)
 | 
			
		||||
      displayName: 'Report code coverage'
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ For device type specific actions `SmartBulb`, `SmartPlug`, or `SmartStrip`
 | 
			
		||||
Module-specific errors are raised as `SmartDeviceException` and are expected
 | 
			
		||||
to be handled by the user of the library.
 | 
			
		||||
"""
 | 
			
		||||
from importlib_metadata import version  # type: ignore
 | 
			
		||||
from kasa.discover import Discover
 | 
			
		||||
from kasa.protocol import TPLinkSmartHomeProtocol
 | 
			
		||||
from kasa.smartbulb import SmartBulb
 | 
			
		||||
@@ -19,6 +20,9 @@ from kasa.smartdimmer import SmartDimmer
 | 
			
		||||
from kasa.smartplug import SmartPlug
 | 
			
		||||
from kasa.smartstrip import SmartStrip
 | 
			
		||||
 | 
			
		||||
__version__ = version("python-kasa")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    "Discover",
 | 
			
		||||
    "TPLinkSmartHomeProtocol",
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ from pprint import pformat as pf
 | 
			
		||||
from typing import cast
 | 
			
		||||
 | 
			
		||||
import asyncclick as click
 | 
			
		||||
 | 
			
		||||
from kasa import Discover, SmartBulb, SmartDevice, SmartPlug, SmartStrip
 | 
			
		||||
 | 
			
		||||
click.anyio_backend = "asyncio"
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ TPLINK_KELVIN = {
 | 
			
		||||
class SmartBulb(SmartDevice):
 | 
			
		||||
    """Representation of a TP-Link Smart Bulb.
 | 
			
		||||
 | 
			
		||||
    Usage example when used as library:
 | 
			
		||||
    Usage example:
 | 
			
		||||
    ```python
 | 
			
		||||
    p = SmartBulb("192.168.1.105")
 | 
			
		||||
    await p.update()
 | 
			
		||||
@@ -33,6 +33,7 @@ class SmartBulb(SmartDevice):
 | 
			
		||||
 | 
			
		||||
    # change state of bulb
 | 
			
		||||
    await p.turn_on()
 | 
			
		||||
    assert p.is_on
 | 
			
		||||
    await p.turn_off()
 | 
			
		||||
 | 
			
		||||
    # query and print current state of plug
 | 
			
		||||
@@ -40,12 +41,11 @@ class SmartBulb(SmartDevice):
 | 
			
		||||
 | 
			
		||||
    # check whether the bulb supports color changes
 | 
			
		||||
    if p.is_color:
 | 
			
		||||
 | 
			
		||||
    # set the color to an HSV tuple
 | 
			
		||||
    await p.set_hsv(180, 100, 100)
 | 
			
		||||
 | 
			
		||||
    # get the current HSV value
 | 
			
		||||
    print(p.hsv)
 | 
			
		||||
        print("we got color!")
 | 
			
		||||
        # set the color to an HSV tuple
 | 
			
		||||
        await p.set_hsv(180, 100, 100)
 | 
			
		||||
        # get the current HSV value
 | 
			
		||||
        print(p.hsv)
 | 
			
		||||
 | 
			
		||||
    # check whether the bulb supports setting color temperature
 | 
			
		||||
    if p.is_variable_color_temp:
 | 
			
		||||
@@ -57,12 +57,11 @@ class SmartBulb(SmartDevice):
 | 
			
		||||
 | 
			
		||||
    # check whether the bulb is dimmable
 | 
			
		||||
    if p.is_dimmable:
 | 
			
		||||
        # set the bulb to 50% brightness
 | 
			
		||||
        await p.set_brightness(50)
 | 
			
		||||
 | 
			
		||||
    # set the bulb to 50% brightness
 | 
			
		||||
    await p.set_brightness(50)
 | 
			
		||||
 | 
			
		||||
    # check the current brightness
 | 
			
		||||
    print(p.brightness)
 | 
			
		||||
        # check the current brightness
 | 
			
		||||
        print(p.brightness)
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
    Errors reported by the device are raised as SmartDeviceExceptions,
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ _LOGGER = logging.getLogger(__name__)
 | 
			
		||||
class SmartPlug(SmartDevice):
 | 
			
		||||
    """Representation of a TP-Link Smart Switch.
 | 
			
		||||
 | 
			
		||||
    Usage example when used a a synchronous library:
 | 
			
		||||
    Usage example:
 | 
			
		||||
    ```python
 | 
			
		||||
    p = SmartPlug("192.168.1.105")
 | 
			
		||||
 | 
			
		||||
@@ -19,9 +19,10 @@ class SmartPlug(SmartDevice):
 | 
			
		||||
 | 
			
		||||
    # change state of plug
 | 
			
		||||
    await p.turn_on()
 | 
			
		||||
    assert p.is_on is True
 | 
			
		||||
    await p.turn_off()
 | 
			
		||||
 | 
			
		||||
    # query and print current state of plug
 | 
			
		||||
    # print current state of plug
 | 
			
		||||
    print(p.state_information)
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import json
 | 
			
		||||
import os
 | 
			
		||||
from os.path import basename
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
import pytest  # type: ignore # see https://github.com/pytest-dev/pytest/issues/3342
 | 
			
		||||
 | 
			
		||||
from kasa import Discover, SmartBulb, SmartDimmer, SmartPlug, SmartStrip
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,16 @@
 | 
			
		||||
import logging
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from voluptuous import REMOVE_EXTRA, All, Any, Coerce, Invalid, Optional, Range, Schema
 | 
			
		||||
from voluptuous import (  # type: ignore
 | 
			
		||||
    REMOVE_EXTRA,
 | 
			
		||||
    All,
 | 
			
		||||
    Any,
 | 
			
		||||
    Coerce,
 | 
			
		||||
    Invalid,
 | 
			
		||||
    Optional,
 | 
			
		||||
    Range,
 | 
			
		||||
    Schema,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from ..protocol import TPLinkSmartHomeProtocol
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from asyncclick.testing import CliRunner
 | 
			
		||||
 | 
			
		||||
from kasa import SmartDevice
 | 
			
		||||
from kasa.cli import alias, brightness, emeter, raw_command, state, sysinfo
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import asyncio
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from unittest.mock import patch
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
import pytest  # type: ignore # https://github.com/pytest-dev/pytest/issues/3342
 | 
			
		||||
 | 
			
		||||
from kasa import DeviceType, SmartDeviceException, SmartStrip
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +0,0 @@
 | 
			
		||||
# flake8: noqa
 | 
			
		||||
__version__ = "0.4.0.dev0"
 | 
			
		||||
							
								
								
									
										57
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
[tool.poetry]
 | 
			
		||||
name = "python-kasa"
 | 
			
		||||
version = "0.4.0.dev0"
 | 
			
		||||
description = "Python API for TP-Link Kasa Smarthome devices"
 | 
			
		||||
license = "GPL-3.0-or-later"
 | 
			
		||||
authors = ["Your Name <you@example.com>"]
 | 
			
		||||
repository = "https://github.com/python-kasa/python-kasa"
 | 
			
		||||
readme = "README.md"
 | 
			
		||||
packages = [
 | 
			
		||||
  { include = "kasa" }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[tool.poetry.scripts]
 | 
			
		||||
kasa = "kasa.cli:cli"
 | 
			
		||||
 | 
			
		||||
[tool.poetry.dependencies]
 | 
			
		||||
python = "^3.7"
 | 
			
		||||
importlib-metadata = "*"
 | 
			
		||||
asyncclick = "^7"
 | 
			
		||||
 | 
			
		||||
[tool.poetry.dev-dependencies]
 | 
			
		||||
pytest = "^5"
 | 
			
		||||
pytest-azurepipelines = "^0.8"
 | 
			
		||||
pytest-cov = "^2.8"
 | 
			
		||||
pytest-asyncio = "^0.11"
 | 
			
		||||
pytest-sugar = "*"
 | 
			
		||||
pre-commit = "*"
 | 
			
		||||
voluptuous = "*"
 | 
			
		||||
toml = "*"
 | 
			
		||||
tox = "*"
 | 
			
		||||
pytest-mock = "^3.1.0"
 | 
			
		||||
codecov = "^2.0"
 | 
			
		||||
 | 
			
		||||
[tool.isort]
 | 
			
		||||
multi_line_output = 3
 | 
			
		||||
include_trailing_comma = true
 | 
			
		||||
force_grid_wrap = 0
 | 
			
		||||
use_parentheses = true
 | 
			
		||||
line_length = 88
 | 
			
		||||
known_first_party = "kasa"
 | 
			
		||||
known_third_party = ["asyncclick", "pytest", "setuptools", "voluptuous"]
 | 
			
		||||
 | 
			
		||||
[tool.coverage.run]
 | 
			
		||||
source = ["kasa"]
 | 
			
		||||
branch = true
 | 
			
		||||
omit = ["kasa/cli.py", "kasa/tests/*"]
 | 
			
		||||
 | 
			
		||||
[tool.coverage.report]
 | 
			
		||||
exclude_lines = [
 | 
			
		||||
  # ignore abstract methods
 | 
			
		||||
  "raise NotImplementedError",
 | 
			
		||||
  "def __repr__"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[build-system]
 | 
			
		||||
requires = ["poetry>=0.12"]
 | 
			
		||||
build-backend = "poetry.masonry.api"
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
asyncclick
 | 
			
		||||
pre-commit
 | 
			
		||||
voluptuous
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
pytest
 | 
			
		||||
pytest-azurepipelines
 | 
			
		||||
pytest-cov
 | 
			
		||||
pytest-asyncio
 | 
			
		||||
pytest-mock
 | 
			
		||||
asyncclick
 | 
			
		||||
voluptuous
 | 
			
		||||
codecov
 | 
			
		||||
							
								
								
									
										19
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								setup.py
									
									
									
									
									
								
							@@ -1,19 +0,0 @@
 | 
			
		||||
from setuptools import setup
 | 
			
		||||
 | 
			
		||||
with open("kasa/version.py") as f:
 | 
			
		||||
    exec(f.read())
 | 
			
		||||
 | 
			
		||||
setup(
 | 
			
		||||
    name="python-kasa",
 | 
			
		||||
    version=__version__,  # type: ignore # noqa: F821
 | 
			
		||||
    description="Python API for TP-Link Kasa Smarthome products",
 | 
			
		||||
    url="https://github.com/python-kasa/python-kasa",
 | 
			
		||||
    author="",
 | 
			
		||||
    author_email="",
 | 
			
		||||
    license="GPLv3",
 | 
			
		||||
    packages=["kasa"],
 | 
			
		||||
    install_requires=["asyncclick"],
 | 
			
		||||
    python_requires=">=3.7",
 | 
			
		||||
    entry_points={"console_scripts": ["kasa=kasa.cli:cli"]},
 | 
			
		||||
    zip_safe=False,
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										72
									
								
								tox.ini
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								tox.ini
									
									
									
									
									
								
							@@ -1,16 +1,35 @@
 | 
			
		||||
[tox]
 | 
			
		||||
envlist=py37,py38,flake8,linting,typing
 | 
			
		||||
envlist=py37,py38,flake8,lint,coverage
 | 
			
		||||
skip_missing_interpreters = True
 | 
			
		||||
isolated_build = True
 | 
			
		||||
 | 
			
		||||
[tox:travis]
 | 
			
		||||
3.7 = py37
 | 
			
		||||
3.8 = py38
 | 
			
		||||
 | 
			
		||||
[testenv]
 | 
			
		||||
passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH
 | 
			
		||||
deps = -r{toxinidir}/requirements_test.txt
 | 
			
		||||
commands=
 | 
			
		||||
    pytest --cov --cov-config=tox.ini kasa
 | 
			
		||||
whitelist_externals =
 | 
			
		||||
  poetry
 | 
			
		||||
  coverage
 | 
			
		||||
commands =
 | 
			
		||||
    poetry install -v
 | 
			
		||||
    poetry run pytest --cov kasa/tests/
 | 
			
		||||
 | 
			
		||||
[testenv:clean]
 | 
			
		||||
deps = coverage
 | 
			
		||||
skip_install = true
 | 
			
		||||
commands = coverage erase
 | 
			
		||||
 | 
			
		||||
[testenv:py37]
 | 
			
		||||
commands = coverage run -m pytest {posargs}
 | 
			
		||||
 | 
			
		||||
[testenv:py38]
 | 
			
		||||
commands = coverage run -m pytest {posargs}
 | 
			
		||||
 | 
			
		||||
[testenv:coverage]
 | 
			
		||||
basepython = python3.8
 | 
			
		||||
skip_install = true
 | 
			
		||||
deps = coverage[toml]
 | 
			
		||||
commands =
 | 
			
		||||
  coverage report
 | 
			
		||||
  coverage html
 | 
			
		||||
 | 
			
		||||
[testenv:flake8]
 | 
			
		||||
deps=
 | 
			
		||||
@@ -18,44 +37,7 @@ deps=
 | 
			
		||||
  flake8-docstrings
 | 
			
		||||
commands=flake8 kasa
 | 
			
		||||
 | 
			
		||||
[testenv:typing]
 | 
			
		||||
skip_install=true
 | 
			
		||||
deps=mypy
 | 
			
		||||
commands=mypy --ignore-missing-imports kasa
 | 
			
		||||
 | 
			
		||||
[flake8]
 | 
			
		||||
exclude = .git,.tox,__pycache__,kasa/tests/newfakes.py,kasa/tests/test_fixtures.py
 | 
			
		||||
max-line-length = 88
 | 
			
		||||
per-file-ignores =
 | 
			
		||||
  kasa/tests/*.py:D100,D101,D102,D103,D104
 | 
			
		||||
  setup.py:D100
 | 
			
		||||
ignore = D105, D107, E203, E501, W503
 | 
			
		||||
#ignore = E203, E266, E501, W503, F403, F401
 | 
			
		||||
#max-complexity = 18
 | 
			
		||||
#select = B,C,E,F,W,T4,B9
 | 
			
		||||
 | 
			
		||||
[testenv:lint]
 | 
			
		||||
deps = pre-commit
 | 
			
		||||
skip_install = true
 | 
			
		||||
commands = pre-commit run --all-files
 | 
			
		||||
 | 
			
		||||
[coverage:run]
 | 
			
		||||
source = kasa
 | 
			
		||||
branch = True
 | 
			
		||||
omit =
 | 
			
		||||
  kasa/tests/*
 | 
			
		||||
 | 
			
		||||
[coverage:report]
 | 
			
		||||
exclude_lines =
 | 
			
		||||
  # ignore abstract methods
 | 
			
		||||
  raise NotImplementedError
 | 
			
		||||
  def __repr__
 | 
			
		||||
 | 
			
		||||
[isort]
 | 
			
		||||
multi_line_output=3
 | 
			
		||||
include_trailing_comma=True
 | 
			
		||||
force_grid_wrap=0
 | 
			
		||||
use_parentheses=True
 | 
			
		||||
line_length=88
 | 
			
		||||
known_first_party=kasa
 | 
			
		||||
known_third_party=click,pytest,setuptools,voluptuous
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user