Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


CircleCI Go Report Card

Native Go implementation for talking CoAP to a IKEA Trådfri gateway over DTLS 1.2.

Note: The author is not in any way affiliated or related to IKEA, this is purely a hobby project!

Note 2: The application is being developed and have bugs and known issues!

This application is just stitching together the excellent work of and into a stand-alone application that can talk to a IKEA Trådfri gateway out-of-the-box without any dependencies on libcoap, openssl or similar libraries.

Inspired by:



tradfri-go has been tested against the following DTLS-enabled COAP servers:

  • IKEA Trådfri Gateway using PSK after token exchange: OK
  • Californicum COAP server on Scandium DTLS: OK


Uses go modules.

export GO111MODULE=on
go build -o tradfri-go

PSK exchange

The Trådfri gateway has its Pre-shared key (PSK) printed on the bottom sticker. However, that PSK is only used for making an initial exchange where you specify a unique Client_id and the original PSK, and you get a new PSK in return that you use for subsequent interactions with the gateway.

tradfri-go supports this operation out of the box using the following command:

> ./tradfri-go --authenticate --client_id=MyCoolID --psk=TheKeyAtTheBottomOfYourGateway --gateway_ip=<ip to your gateway>

The generated new PSK and settings used are stored in the current directory in the file "config.json", e.g:

> cat config.json
  "client_id": "MyCoolID",
  "gateway_address": "",
  "gateway_ip": "",
  "pre_shared_key": "the generated psk goes here",
  "psk": "the generated psk goes here",

tradfri-go will try to read config.json when starting up, and will in that case set the required properties accordingly.

If you don't feel like using config.json, you can either specify the configuration as command-line flags or using the following environment variables:

./tradfri-go --server --client_id MyCoolID122 --psk mynewkey --gateway_ip=


> export CLIENT_ID=MyCoolID1122
> export PRE_SHARED_KEY=mynewkey
> export GATEWAY_IP=

Configuration is resolved in the following order of precedence:

config.json -> command-line arguments -> environment variables

Determine gateway IP

tradfri-go has no means of finding out the IP of the Gateway. I suggest checking your Router's list of connected devices and try to find an item starting with "GW-".

Running in server mode

Server mode connects to your gateway and then publishes a really simple RESTful interface and a gRPC service for querying your gateway or mutating some state on bulbs etc:

./tradfri-go --server

Now, you can use the simple RESTful API provided by tradfri-go which returns more human-readable responses than the raw CoAP responses:

> curl http://localhost:8080/api/device/65538 | jq .
  "deviceMetadata": {
    "id": 65538,
    "name": "Färgglad",
    "vendor": "IKEA of Sweden",
    "type": "TRADFRI bulb E27 CWS opal 600lm"
  "dimmer": 100,
  "xcolor": 30015,
  "ycolor": 26870,
  "rgbcolor": "f1e0b5",
  "power": true

Or use one of the declarative endpoints to mutate the state of the bulb:

> curl -X PUT -d '{"rgbcolor":"f1e0b5"}' http://localhost:8080/api/device/65538/rgb

Blinds support

tradfri-go now supports controlling IKEA Blinds by passing a positioning value between 0-100.

Examples (curl and gRPC)

> curl -X PUT -d '{"positioning": 20}' http://localhost:8080/api/device/65552/position
> grpcurl -plaintext -d '{"id": 65552, "value": 20}' localhost:8081 grpc_server.TradfriService/ChangeDevicePositioning

Sets the position to 20% extended.

gRPC support

If you want to use the gRPC service, implement your client like this:

var client pb.TradfriServiceClient
	conn, err := grpc.Dial("localhost:8081",
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	defer conn.Close()
	client = pb.NewTradfriServiceClient(conn)

while importing pb "".

And, as simple as calling every other method in your code, request the server like this:

resp, err := client.ListGroups(context.Background(), &pb.ListGroupsRequest{})

You can also install grpcurl and query the server via the command line:

> grpcurl -plaintext localhost:8081 grpc_server.TradfriService/ListGroups
> grpcurl -plaintext -d '{"id": 65552}' localhost:8081 grpc_server.TradfriService/TurnDeviceOn

Just like the client mode, the application will try to use clientId/PSK from psk.key or using env vars.

Running in client mode

Client mode lets you GET and PUT raw coap payloads to your gateway using the "-get" and "-put" args.

A few examples:

GET my bulb at /15001/65538:

./tradfri-go --get /15001/65538
{"9019":1,"9001":"Färgglad","9002":1550336061,"9020":1551721891,"9003":65538,"9054":0,"5750":2,"3":{"0":"IKEA of Sweden","1":"TRADFRI bulb E27 CWS opal 600lm","2":"","3":"1.3.009","6":1},"3311":[{"5708":65279,"5850":1,"5851":100,"5707":53953,"5709":20316,"5710":8520,"5706":"8f2686","9003":0}]}

PUT that turns off the bulb at /15001/65538:

./tradfri-go --put /15001/65538 --payload '{ "3311": [{ "5850": 0 }] }'

PUT that turns on the bulb at /15001/65538 and sets dimmer to 200:

./tradfri-go --put /15001/65538 --payload '{ "3311": [{ "5850": 1, "5851": 200 }] }'

PUT that sets color of the bulb at /15001/65538 to purple and the dimmer to 100:

./tradfri-go --put /15001/65538 --payload '{ "3311": [{ "5706": "8f2686", "5851": 100 }] }'

The colors possible to set on the bulbs varies. The colors are in the CIE 1931 color space whose x/y values in theory can be set using the 5709 and 5710 codes to values between 0 and 65535. You can't set arbitrary values due to how the CIE 1931 (yes, it's a standard from 1931!) works. Play around with the values, I havn't broken my full-color "TRADFRI bulb E27 CWS opal 600lm" yet...


Uses MIT license, see LICENSE


Go client for talking to the Ikea trådfri gateway




No packages published

Contributors 4