GoTuya ๐๐ฉ๏ธ
January 11, 2026 ยท View on GitHub
A Go Api to control your Tuya devices through your Local Network (LAN)
Features:
- ๐ง๐ โโ๏ธ Works completely offline without any connection to the ๐ฉ and unsecure chinese clouds
- ๐ Easily extendable: Control any Tuya device with ease
- ๐ฌ Battle tested with a Tuya TCL A/C
Important
Currently only Tuya devices with Version 3.3 are supported because I don't own any devices that are using different protocol versions. Feel free to add them. If you need help you can take a look at the tuyapi project or create an Issue.
Note
This Go api wouldn't be possible without the amazing tuyapi project
I use this package myself at my home with two A/Cs, so don't worry if there is no commit for a longer period of time. If this package breaks I will fix it :)
Quickstart
Install the Package:
$ go get -u github.com/Binozo/GoTuya
Setup your Tuya Device
You will need the following data to control your Tuya device:
- The device's ip in your local network
- The
deviceId - The
localKey
To retrieve those values you have to follow those steps.
Implement the Api
Here is an example for an Air Conditioner:
package main
import (
"fmt"
"github.com/Binozo/GoTuya/pkg/ac"
"time"
)
func main() {
myTclAc := ac.CreateAC("192.168.178.30", "15580880bcaac262j6eg", "A2In><,:-{Hy:[%K7")
isOn, err := myTclAc.IsOn()
if err != nil {
panic(err)
}
fmt.Println("A/C is on:", isOn)
if !isOn {
targetTemp := 20
fmt.Printf("The A/C is not on. Starting cooling with %dยฐC...\n", targetTemp)
if err := myTclAc.SetTemperature(targetTemp); err != nil {
fmt.Println("Couldn't turn on A/C:", err.Error())
return
}
fmt.Println("A/C has been turn on. Waiting for 5 seconds to cool")
time.Sleep(time.Second * 5)
fmt.Println("Turning off")
if err := myTclAc.Power(false); err != nil {
fmt.Println("Couldn't turn off A/C:", err.Error())
}
}
}
๐ Extending with your own Tuya device
Tuya devices work all the same way. They work with dictionaries. Let's explain this with an example:
state := map[string]int{
"TEMPERATURE": 2,
"SPEED": 5,
"FEATURE_C": 0,
"FEATURE_D": 1,
}
Now if we want to set the temperature to 10ยฐC we would just set
state["TEMPERATURE"] = 10
programmatically and upload that dictionary to the Tuya device. We don't need to send every value, we can just send the key value pair we just changed.
This is the way it works under the hood. Easy, isn't it? ๐
Now if you want to add your own device you just have to find out which keys exist in that map and which values the can have:
package main
import (
"fmt"
"github.com/Binozo/GoTuya/pkg/tuya"
)
func main() {
device := tuya.CreateDevice("IP", "DEVICEID", "KEY", tuya.Version_3_3)
if err := device.Connect(); err != nil {
panic(err)
}
defer device.Disconnect()
state := device.GetCurrentStatus() // TODO: Check which values you need
fmt.Println("Current state:", state)
}
Execute this code everytime you changed a parameter (e.g. Temeprature) of your device. This way you can find out which key stands for what feature.
The ac package is a prebuilt wrapper for A/Cs. Looking at the implementation could help you implement your own device.
PRs are always welcome!