Skip to content

Commit

Permalink
Add support for the P300 and P304 power strips
Browse files Browse the repository at this point in the history
  • Loading branch information
mihai-dinculescu committed Oct 20, 2024
1 parent 9b1cefc commit 9ef9727
Show file tree
Hide file tree
Showing 53 changed files with 818 additions and 250 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ file. This change log follows the conventions of

### Changed

- The `openssl` dependency has been replaced with native Rust alternatives to expand cross-compilation options, such as for Android, and to decrease build times.
- The `openssl` dependency has been replaced with native Rust alternatives to expand cross-compilation options, such as for Android, and to decrease build times (thanks to @rbock44).
- `PlugPowerStripHandler` has been renamed to `PowerStripPlugHandler` to be consistent with the rest of the library.
- `PlugPowerStripResult` has been renamed to `PowerStripPlugResult` to be consistent with the rest of the library.

## [Python Unreleased][Unreleased]

### Added

- Added support for the P300 and P304 power strips.

### Changed

- The `openssl` dependency has been replaced with native Rust alternatives to expand cross-compilation options, such as for Android, and to decrease build times.
- The `openssl` dependency has been replaced with native Rust alternatives to expand cross-compilation options, such as for Android, and to decrease build times (thanks to @rbock44).

## [Rust v0.7.16][v0.7.16] - 2024-09-27

Expand Down
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with l
| Feature<br/><br/><br/> | GenericDevice<br/><br/><br/> | L510<br/>L520<br/>L610 | L530<br/>L535<br/>L630<br/> | L900<br/><br/><br/> | L920<br/>L930<br/><br/> | P100<br/>P105<br/><br/> | P110<br/>P115<br/><br/> | P300<br/>P304<br/><br/> | H100<br/><br/><br/> |
| ------------------------------------ | :--------------------------: | :--------------------: | :-------------------------: | :-----------------: | :---------------------: | :---------------------: | :---------------------: | :---------------------: | :-----------------: |
| device_reset | | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | | |
| get_child_device_component_list_json | | | | | | | | &check; | &#x2705; |
| get_child_device_list | | | | | | | | &check; | &#x2705; |
| get_child_device_list_json | | | | | | | | &check; | &#x2705; |
| get_child_device_component_list_json | | | | | | | | &#x2705; | &#x2705; |
| get_child_device_list | | | | | | | | &#x2705; | &#x2705; |
| get_child_device_list_json | | | | | | | | &#x2705; | &#x2705; |
| get_current_power | | | | | | | &#x2705; | | |
| get_device_info | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | &check; | &#x2705; |
| get_device_info_json | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | &check; | &#x2705; |
| get_device_info | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | &#x2705; | &#x2705; |
| get_device_info_json | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | &#x2705; | &#x2705; |
| get_device_usage | | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | | |
| get_energy_data | | | | | | | &#x2705; | | |
| get_energy_usage | | | | | | | &#x2705; | | |
| off | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | | |
| on | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | | |
| refresh_session | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | &check; | &#x2705; |
| refresh_session | &#x2705; | &#x2705; | &#x2705; | &check; | &check; | &#x2705; | &#x2705; | &#x2705; | &#x2705; |
| set_brightness | | &#x2705; | &#x2705; | &check; | &check; | | | | |
| set_color | | | &#x2705; | &check; | &check; | | | | |
| set_color_temperature | | | &#x2705; | &check; | &check; | | | | |
Expand All @@ -54,6 +54,9 @@ Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with l

## Hub (H100) Child Devices Support

&check; - Rust only\
&#x2705; - Rust and Python

