mihai-dinculescu / tapo

Unofficial Tapo API Client. Works with TP-Link Tapo smart devices. Tested with light bulbs (L510, L520, L530, L610, L630), light strips (L900, L920, L930), plugs (P100, P105, P110, P115, P300), hubs (H100), switches (S200B) and sensors (KE100, T100, T110, T300, T310, T315).
MIT License
313 stars 30 forks source link

ApiClient on AWS Lambda #227

Closed LucaLovagnini closed 3 weeks ago

LucaLovagnini commented 3 weeks ago

I'm trying to run the tapo_p100.py example on an AWS Lambda (the local version works with my account and device) with the following code:

"""P100 & P105 Example"""

import asyncio

from tapo import ApiClient

async def test_device():
    tapo_username = "myusername@email.com"
    tapo_password = "mypassword"
    ip_address = "192.168.1.8"

    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()}")

def lambda_handler(event, context):
    asyncio.run(test_device())

However it fails due to tiemout:


{
  "errorMessage": "Http(Error { kind: Timeout, context: None, source: Some(Error { description: \"Timeout was reached\", code: 28, extra: None }), source_type: Some(\"curl::error::Error\"), local_addr: None, remote_addr: None })",
  "errorType": "Exception",
  "requestId": "1a7c8ec3-f4a6-44b8-a1f7-3d34f5ac2963",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 37, in lambda_handler\n    asyncio.run(test_device())\n",
    "  File \"/var/lang/lib/python3.12/asyncio/runners.py\", line 194, in run\n    return runner.run(main)\n",
    "  File \"/var/lang/lib/python3.12/asyncio/runners.py\", line 118, in run\n    return self._loop.run_until_complete(task)\n",
    "  File \"/var/lang/lib/python3.12/asyncio/base_events.py\", line 687, in run_until_complete\n    return future.result()\n",
    "  File \"/var/task/lambda_function.py\", line 14, in test_device\n    device = await client.p100(ip_address)\n"
  ]
}

Again, this works correctly if ran (with a classic main) on my computer.

mihai-dinculescu commented 3 weeks ago

This library is designed to work best over the local network.

You have provided an IP address on your local private network, as you should. However, by default, Lambda (or any cloud service, for that matter) cannot access this device on your local private network.

There are ways to get around this, but they are either insecure (opening the device to the internet) or quite involved (VPNs).

Are you sure that cloud is the best choice for your project? This kind of project usually sits best on a Raspberry Pi that's on the same local private network.