Skip to content

Commit

Permalink
Update get_child_device_list to fetch all pages
Browse files Browse the repository at this point in the history
Addresses #322.
  • Loading branch information
mihai-dinculescu committed Dec 17, 2024
1 parent 504badd commit 1d041e4
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 25 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,18 @@ file. This change log follows the conventions of

- Added functionality for controlling the alarm on the H100 hub via the `play_alarm` and `stop_alarm` methods in the `H100Handler`. Additionally, `get_supported_ringtone_list` is available to retrieve the list of supported ringtones for debugging purposes. (thanks to @kay)

#### Changed

- The internal implementation of `H100Handler`'s `get_child_device_list` has been updated to fetch all pages, not just the first one.
- `H100Handler`'s `get_child_device_list_json` now includes a `start_index` parameter to fetch child devices starting from a specific index.

### Python

#### Changed

- The internal implementation of `H100Handler`'s `get_child_device_list` has been updated to fetch all pages, not just the first one.
- `H100Handler`'s `get_child_device_list_json` now includes a `start_index` parameter to fetch child devices starting from a specific index.

## [v0.8.0][v0.8.0] - 2024-12-07

This marks the first unified release of the Rust and Python libraries. Moving forward, both libraries will be released simultaneously and will share the same version number.
Expand Down
5 changes: 3 additions & 2 deletions tapo-py/src/api/hub_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ impl PyHubHandler {
results
}

