401Unauthorized / broadlink-bridge

An HTTP REST Bridge for Interacting with BroadLink IR Devices
MIT License
5 stars 2 forks source link
automation blaster bridge broadlink broadlink-bridge broadlink-ir-devices ir-command nodejs smarthome

BroadLink Bridge

An HTTP REST Bridge for Interacting with BroadLink IR Devices

Version Documentation Maintenance License: MIT Twitter: stephenmendez_ PayPal

💾 Installation

This is a Node.js module available through the npm registry.

There is also an unaffiliated similar project written in Python lbschenkel/broadlink-bridge

Global installation using the following command is recommended:

$ npm i -g broadlink-bridge

Alternatively, the repo can be cloned and linked instead:

$ git clone https://github.com/401unauthorized/broadlink-bridge.git && cd broadlink-bridge && npm i && npm link

🔌 Quick Start

Run the CLI command to start the server:

$ broadlink-bridge start -p <port> -t <uuid-based-token>,<uuid-based-token>,...

-p <port> sets the port

-t <uuid-based-token>,... comma separated list of user created API tokens

🔮 Features

👓 Transparency

📊 System Diagram

Network Diagram

🛠 Setup & Getting Started

Connect a Blaster

Please note, the following was only tested with the RM mini3

Connecting a new BroadLink device on your local wireless network:

  1. Put the device into AP Mode (reference device manual)
    1. Long press the reset button until the blue LED is blinking quickly
    2. Long press again until blue LED is blinking slowly
  2. Manually connect your computer to the WiFi SSID named BroadlinkProv
  3. Use the CLI to provide your wifi name (SSID), wifi password, and the security mode number to the device:
Number Security
0 none (open)
1 WEP
2 WPA1
3 WPA2
4 WPA1/2

$ broadlink-bridge connect -w wifi_name -p wifi_password -s 3

Review Server Files

To locate configuration and data files on your machine, run the following:

$ broadlink-bridge files

Prints the following information to stdout

{
  "db.json": "/path/to/db.json",
  "db-example.json": "/path/to/db-example.json",
  ".env": "/path/to/.env",
  "postman-bearer-token": "/path/to/broadlink-bridge_bearer_auth.postman_collection.json",
  "postman-query-string": "/path/to/broadlink-bridge_query_string_auth.postman_collection.json"
}

db.json

This is the local JSON database file used for Broadlink-Bridge.

While the server is not running, this file can be manually edited for advanced use cases.

db-example.json

This is a starting example of local JSON database file for Broadlink-Bridge.

Rename this file to db.json for use with the example postman collections.

.env

This file is used to store persistant environmental variables and sensitive information for the server.

After installation, it is advised to create/update this file.

Example of storing information in this file:

PORT=8080
TOKENS=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa,12345678-9012-3456-7890-123456789012

postman-bearer-token

This postman collection provides example requests for interacting with the server using authentication bearer tokens.

Importing into Postman:

  1. Find and Replace <insert-API-token-here> in the .json file with an API Token used by the server
  2. In postman, select import and navigate to the location of the file

postman-query-string

This postman collection provides example requests for interacting with the server using query string tokens.

Importing into Postman:

  1. Find and Replace <insert-API-token-here> in the .json file with an API Token used by the server
  2. In postman, select import and navigate to the location of the file

API Credentials

API tokens are required with most endpoints and may be defined in the following ways:

Passed in as an argument

$ broadlink-bridge start -t <uuid-based-token>,<uuid-based-token>,...

Defined in the .env file

TOKENS=<uuid-based-token>,<uuid-based-token>,...

Running the Server

Run the CLI command to start the server:

$ broadlink-bridge start -p <port> -t <uuid-based-token>,<uuid-based-token>,...

For a full list of commands, enter the following:

$ broadlink-bridge --help

Final Steps

Use the following API endpoints described in this documentation to perform the steps:

  1. Add a new Blaster
  2. Add a new Device for that Blaster
  3. Add (learn) new Commands for that Device
  4. Emit one of those commands
  5. Celebrate! 🎉

📦 Database Schema

The JSON database file contains two, top level fields: blasters & devices.

blasters contains an array of blaster objects.

devices contains an array of device objects.

Blaster Object

A BroadLink IR Blaster

{
  "id": "pMtEfSYMmg",
  "name": "Basement Blaster",
  "type": "148340",
  "address": "192.168.1.2",
  "port": 80,
  "mac": "AA:BB:CC:DD:EE:FF",
  "devices": [ "GZFnCHSDM" ],
  "active": false
}

