A Go library for the YoLink smart home API. Supports HTTP and MQTT transports, strongly-typed controllers for every supported device, real-time event subscriptions, and a CLI tool for shell scripting.
go get github.com/tyandl/yolink-api/v2Requires Go 1.21+.
Authenticate with a YoLink User Access Credential (UAC). Create one in the YoLink mobile app:
Settings → Account → Advanced Settings → User Access Credentials → Create
This yields a UAID (client ID) and a Secret Key (client secret).
import (
"github.com/tyandl/yolink-api/v2/pkg/controller"
_ "github.com/tyandl/yolink-api/v2/pkg/devices" // registers typed device controllers
)
home, err := controller.NewHome(
controller.CloudOptions{},
func() string { return os.Getenv("YOLINK_CLIENT_ID") },
func() string { return os.Getenv("YOLINK_CLIENT_SECRET") },
)
devices, err := home.GetDeviceList()
for _, device := range devices {
fmt.Printf("%s\t%s\t%s\n", device.GetName(), device.GetType(), device.GetId())
}Importing pkg/devices (even as _) registers the typed controllers, so
GetDeviceList and GetDeviceByName return concrete types you can type-assert:
device, err := home.GetDeviceByName("Front Door")
if sensor, ok := device.(*devices.DoorSensor); ok {
state, err := sensor.GetState()
fmt.Printf("state=%s battery=%s\n", state.State.State, state.State.Battery)
}Devices without a registered type fall back to the untyped controller.Device.
if lamp, ok := device.(*devices.Switch); ok {
_, err := lamp.SetState(devices.SwitchSetStateParams{State: types.SwitchCommandOpen})
}if err := home.InitializeMqtt("tcp://mqtt.api.yosmart.com:8003"); err != nil {
log.Fatal(err)
}
defer home.CloseMqtt()
reports, stop, err := home.Subscribe() // whole home; or device.Subscribe() for one device
defer stop()
for report := range reports {
fmt.Printf("%s: %s %v\n", report.Device.GetName(), report.Event, report.Data)
}Note: the YoLink cloud MQTT broker is plaintext TCP on port 8003 — no TLS endpoint is available. The access token travels as the MQTT username. Use
controller.LocalOptions(see "Local Hub" below) to connect to a Local Hub broker on a trusted LAN instead, for transport encryption within your own network boundary.
A Local Hub on the LAN uses a different auth scheme and topic layout than the cloud broker
entirely: the client ID/secret as MQTT username/password (not the access token), and topics
rooted at ylsubnet/{netId}/... instead of yl-home/{homeId}/.... Pass LocalOptions
instead of CloudOptions and this is handled automatically:
home, err := controller.NewHome(
controller.LocalOptions{
Host: "192.168.1.50", // the hub's LAN address
NetId: "C00295", // YoLink app: hub details → "Net Id" (not obtainable via the API)
},
clientId, clientSecret,
)
devices, err := home.GetDeviceList()
err = home.InitializeMqtt()HTTPPort/MQTTPort default to the hub's standard 1080/18080 if left zero.
ch := sensor.GetStateAsync()
result := <-ch
if result.Err != nil {
log.Fatal(result.Err)
}
fmt.Println(result.Response)Home.Save serializes the connect options, home info, and device list to JSON. Credentials
are never written to the blob and must be supplied again at restore time:
blob, err := home.Save()
// later:
home, err = controller.RestoreHome(idFn, secretFn, blob)The cmd/yolink program is a full-featured CLI for interacting with the YoLink API from
the shell.
go build ./cmd/yolink
export YOLINK_CLIENT_ID=<UAID>
export YOLINK_CLIENT_SECRET=<secret># List all devices: name<TAB>type<TAB>id
./yolink ls
# Stream real-time reports as newline-delimited JSON
./yolink listen
./yolink listen --on "Front Door"
# Call a typed method on a device
./yolink do getState --on "Front Door"
./yolink do setState --on "Kitchen Light" --state open
# Connect to a Local Hub instead of the cloud
./yolink --local-hub 192.168.1.50 --net-id C00295 listen| Flag | Default | Description |
|---|---|---|
--log |
warn |
Log verbosity: debug, info, warn, error |
--output |
json |
Output format: json or go |
--client-id |
env | Override YOLINK_CLIENT_ID |
--client-secret |
env | Override YOLINK_CLIENT_SECRET |
--host, --mqtt-broker |
cloud defaults | Cloud endpoint overrides. Cannot combine with --local-hub. |
--local-hub, --net-id |
— | Connect to a Local Hub instead of the cloud (see Local Hub). Required together. |
--local-http-port, --local-mqtt-port |
1080, 18080 |
Override the Local Hub's ports |
| Category | Devices |
|---|---|
| Sensors | DoorSensor, MotionSensor, LeakSensor, VibrationalSensor, ThSensor, SoilThcSensor, WaterDepthSensor, CoSmokeSensor, PowerFailureAlarm, IpCamera |
| Controls | Switch, MultiOutlet, Outlet, Dimmer, Siren, GarageDoor, Lock, LockV2, Manipulator, Sprinkler, SprinklerV2, Thermostat |
| Hubs | Hub, CellularHub, SpeakerHub |
| Metering | WaterMeterController, WaterLeakController |
| Other | Finger, SmartRemoter, InfraredRemoter, CsDevice, Debugger |
Typed device controllers are generated from JSON definitions in pkg/devices/. Each
.json file describes a device's methods and events; the generator produces a
*_gen.go file with typed request/response structs, sync and async method receivers,
and an MQTT event parser.
After adding or editing a device definition:
python3 scripts/gen_device_types.py
go build ./... # verify the generated code compilesDo not edit *_gen.go files directly.
pkg/controller/ HTTP + MQTT transports, Home, device registry, save/restore
pkg/devices/ typed device controllers (*_gen.go) and their JSON definitions
pkg/types/ shared types: enums, timestamps, temperature, status codes
cmd/yolink/ CLI tool
scripts/ code generators
Full go doc output for each package is saved in docs/:
docs/controller.txt—pkg/controller: Home, DeviceController, transports, subscriptionsdocs/devices.txt—pkg/devices: all 32 typed device controllersdocs/types.txt—pkg/types: enums, Temperature, Timestamp, StatusCode
Released under the MIT License.