jasonacox / tinytuya

Python API for Tuya WiFi smart devices using a direct local area network (LAN) connection or the cloud (TuyaCloud API).
MIT License
1.02k stars 180 forks source link

Run tinituya wizard programmatically - provide API ID key, API Secret, API Region and sample Device ID in code #78

Open xtalax opened 3 years ago

xtalax commented 3 years ago

Hi, I'm trying to support Tuya smart plugs in an OctoPrint (3D Printer frontend) PSU plugin, and want to allow users to specify their API ID key, API Secret, API Region and Sample Device ID in the associated settings/config manager.

Is there a way to pass these values to the wizard in code, without a user having to manually enter them in the command line?

jasonacox commented 3 years ago

Hi @xtalax - If this is for juse one or two devices, why not have the user supply the DEVICE_ID and LOCAL_KEY?
You could then initialize TinyTuya and have it autodiscover the IP and VERSION:

    import tinytuya

    d = tinytuya.OutletDevice(DEVICE_ID, 'Auto', LOCAL_KEY)

The Wizard currently doesn't have a way to pass the values to bypass user interaction. Of course, that wouldn't be difficult to change... help me with some questions if I were to add a non-interactive mode where you just supply the 4 parameters:

Whytey commented 2 years ago

Hi @jasonacox,

If I could add my input here, i would like to use tinytuya as a library from within a web-based UI (http://home-assistant.io). The integration I would like to develop would provide the user with a list local devices and the user would choose one for future use in the program. I would like to do the discovery of the local_key in an almost invisible manner for the user.

Probable flow: 1) User initiates a scan (providing API ID key, API Secret, API Region). 2) In the background, do a scan and assuming we get a list of devices choose a random one use the device ID to run the wizard with. 3) In the background, run the wizard to retrieve all devices data in a Python dict. 4) My program parses the dict to match to the devices my integration is interested in (by matching to known dps). 5) Allow the user the choose one of any matching devices to add to home-assistant. 6) Home-assistant will then monitor/control the device using the tinytuya library

jasonacox commented 2 years ago

Hi @Whytey - I love your idea. Some thoughts:

  1. We can add a function to scanner.py to just provide ONE device ID. This would be quick and could be saved to the standard tinytuya.json file.
  2. With that device ID and the user provided API credentials (tinytuya.json), we can add a "non-interactive" function to wizard.py that pulls the Local KEYs from Tuya cloud and scans the network for all Tuya device IPs. It will produce the standard devices.json and snapshot.json files with all this data.
  3. The home-assistant.io UI that you create could read that file and display those as devices for the user to select/add.

Depending on the local network DHCP settings, the devices can change IP addresses especially during power outages or internet router reboots. We would want the ability for the UI to kick off a non-interactive alldevices() scanning function in scanner.py to update the IP addresses for all the devices. Alternatively there could be a service added to home-assistant.io that uses the core part of scanner.py to constantly listen for the Tuya discovery broadcasts (which is a ID + IP paired packet) and dynamically updates IP addresses if they change.

Let me know what you think. I'm happy to invest some time adding those non-interactive functions or even a standalone service (for discovery).

lorenja8 commented 2 months ago

Hi, I'm trying to support Tuya smart plugs in an OctoPrint (3D Printer frontend) PSU plugin, and want to allow users to specify their API ID key, API Secret, API Region and Sample Device ID in the associated settings/config manager.

Is there a way to pass these values to the wizard in code, without a user having to manually enter them in the command line?

Hi, supposedly, this is no longer relevant; however, I would just like to share my solution to the issue described above in case that someone is facing this in the future. I wanted to implement the wizard into the program as well, and did the following:

from unittest.mock import patch
from tinytuya.wizard import wizard as tt_wiz

def fill(self, api_key=str, api_secret=str, device_id=str):
    inputs = [api_key, api_secret, device_id, 'eu', 'Y', 'n']

    # Patch the input function
    with patch('builtins.input', side_effect=inputs):
        tt_wiz()

Running the "fill" function with the proper inputs from the Tuya website then successfully ran the wizard as if it was run from the terminal.

I hope this could help. Good luck.

uzlonewolf commented 2 months ago

I'm not sure if it's documented, but instead of doing that you can just pass in the API credentials:

credentials = {
    'file': None,
    'apiKey': '...',
    'apiSecret': '...',
    'apiRegion': '...',
    'apiDeviceID': '...',
}

wizard(assume_yes=True, skip_poll=True, credentials=credentials)
lorenja8 commented 2 months ago

I'm not sure if it's documented, but instead of doing that you can just pass in the API credentials:

credentials = {
    'file': None,
    'apiKey': '...',
    'apiSecret': '...',
    'apiRegion': '...',
    'apiDeviceID': '...',
}

wizard(assume_yes=True, skip_poll=True, credentials=credentials)

I haven't noticed this anywhere, it is actually much cleverer 😄 Thank you!