id: An auto-generated short ID

name: A user entered blaster name

type: A user entered blaster identifier

address: LAN IP address for the blaster

port: Port for the blaster

mac: MAC address for the blaster

devices: An array of device IDs this blaster controls

active: Is the server able to reach the blaster? (updated dynamically)

Device Object

Any Device with IR Receiver Capabilities

{
  "id": "GZFnCHSDM",
  "name": "Basement Projector",
  "type": "PROJECTOR",
  "commands": []
}

id: An auto-generated short ID

name: A user entered device name

type: A user entered device type (not used)

commands: An array of IR command objects for the device

Commands Object

IR Codes & Metadata

{
  "command": "power on",
  "repeat": 0,
  "delay": 0,
  "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
}

command: A user entered command name (must be URL encodable)

repeat: A user entered repeat count for the command (not used)

delay: A user entered milliseconds delay between repeats for the command (not used)

data: A user entered or a blaster captured hex string representation of an IR command

Complete Example of db.json Database File

{
  "blasters": [
    {
      "id": "pMtEfSYMmg",
      "name": "Basement Blaster",
      "type": "148340",
      "address": "192.168.1.2",
      "port": 80,
      "mac": "AA:BB:CC:DD:EE:FF",
      "devices": [
          "GZFnCHSDM"
      ],
      "active": false
    }
  ],
  "devices": [
    {
      "id": "GZFnCHSDM",
      "name": "Basement Projector",
      "type": "PROJECTOR",
      "commands": [
        {
          "command": "power on",
          "repeat": 0,
          "delay": 0,
          "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
        }
      ]
    }
  ]
}

🌐 API

Most endpoints require authentication via an authentication bearer token or a query string token

Authentication Bearer Token (Header)

"Authentication": "Bearer <token-here>"

Query String Token (Query String)

?token=<token-here>

Generic Endpoints

/

Request (Body)

--

Response (Body)

Welcome to BroadLink Bridge!

/health

Request (Body)

--

Response (Body)

OK

/version

Request (Body)

--

Response (Body)

{
  "version": "1.1.1"
}

/stats

Request (Body)

--

Response (Body)

{
  "timestamp": 1589701522333,
  "uptime": {
      "duration": 64.125,
      "text": "a minute",
      "started": "2020-05-17T07:44:18.209Z"
  },
  "process": {
      "rss": 47550464,
      "heapTotal": 25456640,
      "heapUsed": 16501232,
      "external": 63281,
      "pid": 12345
  }
}

Blaster Endpoints

GET /blasters/

Read all Blasters

Request (Body)

--

Response (Body)

[
  {
    "id": "pMtEfSYMmg",
    "name": "Basement Blaster",
    "type": "148340",
    "address": "192.168.1.2",
    "port": 80,
    "mac": "AA:BB:CC:DD:EE:FF",
    "devices": [ "GZFnCHSDM" ],
    "active": false
  }
]

POST /blasters/

Create a new Blaster.

Blaster type can be derived through the following:

  1. Check this list of blaster identifiers and find the name of your product
  2. Copy what is inside of the [] for the line with your product name
  3. Run node -e 'console.log(<paste-here>)'
  4. The resulting number is what to put for the type field in the JSON body

Request (Body)

{
  "name": "Basement Blaster",
  "type": "148340",
  "address": "192.168.1.2",
  "port": 80,
  "mac": "AA:BB:CC:DD:EE:FF"
}

Response (Body)

{
  "id": "pMtEfSYMmg",
  "name": "Basement Blaster",
  "type": "148340",
  "address": "192.168.1.2",
  "port": 80,
  "mac": "AA:BB:CC:DD:EE:FF",
  "devices": [],
  "active": false
}

GET /blasters/\/

Read a specific Blaster

Request (Body)

--

Response (Body)

{
  "id": "pMtEfSYMmg",
  "name": "Basement Blaster",
  "type": "148340",
  "address": "192.168.1.2",
  "port": 80,
  "mac": "AA:BB:CC:DD:EE:FF",
  "devices": [],
  "active": true
}

PUT /blasters/\/

Update a specific Blaster

Request (Body)

{
  "name": "Basement Blaster Updated"
}

Response (Body)

{
  "id": "pMtEfSYMmg",
  "name": "Basement Blaster Updated",
  "type": "148340",
  "address": "192.168.1.2",
  "port": 80,
  "mac": "AA:BB:CC:DD:EE:FF",
  "devices": [],
  "active": true
}

DELETE /blasters/\/

