jasonacox / tinytuya

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

Door lock control via cloud - mk device #541

Open andyb2000 opened 2 weeks ago

andyb2000 commented 2 weeks ago

I'm trying to add in cloud support for this door lock device. Device details first: image

{
  "result": {
    "active_time": 1725634908,
    "bind_space_id": "153504535",
    "category": "mk",
    "create_time": 1725612531,
    "custom_name": "XX Door Controls",
    "icon": "smart/icon/bay1601253790250Rnas/d0a135a289a77ba1d3f3007308b425d0.jpg",
    "id": "bfc28e88ad23bc91f6mwgz",
    "ip": "62.XX.XX.XX",
    "is_online": true,
    "lat": "54.XX",
    "local_key": "6XXXXXXX",
    "lon": "-1.XX",
    "model": "T12-Wifi-II",
    "name": "Card+PIN",
    "product_id": "s7qamihym60z5jro",
    "product_name": "门控-II",
    "sub": false,
    "time_zone": "+01:00",
    "update_time": 1727972468,
    "uuid": "a5ff34a4121502c2"
  },

In the TUYA API I've worked out that you can trigger an unlock by the "Smart Lock Open Service" by grabbing a temporary key:

https://openapi.tuyaeu.com/v1.0/smart-lock/devices/bfc28e88ad23bc91f6mwgz/password-ticket

Which returns:

{
  "result": {
    "expire_time": 360,
    "ticket_id": "bxEhlNt2",
    "ticket_key": "9B07673040545EA14E972DFBC1D4100A754XXXXX"
  },
  "success": true,
  "t": 1728029558654,
  "tid": "6b869081822811efb777360338XXXXX"
}

From that you can then trigger a temporary unlock using "Unlock Door Without Password" which uses the ticket_id above (8 character so in my example it's bxEhlNt2) so the unlock api call is:

https://openapi.tuyaeu.com/v1.1/devices/bfc28e88ad23bc91f6mwgz/door-lock/password-free/open-door

And the payload/data to set is {"ticket_id":"bxEhlNt2"}

What I'm struggling to work out is how to achieve this via the tinytuya cloud api commands. I've added/setup the cloud functions and can retrieve device state of the unit, etc. How would I turn this into commands? In the example for a smart switch you would:

commands = {
       'commands': [{
               'code': 'switch_1',
               'value': True
       }, {
               'code': 'countdown_1',
               'value': 0
       }]
}
print("Sending command...")
result = c.sendcommand(id,commands)

However, I'm unsure how to do raw api calls/queries using this library. Any pointers please?

uzlonewolf commented 1 week ago

You should be able to just

c = tinytuya.Cloud(...)

ticket = c.cloudrequest( '/v1.0/smart-lock/devices/bfc28e88ad23bc91f6mwgz/password-ticket' )

unlock = c.cloudrequest( '/v1.1/devices/bfc28e88ad23bc91f6mwgz/door-lock/password-free/open-door', post={'ticket_id': '...'} )

cloudrequest:

    def cloudrequest(self, url, action=None, post=None, query=None):
        """
        Make a generic cloud request and return the results.

        Args:
          url:    Required.  The URL to fetch, i.e. "/v1.0/devices/0011223344556677/logs"
          action: Optional.  GET, POST, DELETE, or PUT.  Defaults to GET, unless POST data is supplied.
          post:   Optional.  POST body data.  Will be fed into json.dumps() before posting.
          query:  Optional.  A dict containing query string key/value pairs.
        """