-
-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Mihai Dinculescu <[email protected]>
- Loading branch information
1 parent
22d8dce
commit 3407b56
Showing
24 changed files
with
505 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ version = "0.7.10" | |
edition = "2021" | ||
license = "MIT" | ||
authors = ["Mihai Dinculescu <[email protected]>"] | ||
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L610, L630), light strips (L900, L920, L930), 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, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P115, P300), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)." | ||
keywords = ["IOT", "tapo", "smart-home", "smart-bulb", "smart-plug"] | ||
categories = ["hardware-support", "embedded", "development-tools"] | ||
readme = "README.md" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/// P300 Example | ||
use std::{env, thread, time::Duration}; | ||
|
||
use log::{info, LevelFilter}; | ||
use tapo::{ApiClient, PlugIdentifier}; | ||
|
||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let log_level = env::var("RUST_LOG") | ||
.unwrap_or_else(|_| "info".to_string()) | ||
.parse() | ||
.unwrap_or(LevelFilter::Info); | ||
|
||
pretty_env_logger::formatted_timed_builder() | ||
.filter(Some("tapo"), log_level) | ||
.init(); | ||
|
||
let tapo_username = env::var("TAPO_USERNAME")?; | ||
let tapo_password = env::var("TAPO_PASSWORD")?; | ||
let ip_address = env::var("IP_ADDRESS")?; | ||
|
||
let power_strip = ApiClient::new(tapo_username, tapo_password) | ||
.p300(ip_address) | ||
.await?; | ||
|
||
let device_info = power_strip.get_device_info().await?; | ||
info!("Device info: {device_info:?}"); | ||
|
||
info!("Getting child devices..."); | ||
let child_device_list = power_strip.get_child_device_list().await?; | ||
|
||
for child in child_device_list { | ||
info!( | ||
"Found plug with nickname: {}, id: {}, state: {}.", | ||
child.nickname, child.device_id, child.device_on, | ||
); | ||
|
||
let plug = power_strip | ||
.plug(PlugIdentifier::ByDeviceId(&child.device_id)) | ||
.await?; | ||
|
||
info!("Turning device on..."); | ||
plug.on().await?; | ||
|
||
info!("Waiting 2 seconds..."); | ||
thread::sleep(Duration::from_secs(2)); | ||
|
||
info!("Turning device off..."); | ||
plug.off().await?; | ||
|
||
info!("Waiting 2 seconds..."); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ use serde::de::DeserializeOwned; | |
use crate::api::protocol::{TapoProtocol, TapoProtocolExt}; | ||
use crate::api::{ | ||
ColorLightHandler, ColorLightStripHandler, GenericDeviceHandler, HubHandler, LightHandler, | ||
PlugEnergyMonitoringHandler, PlugHandler, | ||
PlugEnergyMonitoringHandler, PlugHandler, PowerStripHandler, | ||
}; | ||
use crate::error::{Error, TapoResponseError}; | ||
use crate::requests::{ | ||
|
@@ -404,6 +404,32 @@ impl ApiClient { | |
Ok(PlugEnergyMonitoringHandler::new(self)) | ||
} | ||
|
||
/// Specializes the given [`ApiClient`] into an authenticated [`PowerStripHandler`]. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `ip_address` - the IP address of the device | ||
/// | ||
/// # Example | ||
/// | ||
/// ```rust,no_run | ||
/// # use tapo::ApiClient; | ||
/// # #[tokio::main] | ||
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
/// let device = ApiClient::new("[email protected]", "tapo-password") | ||
/// .p300("192.168.1.100") | ||
/// .await?; | ||
/// let child_device_list = device.get_child_device_list().await?; | ||
/// println!("Child device list: {child_device_list:?}"); | ||
/// # Ok(()) | ||
/// # } | ||
/// ``` | ||
pub async fn p300(mut self, ip_address: impl Into<String>) -> Result<PowerStripHandler, Error> { | ||
self.login(ip_address).await?; | ||
|
||
Ok(PowerStripHandler::new(self)) | ||
} | ||
|
||
/// Specializes the given [`ApiClient`] into an authenticated [`PlugEnergyMonitoringHandler`]. | ||
/// | ||
/// # Arguments | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
use crate::api::PowerStripHandler; | ||
use crate::error::{Error, TapoResponseError}; | ||
use crate::requests::{EmptyParams, GenericSetDeviceInfoParams, TapoParams, TapoRequest}; | ||
use crate::responses::{DecodableResultExt, PlugPowerStripResult}; | ||
|
||
/// Handler for the [P300](https://www.tapo.com/en/search/?q=P300) child plugs. | ||
pub struct PlugPowerStripHandler<'h> { | ||
power_strip_handler: &'h PowerStripHandler, | ||
device_id: String, | ||
} | ||
|
||
impl<'h> PlugPowerStripHandler<'h> { | ||
pub(crate) fn new(power_strip_handler: &'h PowerStripHandler, device_id: String) -> Self { | ||
Self { | ||
power_strip_handler, | ||
device_id, | ||
} | ||
} | ||
|
||
/// Returns *device info* as [`PlugPowerStripResult`]. | ||
/// It is not guaranteed to contain all the properties returned from the Tapo API. | ||
pub async fn get_device_info(&self) -> Result<PlugPowerStripResult, Error> { | ||
let request = TapoRequest::GetDeviceInfo(TapoParams::new(EmptyParams)); | ||
|
||
self.power_strip_handler | ||
.control_child::<PlugPowerStripResult>(self.device_id.clone(), request) | ||
.await? | ||
.ok_or_else(|| Error::Tapo(TapoResponseError::EmptyResult)) | ||
.map(|result| result.decode())? | ||
} | ||
|
||
/// Returns *device info* as [`serde_json::Value`]. | ||
/// It is not guaranteed to contain all the properties returned from the Tapo API. | ||
pub async fn get_device_info_json(&self) -> Result<serde_json::Value, Error> { | ||
let request = TapoRequest::GetDeviceInfo(TapoParams::new(EmptyParams)); | ||
|
||
self.power_strip_handler | ||
.control_child::<serde_json::Value>(self.device_id.clone(), request) | ||
.await? | ||
.ok_or_else(|| Error::Tapo(TapoResponseError::EmptyResult)) | ||
} | ||
|
||
/// Turns *on* the device. | ||
pub async fn on(&self) -> Result<(), Error> { | ||
let json = serde_json::to_value(GenericSetDeviceInfoParams::device_on(true)?)?; | ||
let request = TapoRequest::SetDeviceInfo(Box::new(TapoParams::new(json))); | ||
|
||
self.power_strip_handler | ||
.control_child::<serde_json::Value>(self.device_id.clone(), request) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Turns *off* the device. | ||
pub async fn off(&self) -> Result<(), Error> { | ||
let json = serde_json::to_value(GenericSetDeviceInfoParams::device_on(false)?)?; | ||
let request = TapoRequest::SetDeviceInfo(Box::new(TapoParams::new(json))); | ||
|
||
self.power_strip_handler | ||
.control_child::<serde_json::Value>(self.device_id.clone(), request) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.