Delete a specific Blaster

Device Endpoints

GET /blasters/\/devices/

Read a Blaster's Devices

Request (Body)

--

Response (Body)

[
  {
    "id": "GZFnCHSDM",
    "name": "Basement Projector",
    "type": "PROJECTOR",
    "commands": [
      {
        "command": "power on",
        "repeat": 0,
        "delay": 0,
        "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
      },
      {
        "command": "power off",
        "repeat": 1,
        "delay": 300,
        "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
      },
      ...
    ]
  },
  ...
]

POST /blasters/\/devices/

Create a new Blaster's Device

Request (Body)

{
  "name": "Basement Projector",
  "type": "PROJECTOR"
}

Response (Body)

{
  "id": "GZFnCHSDM",
  "name": "Basement Projector",
  "type": "PROJECTOR",
  "commands": []
}

GET /blasters/\/devices/\/

Read a specific Blaster's Device

Request (Body)

--

Response (Body)

{
  "id": "GZFnCHSDM",
  "name": "Basement Projector",
  "type": "PROJECTOR",
  "commands": [
    {
      "command": "power on",
      "repeat": 0,
      "delay": 0,
      "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
    },
    {
      "command": "power off",
      "repeat": 1,
      "delay": 300,
      "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
    },
    ...
  ]
}

PUT /blasters/\/devices/\/

Update a specific Blaster's Device

Request (Body)

{
  "name": "Basement Wall Projector"
}

Response (Body)

{
  "id": "GZFnCHSDM",
  "name": "Basement Wall Projector",
  "type": "PROJECTOR",
  "commands": [
    {
      "command": "power on",
      "repeat": 0,
      "delay": 0,
      "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
    },
    {
      "command": "power off",
      "repeat": 1,
      "delay": 300,
      "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
    },
    ...
  ]
}

DELETE /blasters/\/devices/\/

Delete a specific Blaster's Device

Command Endpoints

GET /blasters/\/devices/\/commands/

Read a Blaster's Device's Commands

Request (Body)

--

Response (Body)

[
  {
    "command": "power on",
    "repeat": 0,
    "delay": 0,
    "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
  },
  {
    "command": "power off",
    "repeat": 1,
    "delay": 300,
    "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
  },
  ...
]

POST /blasters/\/devices/\/commands/

Create a new Blaster's Device's Command.

If the HEX IR code is unknown, start a learning process:

  1. Call the endpoint with the desired command name in the request JSON body
  2. Within 10 seconds, point an IR remote at the blaster and press the corresponding command button
  3. Wait for a response to ensure it was captured correctly

Request (Body)

{
  "command": "power on",
  "repeat": 0,
  "delay": 0
}

If the HEX IR code is already known :

  1. Include a string representation of the data as a field

Request (Body)

{
  "command": "power on",
  "repeat": 0,
  "delay": 0,
  "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
}

Response (Body)

{
  "command": "power on",
  "repeat": 0,
  "delay": 0,
  "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
}

GET /blasters/\/devices/\/commands/\/

Read a Blaster's Device's specific Command

Request (Body)

--

Response (Body)

{
  "command": "power on",
  "repeat": 0,
  "delay": 0,
  "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
}

PUT /blasters/\/devices/\/commands/\/

Update a Blaster's Device's specific Command

Request (Body)

{
    "repeat": 1,
    "delay": 200
}

Response (Body)

{
  "command": "power on",
  "repeat": 1,
  "delay": 200,
  "data": "260054000001299316101512141215111511151115111536153615361537153615361536153616111437153615361536143815111536151115111511151115111412153715111536150003750900019200012a4812000d0500000000"
}

DELETE /blasters/\/devices/\/commands/\/

Delete a Blaster's Device's specific Command

Emit IR Endpoints

POST /blasters/\/devices/\/commands/\/emit

Request (Body)

--

Response (Body)

{
  "status": "Done!"
}

GET /blasters/\/devices/\/commands/\/emit

Request (Body)

--

Response (Body)

{
  "status": "Done!"
}

👤 Author

Stephen Mendez

🤝 Contributing

Contributions, issues and feature requests are welcome!
Feel free to check issues page. You can also take a look at the contributing guide.

😃 Show your support

Give a ⭐️if this project helped you!

Consider making a donation of any amount!

PayPal

📝 License

Copyright © 2020 Stephen Mendez
This project is MIT licensed.


BroadLink is a registered trademark of Hangzhou BroadLink Technology Co. Ltd

Part of this README was generated with ❤️ by readme-md-generator