feat(tapo-agent): add schedule/countdown timer API support
- Fork tapo crate to add missing schedule/timer APIs - Add get_countdown_rules, get_schedule_rules, get_next_event methods - New readings: countdown_active, countdown_remain, schedule_count, schedule_active_count, next_event_time - Add local compilation to build script alongside cross-compilation - Implement offline polling - device collection continues when server disconnects - Add more device readings: on_time, signal_level, rssi, runtime_today/month, energy_month Vendored tapo fork in tapo-fork/ with minimal changes to add schedule APIs.
This commit is contained in:
4
agents/tapo/tapo-fork/tapo-py/.gitignore
vendored
Normal file
4
agents/tapo/tapo-fork/tapo-py/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
__pycache__
|
||||
.pytest_cache
|
||||
**/*.so
|
||||
**/*.pyd
|
||||
1
agents/tapo/tapo-fork/tapo-py/CHANGELOG.md
Symbolic link
1
agents/tapo/tapo-fork/tapo-py/CHANGELOG.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../CHANGELOG.md
|
||||
32
agents/tapo/tapo-fork/tapo-py/Cargo.toml
Normal file
32
agents/tapo/tapo-fork/tapo-py/Cargo.toml
Normal file
@@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "tapo-py"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "tapo"
|
||||
crate-type = ["cdylib"]
|
||||
doc = false
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pyo3 = { workspace = true, features = [
|
||||
"chrono",
|
||||
"experimental-async",
|
||||
"extension-module",
|
||||
"py-clone",
|
||||
] }
|
||||
pyo3-async-runtimes = { version = "0.27", features = ["attributes", "tokio-runtime"] }
|
||||
pyo3-log = { version = "0.13" }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "sync"] }
|
||||
|
||||
tapo = { path = "../tapo", features = ["python"] }
|
||||
1
agents/tapo/tapo-fork/tapo-py/LICENSE
Symbolic link
1
agents/tapo/tapo-fork/tapo-py/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../LICENSE
|
||||
1
agents/tapo/tapo-fork/tapo-py/README.md
Symbolic link
1
agents/tapo/tapo-fork/tapo-py/README.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../README.md
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Discover devices on the local network Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from tapo import ApiClient, DiscoveryResult
|
||||
|
||||
|
||||
async def main():
|
||||
tapo_username = os.getenv("TAPO_USERNAME")
|
||||
tapo_password = os.getenv("TAPO_PASSWORD")
|
||||
target = os.getenv("TARGET", "192.168.1.255")
|
||||
timeout_s = int(os.getenv("TIMEOUT", 10))
|
||||
|
||||
print(f"Discovering Tapo devices on target: {target} for {timeout_s} seconds...")
|
||||
|
||||
api_client = ApiClient(tapo_username, tapo_password)
|
||||
discovery = await api_client.discover_devices(target, timeout_s)
|
||||
|
||||
async for discovery_result in discovery:
|
||||
try:
|
||||
device = discovery_result.get()
|
||||
|
||||
match device:
|
||||
case DiscoveryResult.GenericDevice(device_info, _handler):
|
||||
print(
|
||||
f"Found Unsupported Device '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.Light(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.ColorLight(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.RgbLightStrip(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.RgbicLightStrip(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.Plug(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.PlugEnergyMonitoring(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.PowerStrip(device_info, _handler):
|
||||
print(
|
||||
f"Found Power Strip of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.PowerStripEnergyMonitoring(device_info, _handler):
|
||||
print(
|
||||
f"Found Power Strip with Energy Monitoring of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
case DiscoveryResult.Hub(device_info, _handler):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error discovering device: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,31 @@
|
||||
"""Generic Device 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)
|
||||
device = await client.generic_device(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,30 @@
|
||||
"""Toggle Generic Device 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)
|
||||
device = await client.generic_device(ip_address)
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
|
||||
if device_info.device_on == True:
|
||||
print("Device is on. Turning it off...")
|
||||
await device.off()
|
||||
elif device_info.device_on == False:
|
||||
print("Device is off. Turning it on...")
|
||||
await device.on()
|
||||
else:
|
||||
print("This device does not support on/off functionality.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
120
agents/tapo/tapo-fork/tapo-py/examples/tapo_h100.py
Normal file
120
agents/tapo/tapo-fork/tapo-py/examples/tapo_h100.py
Normal file
@@ -0,0 +1,120 @@
|
||||
"""H100 Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import AlarmRingtone, AlarmVolume, AlarmDuration
|
||||
from tapo.responses import KE100Result, S200BResult, T100Result, T110Result, T300Result, T31XResult
|
||||
|
||||
|
||||
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)
|
||||
hub = await client.h100(ip_address)
|
||||
|
||||
device_info = await hub.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
child_device_list = await hub.get_child_device_list()
|
||||
|
||||
for child in child_device_list:
|
||||
if child is None:
|
||||
print("Found unsupported device.")
|
||||
elif isinstance(child, KE100Result):
|
||||
print(
|
||||
"Found KE100 child device with nickname: {}, id: {}, current temperature: {:.2f} {} and target temperature: {:.2f} {}.".format(
|
||||
child.nickname,
|
||||
child.device_id,
|
||||
child.current_temperature,
|
||||
child.temperature_unit,
|
||||
child.target_temperature,
|
||||
child.temperature_unit,
|
||||
)
|
||||
)
|
||||
elif isinstance(child, S200BResult):
|
||||
s200b = await hub.s200b(device_id=child.device_id)
|
||||
trigger_logs = await s200b.get_trigger_logs(5, 0)
|
||||
|
||||
print(
|
||||
"Found S200B child device with nickname: {}, id: {}, last 5 trigger logs: {}.".format(
|
||||
child.nickname,
|
||||
child.device_id,
|
||||
[log.to_dict() for log in trigger_logs.logs],
|
||||
)
|
||||
)
|
||||
elif isinstance(child, T100Result):
|
||||
t100 = await hub.t100(device_id=child.device_id)
|
||||
trigger_logs = await t100.get_trigger_logs(5, 0)
|
||||
|
||||
print(
|
||||
"Found T100 child device with nickname: {}, id: {}, detected: {}, last 5 trigger logs: {}.".format(
|
||||
child.nickname,
|
||||
child.device_id,
|
||||
child.detected,
|
||||
[log.to_dict() for log in trigger_logs.logs],
|
||||
)
|
||||
)
|
||||
elif isinstance(child, T110Result):
|
||||
t110 = await hub.t110(device_id=child.device_id)
|
||||
trigger_logs = await t110.get_trigger_logs(5, 0)
|
||||
|
||||
print(
|
||||
"Found T110 child device with nickname: {}, id: {}, open: {}, last 5 trigger logs: {}.".format(
|
||||
child.nickname,
|
||||
child.device_id,
|
||||
child.open,
|
||||
[log.to_dict() for log in trigger_logs.logs],
|
||||
)
|
||||
)
|
||||
elif isinstance(child, T300Result):
|
||||
t300 = await hub.t300(device_id=child.device_id)
|
||||
trigger_logs = await t300.get_trigger_logs(5, 0)
|
||||
|
||||
print(
|
||||
"Found T300 child device with nickname: {}, id: {}, in_alarm: {}, water_leak_status: {}, last 5 trigger logs: {}.".format(
|
||||
child.nickname,
|
||||
child.device_id,
|
||||
child.in_alarm,
|
||||
child.water_leak_status,
|
||||
[log.to_dict() for log in trigger_logs.logs],
|
||||
)
|
||||
)
|
||||
elif isinstance(child, T31XResult):
|
||||
t31x = await hub.t315(device_id=child.device_id)
|
||||
temperature_humidity_records = await t31x.get_temperature_humidity_records()
|
||||
|
||||
print(
|
||||
"Found T31X child device with nickname: {}, id: {}, temperature: {:.2f} {}, humidity: {}%, earliest temperature and humidity record available: {}.".format(
|
||||
child.nickname,
|
||||
child.device_id,
|
||||
child.current_temperature,
|
||||
child.temperature_unit,
|
||||
child.current_humidity,
|
||||
(
|
||||
temperature_humidity_records.records[0].to_dict()
|
||||
if temperature_humidity_records.records
|
||||
else None
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
print(f"Triggering the alarm ringtone 'Alarm 1' at a 'Low' volume for '3 Seconds'...")
|
||||
await hub.play_alarm(AlarmRingtone.Alarm1, AlarmVolume.Low, AlarmDuration.Seconds, seconds=3)
|
||||
|
||||
device_info = await hub.get_device_info()
|
||||
print(f"Is device ringing?: {device_info.in_alarm}")
|
||||
|
||||
print("Stopping the alarm after 1 Second...")
|
||||
await asyncio.sleep(1)
|
||||
await hub.stop_alarm()
|
||||
|
||||
device_info = await hub.get_device_info()
|
||||
print(f"Is device ringing?: {device_info.in_alarm}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
40
agents/tapo/tapo-fork/tapo-py/examples/tapo_ke100.py
Normal file
40
agents/tapo/tapo-fork/tapo-py/examples/tapo_ke100.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""KE100 TRV Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import TemperatureUnitKE100
|
||||
|
||||
|
||||
async def main():
|
||||
tapo_username = os.getenv("TAPO_USERNAME")
|
||||
tapo_password = os.getenv("TAPO_PASSWORD")
|
||||
ip_address = os.getenv("IP_ADDRESS")
|
||||
# Name of the KE100 device.
|
||||
# Can be obtained from the Tapo App or by executing `get_child_device_component_list()` on the hub device.
|
||||
device_name = os.getenv("DEVICE_NAME")
|
||||
target_temperature = int(os.getenv("TARGET_TEMPERATURE"))
|
||||
|
||||
client = ApiClient(tapo_username, tapo_password)
|
||||
hub = await client.h100(ip_address)
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.ke100(nickname=device_name)
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
# Set target temperature.
|
||||
# KE100 currently only supports Celsius as temperature unit.
|
||||
print(f"Setting target temperature to {target_temperature} degrees Celsius...")
|
||||
await device.set_target_temperature(target_temperature, TemperatureUnitKE100.Celsius)
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
40
agents/tapo/tapo-fork/tapo-py/examples/tapo_l510.py
Normal file
40
agents/tapo/tapo-fork/tapo-py/examples/tapo_l510.py
Normal file
@@ -0,0 +1,40 @@
|
||||
"""L510, L520 and L610 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)
|
||||
device = await client.l510(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the brightness to 30%...")
|
||||
await device.set_brightness(30)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
device_usage = await device.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
62
agents/tapo/tapo-fork/tapo-py/examples/tapo_l530.py
Normal file
62
agents/tapo/tapo-fork/tapo-py/examples/tapo_l530.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""L530, L535 and L630 Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import Color
|
||||
|
||||
|
||||
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)
|
||||
device = await client.l530(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the brightness to 30%...")
|
||||
await device.set_brightness(30)
|
||||
|
||||
print("Setting the color to `Chocolate`...")
|
||||
await device.set_color(Color.Chocolate)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the color to `Deep Sky Blue` using the `hue` and `saturation`...")
|
||||
await device.set_hue_saturation(195, 100)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the color to `Incandescent` using the `color temperature`...")
|
||||
await device.set_color_temperature(2700)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Using the `set` API to set multiple properties in a single request...")
|
||||
await device.set().brightness(50).color(Color.HotPink).send(device)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
device_usage = await device.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
62
agents/tapo/tapo-fork/tapo-py/examples/tapo_l900.py
Normal file
62
agents/tapo/tapo-fork/tapo-py/examples/tapo_l900.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""L900 Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import Color
|
||||
|
||||
|
||||
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)
|
||||
device = await client.l900(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the brightness to 30%...")
|
||||
await device.set_brightness(30)
|
||||
|
||||
print("Setting the color to `Chocolate`...")
|
||||
await device.set_color(Color.Chocolate)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the color to `Deep Sky Blue` using the `hue` and `saturation`...")
|
||||
await device.set_hue_saturation(195, 100)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the color to `Incandescent` using the `color temperature`...")
|
||||
await device.set_color_temperature(2700)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Using the `set` API to set multiple properties in a single request...")
|
||||
await device.set().brightness(50).color(Color.HotPink).send(device)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
device_usage = await device.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
103
agents/tapo/tapo-fork/tapo-py/examples/tapo_l930.py
Normal file
103
agents/tapo/tapo-fork/tapo-py/examples/tapo_l930.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""L920 and L930 Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import Color, LightingEffect, LightingEffectPreset, LightingEffectType
|
||||
|
||||
|
||||
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)
|
||||
device = await client.l930(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the brightness to 30%...")
|
||||
await device.set_brightness(30)
|
||||
|
||||
print("Setting the color to `Chocolate`...")
|
||||
await device.set_color(Color.Chocolate)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the color to `Deep Sky Blue` using the `hue` and `saturation`...")
|
||||
await device.set_hue_saturation(195, 100)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting the color to `Incandescent` using the `color temperature`...")
|
||||
await device.set_color_temperature(2700)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Using the `set` API to set multiple properties in a single request...")
|
||||
await device.set().brightness(50).color(Color.HotPink).send(device)
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Setting a preset Lighting effect...")
|
||||
await device.set_lighting_effect(LightingEffectPreset.BubblingCauldron)
|
||||
|
||||
print("Waiting 10 seconds...")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
print("Setting a custom static Lighting effect...")
|
||||
custom_effect = (
|
||||
LightingEffect(
|
||||
"My Custom Static Effect", LightingEffectType.Static, True, True, 100, [(359, 85, 100)]
|
||||
)
|
||||
.with_expansion_strategy(1)
|
||||
.with_segments([0, 1, 2])
|
||||
.with_sequence([(359, 85, 100), (0, 0, 100), (236, 72, 100)])
|
||||
)
|
||||
await device.set_lighting_effect(custom_effect)
|
||||
|
||||
print("Waiting 10 seconds...")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
print("Setting a custom sequence Lighting effect...")
|
||||
custom_effect = (
|
||||
LightingEffect(
|
||||
"My Custom Sequence Effect",
|
||||
LightingEffectType.Sequence,
|
||||
True,
|
||||
True,
|
||||
100,
|
||||
[(359, 85, 100)],
|
||||
)
|
||||
.with_expansion_strategy(1)
|
||||
.with_segments([0, 1, 2])
|
||||
.with_sequence([(359, 85, 100), (0, 0, 100), (236, 72, 100)])
|
||||
.with_direction(1)
|
||||
.with_duration(50)
|
||||
)
|
||||
await device.set_lighting_effect(custom_effect)
|
||||
|
||||
print("Waiting 10 seconds...")
|
||||
await asyncio.sleep(10)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
device_usage = await device.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
34
agents/tapo/tapo-fork/tapo-py/examples/tapo_p100.py
Normal file
34
agents/tapo/tapo-fork/tapo-py/examples/tapo_p100.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""P100 and P105 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)
|
||||
device = await client.p100(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
device_usage = await device.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
118
agents/tapo/tapo-fork/tapo-py/examples/tapo_p110.py
Normal file
118
agents/tapo/tapo-fork/tapo-py/examples/tapo_p110.py
Normal file
@@ -0,0 +1,118 @@
|
||||
"""P110, P110M and P115 Example"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import EnergyDataInterval, PowerDataInterval
|
||||
|
||||
|
||||
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)
|
||||
device = await client.p110(ip_address)
|
||||
|
||||
print("Turning device on...")
|
||||
await device.on()
|
||||
|
||||
print("Waiting 2 seconds...")
|
||||
await asyncio.sleep(2)
|
||||
|
||||
print("Turning device off...")
|
||||
await device.off()
|
||||
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
current_power = await device.get_current_power()
|
||||
print(f"Current power: {current_power.to_dict()}")
|
||||
|
||||
device_usage = await device.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
energy_usage = await device.get_energy_usage()
|
||||
print(f"Energy usage: {energy_usage.to_dict()}")
|
||||
|
||||
today = datetime.now(timezone.utc)
|
||||
|
||||
# Energy data - Hourly interval
|
||||
# `start_date` and `end_date` are an inclusive interval that must not be greater than 8 days.
|
||||
energy_data_hourly = await device.get_energy_data(EnergyDataInterval.Hourly, today)
|
||||
print(
|
||||
"Energy data (hourly): "
|
||||
f"Start date time '{energy_data_hourly.start_date_time}', "
|
||||
f"Entries {len(energy_data_hourly.entries)}, "
|
||||
f"First entry: {energy_data_hourly.entries[0].to_dict() if energy_data_hourly.entries else None}"
|
||||
)
|
||||
|
||||
# Energy data - Daily interval
|
||||
# `start_date` must be the first day of a quarter.
|
||||
energy_data_daily = await device.get_energy_data(
|
||||
EnergyDataInterval.Daily,
|
||||
datetime(today.year, get_quarter_start_month(today), 1),
|
||||
)
|
||||
print(
|
||||
"Energy data (daily): "
|
||||
f"Start date time '{energy_data_daily.start_date_time}', "
|
||||
f"Entries {len(energy_data_daily.entries)}, "
|
||||
f"First entry: {energy_data_daily.entries[0].to_dict() if energy_data_daily.entries else None}"
|
||||
)
|
||||
|
||||
# Energy data - Monthly interval
|
||||
# `start_date` must be the first day of a year.
|
||||
energy_data_monthly = await device.get_energy_data(
|
||||
EnergyDataInterval.Monthly,
|
||||
datetime(today.year, 1, 1),
|
||||
)
|
||||
print(
|
||||
"Energy data (monthly): "
|
||||
f"Start date time '{energy_data_monthly.start_date_time}', "
|
||||
f"Entries {len(energy_data_monthly.entries)}, "
|
||||
f"First entry: {energy_data_monthly.entries[0].to_dict() if energy_data_monthly.entries else None}"
|
||||
)
|
||||
|
||||
# Power data - Every 5 minutes interval
|
||||
# `start_date_time` and `end_date_time` describe an exclusive interval.
|
||||
# If the result would yield more than 144 entries (i.e. 12 hours),
|
||||
# the `end_date_time` will be adjusted to an earlier date and time.
|
||||
power_data_every_5_minutes = await device.get_power_data(
|
||||
PowerDataInterval.Every5Minutes,
|
||||
today - timedelta(hours=12),
|
||||
today,
|
||||
)
|
||||
print(
|
||||
"Power data (every 5 minutes): "
|
||||
f"Start date time '{power_data_every_5_minutes.start_date_time}', "
|
||||
f"End date time '{power_data_every_5_minutes.end_date_time}', "
|
||||
f"Entries {len(power_data_every_5_minutes.entries)}, "
|
||||
f"First entry: {power_data_every_5_minutes.entries[0].to_dict() if power_data_every_5_minutes.entries else None}"
|
||||
)
|
||||
|
||||
# Power data - Hourly interval
|
||||
# `start_date_time` and `end_date_time` describe an exclusive interval.
|
||||
# If the result would yield more than 144 entries (i.e. 6 days),
|
||||
# the `end_date_time` will be adjusted to an earlier date and time.
|
||||
power_data_hourly = await device.get_power_data(
|
||||
PowerDataInterval.Hourly,
|
||||
today - timedelta(days=3),
|
||||
today,
|
||||
)
|
||||
print(
|
||||
"Power data (hourly): "
|
||||
f"Start date time '{power_data_hourly.start_date_time}', "
|
||||
f"End date time '{power_data_hourly.end_date_time}', "
|
||||
f"Entries {len(power_data_hourly.entries)}, "
|
||||
f"First entry: {power_data_hourly.entries[0].to_dict() if power_data_hourly.entries else None}"
|
||||
)
|
||||
|
||||
|
||||
def get_quarter_start_month(today: datetime) -> int:
|
||||
return ((today.month - 1) // 3) * 3 + 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
45
agents/tapo/tapo-fork/tapo-py/examples/tapo_p300.py
Normal file
45
agents/tapo/tapo-fork/tapo-py/examples/tapo_p300.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""P300 and P306 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()}")
|
||||
|
||||
print("Getting child devices...")
|
||||
child_device_list = await power_strip.get_child_device_list()
|
||||
print(f"Found {len(child_device_list)} plugs")
|
||||
|
||||
for index, child in enumerate(child_device_list):
|
||||
print(f"=== ({index + 1}) {child.nickname} ===")
|
||||
print(f"Device ID: {child.device_id}")
|
||||
print(f"State: {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())
|
||||
132
agents/tapo/tapo-fork/tapo-py/examples/tapo_p304.py
Normal file
132
agents/tapo/tapo-fork/tapo-py/examples/tapo_p304.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""P304M and P316M Example"""
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import os
|
||||
|
||||
from tapo import ApiClient
|
||||
from tapo.requests import EnergyDataInterval, PowerDataInterval
|
||||
|
||||
|
||||
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.p304(ip_address)
|
||||
|
||||
device_info = await power_strip.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
|
||||
print("Getting child devices...")
|
||||
child_device_list = await power_strip.get_child_device_list()
|
||||
print(f"Found {len(child_device_list)} plugs")
|
||||
|
||||
for index, child in enumerate(child_device_list):
|
||||
print(f"=== ({index + 1}) {child.nickname} ===")
|
||||
print(f"Device ID: {child.device_id}")
|
||||
print(f"State: {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)
|
||||
|
||||
current_power = await plug.get_current_power()
|
||||
print(f"Current power: {current_power.to_dict()}")
|
||||
|
||||
device_usage = await plug.get_device_usage()
|
||||
print(f"Device usage: {device_usage.to_dict()}")
|
||||
|
||||
energy_usage = await plug.get_energy_usage()
|
||||
print(f"Energy usage: {energy_usage.to_dict()}")
|
||||
|
||||
today = datetime.now(timezone.utc)
|
||||
|
||||
# Energy data - Hourly interval
|
||||
# `start_date` and `end_date` are an inclusive interval that must not be greater than 8 days.
|
||||
energy_data_hourly = await plug.get_energy_data(EnergyDataInterval.Hourly, today)
|
||||
print(
|
||||
"Energy data (hourly): "
|
||||
f"Start date time '{energy_data_hourly.start_date_time}', "
|
||||
f"Entries {len(energy_data_hourly.entries)}, "
|
||||
f"First entry: {energy_data_hourly.entries[0].to_dict() if energy_data_hourly.entries else None}"
|
||||
)
|
||||
|
||||
# Energy data - Daily interval
|
||||
# `start_date` must be the first day of a quarter.
|
||||
energy_data_daily = await plug.get_energy_data(
|
||||
EnergyDataInterval.Daily,
|
||||
datetime(today.year, get_quarter_start_month(today), 1),
|
||||
)
|
||||
print(
|
||||
"Energy data (daily): "
|
||||
f"Start date time '{energy_data_daily.start_date_time}', "
|
||||
f"Entries {len(energy_data_daily.entries)}, "
|
||||
f"First entry: {energy_data_daily.entries[0].to_dict() if energy_data_daily.entries else None}"
|
||||
)
|
||||
|
||||
# Energy data - Monthly interval
|
||||
# `start_date` must be the first day of a year.
|
||||
energy_data_monthly = await plug.get_energy_data(
|
||||
EnergyDataInterval.Monthly,
|
||||
datetime(today.year, 1, 1),
|
||||
)
|
||||
print(
|
||||
"Energy data (monthly): "
|
||||
f"Start date time '{energy_data_monthly.start_date_time}', "
|
||||
f"Entries {len(energy_data_monthly.entries)}, "
|
||||
f"First entry: {energy_data_monthly.entries[0].to_dict() if energy_data_monthly.entries else None}"
|
||||
)
|
||||
|
||||
# Power data - Every 5 minutes interval
|
||||
# `start_date_time` and `end_date_time` describe an exclusive interval.
|
||||
# If the result would yield more than 144 entries (i.e. 12 hours),
|
||||
# the `end_date_time` will be adjusted to an earlier date and time.
|
||||
power_data_every_5_minutes = await plug.get_power_data(
|
||||
PowerDataInterval.Every5Minutes,
|
||||
today - timedelta(hours=12),
|
||||
today,
|
||||
)
|
||||
print(
|
||||
"Power data (every 5 minutes): "
|
||||
f"Start date time '{power_data_every_5_minutes.start_date_time}', "
|
||||
f"End date time '{power_data_every_5_minutes.end_date_time}', "
|
||||
f"Entries {len(power_data_every_5_minutes.entries)}, "
|
||||
f"First entry: {power_data_every_5_minutes.entries[0].to_dict() if power_data_every_5_minutes.entries else None}"
|
||||
)
|
||||
|
||||
# Power data - Hourly interval
|
||||
# `start_date_time` and `end_date_time` describe an exclusive interval.
|
||||
# If the result would yield more than 144 entries (i.e. 6 days),
|
||||
# the `end_date_time` will be adjusted to an earlier date and time.
|
||||
power_data_hourly = await plug.get_power_data(
|
||||
PowerDataInterval.Hourly,
|
||||
today - timedelta(days=3),
|
||||
today,
|
||||
)
|
||||
print(
|
||||
"Power data (hourly): "
|
||||
f"Start date time '{power_data_hourly.start_date_time}', "
|
||||
f"End date time '{power_data_hourly.end_date_time}', "
|
||||
f"Entries {len(power_data_hourly.entries)}, "
|
||||
f"First entry: {power_data_hourly.entries[0].to_dict() if power_data_hourly.entries else None}"
|
||||
)
|
||||
|
||||
|
||||
def get_quarter_start_month(today: datetime) -> int:
|
||||
return ((today.month - 1) // 3) * 3 + 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
180
agents/tapo/tapo-fork/tapo-py/poetry.lock
generated
Normal file
180
agents/tapo/tapo-fork/tapo-py/poetry.lock
generated
Normal file
@@ -0,0 +1,180 @@
|
||||
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "25.11.0"
|
||||
description = "The uncompromising code formatter."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "black-25.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ec311e22458eec32a807f029b2646f661e6859c3f61bc6d9ffb67958779f392e"},
|
||||
{file = "black-25.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1032639c90208c15711334d681de2e24821af0575573db2810b0763bcd62e0f0"},
|
||||
{file = "black-25.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c0f7c461df55cf32929b002335883946a4893d759f2df343389c4396f3b6b37"},
|
||||
{file = "black-25.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:f9786c24d8e9bd5f20dc7a7f0cdd742644656987f6ea6947629306f937726c03"},
|
||||
{file = "black-25.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:895571922a35434a9d8ca67ef926da6bc9ad464522a5fe0db99b394ef1c0675a"},
|
||||
{file = "black-25.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cb4f4b65d717062191bdec8e4a442539a8ea065e6af1c4f4d36f0cdb5f71e170"},
|
||||
{file = "black-25.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d81a44cbc7e4f73a9d6ae449ec2317ad81512d1e7dce7d57f6333fd6259737bc"},
|
||||
{file = "black-25.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:7eebd4744dfe92ef1ee349dc532defbf012a88b087bb7ddd688ff59a447b080e"},
|
||||
{file = "black-25.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:80e7486ad3535636657aa180ad32a7d67d7c273a80e12f1b4bfa0823d54e8fac"},
|
||||
{file = "black-25.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6cced12b747c4c76bc09b4db057c319d8545307266f41aaee665540bc0e04e96"},
|
||||
{file = "black-25.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb2d54a39e0ef021d6c5eef442e10fd71fcb491be6413d083a320ee768329dd"},
|
||||
{file = "black-25.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae263af2f496940438e5be1a0c1020e13b09154f3af4df0835ea7f9fe7bfa409"},
|
||||
{file = "black-25.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0a1d40348b6621cc20d3d7530a5b8d67e9714906dfd7346338249ad9c6cedf2b"},
|
||||
{file = "black-25.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:51c65d7d60bb25429ea2bf0731c32b2a2442eb4bd3b2afcb47830f0b13e58bfd"},
|
||||
{file = "black-25.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:936c4dd07669269f40b497440159a221ee435e3fddcf668e0c05244a9be71993"},
|
||||
{file = "black-25.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:f42c0ea7f59994490f4dccd64e6b2dd49ac57c7c84f38b8faab50f8759db245c"},
|
||||
{file = "black-25.11.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:35690a383f22dd3e468c85dc4b915217f87667ad9cce781d7b42678ce63c4170"},
|
||||
{file = "black-25.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:dae49ef7369c6caa1a1833fd5efb7c3024bb7e4499bf64833f65ad27791b1545"},
|
||||
{file = "black-25.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bd4a22a0b37401c8e492e994bce79e614f91b14d9ea911f44f36e262195fdda"},
|
||||
{file = "black-25.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:aa211411e94fdf86519996b7f5f05e71ba34835d8f0c0f03c00a26271da02664"},
|
||||
{file = "black-25.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3bb5ce32daa9ff0605d73b6f19da0b0e6c1f8f2d75594db539fdfed722f2b06"},
|
||||
{file = "black-25.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9815ccee1e55717fe9a4b924cae1646ef7f54e0f990da39a34fc7b264fcf80a2"},
|
||||
{file = "black-25.11.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92285c37b93a1698dcbc34581867b480f1ba3a7b92acf1fe0467b04d7a4da0dc"},
|
||||
{file = "black-25.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:43945853a31099c7c0ff8dface53b4de56c41294fa6783c0441a8b1d9bf668bc"},
|
||||
{file = "black-25.11.0-py3-none-any.whl", hash = "sha256:e3f562da087791e96cefcd9dda058380a442ab322a02e222add53736451f604b"},
|
||||
{file = "black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
packaging = ">=22.0"
|
||||
pathspec = ">=0.9.0"
|
||||
platformdirs = ">=2"
|
||||
pytokens = ">=0.3.0"
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.10)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.1"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"},
|
||||
{file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
groups = ["dev"]
|
||||
markers = "platform_system == \"Windows\""
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maturin"
|
||||
version = "1.10.2"
|
||||
description = "Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "maturin-1.10.2-py3-none-linux_armv6l.whl", hash = "sha256:11c73815f21a755d2129c410e6cb19dbfacbc0155bfc46c706b69930c2eb794b"},
|
||||
{file = "maturin-1.10.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7fbd997c5347649ee7987bd05a92bd5b8b07efa4ac3f8bcbf6196e07eb573d89"},
|
||||
{file = "maturin-1.10.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3ce9b2ad4fb9c341f450a6d32dc3edb409a2d582a81bc46ba55f6e3b6196b22"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:f0d1b7b5f73c8d30a7e71cd2a2189a7f0126a3a3cd8b3d6843e7e1d4db50f759"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:efcd496a3202ffe0d0489df1f83d08b91399782fb2dd545d5a1e7bf6fd81af39"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:a41ec70d99e27c05377be90f8e3c3def2a7bae4d0d9d5ea874aaf2d1da625d5c"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:07a82864352feeaf2167247c8206937ef6c6ae9533025d416b7004ade0ea601d"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:04df81ee295dcda37828bd025a4ac688ea856e3946e4cb300a8f44a448de0069"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96e1d391e4c1fa87edf2a37e4d53d5f2e5f39dd880b9d8306ac9f8eb212d23f8"},
|
||||
{file = "maturin-1.10.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a217aa7c42aa332fb8e8377eb07314e1f02cf0fe036f614aca4575121952addd"},
|
||||
{file = "maturin-1.10.2-py3-none-win32.whl", hash = "sha256:da031771d9fb6ddb1d373638ec2556feee29e4507365cd5749a2d354bcadd818"},
|
||||
{file = "maturin-1.10.2-py3-none-win_amd64.whl", hash = "sha256:da777766fd584440dc9fecd30059a94f85e4983f58b09e438ae38ee4b494024c"},
|
||||
{file = "maturin-1.10.2-py3-none-win_arm64.whl", hash = "sha256:a4c29a770ea2c76082e0afc6d4efd8ee94405588bfae00d10828f72e206c739b"},
|
||||
{file = "maturin-1.10.2.tar.gz", hash = "sha256:259292563da89850bf8f7d37aa4ddba22905214c1e180b1c8f55505dfd8c0e81"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
patchelf = ["patchelf"]
|
||||
zig = ["ziglang (>=0.10.0,<0.13.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.1.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
|
||||
{file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "25.0"
|
||||
description = "Core utilities for Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
|
||||
{file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.12.1"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
||||
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.5.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"},
|
||||
{file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"]
|
||||
type = ["mypy (>=1.18.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytokens"
|
||||
version = "0.3.0"
|
||||
description = "A Fast, spec compliant Python 3.14+ tokenizer that runs on older Pythons."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["dev"]
|
||||
files = [
|
||||
{file = "pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3"},
|
||||
{file = "pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "fdca2529430378024bd7592d1cc9a036dce731d069014afa9422296fe281758a"
|
||||
0
agents/tapo/tapo-fork/tapo-py/py.typed
Normal file
0
agents/tapo/tapo-fork/tapo-py/py.typed
Normal file
55
agents/tapo/tapo-fork/tapo-py/pyproject.toml
Normal file
55
agents/tapo/tapo-fork/tapo-py/pyproject.toml
Normal file
@@ -0,0 +1,55 @@
|
||||
[tool.poetry]
|
||||
name = "tapo"
|
||||
version = "0.8.8"
|
||||
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L535, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P110M, P115), power strips (P300, P304M, P306, P316M), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)."
|
||||
authors = ["Mihai Dinculescu <mihai.dinculescu@outlook.com>"]
|
||||
|
||||
[project]
|
||||
name = "tapo"
|
||||
version = "0.8.8"
|
||||
description = "Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L535, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P110M, P115), power strips (P300, P304M, P306, P316M), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315)."
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
authors = [{ name = "Mihai Dinculescu", email = "mihai.dinculescu@outlook.com" }]
|
||||
maintainers = [{ name = "Mihai Dinculescu", email = "mihai.dinculescu@outlook.com" }]
|
||||
keywords = ["Tapo", "TP-Link", "Smart Home", "Home Automation", "IoT"]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Topic :: Software Development :: Embedded Systems",
|
||||
"Environment :: Console",
|
||||
"Operating System :: OS Independent",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Home Automation",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
]
|
||||
requires-python = ">=3.11"
|
||||
|
||||
[project.urls]
|
||||
Changelog = 'https://github.com/mihai-dinculescu/tapo/blob/main/CHANGELOG.md'
|
||||
Funding = 'https://github.com/mihai-dinculescu'
|
||||
Homepage = 'https://github.com/mihai-dinculescu/tapo'
|
||||
Source = 'https://github.com/mihai-dinculescu/tapo'
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.11"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
maturin = ">=1.0,<2.0"
|
||||
black = ">=25.0,<26.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["maturin>=1.0,<2.0"]
|
||||
build-backend = "maturin"
|
||||
|
||||
[tool.maturin]
|
||||
python-source = "tapo-py"
|
||||
bindings = 'pyo3'
|
||||
features = ["pyo3/extension-module"]
|
||||
include = ["README.md", "CHANGELOG.md", "LICENSE", "tapo-py/tapo-py/tapo/*"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 100
|
||||
29
agents/tapo/tapo-fork/tapo-py/src/api.rs
Normal file
29
agents/tapo/tapo-fork/tapo-py/src/api.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
mod api_client;
|
||||
mod child_devices;
|
||||
mod color_light_handler;
|
||||
mod discovery;
|
||||
mod generic_device_handler;
|
||||
mod hub_handler;
|
||||
mod light_handler;
|
||||
mod plug_energy_monitoring_handler;
|
||||
mod plug_handler;
|
||||
mod power_strip_energy_monitoring_handler;
|
||||
mod power_strip_handler;
|
||||
mod py_handler_ext;
|
||||
mod rgb_light_strip_handler;
|
||||
mod rgbic_light_strip_handler;
|
||||
|
||||
pub use api_client::*;
|
||||
pub use child_devices::*;
|
||||
pub use color_light_handler::*;
|
||||
pub use discovery::*;
|
||||
pub use generic_device_handler::*;
|
||||
pub use hub_handler::*;
|
||||
pub use light_handler::*;
|
||||
pub use plug_energy_monitoring_handler::*;
|
||||
pub use plug_handler::*;
|
||||
pub use power_strip_energy_monitoring_handler::*;
|
||||
pub use power_strip_handler::*;
|
||||
pub use py_handler_ext::*;
|
||||
pub use rgb_light_strip_handler::*;
|
||||
pub use rgbic_light_strip_handler::*;
|
||||
165
agents/tapo/tapo-fork/tapo-py/src/api/api_client.rs
Normal file
165
agents/tapo/tapo-fork/tapo-py/src/api/api_client.rs
Normal file
@@ -0,0 +1,165 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use tapo::{
|
||||
ApiClient, ColorLightHandler, DeviceDiscovery, GenericDeviceHandler, HubHandler, LightHandler,
|
||||
PlugEnergyMonitoringHandler, PlugHandler, PowerStripEnergyMonitoringHandler, PowerStripHandler,
|
||||
RgbLightStripHandler, RgbicLightStripHandler,
|
||||
};
|
||||
|
||||
use crate::call_handler_constructor;
|
||||
use crate::errors::ErrorWrapper;
|
||||
|
||||
use super::{
|
||||
PyColorLightHandler, PyDeviceDiscovery, PyGenericDeviceHandler, PyHubHandler, PyLightHandler,
|
||||
PyPlugEnergyMonitoringHandler, PyPlugHandler, PyPowerStripEnergyMonitoringHandler,
|
||||
PyPowerStripHandler, PyRgbLightStripHandler, PyRgbicLightStripHandler,
|
||||
};
|
||||
|
||||
#[pyclass(name = "ApiClient")]
|
||||
pub struct PyApiClient {
|
||||
client: ApiClient,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyApiClient {
|
||||
#[new]
|
||||
#[pyo3(signature = (tapo_username, tapo_password, timeout_s=None))]
|
||||
pub fn new(
|
||||
tapo_username: String,
|
||||
tapo_password: String,
|
||||
timeout_s: Option<u64>,
|
||||
) -> Result<Self, ErrorWrapper> {
|
||||
let client = match timeout_s {
|
||||
Some(timeout_s) => ApiClient::new(tapo_username, tapo_password)
|
||||
.with_timeout(Duration::from_secs(timeout_s)),
|
||||
None => ApiClient::new(tapo_username, tapo_password),
|
||||
};
|
||||
|
||||
Ok(Self { client })
|
||||
}
|
||||
|
||||
pub async fn discover_devices(
|
||||
&self,
|
||||
target: String,
|
||||
timeout_s: u64,
|
||||
) -> Result<PyDeviceDiscovery, ErrorWrapper> {
|
||||
let discovery: DeviceDiscovery =
|
||||
call_handler_constructor!(self, tapo::ApiClient::discover_devices, target, timeout_s);
|
||||
Ok(PyDeviceDiscovery::new(discovery))
|
||||
}
|
||||
|
||||
pub async fn generic_device(&self, ip_address: String) -> PyResult<PyGenericDeviceHandler> {
|
||||
let handler: GenericDeviceHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::generic_device, ip_address);
|
||||
Ok(PyGenericDeviceHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l510(&self, ip_address: String) -> PyResult<PyLightHandler> {
|
||||
let handler: LightHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l510, ip_address);
|
||||
Ok(PyLightHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l520(&self, ip_address: String) -> PyResult<PyLightHandler> {
|
||||
let handler: LightHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l520, ip_address);
|
||||
Ok(PyLightHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l530(&self, ip_address: String) -> PyResult<PyColorLightHandler> {
|
||||
let handler: ColorLightHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l530, ip_address);
|
||||
Ok(PyColorLightHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l535(&self, ip_address: String) -> PyResult<PyColorLightHandler> {
|
||||
let handler: ColorLightHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l535, ip_address);
|
||||
Ok(PyColorLightHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l610(&self, ip_address: String) -> PyResult<PyLightHandler> {
|
||||
let handler: LightHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l610, ip_address);
|
||||
Ok(PyLightHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l630(&self, ip_address: String) -> PyResult<PyColorLightHandler> {
|
||||
let handler: ColorLightHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l630, ip_address);
|
||||
Ok(PyColorLightHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l900(&self, ip_address: String) -> PyResult<PyRgbLightStripHandler> {
|
||||
let handler: RgbLightStripHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l900, ip_address);
|
||||
Ok(PyRgbLightStripHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l920(&self, ip_address: String) -> PyResult<PyRgbicLightStripHandler> {
|
||||
let handler: RgbicLightStripHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l920, ip_address);
|
||||
Ok(PyRgbicLightStripHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn l930(&self, ip_address: String) -> PyResult<PyRgbicLightStripHandler> {
|
||||
let handler: RgbicLightStripHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::l930, ip_address);
|
||||
Ok(PyRgbicLightStripHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn p100(&self, ip_address: String) -> PyResult<PyPlugHandler> {
|
||||
let handler: PlugHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p100, ip_address);
|
||||
Ok(PyPlugHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn p105(&self, ip_address: String) -> PyResult<PyPlugHandler> {
|
||||
let handler: PlugHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p105, ip_address);
|
||||
Ok(PyPlugHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn p110(&self, ip_address: String) -> PyResult<PyPlugEnergyMonitoringHandler> {
|
||||
let handler: PlugEnergyMonitoringHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p110, ip_address);
|
||||
Ok(PyPlugEnergyMonitoringHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn p115(&self, ip_address: String) -> PyResult<PyPlugEnergyMonitoringHandler> {
|
||||
let handler: PlugEnergyMonitoringHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p115, ip_address);
|
||||
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<PyPowerStripEnergyMonitoringHandler> {
|
||||
let handler: PowerStripEnergyMonitoringHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p304, ip_address);
|
||||
Ok(PyPowerStripEnergyMonitoringHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn p306(&self, ip_address: String) -> PyResult<PyPowerStripHandler> {
|
||||
let handler: PowerStripHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p306, ip_address);
|
||||
Ok(PyPowerStripHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn p316(&self, ip_address: String) -> PyResult<PyPowerStripEnergyMonitoringHandler> {
|
||||
let handler: PowerStripEnergyMonitoringHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::p316, ip_address);
|
||||
Ok(PyPowerStripEnergyMonitoringHandler::new(handler))
|
||||
}
|
||||
|
||||
pub async fn h100(&self, ip_address: String) -> PyResult<PyHubHandler> {
|
||||
let handler: HubHandler =
|
||||
call_handler_constructor!(self, tapo::ApiClient::h100, ip_address);
|
||||
Ok(PyHubHandler::new(handler))
|
||||
}
|
||||
}
|
||||
17
agents/tapo/tapo-fork/tapo-py/src/api/child_devices.rs
Normal file
17
agents/tapo/tapo-fork/tapo-py/src/api/child_devices.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
mod ke100_handler;
|
||||
mod power_strip_plug_energy_monitoring_handler;
|
||||
mod power_strip_plug_handler;
|
||||
mod s200b_handler;
|
||||
mod t100_handler;
|
||||
mod t110_handler;
|
||||
mod t300_handler;
|
||||
mod t31x_handler;
|
||||
|
||||
pub use ke100_handler::*;
|
||||
pub use power_strip_plug_energy_monitoring_handler::*;
|
||||
pub use power_strip_plug_handler::*;
|
||||
pub use s200b_handler::*;
|
||||
pub use t31x_handler::*;
|
||||
pub use t100_handler::*;
|
||||
pub use t110_handler::*;
|
||||
pub use t300_handler::*;
|
||||
@@ -0,0 +1,101 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::KE100Handler;
|
||||
use tapo::responses::{KE100Result, TemperatureUnitKE100};
|
||||
|
||||
use crate::call_handler_method;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "KE100Handler")]
|
||||
pub struct PyKE100Handler {
|
||||
inner: Arc<KE100Handler>,
|
||||
}
|
||||
|
||||
impl PyKE100Handler {
|
||||
pub fn new(handler: KE100Handler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyKE100Handler {
|
||||
pub async fn get_device_info(&self) -> PyResult<KE100Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), KE100Handler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(handler.deref(), KE100Handler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn set_child_protection(&self, on: bool) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), KE100Handler::set_child_protection, on)
|
||||
}
|
||||
|
||||
pub async fn set_frost_protection(&self, on: bool) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), KE100Handler::set_frost_protection, on)
|
||||
}
|
||||
|
||||
pub async fn set_max_control_temperature(
|
||||
&self,
|
||||
value: u8,
|
||||
unit: TemperatureUnitKE100,
|
||||
) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
KE100Handler::set_max_control_temperature,
|
||||
value,
|
||||
unit
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_min_control_temperature(
|
||||
&self,
|
||||
value: u8,
|
||||
unit: TemperatureUnitKE100,
|
||||
) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
KE100Handler::set_min_control_temperature,
|
||||
value,
|
||||
unit
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_target_temperature(
|
||||
&self,
|
||||
value: u8,
|
||||
unit: TemperatureUnitKE100,
|
||||
) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
KE100Handler::set_target_temperature,
|
||||
value,
|
||||
unit
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_temperature_offset(
|
||||
&self,
|
||||
value: i8,
|
||||
unit: TemperatureUnitKE100,
|
||||
) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
KE100Handler::set_temperature_offset,
|
||||
value,
|
||||
unit
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use chrono::{DateTime, NaiveDate, Utc};
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::PowerStripPlugEnergyMonitoringHandler;
|
||||
use tapo::requests::{EnergyDataInterval, PowerDataInterval};
|
||||
use tapo::responses::{
|
||||
CurrentPowerResult, DeviceUsageEnergyMonitoringResult, EnergyDataResult, EnergyUsageResult,
|
||||
PowerDataResult, PowerStripPlugEnergyMonitoringResult,
|
||||
};
|
||||
|
||||
use crate::call_handler_method;
|
||||
use crate::requests::{PyEnergyDataInterval, PyPowerDataInterval};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "PowerStripPlugEnergyMonitoringHandler")]
|
||||
pub struct PyPowerStripPlugEnergyMonitoringHandler {
|
||||
inner: Arc<PowerStripPlugEnergyMonitoringHandler>,
|
||||
}
|
||||
|
||||
impl PyPowerStripPlugEnergyMonitoringHandler {
|
||||
pub fn new(handler: PowerStripPlugEnergyMonitoringHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyPowerStripPlugEnergyMonitoringHandler {
|
||||
pub async fn get_device_info(&self) -> PyResult<PowerStripPlugEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_device_info_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), PowerStripPlugEnergyMonitoringHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), PowerStripPlugEnergyMonitoringHandler::off)
|
||||
}
|
||||
|
||||
pub async fn get_current_power(&self) -> PyResult<CurrentPowerResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_current_power,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_device_usage,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_energy_usage(&self) -> PyResult<EnergyUsageResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_energy_usage,
|
||||
)
|
||||
}
|
||||
|
||||
#[pyo3(signature = (interval, start_date, end_date=None))]
|
||||
pub async fn get_energy_data(
|
||||
&self,
|
||||
interval: PyEnergyDataInterval,
|
||||
start_date: NaiveDate,
|
||||
end_date: Option<NaiveDate>,
|
||||
) -> PyResult<EnergyDataResult> {
|
||||
let interval = match interval {
|
||||
PyEnergyDataInterval::Hourly => EnergyDataInterval::Hourly {
|
||||
start_date,
|
||||
end_date: end_date.unwrap_or(start_date),
|
||||
},
|
||||
PyEnergyDataInterval::Daily => EnergyDataInterval::Daily { start_date },
|
||||
PyEnergyDataInterval::Monthly => EnergyDataInterval::Monthly { start_date },
|
||||
};
|
||||
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_energy_data,
|
||||
interval
|
||||
)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn get_power_data(
|
||||
&self,
|
||||
interval: PyPowerDataInterval,
|
||||
start_date_time: DateTime<Utc>,
|
||||
end_date_time: DateTime<Utc>,
|
||||
) -> PyResult<PowerDataResult> {
|
||||
let interval = match interval {
|
||||
PyPowerDataInterval::Every5Minutes => PowerDataInterval::Every5Minutes {
|
||||
start_date_time,
|
||||
end_date_time,
|
||||
},
|
||||
PyPowerDataInterval::Hourly => PowerDataInterval::Hourly {
|
||||
start_date_time,
|
||||
end_date_time,
|
||||
},
|
||||
};
|
||||
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.deref(),
|
||||
PowerStripPlugEnergyMonitoringHandler::get_power_data,
|
||||
interval
|
||||
)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::PowerStripPlugHandler;
|
||||
use tapo::responses::PowerStripPlugResult;
|
||||
|
||||
use crate::call_handler_method;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "PowerStripPlugHandler")]
|
||||
pub struct PyPowerStripPlugHandler {
|
||||
inner: Arc<PowerStripPlugHandler>,
|
||||
}
|
||||
|
||||
impl PyPowerStripPlugHandler {
|
||||
pub fn new(handler: PowerStripPlugHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyPowerStripPlugHandler {
|
||||
pub async fn get_device_info(&self) -> PyResult<PowerStripPlugResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), PowerStripPlugHandler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result =
|
||||
call_handler_method!(handler.deref(), PowerStripPlugHandler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), PowerStripPlugHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), PowerStripPlugHandler::off)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::S200BHandler;
|
||||
use tapo::responses::S200BResult;
|
||||
|
||||
use crate::call_handler_method;
|
||||
use crate::responses::TriggerLogsS200BResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "S200BHandler")]
|
||||
pub struct PyS200BHandler {
|
||||
inner: Arc<S200BHandler>,
|
||||
}
|
||||
|
||||
impl PyS200BHandler {
|
||||
pub fn new(handler: S200BHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyS200BHandler {
|
||||
pub async fn get_device_info(&self) -> PyResult<S200BResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), S200BHandler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(handler.deref(), S200BHandler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_trigger_logs(
|
||||
&self,
|
||||
page_size: u64,
|
||||
start_id: u64,
|
||||
) -> PyResult<TriggerLogsS200BResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
S200BHandler::get_trigger_logs,
|
||||
page_size,
|
||||
start_id
|
||||
)
|
||||
.map(|result| result.into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::{T100Handler, responses::T100Result};
|
||||
|
||||
use crate::call_handler_method;
|
||||
use crate::responses::TriggerLogsT100Result;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "T100Handler")]
|
||||
pub struct PyT100Handler {
|
||||
inner: Arc<T100Handler>,
|
||||
}
|
||||
|
||||
impl PyT100Handler {
|
||||
pub fn new(handler: T100Handler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyT100Handler {
|
||||
pub async fn get_device_info(&self) -> PyResult<T100Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), T100Handler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(handler.deref(), T100Handler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_trigger_logs(
|
||||
&self,
|
||||
page_size: u64,
|
||||
start_id: u64,
|
||||
) -> PyResult<TriggerLogsT100Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
T100Handler::get_trigger_logs,
|
||||
page_size,
|
||||
start_id
|
||||
)
|
||||
.map(|result| result.into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::T110Handler;
|
||||
use tapo::responses::T110Result;
|
||||
|
||||
use crate::call_handler_method;
|
||||
use crate::responses::TriggerLogsT110Result;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "T110Handler")]
|
||||
pub struct PyT110Handler {
|
||||
inner: Arc<T110Handler>,
|
||||
}
|
||||
|
||||
impl PyT110Handler {
|
||||
pub fn new(handler: T110Handler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyT110Handler {
|
||||
pub async fn get_device_info(&self) -> PyResult<T110Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), T110Handler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(handler.deref(), T110Handler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_trigger_logs(
|
||||
&self,
|
||||
page_size: u64,
|
||||
start_id: u64,
|
||||
) -> PyResult<TriggerLogsT110Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
T110Handler::get_trigger_logs,
|
||||
page_size,
|
||||
start_id
|
||||
)
|
||||
.map(|result| result.into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::T300Handler;
|
||||
use tapo::responses::T300Result;
|
||||
|
||||
use crate::call_handler_method;
|
||||
use crate::responses::TriggerLogsT300Result;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "T300Handler")]
|
||||
pub struct PyT300Handler {
|
||||
inner: Arc<T300Handler>,
|
||||
}
|
||||
|
||||
impl PyT300Handler {
|
||||
pub fn new(handler: T300Handler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyT300Handler {
|
||||
pub async fn get_device_info(&self) -> PyResult<T300Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), T300Handler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(handler.deref(), T300Handler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_trigger_logs(
|
||||
&self,
|
||||
page_size: u64,
|
||||
start_id: u64,
|
||||
) -> PyResult<TriggerLogsT300Result> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
T300Handler::get_trigger_logs,
|
||||
page_size,
|
||||
start_id
|
||||
)
|
||||
.map(|result| result.into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use pyo3::{prelude::*, types::PyDict};
|
||||
use tapo::T31XHandler;
|
||||
use tapo::responses::{T31XResult, TemperatureHumidityRecords};
|
||||
|
||||
use crate::call_handler_method;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "T31XHandler")]
|
||||
pub struct PyT31XHandler {
|
||||
inner: Arc<T31XHandler>,
|
||||
}
|
||||
|
||||
impl PyT31XHandler {
|
||||
pub fn new(handler: T31XHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyT31XHandler {
|
||||
pub async fn get_device_info(&self) -> PyResult<T31XResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.deref(), T31XHandler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(handler.deref(), T31XHandler::get_device_info_json)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_temperature_humidity_records(&self) -> PyResult<TemperatureHumidityRecords> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.deref(),
|
||||
T31XHandler::get_temperature_humidity_records
|
||||
)
|
||||
}
|
||||
}
|
||||
138
agents/tapo/tapo-fork/tapo-py/src/api/color_light_handler.rs
Normal file
138
agents/tapo/tapo-fork/tapo-py/src/api/color_light_handler.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::requests::Color;
|
||||
use tapo::responses::{DeviceInfoColorLightResult, DeviceUsageEnergyMonitoringResult};
|
||||
use tapo::{ColorLightHandler, DeviceManagementExt as _, HandlerExt};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::api::PyHandlerExt;
|
||||
use crate::call_handler_method;
|
||||
use crate::requests::PyColorLightSetDeviceInfoParams;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "ColorLightHandler")]
|
||||
pub struct PyColorLightHandler {
|
||||
inner: Arc<RwLock<ColorLightHandler>>,
|
||||
}
|
||||
|
||||
impl PyColorLightHandler {
|
||||
pub fn new(handler: ColorLightHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyHandlerExt for PyColorLightHandler {
|
||||
fn get_inner_handler(&self) -> Arc<RwLock<impl HandlerExt + 'static>> {
|
||||
Arc::clone(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyColorLightHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
ColorLightHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), ColorLightHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), ColorLightHandler::off)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::device_reset,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoColorLightResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::get_device_info_json,
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::get_device_usage
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set(&self) -> PyColorLightSetDeviceInfoParams {
|
||||
PyColorLightSetDeviceInfoParams::new()
|
||||
}
|
||||
|
||||
pub async fn set_brightness(&self, brightness: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::set_brightness,
|
||||
brightness
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_color(&self, color: Color) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::set_color,
|
||||
color
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_hue_saturation(&self, hue: u16, saturation: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::set_hue_saturation,
|
||||
hue,
|
||||
saturation
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_color_temperature(&self, color_temperature: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
ColorLightHandler::set_color_temperature,
|
||||
color_temperature
|
||||
)
|
||||
}
|
||||
}
|
||||
5
agents/tapo/tapo-fork/tapo-py/src/api/discovery.rs
Normal file
5
agents/tapo/tapo-fork/tapo-py/src/api/discovery.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod device_discovery;
|
||||
mod discovery_result;
|
||||
|
||||
pub use device_discovery::*;
|
||||
pub use discovery_result::*;
|
||||
@@ -0,0 +1,87 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use tapo::{DeviceDiscovery, StreamExt as _};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use super::{PyMaybeDiscoveryResult, convert_result_to_maybe_py};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "DeviceDiscovery")]
|
||||
pub struct PyDeviceDiscovery {
|
||||
pub inner: Arc<Mutex<DeviceDiscovery>>,
|
||||
}
|
||||
|
||||
impl PyDeviceDiscovery {
|
||||
pub fn new(inner: DeviceDiscovery) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(inner)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyDeviceDiscovery {
|
||||
fn __iter__(slf: PyRef<'_, Self>) -> PyResult<PyDeviceDiscoveryIter> {
|
||||
Ok(PyDeviceDiscoveryIter {
|
||||
inner: (*slf).inner.clone(),
|
||||
})
|
||||
}
|
||||
fn __aiter__(slf: PyRef<'_, Self>) -> PyResult<PyDeviceDiscoveryIter> {
|
||||
Ok(PyDeviceDiscoveryIter {
|
||||
inner: (*slf).inner.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(name = "DeviceDiscoveryIter")]
|
||||
pub struct PyDeviceDiscoveryIter {
|
||||
pub inner: Arc<Mutex<DeviceDiscovery>>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyDeviceDiscoveryIter {
|
||||
fn __iter__(slf: Py<Self>) -> Py<Self> {
|
||||
slf
|
||||
}
|
||||
|
||||
fn __aiter__(slf: Py<Self>) -> Py<Self> {
|
||||
slf
|
||||
}
|
||||
|
||||
fn __next__(slf: PyRefMut<'_, Self>) -> PyResult<Option<PyMaybeDiscoveryResult>> {
|
||||
let inner = (*slf).inner.clone();
|
||||
|
||||
let result = Python::attach(|py| {
|
||||
py.detach(|| {
|
||||
crate::runtime::tokio().block_on(async {
|
||||
let mut guard = inner.lock().await;
|
||||
guard.next().await
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
if let Some(result) = result {
|
||||
let result_maybe_py = convert_result_to_maybe_py(result)?;
|
||||
Ok(Some(result_maybe_py))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn __anext__<'py>(slf: PyRefMut<'_, Self>, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
|
||||
let inner = (*slf).inner.clone();
|
||||
|
||||
pyo3_async_runtimes::tokio::future_into_py(py, async move {
|
||||
let mut guard = inner.lock().await;
|
||||
let result = guard.next().await;
|
||||
|
||||
match result {
|
||||
Some(result) => convert_result_to_maybe_py(result),
|
||||
None => Err(PyErr::new::<pyo3::exceptions::PyStopAsyncIteration, _>(
|
||||
"No more devices found",
|
||||
)),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
use pyo3::prelude::*;
|
||||
use tapo::responses::{
|
||||
DeviceInfoColorLightResult, DeviceInfoGenericResult, DeviceInfoHubResult,
|
||||
DeviceInfoLightResult, DeviceInfoPlugEnergyMonitoringResult, DeviceInfoPlugResult,
|
||||
DeviceInfoPowerStripResult, DeviceInfoRgbLightStripResult, DeviceInfoRgbicLightStripResult,
|
||||
};
|
||||
use tapo::{DiscoveryResult, Error};
|
||||
|
||||
use crate::api::{
|
||||
PyColorLightHandler, PyGenericDeviceHandler, PyHubHandler, PyLightHandler,
|
||||
PyPlugEnergyMonitoringHandler, PyPlugHandler, PyPowerStripEnergyMonitoringHandler,
|
||||
PyPowerStripHandler, PyRgbLightStripHandler, PyRgbicLightStripHandler,
|
||||
};
|
||||
use crate::errors::ErrorWrapper;
|
||||
|
||||
#[pyclass(name = "DiscoveryResult")]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum PyDiscoveryResult {
|
||||
GenericDevice {
|
||||
device_info: DeviceInfoGenericResult,
|
||||
handler: PyGenericDeviceHandler,
|
||||
},
|
||||
Light {
|
||||
device_info: DeviceInfoLightResult,
|
||||
handler: PyLightHandler,
|
||||
},
|
||||
ColorLight {
|
||||
device_info: DeviceInfoColorLightResult,
|
||||
handler: PyColorLightHandler,
|
||||
},
|
||||
RgbLightStrip {
|
||||
device_info: DeviceInfoRgbLightStripResult,
|
||||
handler: PyRgbLightStripHandler,
|
||||
},
|
||||
RgbicLightStrip {
|
||||
device_info: DeviceInfoRgbicLightStripResult,
|
||||
handler: PyRgbicLightStripHandler,
|
||||
},
|
||||
Plug {
|
||||
device_info: DeviceInfoPlugResult,
|
||||
handler: PyPlugHandler,
|
||||
},
|
||||
PlugEnergyMonitoring {
|
||||
device_info: DeviceInfoPlugEnergyMonitoringResult,
|
||||
handler: PyPlugEnergyMonitoringHandler,
|
||||
},
|
||||
PowerStrip {
|
||||
device_info: DeviceInfoPowerStripResult,
|
||||
handler: PyPowerStripHandler,
|
||||
},
|
||||
PowerStripEnergyMonitoring {
|
||||
device_info: DeviceInfoPowerStripResult,
|
||||
handler: PyPowerStripEnergyMonitoringHandler,
|
||||
},
|
||||
Hub {
|
||||
device_info: DeviceInfoHubResult,
|
||||
handler: PyHubHandler,
|
||||
},
|
||||
}
|
||||
|
||||
#[pyclass(name = "MaybeDiscoveryResult")]
|
||||
pub struct PyMaybeDiscoveryResult {
|
||||
result: Option<PyDiscoveryResult>,
|
||||
exception: Option<ErrorWrapper>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyMaybeDiscoveryResult {
|
||||
pub fn get(mut slf: PyRefMut<'_, Self>) -> PyResult<PyDiscoveryResult> {
|
||||
if let Some(result) = slf.result.take() {
|
||||
Ok(result)
|
||||
} else if let Some(exception) = slf.exception.take() {
|
||||
Err(exception.into())
|
||||
} else {
|
||||
Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
|
||||
"No result or exception available. `get` can only be called once.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_result_to_maybe_py(
|
||||
result: Result<DiscoveryResult, Error>,
|
||||
) -> PyResult<PyMaybeDiscoveryResult> {
|
||||
match result {
|
||||
Ok(result) => Ok(PyMaybeDiscoveryResult {
|
||||
result: Some(convert_result_to_py(result)),
|
||||
exception: None,
|
||||
}),
|
||||
Err(e) => Ok(PyMaybeDiscoveryResult {
|
||||
result: None,
|
||||
exception: Some(ErrorWrapper::from(e)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_result_to_py(result: DiscoveryResult) -> PyDiscoveryResult {
|
||||
match result {
|
||||
DiscoveryResult::GenericDevice {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::GenericDevice {
|
||||
device_info: *device_info,
|
||||
handler: PyGenericDeviceHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::Light {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::Light {
|
||||
device_info: *device_info,
|
||||
handler: PyLightHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::ColorLight {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::ColorLight {
|
||||
device_info: *device_info,
|
||||
handler: PyColorLightHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::RgbLightStrip {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::RgbLightStrip {
|
||||
device_info: *device_info,
|
||||
handler: PyRgbLightStripHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::RgbicLightStrip {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::RgbicLightStrip {
|
||||
device_info: *device_info,
|
||||
handler: PyRgbicLightStripHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::Plug {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::Plug {
|
||||
device_info: *device_info,
|
||||
handler: PyPlugHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::PlugEnergyMonitoring {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::PlugEnergyMonitoring {
|
||||
device_info: *device_info,
|
||||
handler: PyPlugEnergyMonitoringHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::PowerStrip {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::PowerStrip {
|
||||
device_info: *device_info,
|
||||
handler: PyPowerStripHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::PowerStripEnergyMonitoring {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::PowerStripEnergyMonitoring {
|
||||
device_info: *device_info,
|
||||
handler: PyPowerStripEnergyMonitoringHandler::new(handler),
|
||||
},
|
||||
DiscoveryResult::Hub {
|
||||
device_info,
|
||||
handler,
|
||||
} => PyDiscoveryResult::Hub {
|
||||
device_info: *device_info,
|
||||
handler: PyHubHandler::new(handler),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::GenericDeviceHandler;
|
||||
use tapo::responses::DeviceInfoGenericResult;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::call_handler_method;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "GenericDeviceHandler")]
|
||||
pub struct PyGenericDeviceHandler {
|
||||
inner: Arc<RwLock<GenericDeviceHandler>>,
|
||||
}
|
||||
|
||||
impl PyGenericDeviceHandler {
|
||||
pub fn new(handler: GenericDeviceHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyGenericDeviceHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
GenericDeviceHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), GenericDeviceHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), GenericDeviceHandler::off)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoGenericResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
GenericDeviceHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
GenericDeviceHandler::get_device_info_json,
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
}
|
||||
291
agents/tapo/tapo-fork/tapo-py/src/api/hub_handler.rs
Normal file
291
agents/tapo/tapo-fork/tapo-py/src/api/hub_handler.rs
Normal file
@@ -0,0 +1,291 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyList};
|
||||
use tapo::requests::{AlarmDuration, AlarmRingtone, AlarmVolume};
|
||||
use tapo::responses::{ChildDeviceHubResult, DeviceInfoHubResult};
|
||||
use tapo::{DeviceManagementExt as _, Error, HubDevice, HubHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::api::{
|
||||
PyKE100Handler, PyS200BHandler, PyT31XHandler, PyT100Handler, PyT110Handler, PyT300Handler,
|
||||
};
|
||||
use crate::call_handler_method;
|
||||
use crate::errors::ErrorWrapper;
|
||||
use crate::requests::PyAlarmDuration;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "HubHandler")]
|
||||
pub struct PyHubHandler {
|
||||
inner: Arc<RwLock<HubHandler>>,
|
||||
}
|
||||
|
||||
impl PyHubHandler {
|
||||
pub fn new(handler: HubHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_identifier(
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<HubDevice> {
|
||||
match (device_id, nickname) {
|
||||
(Some(device_id), _) => Ok(HubDevice::ByDeviceId(device_id)),
|
||||
(None, Some(nickname)) => Ok(HubDevice::ByNickname(nickname)),
|
||||
_ => Err(Into::<ErrorWrapper>::into(Error::Validation {
|
||||
field: "identifier".to_string(),
|
||||
message: "Either a device_id or nickname must be provided".to_string(),
|
||||
})
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyHubHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
HubHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
HubHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::device_reset)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoHubResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
HubHandler::get_device_info_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_child_device_list(&self) -> PyResult<Py<PyList>> {
|
||||
let handler = self.inner.clone();
|
||||
let children = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
HubHandler::get_child_device_list
|
||||
)?;
|
||||
|
||||
Python::attach(|py| {
|
||||
let results = PyList::empty(py);
|
||||
|
||||
for child in children {
|
||||
match child {
|
||||
ChildDeviceHubResult::KE100(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
ChildDeviceHubResult::S200B(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
ChildDeviceHubResult::T100(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
ChildDeviceHubResult::T110(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
ChildDeviceHubResult::T300(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
ChildDeviceHubResult::T310(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
ChildDeviceHubResult::T315(device) => {
|
||||
results.append(device.into_pyobject(py)?)?;
|
||||
}
|
||||
_ => {
|
||||
results.append(py.None())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results.into())
|
||||
})
|
||||
}
|
||||
|
||||
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,
|
||||
start_index
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_child_device_component_list_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
HubHandler::get_child_device_component_list_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_supported_ringtone_list(&self) -> PyResult<Vec<String>> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
HubHandler::get_supported_ringtone_list
|
||||
)
|
||||
}
|
||||
|
||||
#[pyo3(signature = (ringtone, volume, duration, seconds=None))]
|
||||
pub async fn play_alarm(
|
||||
&self,
|
||||
ringtone: AlarmRingtone,
|
||||
volume: AlarmVolume,
|
||||
duration: PyAlarmDuration,
|
||||
seconds: Option<u32>,
|
||||
) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
|
||||
let duration = match duration {
|
||||
PyAlarmDuration::Continuous => AlarmDuration::Continuous,
|
||||
PyAlarmDuration::Once => AlarmDuration::Once,
|
||||
PyAlarmDuration::Seconds => {
|
||||
if let Some(seconds) = seconds {
|
||||
AlarmDuration::Seconds(seconds)
|
||||
} else {
|
||||
return Err(Into::<ErrorWrapper>::into(Error::Validation {
|
||||
field: "seconds".to_string(),
|
||||
message:
|
||||
"A value must be provided for seconds when duration = AlarmDuration.Seconds"
|
||||
.to_string(),
|
||||
})
|
||||
.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
HubHandler::play_alarm,
|
||||
ringtone,
|
||||
volume,
|
||||
duration
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn stop_alarm(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::stop_alarm)
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn ke100(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyKE100Handler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyHubHandler::parse_identifier(device_id, nickname)?;
|
||||
|
||||
let child_handler =
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::ke100, identifier)?;
|
||||
Ok(PyKE100Handler::new(child_handler))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn s200b(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyS200BHandler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyHubHandler::parse_identifier(device_id, nickname)?;
|
||||
|
||||
let child_handler =
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::s200b, identifier)?;
|
||||
Ok(PyS200BHandler::new(child_handler))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn t100(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyT100Handler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyHubHandler::parse_identifier(device_id, nickname)?;
|
||||
|
||||
let child_handler =
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::t100, identifier)?;
|
||||
Ok(PyT100Handler::new(child_handler))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn t110(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyT110Handler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyHubHandler::parse_identifier(device_id, nickname)?;
|
||||
|
||||
let child_handler =
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::t110, identifier)?;
|
||||
Ok(PyT110Handler::new(child_handler))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn t300(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyT300Handler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyHubHandler::parse_identifier(device_id, nickname)?;
|
||||
|
||||
let child_handler =
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::t300, identifier)?;
|
||||
Ok(PyT300Handler::new(child_handler))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn t310(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyT31XHandler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyHubHandler::parse_identifier(device_id, nickname)?;
|
||||
|
||||
let child_handler =
|
||||
call_handler_method!(handler.read().await.deref(), HubHandler::t310, identifier)?;
|
||||
Ok(PyT31XHandler::new(child_handler))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None))]
|
||||
pub async fn t315(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
) -> PyResult<PyT31XHandler> {
|
||||
self.t310(device_id, nickname).await
|
||||
}
|
||||
}
|
||||
88
agents/tapo/tapo-fork/tapo-py/src/api/light_handler.rs
Normal file
88
agents/tapo/tapo-fork/tapo-py/src/api/light_handler.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::responses::{DeviceInfoLightResult, DeviceUsageEnergyMonitoringResult};
|
||||
use tapo::{DeviceManagementExt as _, LightHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::call_handler_method;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "LightHandler")]
|
||||
pub struct PyLightHandler {
|
||||
inner: Arc<RwLock<LightHandler>>,
|
||||
}
|
||||
|
||||
impl PyLightHandler {
|
||||
pub fn new(handler: LightHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyLightHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
LightHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), LightHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), LightHandler::off)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
LightHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), LightHandler::device_reset)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoLightResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), LightHandler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
LightHandler::get_device_info_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), LightHandler::get_device_usage)
|
||||
}
|
||||
|
||||
pub async fn set_brightness(&self, brightness: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
LightHandler::set_brightness,
|
||||
brightness
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use chrono::{DateTime, NaiveDate, Utc};
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::requests::{EnergyDataInterval, PowerDataInterval};
|
||||
use tapo::responses::{
|
||||
CurrentPowerResult, DeviceInfoPlugEnergyMonitoringResult, DeviceUsageEnergyMonitoringResult,
|
||||
EnergyDataResult, EnergyUsageResult, PowerDataResult,
|
||||
};
|
||||
use tapo::{DeviceManagementExt as _, PlugEnergyMonitoringHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::call_handler_method;
|
||||
use crate::requests::{PyEnergyDataInterval, PyPowerDataInterval};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "PlugEnergyMonitoringHandler")]
|
||||
pub struct PyPlugEnergyMonitoringHandler {
|
||||
inner: Arc<RwLock<PlugEnergyMonitoringHandler>>,
|
||||
}
|
||||
|
||||
impl PyPlugEnergyMonitoringHandler {
|
||||
pub fn new(handler: PlugEnergyMonitoringHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyPlugEnergyMonitoringHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
PlugEnergyMonitoringHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::on
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::off
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::device_reset,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoPlugEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_device_info,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_device_info_json,
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_current_power(&self) -> PyResult<CurrentPowerResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_current_power,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_device_usage,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_energy_usage(&self) -> PyResult<EnergyUsageResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_energy_usage,
|
||||
)
|
||||
}
|
||||
|
||||
#[pyo3(signature = (interval, start_date, end_date=None))]
|
||||
pub async fn get_energy_data(
|
||||
&self,
|
||||
interval: PyEnergyDataInterval,
|
||||
start_date: NaiveDate,
|
||||
end_date: Option<NaiveDate>,
|
||||
) -> PyResult<EnergyDataResult> {
|
||||
let interval = match interval {
|
||||
PyEnergyDataInterval::Hourly => EnergyDataInterval::Hourly {
|
||||
start_date,
|
||||
end_date: end_date.unwrap_or(start_date),
|
||||
},
|
||||
PyEnergyDataInterval::Daily => EnergyDataInterval::Daily { start_date },
|
||||
PyEnergyDataInterval::Monthly => EnergyDataInterval::Monthly { start_date },
|
||||
};
|
||||
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_energy_data,
|
||||
interval
|
||||
)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn get_power_data(
|
||||
&self,
|
||||
interval: PyPowerDataInterval,
|
||||
start_date_time: DateTime<Utc>,
|
||||
end_date_time: DateTime<Utc>,
|
||||
) -> PyResult<PowerDataResult> {
|
||||
let interval = match interval {
|
||||
PyPowerDataInterval::Every5Minutes => PowerDataInterval::Every5Minutes {
|
||||
start_date_time,
|
||||
end_date_time,
|
||||
},
|
||||
PyPowerDataInterval::Hourly => PowerDataInterval::Hourly {
|
||||
start_date_time,
|
||||
end_date_time,
|
||||
},
|
||||
};
|
||||
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugEnergyMonitoringHandler::get_power_data,
|
||||
interval
|
||||
)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
79
agents/tapo/tapo-fork/tapo-py/src/api/plug_handler.rs
Normal file
79
agents/tapo/tapo-fork/tapo-py/src/api/plug_handler.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::responses::{DeviceInfoPlugResult, DeviceUsageResult};
|
||||
use tapo::{DeviceManagementExt as _, PlugHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::call_handler_method;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "PlugHandler")]
|
||||
pub struct PyPlugHandler {
|
||||
inner: Arc<RwLock<PlugHandler>>,
|
||||
}
|
||||
|
||||
impl PyPlugHandler {
|
||||
pub fn new(handler: PlugHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyPlugHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
PlugHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), PlugHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), PlugHandler::off)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), PlugHandler::device_reset)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoPlugResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), PlugHandler::get_device_info)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PlugHandler::get_device_info_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), PlugHandler::get_device_usage)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyList};
|
||||
use tapo::responses::DeviceInfoPowerStripResult;
|
||||
use tapo::{DeviceManagementExt as _, Error, Plug, PowerStripEnergyMonitoringHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::api::PyPowerStripPlugEnergyMonitoringHandler;
|
||||
use crate::call_handler_method;
|
||||
use crate::errors::ErrorWrapper;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "PowerStripEnergyMonitoringHandler")]
|
||||
pub struct PyPowerStripEnergyMonitoringHandler {
|
||||
inner: Arc<RwLock<PowerStripEnergyMonitoringHandler>>,
|
||||
}
|
||||
|
||||
impl PyPowerStripEnergyMonitoringHandler {
|
||||
pub fn new(handler: PowerStripEnergyMonitoringHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_identifier(
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
position: Option<u8>,
|
||||
) -> PyResult<Plug> {
|
||||
match (device_id, nickname, position) {
|
||||
(Some(device_id), _, _) => Ok(Plug::ByDeviceId(device_id)),
|
||||
(None, Some(nickname), _) => Ok(Plug::ByNickname(nickname)),
|
||||
(None, None, Some(position)) => Ok(Plug::ByPosition(position)),
|
||||
_ => Err(Into::<ErrorWrapper>::into(Error::Validation {
|
||||
field: "identifier".to_string(),
|
||||
message: "Either a device_id, nickname, or position must be provided".to_string(),
|
||||
})
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyPowerStripEnergyMonitoringHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
PowerStripEnergyMonitoringHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::device_reset,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoPowerStripResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::get_device_info_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_child_device_list(&self) -> PyResult<Py<PyList>> {
|
||||
let handler = self.inner.clone();
|
||||
let children = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::get_child_device_list
|
||||
)?;
|
||||
|
||||
Python::attach(|py| {
|
||||
let results = PyList::empty(py);
|
||||
|
||||
for child in children {
|
||||
results.append(child.into_pyobject(py)?)?;
|
||||
}
|
||||
|
||||
Ok(results.into())
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_child_device_list_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::get_child_device_list_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_child_device_component_list_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::get_child_device_component_list_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None, position=None))]
|
||||
pub async fn plug(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
position: Option<u8>,
|
||||
) -> PyResult<PyPowerStripPlugEnergyMonitoringHandler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier =
|
||||
PyPowerStripEnergyMonitoringHandler::parse_identifier(device_id, nickname, position)?;
|
||||
|
||||
let child_handler = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripEnergyMonitoringHandler::plug,
|
||||
identifier
|
||||
)?;
|
||||
Ok(PyPowerStripPlugEnergyMonitoringHandler::new(child_handler))
|
||||
}
|
||||
}
|
||||
143
agents/tapo/tapo-fork/tapo-py/src/api/power_strip_handler.rs
Normal file
143
agents/tapo/tapo-fork/tapo-py/src/api/power_strip_handler.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyList};
|
||||
use tapo::responses::DeviceInfoPowerStripResult;
|
||||
use tapo::{DeviceManagementExt as _, Error, Plug, PowerStripHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::api::PyPowerStripPlugHandler;
|
||||
use crate::call_handler_method;
|
||||
use crate::errors::ErrorWrapper;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "PowerStripHandler")]
|
||||
pub struct PyPowerStripHandler {
|
||||
inner: Arc<RwLock<PowerStripHandler>>,
|
||||
}
|
||||
|
||||
impl PyPowerStripHandler {
|
||||
pub fn new(handler: PowerStripHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_identifier(
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
position: Option<u8>,
|
||||
) -> PyResult<Plug> {
|
||||
match (device_id, nickname, position) {
|
||||
(Some(device_id), _, _) => Ok(Plug::ByDeviceId(device_id)),
|
||||
(None, Some(nickname), _) => Ok(Plug::ByNickname(nickname)),
|
||||
(None, None, Some(position)) => Ok(Plug::ByPosition(position)),
|
||||
_ => Err(Into::<ErrorWrapper>::into(Error::Validation {
|
||||
field: "identifier".to_string(),
|
||||
message: "Either a device_id, nickname, or position must be provided".to_string(),
|
||||
})
|
||||
.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyPowerStripHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
PowerStripHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::device_reset,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoPowerStripResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::get_device_info_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_child_device_list(&self) -> PyResult<Py<PyList>> {
|
||||
let handler = self.inner.clone();
|
||||
let children = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::get_child_device_list
|
||||
)?;
|
||||
|
||||
Python::attach(|py| {
|
||||
let results = PyList::empty(py);
|
||||
|
||||
for child in children {
|
||||
results.append(child.into_pyobject(py)?)?;
|
||||
}
|
||||
|
||||
Ok(results.into())
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_child_device_list_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::get_child_device_list_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_child_device_component_list_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::get_child_device_component_list_json
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
#[pyo3(signature = (device_id=None, nickname=None, position=None))]
|
||||
pub async fn plug(
|
||||
&self,
|
||||
device_id: Option<String>,
|
||||
nickname: Option<String>,
|
||||
position: Option<u8>,
|
||||
) -> PyResult<PyPowerStripPlugHandler> {
|
||||
let handler = self.inner.clone();
|
||||
let identifier = PyPowerStripHandler::parse_identifier(device_id, nickname, position)?;
|
||||
|
||||
let child_handler = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
PowerStripHandler::plug,
|
||||
identifier
|
||||
)?;
|
||||
Ok(PyPowerStripPlugHandler::new(child_handler))
|
||||
}
|
||||
}
|
||||
8
agents/tapo/tapo-fork/tapo-py/src/api/py_handler_ext.rs
Normal file
8
agents/tapo/tapo-fork/tapo-py/src/api/py_handler_ext.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tapo::HandlerExt;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub trait PyHandlerExt: Send + Sync + Sized {
|
||||
fn get_inner_handler(&self) -> Arc<RwLock<impl HandlerExt + 'static>>;
|
||||
}
|
||||
138
agents/tapo/tapo-fork/tapo-py/src/api/rgb_light_strip_handler.rs
Normal file
138
agents/tapo/tapo-fork/tapo-py/src/api/rgb_light_strip_handler.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::requests::Color;
|
||||
use tapo::responses::{DeviceInfoRgbLightStripResult, DeviceUsageEnergyMonitoringResult};
|
||||
use tapo::{DeviceManagementExt as _, HandlerExt, RgbLightStripHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::api::PyHandlerExt;
|
||||
use crate::call_handler_method;
|
||||
use crate::requests::PyColorLightSetDeviceInfoParams;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "RgbLightStripHandler")]
|
||||
pub struct PyRgbLightStripHandler {
|
||||
pub inner: Arc<RwLock<RgbLightStripHandler>>,
|
||||
}
|
||||
|
||||
impl PyRgbLightStripHandler {
|
||||
pub fn new(handler: RgbLightStripHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyHandlerExt for PyRgbLightStripHandler {
|
||||
fn get_inner_handler(&self) -> Arc<RwLock<impl HandlerExt + 'static>> {
|
||||
Arc::clone(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyRgbLightStripHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
RgbLightStripHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), RgbLightStripHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), RgbLightStripHandler::off)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::device_reset,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoRgbLightStripResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::get_device_info_json,
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::get_device_usage
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set(&self) -> PyColorLightSetDeviceInfoParams {
|
||||
PyColorLightSetDeviceInfoParams::new()
|
||||
}
|
||||
|
||||
pub async fn set_brightness(&self, brightness: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::set_brightness,
|
||||
brightness
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_color(&self, color: Color) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::set_color,
|
||||
color
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_hue_saturation(&self, hue: u16, saturation: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::set_hue_saturation,
|
||||
hue,
|
||||
saturation
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_color_temperature(&self, color_temperature: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbLightStripHandler::set_color_temperature,
|
||||
color_temperature
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use pyo3::exceptions::PyTypeError;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyDict;
|
||||
use tapo::requests::{Color, LightingEffect, LightingEffectPreset};
|
||||
use tapo::responses::{DeviceInfoRgbicLightStripResult, DeviceUsageEnergyMonitoringResult};
|
||||
use tapo::{DeviceManagementExt as _, HandlerExt, RgbicLightStripHandler};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::api::PyHandlerExt;
|
||||
use crate::call_handler_method;
|
||||
use crate::requests::{PyColorLightSetDeviceInfoParams, PyLightingEffect};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "RgbicLightStripHandler")]
|
||||
pub struct PyRgbicLightStripHandler {
|
||||
pub inner: Arc<RwLock<RgbicLightStripHandler>>,
|
||||
}
|
||||
|
||||
impl PyRgbicLightStripHandler {
|
||||
pub fn new(handler: RgbicLightStripHandler) -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(handler)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyHandlerExt for PyRgbicLightStripHandler {
|
||||
fn get_inner_handler(&self) -> Arc<RwLock<impl HandlerExt + 'static>> {
|
||||
Arc::clone(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyRgbicLightStripHandler {
|
||||
pub async fn refresh_session(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.write().await.deref_mut(),
|
||||
RgbicLightStripHandler::refresh_session,
|
||||
discard_result
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn on(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), RgbicLightStripHandler::on)
|
||||
}
|
||||
|
||||
pub async fn off(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(handler.read().await.deref(), RgbicLightStripHandler::off)
|
||||
}
|
||||
|
||||
pub async fn device_reboot(&self, delay_s: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::device_reboot,
|
||||
delay_s
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn device_reset(&self) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::device_reset,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info(&self) -> PyResult<DeviceInfoRgbicLightStripResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::get_device_info
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn get_device_info_json(&self) -> PyResult<Py<PyDict>> {
|
||||
let handler = self.inner.clone();
|
||||
let result = call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::get_device_info_json,
|
||||
)?;
|
||||
Python::attach(|py| tapo::python::serde_object_to_py_dict(py, &result))
|
||||
}
|
||||
|
||||
pub async fn get_device_usage(&self) -> PyResult<DeviceUsageEnergyMonitoringResult> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::get_device_usage
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set(&self) -> PyColorLightSetDeviceInfoParams {
|
||||
PyColorLightSetDeviceInfoParams::new()
|
||||
}
|
||||
|
||||
pub async fn set_brightness(&self, brightness: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::set_brightness,
|
||||
brightness
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_color(&self, color: Color) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::set_color,
|
||||
color
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_hue_saturation(&self, hue: u16, saturation: u8) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::set_hue_saturation,
|
||||
hue,
|
||||
saturation
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_color_temperature(&self, color_temperature: u16) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::set_color_temperature,
|
||||
color_temperature
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn set_lighting_effect(&self, lighting_effect: Py<PyAny>) -> PyResult<()> {
|
||||
let handler = self.inner.clone();
|
||||
let lighting_effect = map_lighting_effect(lighting_effect)?;
|
||||
call_handler_method!(
|
||||
handler.read().await.deref(),
|
||||
RgbicLightStripHandler::set_lighting_effect,
|
||||
lighting_effect
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn map_lighting_effect(lighting_effect: Py<PyAny>) -> PyResult<LightingEffect> {
|
||||
if let Some(lighting_effect) =
|
||||
Python::attach(|py| lighting_effect.extract::<LightingEffectPreset>(py).ok())
|
||||
{
|
||||
return Ok(lighting_effect.into());
|
||||
}
|
||||
|
||||
if let Some(lighting_effect) =
|
||||
Python::attach(|py| lighting_effect.extract::<PyLightingEffect>(py).ok())
|
||||
{
|
||||
return Ok(lighting_effect.into());
|
||||
}
|
||||
|
||||
Err(PyErr::new::<PyTypeError, _>(
|
||||
"Invalid lighting effect type. Must be one of `LightingEffect` or `LightingEffectPreset`",
|
||||
))
|
||||
}
|
||||
23
agents/tapo/tapo-fork/tapo-py/src/errors.rs
Normal file
23
agents/tapo/tapo-fork/tapo-py/src/errors.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use pyo3::PyErr;
|
||||
use pyo3::exceptions::PyException;
|
||||
use tapo::Error;
|
||||
|
||||
pub struct ErrorWrapper(pub Error);
|
||||
|
||||
impl From<Error> for ErrorWrapper {
|
||||
fn from(err: Error) -> Self {
|
||||
Self(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for ErrorWrapper {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
Self(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorWrapper> for PyErr {
|
||||
fn from(err: ErrorWrapper) -> PyErr {
|
||||
PyException::new_err(format!("{:?}", err.0))
|
||||
}
|
||||
}
|
||||
209
agents/tapo/tapo-fork/tapo-py/src/lib.rs
Normal file
209
agents/tapo/tapo-fork/tapo-py/src/lib.rs
Normal file
@@ -0,0 +1,209 @@
|
||||
mod api;
|
||||
mod errors;
|
||||
mod requests;
|
||||
mod responses;
|
||||
mod runtime;
|
||||
|
||||
use log::LevelFilter;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3_log::{Caching, Logger};
|
||||
|
||||
use tapo::requests::{AlarmRingtone, AlarmVolume, Color, LightingEffectPreset, LightingEffectType};
|
||||
use tapo::responses::{
|
||||
AutoOffStatus, ColorLightState, CurrentPowerResult, DefaultBrightnessState,
|
||||
DefaultColorLightState, DefaultLightState, DefaultPlugState, DefaultPowerType,
|
||||
DefaultRgbLightStripState, DefaultRgbicLightStripState, DefaultStateType,
|
||||
DeviceInfoColorLightResult, DeviceInfoGenericResult, DeviceInfoHubResult,
|
||||
DeviceInfoLightResult, DeviceInfoPlugEnergyMonitoringResult, DeviceInfoPlugResult,
|
||||
DeviceInfoPowerStripResult, DeviceInfoRgbLightStripResult, DeviceInfoRgbicLightStripResult,
|
||||
DeviceUsageEnergyMonitoringResult, DeviceUsageResult, EnergyDataIntervalResult,
|
||||
EnergyDataResult, EnergyUsageResult, KE100Result, OvercurrentStatus, OverheatStatus, PlugState,
|
||||
PowerDataIntervalResult, PowerDataResult, PowerProtectionStatus,
|
||||
PowerStripPlugEnergyMonitoringResult, PowerStripPlugResult, RgbLightStripState,
|
||||
RgbicLightStripState, S200BLog, S200BResult, S200BRotationParams, Status, T31XResult, T100Log,
|
||||
T100Result, T110Log, T110Result, T300Log, T300Result, TemperatureHumidityRecord,
|
||||
TemperatureHumidityRecords, TemperatureUnit, TemperatureUnitKE100, UsageByPeriodResult,
|
||||
WaterLeakStatus,
|
||||
};
|
||||
|
||||
use api::{
|
||||
PyApiClient, PyColorLightHandler, PyDeviceDiscovery, PyDeviceDiscoveryIter, PyDiscoveryResult,
|
||||
PyGenericDeviceHandler, PyHubHandler, PyKE100Handler, PyLightHandler, PyMaybeDiscoveryResult,
|
||||
PyPlugEnergyMonitoringHandler, PyPlugHandler, PyPowerStripEnergyMonitoringHandler,
|
||||
PyPowerStripHandler, PyPowerStripPlugEnergyMonitoringHandler, PyPowerStripPlugHandler,
|
||||
PyRgbLightStripHandler, PyRgbicLightStripHandler, PyT31XHandler, PyT100Handler, PyT110Handler,
|
||||
PyT300Handler,
|
||||
};
|
||||
use requests::{
|
||||
PyAlarmDuration, PyColorLightSetDeviceInfoParams, PyEnergyDataInterval, PyLightingEffect,
|
||||
PyPowerDataInterval,
|
||||
};
|
||||
use responses::{
|
||||
TriggerLogsS200BResult, TriggerLogsT100Result, TriggerLogsT110Result, TriggerLogsT300Result,
|
||||
};
|
||||
|
||||
#[pymodule]
|
||||
#[pyo3(name = "tapo")]
|
||||
fn tapo_py(py: Python, module: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
Logger::new(py, Caching::LoggersAndLevels)?
|
||||
.filter(LevelFilter::Trace)
|
||||
.install()
|
||||
.expect("Failed to install the logger");
|
||||
|
||||
let requests = PyModule::new(py, "tapo.requests")?;
|
||||
let responses = PyModule::new(py, "tapo.responses")?;
|
||||
|
||||
register_handlers(module)?;
|
||||
register_requests(&requests)?;
|
||||
register_responses(&responses)?;
|
||||
register_responses_hub(&responses)?;
|
||||
register_responses_power_strip(&responses)?;
|
||||
|
||||
module.add_submodule(&requests)?;
|
||||
module.add_submodule(&responses)?;
|
||||
|
||||
let sys = py.import("sys")?;
|
||||
let modules = sys.getattr("modules")?;
|
||||
modules.set_item("tapo.requests", requests)?;
|
||||
modules.set_item("tapo.responses", responses)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_requests(module: &Bound<'_, PyModule>) -> Result<(), PyErr> {
|
||||
module.add_class::<Color>()?;
|
||||
module.add_class::<PyLightingEffect>()?;
|
||||
module.add_class::<LightingEffectPreset>()?;
|
||||
module.add_class::<LightingEffectType>()?;
|
||||
module.add_class::<PyColorLightSetDeviceInfoParams>()?;
|
||||
module.add_class::<PyEnergyDataInterval>()?;
|
||||
module.add_class::<PyPowerDataInterval>()?;
|
||||
|
||||
// hub requests
|
||||
module.add_class::<AlarmRingtone>()?;
|
||||
module.add_class::<AlarmVolume>()?;
|
||||
module.add_class::<PyAlarmDuration>()?;
|
||||
module.add_class::<TemperatureUnitKE100>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_handlers(module: &Bound<'_, PyModule>) -> Result<(), PyErr> {
|
||||
module.add_class::<PyApiClient>()?;
|
||||
module.add_class::<PyColorLightHandler>()?;
|
||||
module.add_class::<PyGenericDeviceHandler>()?;
|
||||
module.add_class::<PyLightHandler>()?;
|
||||
module.add_class::<PyPlugEnergyMonitoringHandler>()?;
|
||||
module.add_class::<PyPlugHandler>()?;
|
||||
module.add_class::<PyRgbLightStripHandler>()?;
|
||||
module.add_class::<PyRgbicLightStripHandler>()?;
|
||||
|
||||
module.add_class::<PyHubHandler>()?;
|
||||
module.add_class::<PyKE100Handler>()?;
|
||||
module.add_class::<PyT100Handler>()?;
|
||||
module.add_class::<PyT110Handler>()?;
|
||||
module.add_class::<PyT300Handler>()?;
|
||||
module.add_class::<PyT31XHandler>()?;
|
||||
|
||||
module.add_class::<PyPowerStripHandler>()?;
|
||||
module.add_class::<PyPowerStripEnergyMonitoringHandler>()?;
|
||||
module.add_class::<PyPowerStripPlugHandler>()?;
|
||||
module.add_class::<PyPowerStripPlugEnergyMonitoringHandler>()?;
|
||||
|
||||
module.add_class::<PyDeviceDiscovery>()?;
|
||||
module.add_class::<PyDeviceDiscoveryIter>()?;
|
||||
module.add_class::<PyDiscoveryResult>()?;
|
||||
module.add_class::<PyMaybeDiscoveryResult>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_responses(module: &Bound<'_, PyModule>) -> Result<(), PyErr> {
|
||||
module.add_class::<CurrentPowerResult>()?;
|
||||
module.add_class::<DefaultBrightnessState>()?;
|
||||
module.add_class::<DefaultPowerType>()?;
|
||||
module.add_class::<DefaultStateType>()?;
|
||||
module.add_class::<DeviceUsageEnergyMonitoringResult>()?;
|
||||
module.add_class::<DeviceUsageResult>()?;
|
||||
module.add_class::<EnergyDataIntervalResult>()?;
|
||||
module.add_class::<EnergyDataResult>()?;
|
||||
module.add_class::<EnergyUsageResult>()?;
|
||||
module.add_class::<OvercurrentStatus>()?;
|
||||
module.add_class::<OverheatStatus>()?;
|
||||
module.add_class::<PowerDataIntervalResult>()?;
|
||||
module.add_class::<PowerDataResult>()?;
|
||||
module.add_class::<PowerProtectionStatus>()?;
|
||||
module.add_class::<UsageByPeriodResult>()?;
|
||||
|
||||
// device info: generic
|
||||
module.add_class::<DeviceInfoGenericResult>()?;
|
||||
|
||||
// device info: light
|
||||
module.add_class::<DeviceInfoLightResult>()?;
|
||||
module.add_class::<DefaultLightState>()?;
|
||||
|
||||
// device info: color light
|
||||
module.add_class::<DeviceInfoColorLightResult>()?;
|
||||
module.add_class::<DefaultColorLightState>()?;
|
||||
module.add_class::<ColorLightState>()?;
|
||||
|
||||
// device info: rgb light strip
|
||||
module.add_class::<DeviceInfoRgbLightStripResult>()?;
|
||||
module.add_class::<DefaultRgbLightStripState>()?;
|
||||
module.add_class::<RgbLightStripState>()?;
|
||||
|
||||
// device info: rgbic light strip
|
||||
module.add_class::<DeviceInfoRgbicLightStripResult>()?;
|
||||
module.add_class::<DefaultRgbicLightStripState>()?;
|
||||
module.add_class::<RgbicLightStripState>()?;
|
||||
module.add_class::<PyLightingEffect>()?;
|
||||
module.add_class::<LightingEffectType>()?;
|
||||
|
||||
// device info: plugs
|
||||
module.add_class::<DefaultPlugState>()?;
|
||||
module.add_class::<DeviceInfoPlugEnergyMonitoringResult>()?;
|
||||
module.add_class::<DeviceInfoPlugResult>()?;
|
||||
module.add_class::<PlugState>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_responses_hub(module: &Bound<'_, PyModule>) -> Result<(), PyErr> {
|
||||
module.add_class::<DeviceInfoHubResult>()?;
|
||||
module.add_class::<KE100Result>()?;
|
||||
module.add_class::<S200BResult>()?;
|
||||
module.add_class::<T100Result>()?;
|
||||
module.add_class::<T110Result>()?;
|
||||
module.add_class::<T300Result>()?;
|
||||
module.add_class::<T31XResult>()?;
|
||||
|
||||
// child devices
|
||||
module.add_class::<S200BLog>()?;
|
||||
module.add_class::<S200BRotationParams>()?;
|
||||
module.add_class::<Status>()?;
|
||||
module.add_class::<T100Log>()?;
|
||||
module.add_class::<T110Log>()?;
|
||||
module.add_class::<T300Log>()?;
|
||||
module.add_class::<TemperatureHumidityRecord>()?;
|
||||
module.add_class::<TemperatureHumidityRecords>()?;
|
||||
module.add_class::<TemperatureUnit>()?;
|
||||
module.add_class::<TemperatureUnitKE100>()?;
|
||||
module.add_class::<TriggerLogsS200BResult>()?;
|
||||
module.add_class::<TriggerLogsT100Result>()?;
|
||||
module.add_class::<TriggerLogsT110Result>()?;
|
||||
module.add_class::<TriggerLogsT300Result>()?;
|
||||
module.add_class::<WaterLeakStatus>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_responses_power_strip(module: &Bound<'_, PyModule>) -> Result<(), PyErr> {
|
||||
module.add_class::<DeviceInfoPowerStripResult>()?;
|
||||
|
||||
// child devices
|
||||
module.add_class::<AutoOffStatus>()?;
|
||||
module.add_class::<PowerStripPlugResult>()?;
|
||||
module.add_class::<PowerStripPlugEnergyMonitoringResult>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
9
agents/tapo/tapo-fork/tapo-py/src/requests.rs
Normal file
9
agents/tapo/tapo-fork/tapo-py/src/requests.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
mod energy_data_interval;
|
||||
mod play_alarm;
|
||||
mod power_data_interval;
|
||||
mod set_device_info;
|
||||
|
||||
pub use energy_data_interval::*;
|
||||
pub use play_alarm::*;
|
||||
pub use power_data_interval::*;
|
||||
pub use set_device_info::*;
|
||||
@@ -0,0 +1,9 @@
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[pyclass(name = "EnergyDataInterval", eq, eq_int)]
|
||||
pub enum PyEnergyDataInterval {
|
||||
Hourly,
|
||||
Daily,
|
||||
Monthly,
|
||||
}
|
||||
9
agents/tapo/tapo-fork/tapo-py/src/requests/play_alarm.rs
Normal file
9
agents/tapo/tapo-fork/tapo-py/src/requests/play_alarm.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[pyclass(name = "AlarmDuration", eq)]
|
||||
pub enum PyAlarmDuration {
|
||||
Continuous,
|
||||
Once,
|
||||
Seconds,
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[pyclass(name = "PowerDataInterval", eq, eq_int)]
|
||||
pub enum PyPowerDataInterval {
|
||||
Every5Minutes,
|
||||
Hourly,
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mod color_light;
|
||||
mod lighting_effect;
|
||||
|
||||
pub use color_light::*;
|
||||
pub use lighting_effect::*;
|
||||
@@ -0,0 +1,108 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use tapo::requests::{Color, ColorLightSetDeviceInfoParams};
|
||||
|
||||
use crate::api::{
|
||||
PyColorLightHandler, PyHandlerExt, PyRgbLightStripHandler, PyRgbicLightStripHandler,
|
||||
};
|
||||
use crate::errors::ErrorWrapper;
|
||||
use crate::runtime::tokio;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "LightSetDeviceInfoParams")]
|
||||
pub struct PyColorLightSetDeviceInfoParams {
|
||||
params: ColorLightSetDeviceInfoParams,
|
||||
}
|
||||
|
||||
impl PyColorLightSetDeviceInfoParams {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
params: ColorLightSetDeviceInfoParams::new(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn _send_to_inner_handler(&self, handler: impl PyHandlerExt) -> PyResult<()> {
|
||||
let params = self.params.clone();
|
||||
let handler = handler.get_inner_handler();
|
||||
|
||||
tokio()
|
||||
.spawn(async move {
|
||||
let handler_lock = handler.read().await;
|
||||
|
||||
params
|
||||
.send(handler_lock.deref())
|
||||
.await
|
||||
.map_err(ErrorWrapper)?;
|
||||
|
||||
Ok::<_, ErrorWrapper>(())
|
||||
})
|
||||
.await
|
||||
.map_err(anyhow::Error::from)
|
||||
.map_err(ErrorWrapper::from)??;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyColorLightSetDeviceInfoParams {
|
||||
pub fn on(&self) -> Self {
|
||||
Self {
|
||||
params: self.params.clone().on(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn off(&self) -> Self {
|
||||
Self {
|
||||
params: self.params.clone().off(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn brightness(&self, brightness: u8) -> Self {
|
||||
Self {
|
||||
params: self.params.clone().brightness(brightness),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color(&self, color: Color) -> Self {
|
||||
Self {
|
||||
params: self.params.clone().color(color),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hue_saturation(&self, hue: u16, saturation: u8) -> Self {
|
||||
Self {
|
||||
params: self.params.clone().hue_saturation(hue, saturation),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color_temperature(&self, color_temperature: u16) -> Self {
|
||||
Self {
|
||||
params: self.params.clone().color_temperature(color_temperature),
|
||||
}
|
||||
}
|
||||
|
||||
async fn send(&self, handler: Py<PyAny>) -> PyResult<()> {
|
||||
if let Some(handler) = Python::attach(|py| handler.extract::<PyColorLightHandler>(py).ok())
|
||||
{
|
||||
return self._send_to_inner_handler(handler).await;
|
||||
}
|
||||
|
||||
if let Some(handler) =
|
||||
Python::attach(|py| handler.extract::<PyRgbLightStripHandler>(py).ok())
|
||||
{
|
||||
return self._send_to_inner_handler(handler).await;
|
||||
}
|
||||
|
||||
if let Some(handler) =
|
||||
Python::attach(|py| handler.extract::<PyRgbicLightStripHandler>(py).ok())
|
||||
{
|
||||
return self._send_to_inner_handler(handler).await;
|
||||
}
|
||||
|
||||
Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
|
||||
"Invalid handler type. Must be one of `PyColorLightHandler`, `PyRgbLightStripHandler` or `PyRgbicLightStripHandler`",
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
use pyo3::prelude::*;
|
||||
use tapo::requests::{LightingEffect, LightingEffectType};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[pyclass(name = "LightingEffect")]
|
||||
pub struct PyLightingEffect {
|
||||
inner: LightingEffect,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyLightingEffect {
|
||||
#[new]
|
||||
fn new(
|
||||
name: String,
|
||||
r#type: LightingEffectType,
|
||||
is_custom: bool,
|
||||
enabled: bool,
|
||||
brightness: u8,
|
||||
display_colors: Vec<[u16; 3]>,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: LightingEffect::new(
|
||||
name,
|
||||
r#type,
|
||||
is_custom,
|
||||
enabled,
|
||||
brightness,
|
||||
display_colors,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_brightness(mut slf: PyRefMut<'_, Self>, brightness: u8) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.brightness = brightness;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_is_custom(mut slf: PyRefMut<'_, Self>, is_custom: bool) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.is_custom = is_custom;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_display_colors(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
display_colors: Vec<[u16; 3]>,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.display_colors = display_colors;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_enabled(mut slf: PyRefMut<'_, Self>, enabled: bool) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.enabled = enabled;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_id(mut slf: PyRefMut<'_, Self>, id: String) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.id = id;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_name(mut slf: PyRefMut<'_, Self>, name: String) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.name = name;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_type(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
r#type: LightingEffectType,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.r#type = r#type;
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_backgrounds(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
backgrounds: Vec<[u16; 3]>,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.backgrounds = Some(backgrounds);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_brightness_range(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
brightness_range: [u8; 2],
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.brightness_range = Some(brightness_range.to_vec());
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_direction(mut slf: PyRefMut<'_, Self>, direction: u8) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.direction = Some(direction);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_duration(mut slf: PyRefMut<'_, Self>, duration: u64) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.duration = Some(duration);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_expansion_strategy(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
expansion_strategy: u8,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.expansion_strategy = Some(expansion_strategy);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_fade_off(mut slf: PyRefMut<'_, Self>, fade_off: u16) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.fade_off = Some(fade_off);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_hue_range(mut slf: PyRefMut<'_, Self>, hue_range: [u16; 2]) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.hue_range = Some(hue_range);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_init_states(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
init_states: Vec<[u16; 3]>,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.init_states = Some(init_states);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_random_seed(mut slf: PyRefMut<'_, Self>, random_seed: u64) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.random_seed = Some(random_seed);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_repeat_times(mut slf: PyRefMut<'_, Self>, repeat_times: u8) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.repeat_times = Some(repeat_times);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_run_time(mut slf: PyRefMut<'_, Self>, run_time: u64) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.run_time = Some(run_time);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_saturation_range(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
saturation_range: [u8; 2],
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.saturation_range = Some(saturation_range);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_segment_length(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
segment_length: u8,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.segment_length = Some(segment_length);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_segments(mut slf: PyRefMut<'_, Self>, segments: Vec<u8>) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.segments = Some(segments);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_sequence(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
sequence: Vec<[u16; 3]>,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.sequence = Some(sequence);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_spread(mut slf: PyRefMut<'_, Self>, spread: u8) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.spread = Some(spread);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_transition(mut slf: PyRefMut<'_, Self>, transition: u16) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.transition = Some(transition);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_transition_range(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
transition_range: [u16; 2],
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.transition_range = Some(transition_range);
|
||||
slf
|
||||
}
|
||||
|
||||
pub fn with_transition_sequence(
|
||||
mut slf: PyRefMut<'_, Self>,
|
||||
transition_sequence: Vec<u16>,
|
||||
) -> PyRefMut<'_, Self> {
|
||||
(*slf).inner.transition_sequence = Some(transition_sequence);
|
||||
slf
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PyLightingEffect> for LightingEffect {
|
||||
fn from(effect: PyLightingEffect) -> Self {
|
||||
effect.inner
|
||||
}
|
||||
}
|
||||
3
agents/tapo/tapo-fork/tapo-py/src/responses.rs
Normal file
3
agents/tapo/tapo-fork/tapo-py/src/responses.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod child_device_list_hub_result;
|
||||
|
||||
pub use child_device_list_hub_result::*;
|
||||
@@ -0,0 +1,9 @@
|
||||
mod s200b_result;
|
||||
mod t100_result;
|
||||
mod t110_result;
|
||||
mod t300_result;
|
||||
|
||||
pub use s200b_result::*;
|
||||
pub use t100_result::*;
|
||||
pub use t110_result::*;
|
||||
pub use t300_result::*;
|
||||
@@ -0,0 +1,32 @@
|
||||
use pyo3::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tapo::responses::{S200BLog, TriggerLogsResult};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[pyclass(get_all)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct TriggerLogsS200BResult {
|
||||
start_id: u64,
|
||||
sum: u64,
|
||||
logs: Vec<S200BLog>,
|
||||
}
|
||||
|
||||
impl From<TriggerLogsResult<S200BLog>> for TriggerLogsS200BResult {
|
||||
fn from(result: TriggerLogsResult<S200BLog>) -> Self {
|
||||
Self {
|
||||
start_id: result.start_id,
|
||||
sum: result.sum,
|
||||
logs: result.logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyo3::pymethods]
|
||||
impl TriggerLogsS200BResult {
|
||||
pub fn to_dict(&self, py: pyo3::Python) -> pyo3::PyResult<pyo3::Py<pyo3::types::PyDict>> {
|
||||
let value = serde_json::to_value(self)
|
||||
.map_err(|e| pyo3::exceptions::PyException::new_err(e.to_string()))?;
|
||||
|
||||
tapo::python::serde_object_to_py_dict(py, &value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use pyo3::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tapo::responses::{T100Log, TriggerLogsResult};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[pyclass(get_all)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct TriggerLogsT100Result {
|
||||
start_id: u64,
|
||||
sum: u64,
|
||||
logs: Vec<T100Log>,
|
||||
}
|
||||
|
||||
impl From<TriggerLogsResult<T100Log>> for TriggerLogsT100Result {
|
||||
fn from(result: TriggerLogsResult<T100Log>) -> Self {
|
||||
Self {
|
||||
start_id: result.start_id,
|
||||
sum: result.sum,
|
||||
logs: result.logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyo3::pymethods]
|
||||
impl TriggerLogsT100Result {
|
||||
pub fn to_dict(&self, py: pyo3::Python) -> pyo3::PyResult<pyo3::Py<pyo3::types::PyDict>> {
|
||||
let value = serde_json::to_value(self)
|
||||
.map_err(|e| pyo3::exceptions::PyException::new_err(e.to_string()))?;
|
||||
|
||||
tapo::python::serde_object_to_py_dict(py, &value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use pyo3::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tapo::responses::{T110Log, TriggerLogsResult};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[pyclass(get_all)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct TriggerLogsT110Result {
|
||||
start_id: u64,
|
||||
sum: u64,
|
||||
logs: Vec<T110Log>,
|
||||
}
|
||||
|
||||
impl From<TriggerLogsResult<T110Log>> for TriggerLogsT110Result {
|
||||
fn from(result: TriggerLogsResult<T110Log>) -> Self {
|
||||
Self {
|
||||
start_id: result.start_id,
|
||||
sum: result.sum,
|
||||
logs: result.logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyo3::pymethods]
|
||||
impl TriggerLogsT110Result {
|
||||
pub fn to_dict(&self, py: pyo3::Python) -> pyo3::PyResult<pyo3::Py<pyo3::types::PyDict>> {
|
||||
let value = serde_json::to_value(self)
|
||||
.map_err(|e| pyo3::exceptions::PyException::new_err(e.to_string()))?;
|
||||
|
||||
tapo::python::serde_object_to_py_dict(py, &value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use pyo3::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tapo::responses::{T300Log, TriggerLogsResult};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[pyclass(get_all)]
|
||||
#[allow(missing_docs)]
|
||||
pub struct TriggerLogsT300Result {
|
||||
start_id: u64,
|
||||
sum: u64,
|
||||
logs: Vec<T300Log>,
|
||||
}
|
||||
|
||||
impl From<TriggerLogsResult<T300Log>> for TriggerLogsT300Result {
|
||||
fn from(result: TriggerLogsResult<T300Log>) -> Self {
|
||||
Self {
|
||||
start_id: result.start_id,
|
||||
sum: result.sum,
|
||||
logs: result.logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyo3::pymethods]
|
||||
impl TriggerLogsT300Result {
|
||||
pub fn to_dict(&self, py: pyo3::Python) -> pyo3::PyResult<pyo3::Py<pyo3::types::PyDict>> {
|
||||
let value = serde_json::to_value(self)
|
||||
.map_err(|e| pyo3::exceptions::PyException::new_err(e.to_string()))?;
|
||||
|
||||
tapo::python::serde_object_to_py_dict(py, &value)
|
||||
}
|
||||
}
|
||||
60
agents/tapo/tapo-fork/tapo-py/src/runtime.rs
Normal file
60
agents/tapo/tapo-fork/tapo-py/src/runtime.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
pub fn tokio() -> &'static tokio::runtime::Runtime {
|
||||
use std::sync::OnceLock;
|
||||
use tokio::runtime::Runtime;
|
||||
static RT: std::sync::OnceLock<Runtime> = OnceLock::new();
|
||||
RT.get_or_init(|| Runtime::new().expect("Failed to create tokio runtime"))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! call_handler_constructor {
|
||||
($self:ident, $constructor:path, $($params:expr),*) => {{
|
||||
let client = $self.client.clone();
|
||||
let handler = $crate::runtime::tokio()
|
||||
.spawn(async move {
|
||||
$constructor(client, $($params),*)
|
||||
.await
|
||||
.map_err($crate::errors::ErrorWrapper)
|
||||
})
|
||||
.await
|
||||
.map_err(anyhow::Error::from)
|
||||
.map_err($crate::errors::ErrorWrapper::from)??;
|
||||
|
||||
handler
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! call_handler_method {
|
||||
($handler:expr, $method:path) => (call_handler_method!($handler, $method,));
|
||||
($handler:expr, $method:path, discard_result) => (call_handler_method!($handler, $method, discard_result,));
|
||||
($handler:expr, $method:path, $($param:expr),*) => {{
|
||||
let result = $crate::runtime::tokio()
|
||||
.spawn(async move {
|
||||
let result = $method($handler, $($param),*)
|
||||
.await
|
||||
.map_err($crate::errors::ErrorWrapper)?;
|
||||
|
||||
Ok::<_, $crate::errors::ErrorWrapper>(result)
|
||||
})
|
||||
.await
|
||||
.map_err(anyhow::Error::from)
|
||||
.map_err($crate::errors::ErrorWrapper::from)??;
|
||||
|
||||
Ok::<_, PyErr>(result)
|
||||
}};
|
||||
($handler:expr, $method:path, discard_result, $($param:expr),*) => {{
|
||||
let result = $crate::runtime::tokio()
|
||||
.spawn(async move {
|
||||
$method($handler, $($param),*)
|
||||
.await
|
||||
.map_err($crate::errors::ErrorWrapper)?;
|
||||
|
||||
Ok::<_, $crate::errors::ErrorWrapper>(())
|
||||
})
|
||||
.await
|
||||
.map_err(anyhow::Error::from)
|
||||
.map_err($crate::errors::ErrorWrapper::from)??;
|
||||
|
||||
Ok(result)
|
||||
}};
|
||||
}
|
||||
5
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/__init__.py
Normal file
5
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .tapo import *
|
||||
|
||||
__doc__ = tapo.__doc__
|
||||
if hasattr(tapo, "__all__"):
|
||||
__all__ = tapo.__all__
|
||||
23
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/__init__.pyi
Normal file
23
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/__init__.pyi
Normal file
@@ -0,0 +1,23 @@
|
||||
from .api_client import *
|
||||
from .color_light_handler import *
|
||||
from .device_discovery import *
|
||||
from .discovery_result import *
|
||||
from .generic_device_handler import *
|
||||
from .hub_handler import *
|
||||
from .ke100_handler import *
|
||||
from .light_handler import *
|
||||
from .plug_energy_monitoring_handler import *
|
||||
from .plug_handler import *
|
||||
from .power_strip_energy_monitoring_handler import *
|
||||
from .power_strip_handler import *
|
||||
from .power_strip_plug_energy_monitoring_handler import *
|
||||
from .power_strip_plug_handler import *
|
||||
from .requests import *
|
||||
from .responses import *
|
||||
from .rgb_light_strip_handler import *
|
||||
from .rgbic_light_strip_handler import *
|
||||
from .s200b_handler import *
|
||||
from .t100_handler import *
|
||||
from .t110_handler import *
|
||||
from .t300_handler import *
|
||||
from .t31x_handler import *
|
||||
487
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/api_client.pyi
Normal file
487
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/api_client.pyi
Normal file
@@ -0,0 +1,487 @@
|
||||
"""Tapo API Client.
|
||||
|
||||
Tested with light bulbs (L510, L520, L530, L535, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P110M, P115),
|
||||
power strips (P300, P304M, P306, P316M), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315).
|
||||
|
||||
Example:
|
||||
```python
|
||||
import asyncio
|
||||
from tapo import ApiClient
|
||||
|
||||
|
||||
async def main():
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l530("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
See [more examples](https://github.com/mihai-dinculescu/tapo/tree/main/tapo-py/examples).
|
||||
"""
|
||||
|
||||
from .color_light_handler import ColorLightHandler
|
||||
from .device_discovery import DeviceDiscovery
|
||||
from .generic_device_handler import GenericDeviceHandler
|
||||
from .hub_handler import HubHandler
|
||||
from .light_handler import LightHandler
|
||||
from .plug_energy_monitoring_handler import PlugEnergyMonitoringHandler
|
||||
from .plug_handler import PlugHandler
|
||||
from .power_strip_energy_monitoring_handler import PowerStripEnergyMonitoringHandler
|
||||
from .power_strip_handler import PowerStripHandler
|
||||
from .rgb_light_strip_handler import RgbLightStripHandler
|
||||
from .rgbic_light_strip_handler import RgbicLightStripHandler
|
||||
|
||||
class ApiClient:
|
||||
"""Tapo API Client.
|
||||
|
||||
Tested with light bulbs (L510, L520, L530, L535, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P110M, P115),
|
||||
power strips (P300, P304M, P306, P316M), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315).
|
||||
|
||||
Example:
|
||||
```python
|
||||
import asyncio
|
||||
from tapo import ApiClient
|
||||
|
||||
|
||||
async def main():
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l530("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
See [more examples](https://github.com/mihai-dinculescu/tapo/tree/main/tapo-py/examples).
|
||||
"""
|
||||
|
||||
def __init__(self, tapo_username: str, tapo_password: str, timeout_s: int = 30) -> None:
|
||||
"""Returns a new instance of `ApiClient`.
|
||||
|
||||
Args:
|
||||
tapo_username (str): The Tapo username.
|
||||
tapo_password (str): The Tapo password.
|
||||
timeout_s (int): The connection timeout in seconds. The default value is 30 seconds.
|
||||
|
||||
Returns:
|
||||
ApiClient: Tapo API Client.
|
||||
|
||||
Example:
|
||||
```python
|
||||
import asyncio
|
||||
from tapo import ApiClient
|
||||
|
||||
|
||||
async def main():
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l530("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
See [more examples](https://github.com/mihai-dinculescu/tapo/tree/main/tapo-py/examples).
|
||||
"""
|
||||
|
||||
async def discover_devices(self, target: str, timeout_s: int = 10) -> DeviceDiscovery:
|
||||
"""Discovers one or more devices located at a specified unicast or broadcast IP address.
|
||||
|
||||
Args:
|
||||
target (str): The IP address at which the discovery will take place.
|
||||
This address can be either a unicast (e.g. `192.168.1.10`) or a
|
||||
broadcast address (e.g. `192.168.1.255`, `255.255.255.255`, etc.).
|
||||
timeout_s (int): The maximum time to wait for a response from the device(s) in seconds.
|
||||
Must be between `1` and `60`.
|
||||
|
||||
Returns:
|
||||
AsyncIterator[MaybeDiscoveryResult]: An asynchronous iterator that yields `MaybeDiscoveryResult` objects.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
|
||||
async for device in client.discover_devices("192.168.1.255"):
|
||||
try:
|
||||
device = discovery_result.get()
|
||||
match device:
|
||||
case DiscoveryResult.PlugEnergyMonitoring(device_info):
|
||||
print(
|
||||
f"Found '{device_info.nickname}' of model '{device_info.model}' at IP address '{device_info.ip}'."
|
||||
)
|
||||
# ...
|
||||
except Exception as e:
|
||||
print(f"Error discovering device: {e}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def generic_device(self, ip_address: str) -> GenericDeviceHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `GenericDeviceHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
GenericDeviceHandler: Handler for generic devices. It provides the
|
||||
functionality common to all Tapo [devices](https://www.tapo.com/en/).
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.generic_device("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l510(self, ip_address: str) -> LightHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `LightHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
LightHandler: Handler for the [L510](https://www.tapo.com/en/search/?q=L510),
|
||||
[L520](https://www.tapo.com/en/search/?q=L520) and [L610](https://www.tapo.com/en/search/?q=L610) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l510("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l520(self, ip_address: str) -> LightHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `LightHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
LightHandler: Handler for the [L510](https://www.tapo.com/en/search/?q=L510),
|
||||
[L520](https://www.tapo.com/en/search/?q=L520) and [L610](https://www.tapo.com/en/search/?q=L610) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l520("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l530(self, ip_address: str) -> ColorLightHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `ColorLightHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
ColorLightHandler: Handler for the [L530](https://www.tapo.com/en/search/?q=L530),
|
||||
[L535](https://www.tapo.com/en/search/?q=L535) and [L630](https://www.tapo.com/en/search/?q=L630) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l530("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l535(self, ip_address: str) -> ColorLightHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `ColorLightHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
ColorLightHandler: Handler for the [L530](https://www.tapo.com/en/search/?q=L530),
|
||||
[L535](https://www.tapo.com/en/search/?q=L535) and [L630](https://www.tapo.com/en/search/?q=L630) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l535("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l610(self, ip_address: str) -> LightHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `LightHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
LightHandler: Handler for the [L510](https://www.tapo.com/en/search/?q=L510),
|
||||
[L520](https://www.tapo.com/en/search/?q=L520) and [L610](https://www.tapo.com/en/search/?q=L610) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l610("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l630(self, ip_address: str) -> ColorLightHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `ColorLightHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
ColorLightHandler: Handler for the [L530](https://www.tapo.com/en/search/?q=L530),
|
||||
[L630](https://www.tapo.com/en/search/?q=L630) and [L900](https://www.tapo.com/en/search/?q=L900) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l630("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l900(self, ip_address: str) -> RgbLightStripHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `RgbLightStripHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
RgbLightStripHandler: Handler for the [L900](https://www.tapo.com/en/search/?q=L900) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l900("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l920(self, ip_address: str) -> RgbicLightStripHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `RgbicLightStripHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
RgbicLightStripHandler: Handler for the [L920](https://www.tapo.com/en/search/?q=L920) and
|
||||
[L930](https://www.tapo.com/en/search/?q=L930) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l920("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def l930(self, ip_address: str) -> RgbicLightStripHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `RgbicLightStripHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
RgbicLightStripHandler: Handler for the [L920](https://www.tapo.com/en/search/?q=L920) and
|
||||
[L930](https://www.tapo.com/en/search/?q=L930) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.l930("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def p100(self, ip_address: str) -> PlugHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PlugHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PlugHandler: Handler for the [P100](https://www.tapo.com/en/search/?q=P100) and
|
||||
[P105](https://www.tapo.com/en/search/?q=P105) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.p100("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def p105(self, ip_address: str) -> PlugHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PlugHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PlugHandler: Handler for the [P100](https://www.tapo.com/en/search/?q=P100) and
|
||||
[P105](https://www.tapo.com/en/search/?q=P105) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.p105("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def p110(self, ip_address: str) -> PlugEnergyMonitoringHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PlugEnergyMonitoringHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PlugEnergyMonitoringHandler: Handler for the [P110](https://www.tapo.com/en/search/?q=P110),
|
||||
[P110M](https://www.tapo.com/en/search/?q=P110M) and
|
||||
[P115](https://www.tapo.com/en/search/?q=P115) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.p110("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def p115(self, ip_address: str) -> PlugEnergyMonitoringHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PlugEnergyMonitoringHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PlugEnergyMonitoringHandler: Handler for the [P110](https://www.tapo.com/en/search/?q=P110),
|
||||
[P110M](https://www.tapo.com/en/search/?q=P110M) and
|
||||
[P115](https://www.tapo.com/en/search/?q=P115) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
device = await client.p115("192.168.1.100")
|
||||
|
||||
await device.on()
|
||||
```
|
||||
"""
|
||||
|
||||
async def p300(self, ip_address: str) -> PowerStripHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PowerStripHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PowerStripHandler: Handler for the [P300](https://www.tp-link.com/en/search/?q=P300) and
|
||||
[P306](https://www.tp-link.com/us/search/?q=P306) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
power_strip = await client.p300("192.168.1.100")
|
||||
|
||||
child_device_list = await power_strip.get_child_device_list()
|
||||
print(f"Child device list: {child_device_list.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def p304(self, ip_address: str) -> PowerStripEnergyMonitoringHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PowerStripEnergyMonitoringHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PowerStripEnergyMonitoringHandler: Handler for the [P304M](https://www.tp-link.com/uk/search/?q=P304M) and
|
||||
[P316M](https://www.tp-link.com/us/search/?q=P316M) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
power_strip = await client.p304("192.168.1.100")
|
||||
|
||||
child_device_list = await power_strip.get_child_device_list()
|
||||
print(f"Child device list: {child_device_list.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def p306(self, ip_address: str) -> PowerStripHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PowerStripHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PowerStripHandler: Handler for the [P300](https://www.tp-link.com/en/search/?q=P300) and
|
||||
[P306](https://www.tp-link.com/us/search/?q=P306) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
power_strip = await client.p306("192.168.1.100")
|
||||
|
||||
child_device_list = await power_strip.get_child_device_list()
|
||||
print(f"Child device list: {child_device_list.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def p316(self, ip_address: str) -> PowerStripHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `PowerStripHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
PowerStripEnergyMonitoringHandler: Handler for the [P304M](https://www.tp-link.com/uk/search/?q=P304M) and
|
||||
[P316M](https://www.tp-link.com/us/search/?q=P316M) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
power_strip = await client.p316("192.168.1.100")
|
||||
|
||||
child_device_list = await power_strip.get_child_device_list()
|
||||
print(f"Child device list: {child_device_list.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def h100(self, ip_address: str) -> HubHandler:
|
||||
"""Specializes the given `ApiClient` into an authenticated `HubHandler`.
|
||||
|
||||
Args:
|
||||
ip_address (str): The IP address of the device
|
||||
|
||||
Returns:
|
||||
HubHandler: Handler for the [H100](https://www.tapo.com/en/search/?q=H100) hubs.
|
||||
|
||||
Example:
|
||||
```python
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
child_device_list = await hub.get_child_device_list()
|
||||
print(f"Child device list: {child_device_list.to_dict()}")
|
||||
```
|
||||
"""
|
||||
@@ -0,0 +1,88 @@
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.requests import Color, ColorLightSetDeviceInfoParams
|
||||
from tapo.responses import DeviceInfoColorLightResult, DeviceUsageResult
|
||||
|
||||
class ColorLightHandler(DeviceManagementExt):
|
||||
"""Handler for the [L530](https://www.tapo.com/en/search/?q=L530),
|
||||
[L535](https://www.tapo.com/en/search/?q=L535) and
|
||||
[L630](https://www.tapo.com/en/search/?q=L630) devices.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoColorLightResult:
|
||||
"""Returns *device info* as `DeviceInfoColorLightResult`.
|
||||
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 `ColorLightHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoColorLightResult: Device info of Tapo L530, L535 and L630.
|
||||
Superset of `GenericDeviceInfoResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_device_usage(self) -> DeviceUsageResult:
|
||||
"""Returns *device usage* as `DeviceUsageResult`.
|
||||
|
||||
Returns:
|
||||
DeviceUsageResult: Contains the time usage.
|
||||
"""
|
||||
|
||||
def set(self) -> ColorLightSetDeviceInfoParams:
|
||||
"""Returns a `ColorLightSetDeviceInfoParams` builder that allows
|
||||
multiple properties to be set in a single request.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
|
||||
Returns:
|
||||
ColorLightSetDeviceInfoParams: Builder that is used by the
|
||||
`ColorLightHandler.set` API to set multiple properties in a single request.
|
||||
"""
|
||||
|
||||
async def set_brightness(self, brightness: int) -> None:
|
||||
"""Sets the *brightness* and turns *on* the device.
|
||||
|
||||
Args:
|
||||
brightness (int): between 1 and 100
|
||||
"""
|
||||
|
||||
async def set_color(self, color: Color) -> None:
|
||||
"""Sets the *color* and turns *on* the device.
|
||||
|
||||
Args:
|
||||
color (Color): one of `tapo.Color` as defined in the Google Home app.
|
||||
"""
|
||||
|
||||
async def set_hue_saturation(self, hue: int, saturation: int) -> None:
|
||||
"""Sets the *hue*, *saturation* and turns *on* the device.
|
||||
|
||||
Args:
|
||||
hue (int): between 0 and 360
|
||||
saturation (int): between 1 and 100
|
||||
"""
|
||||
|
||||
async def set_color_temperature(self, color_temperature: int) -> None:
|
||||
"""Sets the *color temperature* and turns *on* the device.
|
||||
|
||||
Args:
|
||||
color_temperature (int): between 2500 and 6500
|
||||
"""
|
||||
@@ -0,0 +1,14 @@
|
||||
from __future__ import annotations
|
||||
from typing import AsyncIterable, Iterable, Iterator, AsyncIterator
|
||||
|
||||
from .discovery_result import MaybeDiscoveryResult
|
||||
|
||||
class DeviceDiscoveryIter(Iterator[MaybeDiscoveryResult], AsyncIterator[MaybeDiscoveryResult]):
|
||||
def __iter__(self) -> DeviceDiscoveryIter: ...
|
||||
def __aiter__(self) -> DeviceDiscoveryIter: ...
|
||||
def __next__(self) -> MaybeDiscoveryResult: ...
|
||||
async def __anext__(self) -> MaybeDiscoveryResult: ...
|
||||
|
||||
class DeviceDiscovery(Iterable[MaybeDiscoveryResult], AsyncIterable[MaybeDiscoveryResult]):
|
||||
def __iter__(self) -> DeviceDiscoveryIter: ...
|
||||
def __aiter__(self) -> DeviceDiscoveryIter: ...
|
||||
@@ -0,0 +1,27 @@
|
||||
class DeviceManagementExt:
|
||||
"""Extension class for device management capabilities like `device_reboot` and `device_reset`."""
|
||||
|
||||
async def device_reboot(self, delay_s: int) -> None:
|
||||
"""*Reboots* the device.
|
||||
|
||||
Notes:
|
||||
* Using a very small delay (e.g. 0 seconds) may cause a `ConnectionReset` or `TimedOut` error as the device reboots immediately.
|
||||
* Using a larger delay (e.g. 2-3 seconds) allows the device to respond before rebooting, reducing the chance of errors.
|
||||
* With larger delays, the method completes successfully before the device reboots.
|
||||
However, subsequent commands may fail if sent during the reboot process or before the device reconnects to the network.
|
||||
|
||||
Args:
|
||||
delay_s (int): The delay in seconds before the device is rebooted.
|
||||
"""
|
||||
|
||||
async def device_reset(self) -> None:
|
||||
"""*Hardware resets* the device.
|
||||
|
||||
Warning:
|
||||
This action will reset the device to its factory settings.
|
||||
The connection to the Wi-Fi network and the Tapo app will be lost,
|
||||
and the device will need to be reconfigured.
|
||||
|
||||
This feature is especially useful when the device is difficult to access
|
||||
and requires reconfiguration.
|
||||
"""
|
||||
238
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/discovery_result.pyi
Normal file
238
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/discovery_result.pyi
Normal file
@@ -0,0 +1,238 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Type, Union
|
||||
|
||||
from tapo import (
|
||||
ColorLightHandler,
|
||||
GenericDeviceHandler,
|
||||
HubHandler,
|
||||
LightHandler,
|
||||
PlugEnergyMonitoringHandler,
|
||||
PlugHandler,
|
||||
PowerStripEnergyMonitoringHandler,
|
||||
PowerStripHandler,
|
||||
RgbicLightStripHandler,
|
||||
RgbLightStripHandler,
|
||||
)
|
||||
from tapo.responses import (
|
||||
DeviceInfoColorLightResult,
|
||||
DeviceInfoGenericResult,
|
||||
DeviceInfoHubResult,
|
||||
DeviceInfoLightResult,
|
||||
DeviceInfoPlugEnergyMonitoringResult,
|
||||
DeviceInfoPlugResult,
|
||||
DeviceInfoPowerStripResult,
|
||||
DeviceInfoRgbicLightStripResult,
|
||||
DeviceInfoRgbLightStripResult,
|
||||
)
|
||||
|
||||
class MaybeDiscoveryResult:
|
||||
"""Potential result of the device discovery process. Using `get` will return the actual result or raise an exception."""
|
||||
|
||||
def get(
|
||||
self,
|
||||
) -> Union[
|
||||
GenericDevice,
|
||||
Light,
|
||||
ColorLight,
|
||||
RgbLightStrip,
|
||||
RgbicLightStrip,
|
||||
Plug,
|
||||
PlugEnergyMonitoring,
|
||||
PowerStrip,
|
||||
PowerStripEnergyMonitoring,
|
||||
Hub,
|
||||
]:
|
||||
"""Retrieves the actual discovery result or raises an exception."""
|
||||
|
||||
@dataclass
|
||||
class GenericDevice:
|
||||
"""A Generic Tapo device.
|
||||
|
||||
If you believe this device is already supported, or would like to explore adding support for a currently
|
||||
unsupported model, please [open an issue on GitHub](https://github.com/mihai-dinculescu/tapo/issues)
|
||||
to start the discussion.
|
||||
"""
|
||||
|
||||
device_info: DeviceInfoGenericResult
|
||||
"""Device info of a Generic Tapo device.
|
||||
|
||||
If you believe this device is already supported, or would like to explore adding support for a currently
|
||||
unsupported model, please [open an issue on GitHub](https://github.com/mihai-dinculescu/tapo/issues)
|
||||
to start the discussion.
|
||||
"""
|
||||
|
||||
handler: GenericDeviceHandler
|
||||
"""Handler for generic devices. It provides the functionality common to all Tapo [devices](https://www.tapo.com/en/).
|
||||
|
||||
If you believe this device is already supported, or would like to explore adding support for a currently
|
||||
unsupported model, please [open an issue on GitHub](https://github.com/mihai-dinculescu/tapo/issues)
|
||||
to start the discussion.
|
||||
"""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class Light:
|
||||
"""Tapo L510, L520 and L610 devices."""
|
||||
|
||||
device_info: DeviceInfoLightResult
|
||||
"""Device info of Tapo L510, L520 and L610."""
|
||||
|
||||
handler: LightHandler
|
||||
"""Handler for the [L510](https://www.tapo.com/en/search/?q=L510),
|
||||
[L520](https://www.tapo.com/en/search/?q=L520) and
|
||||
[L610](https://www.tapo.com/en/search/?q=L610) devices.
|
||||
"""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class ColorLight:
|
||||
"""Tapo L530, L535 and L630 devices."""
|
||||
|
||||
device_info: DeviceInfoColorLightResult
|
||||
"""Device info of Tapo L530, L535 and L630."""
|
||||
|
||||
handler: ColorLightHandler
|
||||
"""Handler for the [L530](https://www.tapo.com/en/search/?q=L530),
|
||||
[L535](https://www.tapo.com/en/search/?q=L535) and
|
||||
[L630](https://www.tapo.com/en/search/?q=L630) devices.
|
||||
"""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class RgbLightStrip:
|
||||
"""Tapo L900 devices."""
|
||||
|
||||
device_info: DeviceInfoRgbLightStripResult
|
||||
"""Device info of Tapo L900."""
|
||||
|
||||
handler: RgbLightStripHandler
|
||||
"""Handler for the [L900](https://www.tapo.com/en/search/?q=L900) devices."""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class RgbicLightStrip:
|
||||
"""Tapo L920 and L930 devices."""
|
||||
|
||||
device_info: DeviceInfoRgbicLightStripResult
|
||||
"""Device info of Tapo L920 and L930."""
|
||||
|
||||
handler: RgbicLightStripHandler
|
||||
"""Handler for the [L920](https://www.tapo.com/en/search/?q=L920) and
|
||||
[L930](https://www.tapo.com/en/search/?q=L930) devices."""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class Plug:
|
||||
"""Tapo P100 and P105 devices."""
|
||||
|
||||
device_info: DeviceInfoPlugResult
|
||||
"""Device info of Tapo P100 and P105."""
|
||||
|
||||
handler: PlugHandler
|
||||
"""Handler for the [P100](https://www.tapo.com/en/search/?q=P100) and
|
||||
[P105](https://www.tapo.com/en/search/?q=P105) devices."""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class PlugEnergyMonitoring:
|
||||
"""Tapo P110, P110M and P115 devices."""
|
||||
|
||||
device_info: DeviceInfoPlugEnergyMonitoringResult
|
||||
"""Device info of Tapo P110, P110M and P115."""
|
||||
|
||||
handler: PlugEnergyMonitoringHandler
|
||||
"""Handler for the [P110](https://www.tapo.com/en/search/?q=P110),
|
||||
[P110M](https://www.tapo.com/en/search/?q=P110M) and
|
||||
[P115](https://www.tapo.com/en/search/?q=P115) devices."""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class PowerStrip:
|
||||
"""Tapo P300 and P306 devices."""
|
||||
|
||||
device_info: DeviceInfoPowerStripResult
|
||||
"""Device info of Tapo P300 and P306."""
|
||||
|
||||
handler: PowerStripHandler
|
||||
"""Handler for the [P300](https://www.tp-link.com/en/search/?q=P300) and
|
||||
[P306](https://www.tp-link.com/us/search/?q=P306) devices.
|
||||
"""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class PowerStripEnergyMonitoring:
|
||||
"""Tapo P304M and P316M devices."""
|
||||
|
||||
device_info: DeviceInfoPowerStripResult
|
||||
"""Device info of Tapo P304M and P316M."""
|
||||
|
||||
handler: PowerStripEnergyMonitoringHandler
|
||||
"""Handler for the [P304M](https://www.tp-link.com/uk/search/?q=P304M) and
|
||||
[P316M](https://www.tp-link.com/us/search/?q=P316M) devices.
|
||||
"""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
@dataclass
|
||||
class Hub:
|
||||
"""Tapo H100 devices."""
|
||||
|
||||
device_info: DeviceInfoHubResult
|
||||
"""Device info of Tapo H100."""
|
||||
|
||||
handler: HubHandler
|
||||
"""Handler for the [H100](https://www.tapo.com/en/search/?q=H100) devices."""
|
||||
|
||||
__match_args__ = (
|
||||
"device_info",
|
||||
"handler",
|
||||
)
|
||||
|
||||
class DiscoveryResult:
|
||||
"""Result of the device discovery process."""
|
||||
|
||||
GenericDevice: Type[GenericDevice] = GenericDevice
|
||||
Light: Type[Light] = Light
|
||||
ColorLight: Type[ColorLight] = ColorLight
|
||||
RgbLightStrip: Type[RgbLightStrip] = RgbLightStrip
|
||||
RgbicLightStrip: Type[RgbicLightStrip] = RgbicLightStrip
|
||||
Plug: Type[Plug] = Plug
|
||||
PlugEnergyMonitoring: Type[PlugEnergyMonitoring] = PlugEnergyMonitoring
|
||||
PowerStrip: Type[PowerStrip] = PowerStrip
|
||||
PowerStripEnergyMonitoring: Type[PowerStripEnergyMonitoring] = PowerStripEnergyMonitoring
|
||||
Hub: Type[Hub] = Hub
|
||||
@@ -0,0 +1,41 @@
|
||||
from tapo.responses import DeviceInfoGenericResult
|
||||
|
||||
class GenericDeviceHandler:
|
||||
"""Handler for generic devices. It provides the functionality common to
|
||||
all Tapo [devices](https://www.tapo.com/en/).
|
||||
|
||||
If you'd like to propose support for a device that isn't currently supported,
|
||||
please [open an issue on GitHub](https://github.com/mihai-dinculescu/tapo/issues) to start the conversation.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoGenericResult:
|
||||
"""Returns *device info* as `DeviceInfoGenericResult`.
|
||||
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 `GenericDeviceHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoGenericResult: Device info of a Generic Tapo device.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
295
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/hub_handler.pyi
Normal file
295
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/hub_handler.pyi
Normal file
@@ -0,0 +1,295 @@
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from tapo import KE100Handler, S200BHandler, T100Handler, T110Handler, T300Handler, T31XHandler
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.requests import AlarmDuration, AlarmRingtone, AlarmVolume
|
||||
from tapo.responses import (
|
||||
DeviceInfoHubResult,
|
||||
KE100Result,
|
||||
S200BResult,
|
||||
T100Result,
|
||||
T110Result,
|
||||
T300Result,
|
||||
T31XResult,
|
||||
)
|
||||
|
||||
class HubHandler(DeviceManagementExt):
|
||||
"""Handler for the [H100](https://www.tapo.com/en/search/?q=H100) devices."""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoHubResult:
|
||||
"""Returns *device info* as `DeviceInfoHubResult`.
|
||||
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 `HubHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoHubResult: Device info of Tapo H100.
|
||||
Superset of `GenericDeviceInfoResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_list(
|
||||
self,
|
||||
) -> List[
|
||||
Union[KE100Result, S200BResult, T100Result, T110Result, T300Result, T31XResult, None]
|
||||
]:
|
||||
"""Returns *child device list* as `List[KE100Result | S200BResult | T100Result | T110Result | T300Result | T31XResult | None]`.
|
||||
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.
|
||||
If the deserialization fails, or if a property that you care about it's not present,
|
||||
try `HubHandler.get_child_device_list_json`.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
async def get_child_device_component_list_json(self) -> dict:
|
||||
"""Returns *child device component list* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_supported_ringtone_list() -> List[str]:
|
||||
"""Returns a list of ringtones (alarm types) supported by the hub.
|
||||
Used for debugging only.
|
||||
|
||||
Returns:
|
||||
List[str]: List of the ringtones supported by the hub.
|
||||
"""
|
||||
|
||||
async def play_alarm(
|
||||
self,
|
||||
ringtone: AlarmRingtone,
|
||||
volume: AlarmVolume,
|
||||
duration: AlarmDuration,
|
||||
seconds: Optional[int] = None,
|
||||
) -> None:
|
||||
"""Start playing the hub alarm.
|
||||
|
||||
Args:
|
||||
ringtone (AlarmRingtone): The ringtone of a H100 alarm.
|
||||
volume (AlarmVolume): The volume of the alarm.
|
||||
duration (AlarmDuration): Controls how long the alarm plays for.
|
||||
seconds (Optional[int]): Play the alarm a number of seconds. Required if `duration` is `AlarmDuration.Seconds`.
|
||||
"""
|
||||
|
||||
async def stop_alarm(self) -> None:
|
||||
"""Stop playing the hub alarm, if it's currently playing."""
|
||||
|
||||
async def ke100(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> KE100Handler:
|
||||
"""Returns a `KE100Handler` for the device matching the provided `device_id` or `nickname`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
KE100Handler: Handler for the [KE100](https://www.tp-link.com/en/search/?q=KE100) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.ke100(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def s200b(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> S200BHandler:
|
||||
"""Returns a `S200BHandler` for the device matching the provided `device_id` or `nickname`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
S200BHandler: Handler for the [S200B](https://www.tapo.com/en/search/?q=S200B) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.s200b(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def t100(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> T100Handler:
|
||||
"""Returns a `T100Handler` for the device matching the provided `device_id` or `nickname`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
T100Handler: Handler for the [T100](https://www.tapo.com/en/search/?q=T100) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.t100(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def t110(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> T110Handler:
|
||||
"""Returns a `T110Handler` for the device matching the provided `device_id` or `nickname`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
T110Handler: Handler for the [T110](https://www.tapo.com/en/search/?q=T110) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.t110(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def t300(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> T300Handler:
|
||||
"""Returns a `T300Handler` for the device matching the provided `device_id` or `nickname`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
T300Handler: Handler for the [T300](https://www.tapo.com/en/search/?q=T300) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.t300(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def t310(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> T31XHandler:
|
||||
"""Returns a `T31XHandler` for the device matching the provided `device_id` or `nickname`.
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
T31XHandler: Handler for the [T310](https://www.tapo.com/en/search/?q=T310)
|
||||
and [T315](https://www.tapo.com/en/search/?q=T315) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.t310(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
|
||||
async def t315(
|
||||
self, device_id: Optional[str] = None, nickname: Optional[str] = None
|
||||
) -> T31XHandler:
|
||||
"""Returns a `T31XHandler` for the device matching the provided `device_id` or `nickname`.
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
|
||||
Returns:
|
||||
T31XHandler: Handler for the [T310](https://www.tapo.com/en/search/?q=T310)
|
||||
and [T315](https://www.tapo.com/en/search/?q=T315) devices.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
hub = await client.h100("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await hub.t315(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
69
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/ke100_handler.pyi
Normal file
69
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/ke100_handler.pyi
Normal file
@@ -0,0 +1,69 @@
|
||||
from tapo.requests import TemperatureUnitKE100
|
||||
from tapo.responses import KE100Result
|
||||
|
||||
class KE100Handler:
|
||||
"""Handler for the [KE100](https://www.tp-link.com/en/search/?q=KE100) devices."""
|
||||
|
||||
async def get_device_info(self) -> KE100Result:
|
||||
"""Returns *device info* as `KE100Result`.
|
||||
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 `KE100Handler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
KE100Result: Device info of Tapo KE100 thermostatic radiator valve (TRV).
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def set_child_protection(self, on: bool) -> None:
|
||||
"""Sets *child protection* on the device to *on* or *off*.
|
||||
|
||||
Args:
|
||||
on (bool)
|
||||
"""
|
||||
|
||||
async def set_frost_protection(self, on: bool) -> None:
|
||||
"""Sets *frost protection* on the device to *on* or *off*.
|
||||
|
||||
Args:
|
||||
on (bool)
|
||||
"""
|
||||
|
||||
async def set_max_control_temperature(self, value: int, unit: TemperatureUnitKE100) -> None:
|
||||
"""Sets the *maximum control temperature*.
|
||||
|
||||
Args:
|
||||
value (int)
|
||||
unit (TemperatureUnitKE100)
|
||||
"""
|
||||
|
||||
async def set_min_control_temperature(self, value: int, unit: TemperatureUnitKE100) -> None:
|
||||
"""Sets the *minimum control temperature*.
|
||||
|
||||
Args:
|
||||
value (int)
|
||||
unit (TemperatureUnitKE100)
|
||||
"""
|
||||
|
||||
async def set_target_temperature(self, value: int, unit: TemperatureUnitKE100) -> None:
|
||||
"""Sets the *target temperature*.
|
||||
|
||||
Args:
|
||||
value (int): between `min_control_temperature` and `max_control_temperature`
|
||||
unit (TemperatureUnitKE100)
|
||||
"""
|
||||
|
||||
async def set_temperature_offset(self, value: int, unit: TemperatureUnitKE100) -> None:
|
||||
"""Sets the *temperature offset*.
|
||||
|
||||
Args:
|
||||
value (int): between -10 and 10
|
||||
unit (TemperatureUnitKE100)
|
||||
"""
|
||||
54
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/light_handler.pyi
Normal file
54
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/light_handler.pyi
Normal file
@@ -0,0 +1,54 @@
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.responses import DeviceInfoLightResult, DeviceUsageResult
|
||||
|
||||
class LightHandler(DeviceManagementExt):
|
||||
"""Handler for the [L510](https://www.tapo.com/en/search/?q=L510),
|
||||
[L520](https://www.tapo.com/en/search/?q=L520) and
|
||||
[L610](https://www.tapo.com/en/search/?q=L610) devices."""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoLightResult:
|
||||
"""Returns *device info* as `DeviceInfoLightResult`.
|
||||
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 `LightHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoLightResult: Device info of Tapo L510, L520 and L610.
|
||||
Superset of `GenericDeviceInfoResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_device_usage(self) -> DeviceUsageResult:
|
||||
"""Returns *device usage* as `DeviceUsageResult`.
|
||||
|
||||
Returns:
|
||||
DeviceUsageResult: Contains the time usage.
|
||||
"""
|
||||
|
||||
async def set_brightness(self, brightness: int) -> None:
|
||||
"""Sets the *brightness* and turns *on* the device.
|
||||
|
||||
Args:
|
||||
brightness (int): between 1 and 100
|
||||
"""
|
||||
@@ -0,0 +1,98 @@
|
||||
from datetime import datetime
|
||||
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.requests import EnergyDataInterval, PowerDataInterval
|
||||
from tapo.responses import (
|
||||
CurrentPowerResult,
|
||||
DeviceInfoPlugEnergyMonitoringResult,
|
||||
DeviceUsageEnergyMonitoringResult,
|
||||
EnergyDataResult,
|
||||
EnergyUsageResult,
|
||||
PowerDataResult,
|
||||
)
|
||||
|
||||
class PlugEnergyMonitoringHandler(DeviceManagementExt):
|
||||
"""Handler for the [P110](https://www.tapo.com/en/search/?q=P110),
|
||||
[P110M](https://www.tapo.com/en/search/?q=P110M) and
|
||||
[P115](https://www.tapo.com/en/search/?q=P115) devices.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoPlugEnergyMonitoringResult:
|
||||
"""Returns *device info* as `DeviceInfoPlugEnergyMonitoringResult`.
|
||||
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 `PlugEnergyMonitoringHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoPlugEnergyMonitoringResult: Device info of P110, P110M and P115.
|
||||
Superset of `GenericDeviceInfoResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_current_power(self) -> CurrentPowerResult:
|
||||
"""Returns *current power* as `CurrentPowerResult`.
|
||||
|
||||
Returns:
|
||||
CurrentPowerResult: Contains the current power reading of the device.
|
||||
"""
|
||||
|
||||
async def get_device_usage(self) -> DeviceUsageEnergyMonitoringResult:
|
||||
"""Returns *device usage* as `DeviceUsageResult`.
|
||||
|
||||
Returns:
|
||||
DeviceUsageEnergyMonitoringResult:
|
||||
Contains the time usage, the power consumption, and the energy savings of the device.
|
||||
"""
|
||||
|
||||
async def get_energy_usage(self) -> EnergyUsageResult:
|
||||
"""Returns *energy usage* as `EnergyUsageResult`.
|
||||
|
||||
Returns:
|
||||
EnergyUsageResult:
|
||||
Contains local time, current power and the energy usage and runtime for today and for the current month.
|
||||
"""
|
||||
|
||||
async def get_energy_data(
|
||||
self,
|
||||
interval: EnergyDataInterval,
|
||||
start_date: datetime,
|
||||
end_date: datetime = None,
|
||||
) -> EnergyDataResult:
|
||||
"""Returns *energy data* as `EnergyDataResult`.
|
||||
|
||||
Returns:
|
||||
EnergyDataResult: Energy data result for the requested `EnergyDataInterval`.
|
||||
"""
|
||||
|
||||
async def get_power_data(
|
||||
self,
|
||||
interval: PowerDataInterval,
|
||||
start_date_time: datetime,
|
||||
end_date_time: datetime,
|
||||
) -> PowerDataResult:
|
||||
"""Returns *power data* as `PowerDataResult`.
|
||||
|
||||
Returns:
|
||||
PowerDataResult: Power data result for the requested `PowerDataInterval`.
|
||||
"""
|
||||
47
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/plug_handler.pyi
Normal file
47
agents/tapo/tapo-fork/tapo-py/tapo-py/tapo/plug_handler.pyi
Normal file
@@ -0,0 +1,47 @@
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.responses import DeviceInfoPlugResult, DeviceUsageResult
|
||||
|
||||
class PlugHandler(DeviceManagementExt):
|
||||
"""Handler for the [P100](https://www.tapo.com/en/search/?q=P100) and
|
||||
[P105](https://www.tapo.com/en/search/?q=P105) devices.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoPlugResult:
|
||||
"""Returns *device info* as `DeviceInfoPlugResult`.
|
||||
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 `PlugHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoPlugResult: Device info of Tapo P100 and P105.
|
||||
Superset of `GenericDeviceInfoResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_device_usage(self) -> DeviceUsageResult:
|
||||
"""Returns *device usage* as `DeviceUsageResult`.
|
||||
|
||||
Returns:
|
||||
DeviceUsageResult: Contains the time usage.
|
||||
"""
|
||||
@@ -0,0 +1,96 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from tapo import PowerStripPlugEnergyMonitoringHandler
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.responses import DeviceInfoPowerStripResult, PowerStripPlugEnergyMonitoringResult
|
||||
|
||||
class PowerStripEnergyMonitoringHandler(DeviceManagementExt):
|
||||
"""Handler for the [P304M](https://www.tp-link.com/uk/search/?q=P304M) and
|
||||
[P316M](https://www.tp-link.com/us/search/?q=P316M) devices.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoPowerStripResult:
|
||||
"""Returns *device info* as `DeviceInfoPowerStripResult`.
|
||||
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 `PowerStripEnergyMonitoringHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoPowerStripResult: Device info of Tapo P300, P304M, P306 and P316M. Superset of `DeviceInfoGenericResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_list(
|
||||
self,
|
||||
) -> List[PowerStripPlugEnergyMonitoringResult]:
|
||||
"""Returns *child device list* as `List[PowerStripPlugEnergyMonitoringResult]`.
|
||||
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 `PowerStripEnergyMonitoringHandler.get_child_device_list_json`.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_list_json(self) -> dict:
|
||||
"""Returns *child device list* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_component_list_json(self) -> dict:
|
||||
"""Returns *child device component list* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def plug(
|
||||
self,
|
||||
device_id: Optional[str] = None,
|
||||
nickname: Optional[str] = None,
|
||||
position: Optional[int] = None,
|
||||
) -> PowerStripPlugEnergyMonitoringHandler:
|
||||
"""Returns a `PowerStripPlugEnergyMonitoringHandler` for the device matching the provided `device_id`, `nickname`, or `position`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
position (Optional[str]): The Position of the device
|
||||
|
||||
Returns:
|
||||
PowerStripPlugEnergyMonitoringHandler: Handler for the [P304M](https://www.tp-link.com/uk/search/?q=P304M) and
|
||||
[P316M](https://www.tp-link.com/us/search/?q=P316M) child plugs.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
power_strip = await client.p304("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await power_strip.plug(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
@@ -0,0 +1,96 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from tapo import PowerStripPlugHandler
|
||||
from tapo.device_management_ext import DeviceManagementExt
|
||||
from tapo.responses import DeviceInfoPowerStripResult, PowerStripPlugResult
|
||||
|
||||
class PowerStripHandler(DeviceManagementExt):
|
||||
"""Handler for the [P300](https://www.tp-link.com/en/search/?q=P300) and
|
||||
[P306](https://www.tp-link.com/us/search/?q=P306) devices.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def refresh_session(self) -> None:
|
||||
"""Refreshes the authentication session."""
|
||||
|
||||
async def get_device_info(self) -> DeviceInfoPowerStripResult:
|
||||
"""Returns *device info* as `DeviceInfoPowerStripResult`.
|
||||
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_device_info_json`.
|
||||
|
||||
Returns:
|
||||
DeviceInfoPowerStripResult: Device info of Tapo P300, P304M, P306 and P316M. Superset of `DeviceInfoGenericResult`.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_list(
|
||||
self,
|
||||
) -> List[PowerStripPlugResult]:
|
||||
"""Returns *child device list* as `List[PowerStripPlugResult]`.
|
||||
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`.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_list_json(self) -> dict:
|
||||
"""Returns *child device list* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_child_device_component_list_json(self) -> dict:
|
||||
"""Returns *child device component list* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def plug(
|
||||
self,
|
||||
device_id: Optional[str] = None,
|
||||
nickname: Optional[str] = None,
|
||||
position: Optional[int] = None,
|
||||
) -> PowerStripPlugHandler:
|
||||
"""Returns a `PowerStripPlugHandler` for the device matching the provided `device_id`, `nickname`, or `position`.
|
||||
|
||||
Args:
|
||||
device_id (Optional[str]): The Device ID of the device
|
||||
nickname (Optional[str]): The Nickname of the device
|
||||
position (Optional[str]): The Position of the device
|
||||
|
||||
Returns:
|
||||
PowerStripPlugHandler: Handler for the [P300](https://www.tp-link.com/en/search/?q=P300) and
|
||||
[P306](https://www.tp-link.com/us/search/?q=P306) child plugs.
|
||||
|
||||
Example:
|
||||
```python
|
||||
# Connect to the hub
|
||||
client = ApiClient("tapo-username@example.com", "tapo-password")
|
||||
power_strip = await client.p300("192.168.1.100")
|
||||
|
||||
# Get a handler for the child device
|
||||
device = await power_strip.plug(device_id="0000000000000000000000000000000000000000")
|
||||
|
||||
# Get the device info of the child device
|
||||
device_info = await device.get_device_info()
|
||||
print(f"Device info: {device_info.to_dict()}")
|
||||
```
|
||||
"""
|
||||
@@ -0,0 +1,92 @@
|
||||
from datetime import datetime
|
||||
|
||||
from tapo.requests import EnergyDataInterval, PowerDataInterval
|
||||
from tapo.responses import (
|
||||
CurrentPowerResult,
|
||||
DeviceUsageEnergyMonitoringResult,
|
||||
EnergyDataResult,
|
||||
EnergyUsageResult,
|
||||
PowerDataResult,
|
||||
PowerStripPlugEnergyMonitoringResult,
|
||||
)
|
||||
|
||||
class PowerStripPlugEnergyMonitoringHandler:
|
||||
"""Handler for the [P304M](https://www.tp-link.com/uk/search/?q=P304M) and
|
||||
[P316M](https://www.tp-link.com/us/search/?q=P316M) child plugs.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> PowerStripPlugEnergyMonitoringResult:
|
||||
"""Returns *device info* as `PowerStripPlugEnergyMonitoringResult`.
|
||||
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 `PowerStripPlugEnergyMonitoringHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
PowerStripPlugEnergyMonitoringResult: P304M and P316M power strip child plugs.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
|
||||
async def get_current_power(self) -> CurrentPowerResult:
|
||||
"""Returns *current power* as `CurrentPowerResult`.
|
||||
|
||||
Returns:
|
||||
CurrentPowerResult: Contains the current power reading of the device.
|
||||
"""
|
||||
|
||||
async def get_device_usage(self) -> DeviceUsageEnergyMonitoringResult:
|
||||
"""Returns *device usage* as `DeviceUsageResult`.
|
||||
|
||||
Returns:
|
||||
DeviceUsageEnergyMonitoringResult:
|
||||
Contains the time usage, the power consumption, and the energy savings of the device.
|
||||
"""
|
||||
|
||||
async def get_energy_usage(self) -> EnergyUsageResult:
|
||||
"""Returns *energy usage* as `EnergyUsageResult`.
|
||||
|
||||
Returns:
|
||||
EnergyUsageResult:
|
||||
Contains local time, current power and the energy usage and runtime for today and for the current month.
|
||||
"""
|
||||
|
||||
async def get_energy_data(
|
||||
self,
|
||||
interval: EnergyDataInterval,
|
||||
start_date: datetime,
|
||||
end_date: datetime = None,
|
||||
) -> EnergyDataResult:
|
||||
"""Returns *energy data* as `EnergyDataResult`.
|
||||
|
||||
Returns:
|
||||
EnergyDataResult: Energy data result for the requested `EnergyDataInterval`.
|
||||
"""
|
||||
|
||||
async def get_power_data(
|
||||
self,
|
||||
interval: PowerDataInterval,
|
||||
start_date_time: datetime,
|
||||
end_date_time: datetime,
|
||||
) -> PowerDataResult:
|
||||
"""Returns *power data* as `PowerDataResult`.
|
||||
|
||||
Returns:
|
||||
PowerDataResult: Power data result for the requested `PowerDataInterval`.
|
||||
"""
|
||||
@@ -0,0 +1,35 @@
|
||||
from tapo.responses import PowerStripPlugResult
|
||||
|
||||
class PowerStripPlugHandler:
|
||||
"""Handler for the [P300](https://www.tp-link.com/en/search/?q=P300) and
|
||||
[P306](https://www.tp-link.com/us/search/?q=P306) child plugs.
|
||||
"""
|
||||
|
||||
def __init__(self, handler: object):
|
||||
"""Private constructor.
|
||||
It should not be called from outside the tapo library.
|
||||
"""
|
||||
|
||||
async def on(self) -> None:
|
||||
"""Turns *on* the device."""
|
||||
|
||||
async def off(self) -> None:
|
||||
"""Turns *off* the device."""
|
||||
|
||||
async def get_device_info(self) -> PowerStripPlugResult:
|
||||
"""Returns *device info* as `PowerStripPlugResult`.
|
||||
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 `PowerStripPlugHandler.get_device_info_json`.
|
||||
|
||||
Returns:
|
||||
PowerStripPlugResult: P300 and P306 power strip child plugs.
|
||||
"""
|
||||
|
||||
async def get_device_info_json(self) -> dict:
|
||||
"""Returns *device info* as json.
|
||||
It contains all the properties returned from the Tapo API.
|
||||
|
||||
Returns:
|
||||
dict: Device info as a dictionary.
|
||||
"""
|
||||
@@ -0,0 +1,6 @@
|
||||
from .energy_data_interval import *
|
||||
from .play_alarm import *
|
||||
from .power_data_interval import *
|
||||
from .set_device_info import *
|
||||
|
||||
from tapo.responses import TemperatureUnitKE100 as TemperatureUnitKE100
|
||||
@@ -0,0 +1,15 @@
|
||||
from enum import Enum
|
||||
|
||||
class EnergyDataInterval(str, Enum):
|
||||
"""Energy data interval."""
|
||||
|
||||
Hourly = "Hourly"
|
||||
"""Hourly interval. `start_date` and `end_date` are an inclusive interval
|
||||
that must not be greater than 8 days.
|
||||
"""
|
||||
|
||||
Daily = "Daily"
|
||||
"""Daily interval. `start_date` must be the first day of a quarter."""
|
||||
|
||||
Monthly = "Monthly"
|
||||
"""Monthly interval. `start_date` must be the first day of a year."""
|
||||
@@ -0,0 +1,103 @@
|
||||
from enum import Enum
|
||||
|
||||
class AlarmVolume(str, Enum):
|
||||
"""The volume of the alarm.
|
||||
For the H100, this is a fixed list of volume levels."""
|
||||
|
||||
Default = "Default"
|
||||
"""Use the default volume for the hub."""
|
||||
|
||||
Mute = "Mute"
|
||||
"""Mute the audio output from the alarm.
|
||||
This causes the alarm to be shown as triggered in the Tapo App
|
||||
without an audible sound, and makes the `in_alarm` property
|
||||
in `DeviceInfoHubResult` return as `True`."""
|
||||
|
||||
Low = "Low"
|
||||
"""Lowest volume."""
|
||||
|
||||
Normal = "Normal"
|
||||
"""Normal volume. This is the default."""
|
||||
|
||||
High = "High"
|
||||
"""Highest volume."""
|
||||
|
||||
class AlarmRingtone(str, Enum):
|
||||
"""The ringtone of a H100 alarm."""
|
||||
|
||||
Alarm1 = "Alarm1"
|
||||
"""Alarm 1"""
|
||||
|
||||
Alarm2 = "Alarm2"
|
||||
"""Alarm 2"""
|
||||
|
||||
Alarm3 = "Alarm3"
|
||||
"""Alarm 3"""
|
||||
|
||||
Alarm4 = "Alarm4"
|
||||
"""Alarm 4"""
|
||||
|
||||
Alarm5 = "Alarm5"
|
||||
"""Alarm 5"""
|
||||
|
||||
Connection1 = "Connection1"
|
||||
"""Connection 1"""
|
||||
|
||||
Connection2 = "Connection2"
|
||||
"""Connection 2"""
|
||||
|
||||
DoorbellRing1 = "DoorbellRing1"
|
||||
"""Doorbell Ring 1"""
|
||||
|
||||
DoorbellRing2 = "DoorbellRing2"
|
||||
"""Doorbell Ring 2"""
|
||||
|
||||
DoorbellRing3 = "DoorbellRing3"
|
||||
"""Doorbell Ring 3"""
|
||||
|
||||
DoorbellRing4 = "DoorbellRing4"
|
||||
"""Doorbell Ring 4"""
|
||||
|
||||
DoorbellRing5 = "DoorbellRing5"
|
||||
"""Doorbell Ring 5"""
|
||||
|
||||
DoorbellRing6 = "DoorbellRing6"
|
||||
"""Doorbell Ring 6"""
|
||||
|
||||
DoorbellRing7 = "DoorbellRing7"
|
||||
"""Doorbell Ring 7"""
|
||||
|
||||
DoorbellRing8 = "DoorbellRing8"
|
||||
"""Doorbell Ring 8"""
|
||||
|
||||
DoorbellRing9 = "DoorbellRing9"
|
||||
"""Doorbell Ring 9"""
|
||||
|
||||
DoorbellRing10 = "DoorbellRing10"
|
||||
"""Doorbell Ring 10"""
|
||||
|
||||
DrippingTap = "DrippingTap"
|
||||
"""Dripping Tap"""
|
||||
|
||||
PhoneRing = "PhoneRing"
|
||||
"""Phone Ring"""
|
||||
|
||||
class AlarmDuration(str, Enum):
|
||||
"""Controls how long the alarm plays for."""
|
||||
|
||||
Continuous = "Continuous"
|
||||
"""Play the alarm continuously until stopped."""
|
||||
|
||||
Once = "Once"
|
||||
"""Play the alarm once.
|
||||
This is useful for previewing the audio.
|
||||
|
||||
Limitations:
|
||||
|
||||
The `in_alarm` field of `DeviceInfoHubResult` will not remain `True` for the
|
||||
duration of the audio track. Each audio track has a different runtime.
|
||||
|
||||
Has no observable affect when used in conjunction with `AlarmVolume.Mute`."""
|
||||
|
||||
Seconds = "Seconds"
|
||||
"""Play the alarm a number of seconds."""
|
||||
@@ -0,0 +1,16 @@
|
||||
from enum import Enum
|
||||
|
||||
class PowerDataInterval(str, Enum):
|
||||
"""Power data interval."""
|
||||
|
||||
Every5Minutes = "5min"
|
||||
"""Every 5 minutes interval. `start_date_time` and `end_date_time` describe an exclusive interval.
|
||||
If the result would yield more than 144 entries (i.e. 12 hours),
|
||||
the `end_date_time` will be adjusted to an earlier date and time.
|
||||
"""
|
||||
|
||||
Hourly = "Hourly"
|
||||
"""Hourly interval. `start_date_time` and `end_date_time` describe an exclusive interval.
|
||||
If the result would yield more than 144 entries (i.e. 6 days),
|
||||
the `end_date_time` will be adjusted to an earlier date and time.
|
||||
"""
|
||||
@@ -0,0 +1,3 @@
|
||||
from .color import *
|
||||
from .color_light import *
|
||||
from .lighting_effect import *
|
||||
@@ -0,0 +1,50 @@
|
||||
from enum import Enum
|
||||
from typing import Tuple
|
||||
|
||||
class Color(str, Enum):
|
||||
"""List of preset colors as defined in the Google Home app."""
|
||||
|
||||
CoolWhite = "CoolWhite"
|
||||
Daylight = "Daylight"
|
||||
Ivory = "Ivory"
|
||||
WarmWhite = "WarmWhite"
|
||||
Incandescent = "Incandescent"
|
||||
Candlelight = "Candlelight"
|
||||
Snow = "Snow"
|
||||
GhostWhite = "GhostWhite"
|
||||
AliceBlue = "AliceBlue"
|
||||
LightGoldenrod = "LightGoldenrod"
|
||||
LemonChiffon = "LemonChiffon"
|
||||
AntiqueWhite = "AntiqueWhite"
|
||||
Gold = "Gold"
|
||||
Peru = "Peru"
|
||||
Chocolate = "Chocolate"
|
||||
SandyBrown = "SandyBrown"
|
||||
Coral = "Coral"
|
||||
Pumpkin = "Pumpkin"
|
||||
Tomato = "Tomato"
|
||||
Vermilion = "Vermilion"
|
||||
OrangeRed = "OrangeRed"
|
||||
Pink = "Pink"
|
||||
Crimson = "Crimson"
|
||||
DarkRed = "DarkRed"
|
||||
HotPink = "HotPink"
|
||||
Smitten = "Smitten"
|
||||
MediumPurple = "MediumPurple"
|
||||
BlueViolet = "BlueViolet"
|
||||
Indigo = "Indigo"
|
||||
LightSkyBlue = "LightSkyBlue"
|
||||
CornflowerBlue = "CornflowerBlue"
|
||||
Ultramarine = "Ultramarine"
|
||||
DeepSkyBlue = "DeepSkyBlue"
|
||||
Azure = "Azure"
|
||||
NavyBlue = "NavyBlue"
|
||||
LightTurquoise = "LightTurquoise"
|
||||
Aquamarine = "Aquamarine"
|
||||
Turquoise = "Turquoise"
|
||||
LightGreen = "LightGreen"
|
||||
Lime = "Lime"
|
||||
ForestGreen = "ForestGreen"
|
||||
|
||||
def get_color_config(self) -> Tuple[int, int, int]:
|
||||
"""Get the `hue`, `saturation`, and `color_temperature` of the color."""
|
||||
@@ -0,0 +1,65 @@
|
||||
from typing import Union
|
||||
|
||||
from tapo.color_light_handler import ColorLightHandler
|
||||
from tapo.requests import Color
|
||||
from tapo.rgb_light_strip_handler import RgbLightStripHandler
|
||||
|
||||
class ColorLightSetDeviceInfoParams:
|
||||
"""Builder that is used by the `ColorLightHandler.set` API to set
|
||||
multiple properties in a single request.
|
||||
"""
|
||||
|
||||
def on(self) -> ColorLightSetDeviceInfoParams:
|
||||
"""Turns *on* the device.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
"""
|
||||
|
||||
def off(self) -> ColorLightSetDeviceInfoParams:
|
||||
"""Turns *off* the device.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
"""
|
||||
|
||||
def brightness(self, brightness: int) -> ColorLightSetDeviceInfoParams:
|
||||
"""Sets the *brightness*.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
The device will also be turned *on*, unless `ColorLightSetDeviceInfoParams.off` is called.
|
||||
|
||||
Args:
|
||||
brightness (int): between 1 and 100
|
||||
"""
|
||||
|
||||
def color(self, color: Color) -> ColorLightSetDeviceInfoParams:
|
||||
"""Sets the *color*.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
The device will also be turned *on*, unless `ColorLightSetDeviceInfoParams.off` is called.
|
||||
|
||||
Args:
|
||||
color (Color): one of `tapo.Color` as defined in the Google Home app.
|
||||
"""
|
||||
|
||||
def hue_saturation(self, hue: int, saturation: int) -> ColorLightSetDeviceInfoParams:
|
||||
"""Sets the *hue* and *saturation*.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
The device will also be turned *on*, unless `ColorLightSetDeviceInfoParams.off` is called.
|
||||
|
||||
Args:
|
||||
hue (int): between 0 and 360
|
||||
saturation (int): between 1 and 100
|
||||
"""
|
||||
|
||||
def color_temperature(self, color_temperature: int) -> ColorLightSetDeviceInfoParams:
|
||||
"""
|
||||
Sets the *color temperature*.
|
||||
`ColorLightSetDeviceInfoParams.send` must be called at the end to apply the changes.
|
||||
The device will also be turned *on*, unless `ColorLightSetDeviceInfoParams.off` is called.
|
||||
|
||||
Args:
|
||||
color_temperature (int): between 2500 and 6500
|
||||
"""
|
||||
|
||||
async def send(self, handler: Union[ColorLightHandler, RgbLightStripHandler]) -> None:
|
||||
"""Performs a request to apply the changes to the device.
|
||||
|
||||
Args:
|
||||
handler (`ColorLightHandler` | `RgbLightStripHandler`)
|
||||
"""
|
||||
@@ -0,0 +1,92 @@
|
||||
from enum import Enum
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
class LightingEffectType(str, Enum):
|
||||
Sequence = "Sequence"
|
||||
Random = "Random"
|
||||
Pulse = "Pulse"
|
||||
Static = "Static"
|
||||
|
||||
class LightingEffect:
|
||||
brightness: int
|
||||
is_custom: bool
|
||||
display_colors: List[Tuple[int, int, int]]
|
||||
"""The colors that will be displayed in the Tapo app."""
|
||||
enabled: bool
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
backgrounds: Optional[List[Tuple[int, int, int]]]
|
||||
brightness_range: Optional[List[Tuple[int, int]]]
|
||||
direction: Optional[int]
|
||||
duration: Optional[int]
|
||||
expansion_strategy: Optional[int]
|
||||
fade_off: Optional[int]
|
||||
hue_range: Optional[List[Tuple[int, int]]]
|
||||
init_states: Optional[List[Tuple[int, int, int]]]
|
||||
random_seed: Optional[int]
|
||||
repeat_times: Optional[int]
|
||||
run_time: Optional[int]
|
||||
saturation_range: Optional[List[Tuple[int, int]]]
|
||||
segment_length: Optional[int]
|
||||
segments: Optional[List[int]]
|
||||
sequence: Optional[List[Tuple[int, int, int]]]
|
||||
spread: Optional[int]
|
||||
transition: Optional[int]
|
||||
transition_range: Optional[List[Tuple[int, int]]]
|
||||
transition_sequence: Optional[List[int]]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
type: LightingEffectType,
|
||||
is_custom: bool,
|
||||
enabled: bool,
|
||||
brightness: int,
|
||||
display_colors: List[Tuple[int, int, int]],
|
||||
) -> None: ...
|
||||
def with_brightness(self, brightness: int) -> LightingEffect: ...
|
||||
def with_is_custom(self, is_custom: bool) -> LightingEffect: ...
|
||||
def with_display_colors(self, display_colors: List[Tuple[int, int, int]]) -> LightingEffect: ...
|
||||
def with_enabled(self, enabled: bool) -> LightingEffect: ...
|
||||
def with_id(self, id: str) -> LightingEffect: ...
|
||||
def with_name(self, name: str) -> LightingEffect: ...
|
||||
def with_type(self, type: LightingEffectType) -> LightingEffect: ...
|
||||
def with_backgrounds(self, backgrounds: List[Tuple[int, int, int]]) -> LightingEffect: ...
|
||||
def with_brightness_range(self, brightness_range: Tuple[int, int]) -> LightingEffect: ...
|
||||
def with_direction(self, direction: int) -> LightingEffect: ...
|
||||
def with_duration(self, duration: int) -> LightingEffect: ...
|
||||
def with_expansion_strategy(self, expansion_strategy: int) -> LightingEffect: ...
|
||||
def with_fade_off(self, fade_off: int) -> LightingEffect: ...
|
||||
def with_hue_range(self, hue_range: Tuple[int, int]) -> LightingEffect: ...
|
||||
def with_init_states(self, init_states: List[Tuple[int, int, int]]) -> LightingEffect: ...
|
||||
def with_random_seed(self, random_seed: int) -> LightingEffect: ...
|
||||
def with_repeat_times(self, repeat_times: int) -> LightingEffect: ...
|
||||
def with_run_time(self, run_time: int) -> LightingEffect: ...
|
||||
def with_saturation_range(self, saturation_range: Tuple[int, int]) -> LightingEffect: ...
|
||||
def with_segment_length(self, segment_length: int) -> LightingEffect: ...
|
||||
def with_segments(self, segments: List[int]) -> LightingEffect: ...
|
||||
def with_sequence(self, sequence: List[Tuple[int, int, int]]) -> LightingEffect: ...
|
||||
def with_spread(self, spread: int) -> LightingEffect: ...
|
||||
def with_transition(self, transition: int) -> LightingEffect: ...
|
||||
def with_transition_range(self, transition_range: Tuple[int, int]) -> LightingEffect: ...
|
||||
def with_transition_sequence(self, transition_sequence: List[int]) -> LightingEffect: ...
|
||||
|
||||
class LightingEffectPreset(str, Enum):
|
||||
Aurora = "Aurora"
|
||||
BubblingCauldron = "BubblingCauldron"
|
||||
CandyCane = "CandyCane"
|
||||
Christmas = "Christmas"
|
||||
Flicker = "Flicker"
|
||||
GrandmasChristmasLights = "GrandmasChristmasLights"
|
||||
Hanukkah = "Hanukkah"
|
||||
HauntedMansion = "HauntedMansion"
|
||||
Icicle = "Icicle"
|
||||
Lightning = "Lightning"
|
||||
Ocean = "Ocean"
|
||||
Rainbow = "Rainbow"
|
||||
Raindrop = "Raindrop"
|
||||
Spring = "Spring"
|
||||
Sunrise = "Sunrise"
|
||||
Sunset = "Sunset"
|
||||
Valentines = "Valentines"
|
||||
@@ -0,0 +1,9 @@
|
||||
from .child_device_list_hub_result import *
|
||||
from .child_device_list_power_strip_result import *
|
||||
from .current_power_result import *
|
||||
from .device_info_result import *
|
||||
from .device_usage_energy_monitoring_result import *
|
||||
from .device_usage_result import *
|
||||
from .energy_data_result import *
|
||||
from .energy_usage_result import *
|
||||
from .power_data_result import *
|
||||
@@ -0,0 +1,10 @@
|
||||
from .hub_result import *
|
||||
from .status import *
|
||||
from .temperature_unit import *
|
||||
|
||||
from .ke100_result import *
|
||||
from .s200b_result import *
|
||||
from .t100_result import *
|
||||
from .t110_result import *
|
||||
from .t300_result import *
|
||||
from .t31x_result import *
|
||||
@@ -0,0 +1,32 @@
|
||||
from tapo.responses.child_device_list_hub_result.status import Status
|
||||
|
||||
class HubResult:
|
||||
"""Hub result. This is an abstract base class for all hub results."""
|
||||
|
||||
at_low_battery: bool
|
||||
avatar: str
|
||||
bind_count: int
|
||||
category: str
|
||||
device_id: str
|
||||
fw_ver: str
|
||||
hw_id: str
|
||||
hw_ver: str
|
||||
jamming_rssi: int
|
||||
jamming_signal_level: int
|
||||
mac: str
|
||||
nickname: str
|
||||
oem_id: str
|
||||
parent_device_id: str
|
||||
region: str
|
||||
rssi: int
|
||||
signal_level: int
|
||||
specs: str
|
||||
status: Status
|
||||
type: str
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Gets all the properties of this result as a dictionary.
|
||||
|
||||
Returns:
|
||||
dict: The result as a dictionary.
|
||||
"""
|
||||
@@ -0,0 +1,28 @@
|
||||
from enum import Enum
|
||||
|
||||
from tapo.responses.child_device_list_hub_result.hub_result import HubResult
|
||||
|
||||
class KE100Result(HubResult):
|
||||
"""Device info of Tapo KE100 thermostatic radiator valve (TRV).
|
||||
|
||||
Specific properties: `temperature_unit`, `current_temperature`, `target_temperature`,
|
||||
`min_control_temperature`, `max_control_temperature`, `temperature_offset`,
|
||||
`child_protection_on`, `frost_protection_on`, `location`.
|
||||
"""
|
||||
|
||||
child_protection_on: bool
|
||||
current_temperature: float
|
||||
frost_protection_on: bool
|
||||
location: str
|
||||
max_control_temperature: int
|
||||
min_control_temperature: int
|
||||
target_temperature: float
|
||||
temperature_offset: int
|
||||
temperature_unit: TemperatureUnitKE100
|
||||
|
||||
class TemperatureUnitKE100(str, Enum):
|
||||
"""Temperature unit for KE100 devices.
|
||||
Currently *Celsius* is the only unit supported by KE100.
|
||||
"""
|
||||
|
||||
Celsius = "Celsius"
|
||||
@@ -0,0 +1,12 @@
|
||||
from tapo.responses.child_device_list_hub_result.hub_result import HubResult
|
||||
|
||||
class S200BResult(HubResult):
|
||||
"""Device info of Tapo S200B button switch.
|
||||
|
||||
Specific properties: `report_interval`, `last_onboarding_timestamp`, `status_follow_edge`.
|
||||
"""
|
||||
|
||||
last_onboarding_timestamp: int
|
||||
report_interval: int
|
||||
"""The time in seconds between each report."""
|
||||
status_follow_edge: bool
|
||||
@@ -0,0 +1,7 @@
|
||||
from enum import Enum
|
||||
|
||||
class Status(str, Enum):
|
||||
"""Device status."""
|
||||
|
||||
Online = "Online"
|
||||
Offline = "Offline"
|
||||
@@ -0,0 +1,14 @@
|
||||
from tapo.responses.child_device_list_hub_result.hub_result import HubResult
|
||||
|
||||
class T100Result(HubResult):
|
||||
"""Device info of Tapo T100 motion sensor.
|
||||
|
||||
Specific properties: `detected`, `report_interval`,
|
||||
`last_onboarding_timestamp`, `status_follow_edge`.
|
||||
"""
|
||||
|
||||
detected: bool
|
||||
last_onboarding_timestamp: int
|
||||
report_interval: int
|
||||
"""The time in seconds between each report."""
|
||||
status_follow_edge: bool
|
||||
@@ -0,0 +1,14 @@
|
||||
from tapo.responses.child_device_list_hub_result.hub_result import HubResult
|
||||
|
||||
class T110Result(HubResult):
|
||||
"""Device info of Tapo T110 contact sensor.
|
||||
|
||||
Specific properties: `open`, `report_interval`,
|
||||
`last_onboarding_timestamp`,`status_follow_edge`.
|
||||
"""
|
||||
|
||||
last_onboarding_timestamp: int
|
||||
open: bool
|
||||
report_interval: int
|
||||
"""The time in seconds between each report."""
|
||||
status_follow_edge: bool
|
||||
@@ -0,0 +1,23 @@
|
||||
from enum import Enum
|
||||
from tapo.responses.child_device_list_hub_result.hub_result import HubResult
|
||||
|
||||
class T300Result(HubResult):
|
||||
"""Device info of Tapo T300 water sensor.
|
||||
|
||||
Specific properties: `in_alarm`, `water_leak_status`, `report_interval`,
|
||||
`last_onboarding_timestamp`, `status_follow_edge`.
|
||||
"""
|
||||
|
||||
in_alarm: bool
|
||||
last_onboarding_timestamp: int
|
||||
report_interval: int
|
||||
"""The time in seconds between each report."""
|
||||
status_follow_edge: bool
|
||||
water_leak_status: WaterLeakStatus
|
||||
|
||||
class WaterLeakStatus(str, Enum):
|
||||
"""Water leak status."""
|
||||
|
||||
Normal = "Normal"
|
||||
WaterDry = "WaterDry"
|
||||
WaterLeak = "WaterLeak"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user