├── .gitignore ├── tapo_p100_control ├── __init__.py ├── manifest.json ├── switch.py └── light.py ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .idea/ -------------------------------------------------------------------------------- /tapo_p100_control/__init__.py: -------------------------------------------------------------------------------- 1 | """Tapo P100 Integration""" 2 | -------------------------------------------------------------------------------- /tapo_p100_control/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "tapo_p100_control", 3 | "name": "Tapo P100 Plug Control", 4 | "documentation": "https://github.com/fishbigger/HomeAssistant-Tapo-P100-Control", 5 | "issue_tracker": "https://github.com/fishbigger/HomeAssistant-Tapo-P100-Control/issues", 6 | "dependencies": [], 7 | "codeowners": ["@fishbigger"], 8 | "requirements": ["PyP100==0.0.19"], 9 | "version": "1.0.0" 10 | } 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 fishbigger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Home Assistant Tapo P100 Control 2 | A custom integration for home assistant to control the Tapo P100 plugs 3 | 4 | ## Installation 5 | 6 | To install the Tapo P100 integration copy the `tapo_p100_control` folder into the `custom_components` folder on your home assistant instance then these lines should be added to your `configuration.yaml` file. 7 | 8 | ```yaml 9 | 10 | #P100 or P105 Plug 11 | switch: 12 | platform: tapo_p100_control 13 | ip_address: 192.168.x.x 14 | email: email@gmail.com 15 | password: Password123 16 | 17 | #L510 Series Bulbs 18 | light: 19 | platform: tapo_p100_control 20 | ip_address: 192.168.x.x 21 | email: email@gmail.com 22 | password: Password123 23 | ``` 24 | 25 | ## Contributing 26 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change 27 | 28 | ## Upcoming Features: 29 | * Support for L530 Colour Bulbs 30 | * UI setup integration 31 | * Uploading to HACS 32 | 33 | ## Contributors 34 | * [K4CZP3R](https://github.com/K4CZP3R) 35 | * [Extreeeme](https://github.com/Extreeeme) 36 | 37 | 38 | ## License 39 | [MIT](https://choosealicense.com/licenses/mit/) 40 | -------------------------------------------------------------------------------- /tapo_p100_control/switch.py: -------------------------------------------------------------------------------- 1 | """Tapo P100 Plug Home Assistant Integration""" 2 | import logging 3 | 4 | from PyP100 import PyP100 5 | import voluptuous as vol 6 | from base64 import b64decode 7 | 8 | import homeassistant.helpers.config_validation as cv 9 | 10 | from homeassistant.components.switch import ( 11 | SwitchEntity, 12 | PLATFORM_SCHEMA, 13 | ) 14 | from homeassistant.const import CONF_IP_ADDRESS, CONF_EMAIL, CONF_PASSWORD 15 | 16 | import json 17 | 18 | # Validation of the user's configuration 19 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 20 | vol.Required(CONF_IP_ADDRESS): cv.string, 21 | vol.Required(CONF_EMAIL): cv.string, 22 | vol.Required(CONF_PASSWORD): cv.string, 23 | }) 24 | 25 | _LOGGER = logging.getLogger(__name__) 26 | 27 | def setup_platform(hass, config, add_entities, discovery_info=None): 28 | """Set up the Awesome Light platform.""" 29 | # Assign configuration variables. 30 | # The configuration check takes care they are present. 31 | ipAddress = config[CONF_IP_ADDRESS] 32 | email = config[CONF_EMAIL] 33 | password = config.get(CONF_PASSWORD) 34 | 35 | # Setup connection with devices/cloud 36 | p100 = PyP100.P100(ipAddress, email, password) 37 | 38 | try: 39 | p100.handshake() 40 | p100.login() 41 | except: 42 | _LOGGER.error("Could not connect to plug. Possibly invalid credentials") 43 | 44 | add_entities([P100Plug(p100)]) 45 | 46 | class P100Plug(SwitchEntity): 47 | """Representation of a P100 Plug""" 48 | 49 | def __init__(self, p100): 50 | self._p100 = p100 51 | self._is_on = False 52 | self._name = "Tapo P100 Plug" 53 | self.update() 54 | 55 | @property 56 | def name(self): 57 | """Name of the device.""" 58 | return self._name 59 | 60 | @property 61 | def unique_id(self): 62 | """Unique id.""" 63 | return self._unique_id 64 | 65 | @property 66 | def is_on(self): 67 | """Device State""" 68 | return self._is_on 69 | 70 | def turn_on(self, **kwargs) -> None: 71 | """Turn Plug On""" 72 | 73 | self._p100.turnOn() 74 | self._is_on = True 75 | 76 | def turn_off(self, **kwargs): 77 | """Turn Plug Off""" 78 | 79 | self._p100.turnOff() 80 | self._is_on = False 81 | 82 | def update(self): 83 | self._p100.handshake() 84 | self._p100.login() 85 | 86 | data = self._p100.getDeviceInfo() 87 | 88 | encodedName = data["result"]["nickname"] 89 | name = b64decode(encodedName) 90 | self._name = name.decode("utf-8") 91 | 92 | self._is_on = data["result"]["device_on"] 93 | self._unique_id = data["result"]["device_id"] 94 | -------------------------------------------------------------------------------- /tapo_p100_control/light.py: -------------------------------------------------------------------------------- 1 | """Tapo L1510 Bulb Home Assistant Intergration""" 2 | import logging 3 | 4 | from PyP100 import PyL530 5 | import voluptuous as vol 6 | from base64 import b64decode 7 | 8 | import homeassistant.helpers.config_validation as cv 9 | 10 | from homeassistant.components.light import ( 11 | LightEntity, 12 | PLATFORM_SCHEMA, 13 | SUPPORT_BRIGHTNESS, 14 | ATTR_BRIGHTNESS 15 | ) 16 | from homeassistant.const import CONF_IP_ADDRESS, CONF_EMAIL, CONF_PASSWORD 17 | 18 | import json 19 | 20 | # Validation of the user's configuration 21 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 22 | vol.Required(CONF_IP_ADDRESS): cv.string, 23 | vol.Required(CONF_EMAIL): cv.string, 24 | vol.Required(CONF_PASSWORD): cv.string, 25 | }) 26 | 27 | _LOGGER = logging.getLogger(__name__) 28 | 29 | def setup_platform(hass, config, add_entities, discovery_info=None): 30 | """Set up the Awesome Light platform.""" 31 | # Assign configuration variables. 32 | # The configuration check takes care they are present. 33 | ipAddress = config[CONF_IP_ADDRESS] 34 | email = config[CONF_EMAIL] 35 | password = config.get(CONF_PASSWORD) 36 | 37 | # Setup connection with devices/cloud 38 | l530 = PyL530.L530(ipAddress, email, password) 39 | 40 | try: 41 | l530.handshake() 42 | l530.login() 43 | except: 44 | _LOGGER.error("Could not connect to plug. Possibly invalid credentials") 45 | 46 | add_entities([L1510Bulb(l530)]) 47 | 48 | class L1510Bulb(LightEntity): 49 | """Representation of a P100 Plug""" 50 | 51 | def __init__(self, l530): 52 | self._l530 = l530 53 | self._is_on = False 54 | self._brightness = 255 55 | 56 | self.update() 57 | 58 | @property 59 | def name(self): 60 | """Name of the device.""" 61 | return self._name 62 | 63 | @property 64 | def unique_id(self): 65 | """Unique id.""" 66 | return self._unique_id 67 | 68 | @property 69 | def is_on(self): 70 | """Name of the device.""" 71 | return self._is_on 72 | 73 | @property 74 | def brightness(self): 75 | return self._brightness 76 | 77 | @property 78 | def supported_features(self): 79 | """Flag supported features.""" 80 | return SUPPORT_BRIGHTNESS 81 | 82 | def turn_on(self, **kwargs) -> None: 83 | """Turn Plug On""" 84 | 85 | newBrightness = kwargs.get(ATTR_BRIGHTNESS, 255) 86 | 87 | self._l530.setBrightness(round(newBrightness / 255 * 100)) 88 | self._l530.turnOn() 89 | 90 | self._is_on = True 91 | self._brightness = newBrightness 92 | 93 | def turn_off(self, **kwargs): 94 | """Turn Plug Off""" 95 | self._l530.turnOff() 96 | 97 | self._is_on = False 98 | 99 | def update(self): 100 | self._l530.handshake() 101 | self._l530.login() 102 | 103 | data = self._l530.getDeviceInfo() 104 | 105 | encodedName = data["result"]["nickname"] 106 | name = b64decode(encodedName) 107 | self._name = name.decode("utf-8") 108 | 109 | self._is_on = data["result"]["device_on"] 110 | self._unique_id = data["result"]["device_id"] 111 | self._brightness = round(data["result"]["brightness"] * 255 / 100) 112 | --------------------------------------------------------------------------------