jasonacox / tinytuya

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

Can't Control without tuya cloud - Pet Feeder #461

Open meluvalli opened 4 months ago

meluvalli commented 4 months ago

Hello. I have a device that will only get dps once it connects to the cloud.

If I run :

data = d.status() 
print('set_status() result %r' % data)

My output if I block my device from the internet is:

set_status() result {'dps': {}, 'type': 'query', 't': 179}

But if I unblock it then it changes to:

set_status() result {'dps': {'12': False, '14': 0, '15': 0, '19': True, '101': 'ac_power_on', '103': 'real_time_mode', '112': 3}}

I blocked it again, rebooted it, then ran monitor on it and this is what it shows:

Received Payload: None
 > Send Heartbeat Ping <
Received Payload: {'dps': {'1': ''}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'3': 1}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'19': True}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'103': 'real_time_mode'}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'112': 3}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'12': False}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'14': 0}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: {'dps': {'101': 'ac_power_on'}, 't': 884}
 > Send Heartbeat Ping <
Received Payload: None
 > Send Heartbeat Ping <
Received Payload: {'dps': {'11': 0}, 't': 884}
 > Send Heartbeat Ping <

Any idea how to get dps's without connecting it to Tuya cloud?

jasonacox commented 4 months ago

Hi @meluvalli - Can you post what type of device this is (and link to a details about it if you can). That will help others who have a similar device.

Keep in mind that Tuya devices are designed to connect to the cloud. That is their primary function. The local access point that many of the Tuya devices have, and TinyTuya uses for local status/control, is a secondary feature. You will need cloud access to register them and to get the local access key. Some devices, once registered, will work perfectly fine offline (no internet), others will refuse to work at all.

For your device, you are getting some updates during the monitor loop so at least it isn't fully disabled. You could try sending the updatedps command to see if that helps:

d.updatedps(['18','19','20'], nowait=True)
meluvalli commented 4 months ago

Well, apparently after more research, some devices doesn't advertise the DPS correctly until the entity has been properly initialized onto Tuya server... So, i'm guessing no way around this at this point. I tried the d.updatedps, but didn't change anything. Device still reports no dps's while offline.

This device in question is a pet feeder. Below is the device information:

[
    {
        "name": "Pet Feeder",
        "id": "XXXXXXXXXXXXX",
        "key": "XXXXXXXXXXXXX",
        "mac": "XX:XX:XX:XX:XX:XX",
        "uuid": "XXXXXXXXXXXXX",
        "sn": "XXXXXXXXXXXXX",
        "category": "cwwsq",
        "product_name": "XTUOES",
        "product_id": "ibxe5jf6mtqmdfxl",
        "biz_type": 0,
        "model": "",
        "sub": false,
        "icon": "https://images.tuyaus.com/smart/icon/bay16227127058150Bvl/cce4b4106abc9a283c7add8cad7f6e5b.png",
        "mapping": {
            "1": {
                "code": "meal_plan",
                "type": "Raw",
                "values": {}
            },
            "3": {
                "code": "manual_feed",
                "type": "Integer",
                "values": {
                    "unit": "",
                    "min": 1,
                    "max": 20,
                    "scale": 0,
                    "step": 1
                }
            },
            "9": {
                "code": "factory_reset",
                "type": "Boolean",
                "values": {}
            },
            "11": {
                "code": "battery_percentage",
                "type": "Integer",
                "values": {
                    "unit": "%",
                    "min": 0,
                    "max": 100,
                    "scale": 0,
                    "step": 1
                }
            },
            "12": {
                "code": "charge_state",
                "type": "Boolean",
                "values": {}
            },
            "15": {
                "code": "feed_report",
                "type": "Integer",
                "values": {
                    "unit": "",
                    "min": 0,
                    "max": 20,
                    "scale": 0,
                    "step": 1
                }
            },
            "19": {
                "code": "light",
                "type": "Boolean",
                "values": {}
            }
        },
        "ip": "XX.XX.XX.XX",
        "version": "3.3"
    }
]
meluvalli commented 4 months ago

What's strange about it is that I can still control the device using:

data = d.set_status(3, 3)

It still does the feeder even though the dps isn't there. And even after that, the dps still isn't there!

jasonacox commented 4 months ago

Did you try sending updatedps() with that index? I suspect it won't make a difference, but worth trying.

d.updatedps(['3'], nowait=True)
meluvalli commented 4 months ago

Yep. No difference :(

set_status() result {'dps': {}, 'type': 'query', 't': 1474}
jasonacox commented 4 months ago

set_status()

Did you mean status()? You're not going to get full DPS response with set_status() as that function is used to set DPS values rather than read them.

meluvalli commented 4 months ago

Yes. Sorry, just coppied and pasted from another script :)

data = d.status() 
print('set_status() result %r' % data)

Was the code I used. It is actually d.status :)