| Feature<br/><br/> | KE100<br/><br/> | S200B<br/><br/> | T100<br/><br/> | T110<br/><br/> | T300<br/><br/> | T310<br/>T315 |
| -------------------------------- | :-------------: | :-------------: | :------------: | :------------: | :------------: | :-----------: |
| get_device_info \* | &#x2705; | &#x2705; | &#x2705; | &#x2705; | &#x2705; | &#x2705; |
Expand Down
47 changes: 47 additions & 0 deletions tapo-py/examples/tapo_p300.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""P300 and P304 Example"""

import asyncio
import os

from tapo import ApiClient


async def main():
tapo_username = os.getenv("TAPO_USERNAME")
tapo_password = os.getenv("TAPO_PASSWORD")
ip_address = os.getenv("IP_ADDRESS")

client = ApiClient(tapo_username, tapo_password)
power_strip = await client.p300(ip_address)

device_info = await power_strip.get_device_info()
print(f"Device info: {device_info.to_dict()}")

child_device_list = await power_strip.get_child_device_list()

for child in child_device_list:
print(
"Found plug with nickname: {}, id: {}, state: {}.".format(
child.nickname,
child.device_id,
child.device_on,
)
)

plug = await power_strip.plug(device_id=child.device_id)

print("Turning device on...")
await plug.on()

print("Waiting 2 seconds...")
await asyncio.sleep(2)

print("Turning device off...")
await plug.off()

print("Waiting 2 seconds...")
await asyncio.sleep(2)


if __name__ == "__main__":
asyncio.run(main())
4 changes: 2 additions & 2 deletions tapo-py/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[tool.poetry]
name = "tapo"
version = "0.5.1"
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L535, L610, L630), plugs (P100, P105, P110, P115), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)."
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L535, L610, L630), plugs (P100, P105, P110, P115), power strips (P300, P304), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)."
authors = ["Mihai Dinculescu <[email protected]>"]

[project]
name = "tapo"
version = "0.5.1"
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L535, L610, L630), plugs (P100, P105, P110, P115), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)."
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L535, L610, L630), plugs (P100, P105, P110, P115), power strips (P300, P304), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)."
readme = "README.md"
license = { file = "LICENSE" }
authors = [
Expand Down
16 changes: 14 additions & 2 deletions tapo-py/src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ use pyo3::prelude::*;
use std::time::Duration;
use tapo::{
ApiClient, ColorLightHandler, GenericDeviceHandler, HubHandler, LightHandler,
PlugEnergyMonitoringHandler, PlugHandler,
PlugEnergyMonitoringHandler, PlugHandler, PowerStripHandler,
};

use crate::call_handler_constructor;
use crate::errors::ErrorWrapper;
use crate::handlers::{
PyColorLightHandler, PyGenericDeviceHandler, PyHubHandler, PyLightHandler,
PyPlugEnergyMonitoringHandler, PyPlugHandler,
PyPlugEnergyMonitoringHandler, PyPlugHandler, PyPowerStripHandler,
};

#[pyclass(name = "ApiClient")]
Expand Down Expand Up @@ -101,6 +101,18 @@ impl PyApiClient {
Ok(PyPlugEnergyMonitoringHandler::new(handler))
}

pub async fn p300(&self, ip_address: String) -> PyResult<PyPowerStripHandler> {
let handler: PowerStripHandler =
call_handler_constructor!(self, tapo::ApiClient::p300, ip_address);
Ok(PyPowerStripHandler::new(handler))
}

pub async fn p304(&self, ip_address: String) -> PyResult<PyPowerStripHandler> {
let handler: PowerStripHandler =
call_handler_constructor!(self, tapo::ApiClient::p304, ip_address);
Ok(PyPowerStripHandler::new(handler))
}

pub async fn h100(&self, ip_address: String) -> PyResult<PyHubHandler> {
let handler: HubHandler =
call_handler_constructor!(self, tapo::ApiClient::h100, ip_address);
Expand Down
2 changes: 2 additions & 0 deletions tapo-py/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod hub_handler;
mod light_handler;
mod plug_energy_monitoring_handler;
mod plug_handler;
mod power_strip_handler;

pub use child_devices::*;
pub use color_light_handler::*;
Expand All @@ -13,3 +14,4 @@ pub use hub_handler::*;
pub use light_handler::*;
pub use plug_energy_monitoring_handler::*;
pub use plug_handler::*;
pub use power_strip_handler::*;
2 changes: 2 additions & 0 deletions tapo-py/src/handlers/child_devices.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod power_strip_plug_handler;
mod s200b_handler;
mod t100_handler;
mod t110_handler;
mod t300_handler;
mod t31x_handler;

pub use power_strip_plug_handler::*;
pub use s200b_handler::*;
pub use t100_handler::*;
pub use t110_handler::*;
Expand Down
46 changes: 46 additions & 0 deletions tapo-py/src/handlers/child_devices/power_strip_plug_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::{ops::Deref, sync::Arc};

use pyo3::{prelude::*, types::PyDict};
use tapo::responses::PowerStripPlugResult;
use tapo::PowerStripPlugHandler;

use crate::call_handler_method;

#[derive(Clone)]
#[pyclass(name = "PowerStripPlugHandler")]
pub struct PyPowerStripPlugHandler {
handler: Arc<PowerStripPlugHandler>,
}

impl PyPowerStripPlugHandler {
pub fn new(handler: PowerStripPlugHandler) -> Self {
Self {
handler: Arc::new(handler),
}
}
}

#[pymethods]
impl PyPowerStripPlugHandler {
pub async fn get_device_info(&self) -> PyResult<PowerStripPlugResult> {
let handler = self.handler.clone();
call_handler_method!(handler.deref(), PowerStripPlugHandler::get_device_info)
}

pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
let handler = self.handler.clone();
let result =
call_handler_method!(handler.deref(), PowerStripPlugHandler::get_device_info_json)?;
Python::with_gil(|py| tapo::python::serde_object_to_py_dict(py, &result))
}

pub async fn on(&self) -> PyResult<()> {
let handler = self.handler.clone();
call_handler_method!(handler.deref(), PowerStripPlugHandler::on)
}

pub async fn off(&self) -> PyResult<()> {
let handler = self.handler.clone();
call_handler_method!(handler.deref(), PowerStripPlugHandler::off)
}
}
34 changes: 17 additions & 17 deletions tapo-py/src/handlers/hub_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,37 +77,37 @@ impl PyHubHandler {

for child in children {
match child {
ChildDeviceHubResult::KE100(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::KE100(device) => {
results.append(device.into_py(py))?;
}
ChildDeviceHubResult::S200B(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::S200B(device) => {
results.append(device.into_py(py))?;
}
ChildDeviceHubResult::T100(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::T100(device) => {
results.append(device.into_py(py))?;
}
ChildDeviceHubResult::T110(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::T110(device) => {
results.append(device.into_py(py))?;
}
ChildDeviceHubResult::T300(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::T300(device) => {
results.append(device.into_py(py))?;
}
ChildDeviceHubResult::T310(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::T310(device) => {
results.append(device.into_py(py))?;
}
ChildDeviceHubResult::T315(x) => {
let _ = results.append(x.into_py(py));
ChildDeviceHubResult::T315(device) => {
results.append(device.into_py(py))?;
}
_ => {
let _ = results.append(py.None());
results.append(py.None())?;
}
}
}

results.into()
Ok(results.into())
});

Ok(results)
results
}

pub async fn get_child_device_list_json(&self) -> PyResult<Py<PyDict>> {
Expand Down
Loading

0 comments on commit 9ef9727

Please sign in to comment.