Awesome
Tuya
Kit
A library to control Tuya smart home devices via local TCP connection.
// Once you setup a device...
socket = new Woox_R4026()
{
IP = "192.168.0.100",
port = 6668,
protocolVersion = "3.1",
name = "Lounge Light Socket",
devId = "<DEV_ID>",
localKey = "<LOCAL_KEY>"
};
// ...you can simply set states via device wrapper.
socket.TurnOn();
Credits
Based on Max Isom's reverse engineered TuyAPI library (and corresponding TuyaCore .NET port by Marcus Lum).
Tuya services
Tuya distributed devices are mostly controlled with an ESP8266 WiFi module with a specific firmware (see Module Overview). By default you can control the devices via a Tuya specific app, like Tuya Smart, Smart Life, Jinvoo Smart, Lohas Smart or Woox Home to name a few. Under the hood they are all various derivatives of the white labeled Tuya Smart Cloud Service (brands have separate containers for device data though).
Once you have registered your device with one of the apps, it will have a localKey
assigned upon pairing. From then on the app encrypts device requests with that key.
This library just does the same. Once you have the corresponding device data it orchestrates the encryption and the communication protocol via local TCP connection.
Getting device data
After you registered you device in one of the consumer apps mentioned above, you can find device information details in there somewhere. It tells you the devId
(Smart Life app calls it Virtual ID) and the Mac Address. Having the Mac Address you can look up the Local IP Address of the device in the DHCP Client List of your WiFi Router. Port number and Protocol Version is set to 6668
and 3.1
by default.
Getting the localKey
can be tricky. Luckily Max Isom created a tool tuya-cli
to extract device data from the network traffic. See Linking a Tuya Device for a detailed breakdown.
Device control schema
To obtain the dps
schema (the device properties you can manage) I simply inspected the console output of the Android Smart Life app using adb logcat
. It gives you a pretty detailed log when navigating to the Device Information view. For a Woox R4026 Smart Plug it shows this schema:
{
"initialProps": {
"devInfo": {
...
"dps": {
"1": true,
"9": 0
},
...
"schema": {
"1": {
"type": "obj",
"name": "开关1",
"mode": "rw",
"code": "switch_1",
"id": "1",
"schemaType": "bool",
"iconname": "icon-dp_power2",
"property": "{\"type\":\"bool\"}"
},
"9": {
"type": "obj",
"name": "开关1倒计时",
"mode": "rw",
"code": "countdown_1",
"id": "9",
"schemaType": "value",
"iconname": "icon-dp_time2",
"property": "{\"max\":86400,\"min\":0,\"scale\":0,\"step\":1,\"type\":\"value\",\"unit\":\"s\"}"
}
}
...
}
}
}
It shows a bool
switch on ["dps"]["1"]
and a countdown value (seconds) on ["dps"]["9"]
.
Implementing a device
After you created a Device
instance, you can send any JSON data to it using a Request
object.
// Get device properties.
JObject response = await new Request().SendJSONObjectForCommandToDevice(
new Dictionary<string, object>
{
["gwId"] = socket.gwId,
["devId"] = socket.devId
},
Request.Command.GetStatus,
socket);
A Woox R4026 Smart Plug responds with a status like below:
{
"devId":"58205000840d8e46ebb0",
"dps":
{
"1" : true,
"9" : 0
}
}
It gives you a status report according the very same control schema obtained above. To cut boilerplate, it is wrapped into a simple Get()
method in Device
class that gives you back only the dps
data you care about.
// Get device properties.
Dictionary<string, object> dps = await socket.Get();
{
"1" : true,
"9" : 0
}
To set dps
you can use Device.Set()
.
// Set device properties.
await socket.Set(
new Dictionary<string, object>
{
["1"] = false,
["2"] = 0
}
);
Once you have a specific device, you can wrap up dps
all communication into a Device
subclass (see Woox_R4026.cs
for more).
...
public async void TurnOff()
{
await Set(
new Dictionary<string, object>
{
["1"] = false,
["2"] = 0
}
);
}
public async void TurnOn()
{
await Set(
new Dictionary<string, object>
{
["1"] = true,
["2"] = 0
}
);
}
...
After that you can use pretty much without any boilerplate.
socket.TurnOn();
Next up
Will probably implement retry attempts, also I'm planning to create the library for iOS.
Furthermore, would be great if you guys could contribute with various Device
implementations. I saw that there is a myriad of manufacturers out there, let me just highligt some of the brands I encountered.
Cotify, Ushawn, Elegant Choise, Cxy, Zenic, Sonew, Venoro, Innens, Oittm, Lixada, Woox
License
Licensed under the MIT license.