pub async fn get_child_device_list_json(&self) -> PyResult<Py<PyDict>> {
pub async fn get_child_device_list_json(&self, start_index: u64) -> PyResult<Py<PyDict>> {
let handler = self.inner.clone();
let result = call_handler_method!(
handler.read().await.deref(),
HubHandler::get_child_device_list_json
HubHandler::get_child_device_list_json,
start_index
)?;
Python::with_gil(|py| tapo::python::serde_object_to_py_dict(py, &result))
}
Expand Down
6 changes: 5 additions & 1 deletion tapo-py/tapo-py/tapo/hub_handler.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,14 @@ class HubHandler:
dict: Device info as a dictionary.
"""

async def get_child_device_list_json(self) -> dict:
async def get_child_device_list_json(self, start_index: int) -> dict:
"""Returns *child device list* as json.
It contains all the properties returned from the Tapo API.
Args:
start_index (int): the index to start fetching the child device list.
It should be `0` for the first page, `10` for the second, and so on.
Returns:
dict: Device info as a dictionary.
"""
Expand Down
3 changes: 1 addition & 2 deletions tapo-py/tapo-py/tapo/power_strip_handler.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ class PowerStripHandler:
self,
) -> List[PowerStripPlugResult]:
"""Returns *child device list* as `List[PowerStripPlugResult]`.
It is not guaranteed to contain all the properties returned from the Tapo API
or to support all the possible devices connected to the hub.
It is not guaranteed to contain all the properties returned from the Tapo API.
If the deserialization fails, or if a property that you care about it's not present,
try `PowerStripHandler.get_child_device_list_json`.
Expand Down
13 changes: 8 additions & 5 deletions tapo/src/api/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use crate::api::{
};
use crate::error::{Error, TapoResponseError};
use crate::requests::{
ControlChildParams, EmptyParams, EnergyDataInterval, GetEnergyDataParams, LightingEffect,
MultipleRequestParams, PlayAlarmParams, TapoParams, TapoRequest,
ControlChildParams, EmptyParams, EnergyDataInterval, GetChildDeviceListParams,
GetEnergyDataParams, LightingEffect, MultipleRequestParams, PlayAlarmParams, TapoParams,
TapoRequest,
};
use crate::responses::{
validate_response, ControlChildResult, CurrentPowerResult, DecodableResultExt,
Expand Down Expand Up @@ -685,12 +686,14 @@ impl ApiClient {
.ok_or_else(|| Error::Tapo(TapoResponseError::EmptyResult))
}

pub(crate) async fn get_child_device_list<R>(&self) -> Result<R, Error>
pub(crate) async fn get_child_device_list<R>(&self, start_index: u64) -> Result<R, Error>
where
R: fmt::Debug + DeserializeOwned + TapoResponseExt + DecodableResultExt,
{
debug!("Get Child device list...");
let request = TapoRequest::GetChildDeviceList(TapoParams::new(EmptyParams));
debug!("Get Child device list starting with index {start_index}...");
let request = TapoRequest::GetChildDeviceList(TapoParams::new(
GetChildDeviceListParams::new(start_index),
));

self.get_protocol()?
.execute_request::<R>(request, true)
Expand Down
41 changes: 33 additions & 8 deletions tapo/src/api/hub_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,43 @@ impl HubHandler {
/// or to support all the possible devices connected to the hub.
/// If the deserialization fails, or if a property that you care about it's not present, try [`HubHandler::get_child_device_list_json`].
pub async fn get_child_device_list(&self) -> Result<Vec<ChildDeviceHubResult>, Error> {
self.client
.read()
.await
.get_child_device_list::<ChildDeviceListHubResult>()
.await
.map(|r| r.devices)
let mut results = Vec::new();
let mut start_index = 0;
let mut fetch = true;

while fetch {
let devices = self
.client
.read()
.await
.get_child_device_list::<ChildDeviceListHubResult>(start_index)
.await
.map(|r| r.devices)?;

fetch = devices.len() == 10;
start_index += 10;
results.extend(devices);
}

Ok(results)
}

/// Returns *child device list* as [`serde_json::Value`].
/// It contains all the properties returned from the Tapo API.
pub async fn get_child_device_list_json(&self) -> Result<serde_json::Value, Error> {
self.client.read().await.get_child_device_list().await
///
/// # Arguments
///
/// * `start_index` - the index to start fetching the child device list.
/// It should be `0` for the first page, `10` for the second, and so on.
pub async fn get_child_device_list_json(
&self,
start_index: u64,
) -> Result<serde_json::Value, Error> {
self.client
.read()
.await
.get_child_device_list(start_index)
.await
}

/// Returns *child device component list* as [`serde_json::Value`].
Expand Down
9 changes: 5 additions & 4 deletions tapo/src/api/power_strip_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,22 @@ impl PowerStripHandler {
}

/// Returns *child device list* as [`Vec<PowerStripPlugResult>`].
/// It is not guaranteed to contain all the properties returned from the Tapo API
/// or to support all the possible devices connected to the hub.
/// It is not guaranteed to contain all the properties returned from the Tapo API.
/// If the deserialization fails, or if a property that you care about it's not present,
/// try [`PowerStripHandler::get_child_device_list_json`].
pub async fn get_child_device_list(&self) -> Result<Vec<PowerStripPlugResult>, Error> {
self.client
.read()
.await
.get_child_device_list::<ChildDeviceListPowerStripResult>()
.get_child_device_list::<ChildDeviceListPowerStripResult>(0)
.await
.map(|r| r.plugs)
}

/// Returns *child device list* as [`serde_json::Value`].
/// It contains all the properties returned from the Tapo API.
pub async fn get_child_device_list_json(&self) -> Result<serde_json::Value, Error> {
self.client.read().await.get_child_device_list().await
self.client.read().await.get_child_device_list(0).await
}

/// Returns *child device component list* as [`serde_json::Value`].
Expand Down
2 changes: 2 additions & 0 deletions tapo/src/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
mod control_child;
mod energy_data_interval;
mod get_child_device_list;
mod get_energy_data;
mod get_trigger_logs;
mod handshake;
Expand All @@ -18,6 +19,7 @@ pub use play_alarm::*;
pub use set_device_info::*;

pub(crate) use control_child::*;
pub(crate) use get_child_device_list::*;
pub(crate) use get_energy_data::*;
pub(crate) use get_trigger_logs::*;
pub(crate) use handshake::*;
Expand Down
12 changes: 12 additions & 0 deletions tapo/src/requests/get_child_device_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use serde::Serialize;

#[derive(Debug, Default, Serialize)]
pub(crate) struct GetChildDeviceListParams {
start_index: u64,
}

impl GetChildDeviceListParams {
pub fn new(start_index: u64) -> Self {
Self { start_index }
}
}
7 changes: 4 additions & 3 deletions tapo/src/requests/tapo_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use std::time::{SystemTime, UNIX_EPOCH};
use serde::Serialize;

use crate::requests::{
ControlChildParams, GetEnergyDataParams, GetTriggerLogsParams, HandshakeParams, LightingEffect,
LoginDeviceParams, MultipleRequestParams, PlayAlarmParams, SecurePassthroughParams,
ControlChildParams, GetChildDeviceListParams, GetEnergyDataParams, GetTriggerLogsParams,
HandshakeParams, LightingEffect, LoginDeviceParams, MultipleRequestParams, PlayAlarmParams,
SecurePassthroughParams,
};

#[derive(Debug, Serialize)]
Expand All @@ -25,7 +26,7 @@ pub(crate) enum TapoRequest {
GetEnergyUsage(TapoParams<EmptyParams>),
GetEnergyData(TapoParams<GetEnergyDataParams>),
GetCurrentPower(TapoParams<EmptyParams>),
GetChildDeviceList(TapoParams<EmptyParams>),
GetChildDeviceList(TapoParams<GetChildDeviceListParams>),
GetChildDeviceComponentList(TapoParams<EmptyParams>),
ControlChild(Box<TapoParams<ControlChildParams>>),
// Child requests
Expand Down

0 comments on commit 1d041e4

Please sign in to comment.