Package: tuyaface
Tuya client that allows you to locally communicate with tuya deviceswithoutthe tuya-cloud.Installationpip install tuyafaceModuletuyaface{#tuyaface}Functionality for communicating with a Tuya device.Sub-modulestuyaface.aesciphertuyaface.consttuyaface.helpertuyaface.tuyaclientFunctionsFunctionset_state{#tuyaface.set_state}def set_state(device: dict, value, idx: int = 1)Send status update request for one dps value to the tuya device.returns boolFunctionset_status{#tuyaface.set_status}def set_status(device: dict, dps: dict)Send state update request to the tuya device and waits for response.returns boolFunctionstatus{#tuyaface.status}def status(device: dict)Request status of the tuya device.returns dictModuletuyaface.aescipher{#tuyaface.aescipher}Helpers for AES crypto.FunctionsFunctiondecrypt{#tuyaface.aescipher.decrypt}def decrypt(key, enc, use_base64=True)Optionally base64-decode and decrypt.Functionencrypt{#tuyaface.aescipher.encrypt}def encrypt(key, raw, use_base64=True)Encrypt and optionally base64-encode.Moduletuyaface.const{#tuyaface.const}Tuya constants.Moduletuyaface.helper{#tuyaface.helper}Helpers.FunctionsFunctionbytes2hex{#tuyaface.helper.bytes2hex}def bytes2hex(data: bytes, pretty: bool = False)Render hexstring from bytes.Functionhex2bytes{#tuyaface.helper.hex2bytes}def hex2bytes(data: str)Parse hexstring to bytes.Moduletuyaface.tuyaclient{#tuyaface.tuyaclient}Helper to maintain a connection to and serialize access to a Tuya device.ClassesClassTuyaClient{#tuyaface.tuyaclient.TuyaClient}class TuyaClient(device: dict, on_status: <built-in function callable> = None, on_connection: <built-in function callable> = None)Helper class to maintain a connection to and serialize access to a Tuya device.Initialize the Tuya client.Ancestors (in MRO)threading.ThreadMethodsMethodrun{#tuyaface.tuyaclient.TuyaClient.run}def run(self)Tuya client main loop.Methodset_state{#tuyaface.tuyaclient.TuyaClient.set_state}def set_state(self, value, idx: int = 1)Set state.Methodstatus{#tuyaface.tuyaclient.TuyaClient.status}def status(self)Request status.Methodstop_client{#tuyaface.tuyaclient.TuyaClient.stop_client}def stop_client(self)Close the connection and stop the worker thread.examplefrom tuyaface.tuyaclient import TuyaClient

def on_status(data: dict):
    print(data)

def on_connection(value: bool):
    print(value)

device = {
    'protocol': '3.3', # 3.1 | 3.3
    'deviceid': '34280100600194d17c96',
    'localkey': 'e7e9339aa82abe61',
    'ip': '192.168.1.101',            
}

client = TuyaClient(device, on_status, on_connection)
client.start()

data = client.status()
client.set_state(!data['dps']['1'], 1) #toggle
client.stop_client()Data structureDevice dictdevice = {
    'protocol': '3.3', # 3.1 | 3.3
    'deviceid': '34280100600194d17c96',
    'localkey': 'e7e9339aa82abe61',
    'ip': '192.168.1.101',
    'pref_status_cmd': 10 #optional, default 10
}TuyaFace will automatically addtuyafacedict to the device with data to support implementations without the TuyaClient class.tuyaface = {
    "sequence_nr": 0, # Request counter
    "connection": None, # Holds the connection 
    "availability": False, # If the device could be reached
    "pref_status_cmd": 10, # Preferred status command 
    "status": None, # Reply to the last status request
}DPS dictdps = {
    '1': True,
    '2': False,
    '101': 255,
    '102': 128,
    ...etc...
}ImprovementsDo you have ideas how we can make this package even better? Or would you like to contribute in another way? Drop a line in the issue section, all help is welcome.Acknowledgementshttps://github.com/emontnemerytuyaclient and much morehttps://github.com/jkerdreux-imtseveral improvementshttps://github.com/SDNick484for testing protocol 3.1 reimplementationhttps://github.com/PortableProgrammerhelp on #20https://github.com/clach04/python-tuyaformed the base for this libhttps://github.com/codetheweb/tuyapias reference on commandsImplementationshttps://github.com/TradeFace/tuyamqttlet me know, I'll add it here