Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/frklan/caesium

NodeJS based API to control lightbulbs in Ikea's Trådfri series
https://github.com/frklan/caesium

api ikea javascript nodejs smarthome tradfri

Last synced: 16 days ago
JSON representation

NodeJS based API to control lightbulbs in Ikea's Trådfri series

Awesome Lists containing this project

README

        

# CAESIUM

[![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](https://github.com/frklan/caesium/blob/master/LICENSE)

**N.B. Very much in Alpha mode -- beware of bugs and unexpected behaviour.**

A Rest API to control Ikea Trådfri Lightbulbs. Pretty basic and probably unsecure. Make sure you understand the risks exposing the API to the world.

# Using the API

## Prerequisites

Make sure you have:

* NodeJS
* Ikea Trådfi Lightbulb
* Ikea Trådfri Gateway
* An SSL certificate for your domain (optional)

## Installation

1. Clone the repository ````$ git clone [email protected]:frklan/caesium.git````

2. Install dependencies with ````$ npm install ````

3. Create an .env file in the root of the project containing:

GW_PASSWORD=
JWT_SECRET=
OTP_SECRET=

*Please refer to below instructions how to generate the JWT\_SECRET and OTP\_SECRET*

Alternatively you can set the corresponding environment variables using your preferred method.

4. Run ```$ npm run start```

Access the API on port 5000 (or set a port in the .env file: ```PORT=```)

## JWT_SECRET

The JWT_SECRET can be generated by any means, it should be a 32 character cryptographically strong random string, store it either in:

a. the .env file in the root of the project as

JWT_SECRET=

b. the $JWT_SECRET environment variable, e.g.:

$ export JWT_SECRET=

## Generating a JWT token

A JWT token can be manually generated with the following sequence:

1. run ```$ src/util/generateJwtToken```, the output will be similar to:

src/util/generateJwtToken
ID: caesium_api_user
TTL: 3600
Extra data:
JWT token: eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A

2. Set the header field ```token``` to the JWT token displayed when using the API endpoint, e.g.:

$ curl https://[YOUR-DOMAIN]:5000/api/v1/bulbs -H "token: eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A"

**Note** that the JWT token will default expire in 3600 seconds. A longer (or shorter) expiration time can be set with the option --ttl, refer to ```$ src/util/generateJwtToken --help``` for details. There is no way of invalidating JWT tokens unless it expires automatically, hence it is important to treat them as secrets.

## SSL encryption

If the API is served openly on the internet it is recommended to encrypt all traffic with SSL. It's pretty easy to generate an SSL certificate with letsencrypt and it costs 0€! Yo do, however, need access to a domain or a public webserver. My preferred way of generating the SSL certificate is these easy steps:

1. Get a domain name, e.g. from [namecheap](https://www.namecheap.com/)

2. Install [certbot](https://certbot.eff.org/),

3. Generate the certificate with ```$certbot certonly --config-dir ./conf --work-dir ./ --logs-dir ./ --preferred-challenges dns -d [YOUR-DOMAIN] --manual``` (replace \[YOUR-DOMAIN] with your actuall domain)

4. Follow certbot's instruction how to verify your identity and prove that you own \[YOUR-DOMAIN].

5. Set the following environment variables

```shell
SSL_CERT_FILE=../conf/live/[YOUR-DOMAIN]/fullchain.pem
SSL_KEY_FILE=../conf/live/[YOUR-DOMAIN]/privkey.pem
USE_SSL=TRUE
```

6. Run the server as normal and access the the API at https://.....

**Note.** if you'd like to get an official certificate but not expose the API to the internet, you can generate the certificate for a 'non existing' domain, e.g. dev.example.com and then route dev.example.com to a local ip address by changing your hosts file.

**Note.** Do NOT show, transmit or otherwise expose the private key associated with your SSL certificate.

# API endpoints

### POST login

```shell
$ curl https://[YOUR-DOMAIN]:5000/login -X POST -H "id: caesium_api_user" -H "otp: 349721"
```

Response:

```shell
{
"success":true,
"token":"eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A"
}
```

### GET api/v1/bulbs

Lists current known bulbs and states

Example:

```shell
$ curl https://[YOUR-DOMAIN]:5000/api/v1/bulbs -X GET -H "token: eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A"
```

Response:

```shell
{
"gateway": {
"status": "online",
"name": "gw-xxxxxxxxxxxx",
"host": "TRADFRI-Gateway-xxxxxxxxxxxx.local"
},
"lightbulbs": [
{
"name": "Table",
"id": 65537,
"lastSeen": 1533745439,
"light": {
"onOff": false,
"dimmer": 22.8,
"color": "f1e0b5",
"colorTemperature": 0,
"colorX": 0,
"colorY": 0,
"transitionTime": 0.5
}
},
{
"name": "Window",
"id": 65539,
"lastSeen": 1533667468,
"light": {
"onOff": false,
"dimmer": 0,
"color": "0",
"colorTemperature": 0,
"colorX": 0,
"colorY": 0,
"transitionTime": 0.5
}
},
`
```

### GET api/v1/bulb/[bulb id]

Report state on a single bulb

Example:

```shell
$ curl https://[YOUR-DOMAIN]:5000/api/v1/bulb/65530 -X GET -H "token: eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A"
```

Response:

```shell
{
"gateway": {
"status": "online",
"name": "gw-xxxxxxxxxxxx",
"host": "TRADFRI-Gateway-xxxxxxxxxxxx.local"
},
"lightbulbs": [
{
"name": "Window",
"id": 65539,
"lastSeen": 1533667468,
"light": {
"onOff": false,
"dimmer": 0,
"color": "0",
"colorTemperature": 0,
"colorX": 0,
"colorY": 0,
"transitionTime": 0.5
}
}
}
]
}
```

### POST api/v1/bulb/[bulb id]/toggle

Toggles a bulb on or off

Example:

```shell
$ curl https://[YOUR-DOMAIN]:5000/api/v1/bulb/65530/toggle -X POST -H "token: eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A"
```

Response:

```shell
{
"gateway": {
"status": "online",
"name": "gw-xxxxxxxxxxxx",
"host": "TRADFRI-Gateway-xxxxxxxxxxxx.local"
},
"status": "done"
}
```

### POST api/v1/bulb/[bulb id]/[ON] || [OFF]

Switches a bulb on or off.

Example:

```shell
$ curl https://[YOUR-DOMAIN]:5000/api/v1/bulb/65530/ON -X POST -H "token: eyJhbGciOiJIUz....WTlOioJg_0zIjKZnB-txLqbT4A"
```

Response:

```shell
{
"gateway": {
"status": "online",
"name": "gw-xxxxxxxxxxxx",
"host": "TRADFRI-Gateway-xxxxxxxxxxxx.local"
},
"status": "done"
}
```

# TODO's

- [ ] - [ ] Replace the JWT token with 2FA OTP?
Using both JWT and OTP's seems overly complicated, perhaps a single method is enough?

# Contributing

Contributions are always welcome!

When contributing to this repository, please first discuss the change you wish to make via the issue tracker, email, or any other method with the owner of this repository before making a change.

Please note that we have a code of conduct, you are required to follow it in all your interactions with the project.

# Versioning

We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/frklan/caesium/tags).

# Authors

* **Fredrik Andersson** - *Initial work* - [frklan](https://github.com/frklan)

# License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details