remootio / remootio-api-client-node

Remootio Websocket API client for Node.js
MIT License
5 stars 4 forks source link

Remootio API Client for Node.js

This module is a Node.js client for Remootio's websocket API. Remootio is a smart gate and garage door controller product. To learn more please visit www.remootio.com. The API documentation can be found here. The API client package handles the connection with your Remootio device, sends keepalive PING frame, encrypts and decrypts ENCRYPTED frames automatically, and can also reconnect automatically if the connection is lost.

Installation

Install the package using npm:

npm install remootio-api-client

Usage

First of all make sure that the Remootio Websocket API is enabled for your Remootio device in the Remootio app. Please take note of the API Secret key and API Auth Key along with the IP address of the device, as you will need these.

Step 1

Import the module by

const RemootioDevice = require('remootio-api-client');

Create a RemootioDevice object that represents a physical Remootio device by:

let garagedoor1 = new RemootioDevice(
    '192.168.1.23', //Device IP address
    'EFD0E4BF75D49BDD4F5CD5492D55C92FE96040E9CD74BED9F19ACA2658EA0FA9', //API Secret Key
    '7B456E7AE95E55F714E2270983C33360514DAD96C93AE1990AFE35FD5BF00A72', //API Auth Key
    )
//Constructor arguments:
//The IP address of the device is available in the Remootio app once you set up Wi-Fi connectivity
//The API Secret Key of the device is available in the Remootio app once you enable API access
//The API Auth Key of the device is available in the Remootio app once you enable API access
//Optional parameter here is how often the RemootioDevice class will send PING frames to the device to keep the connection alive (defaults to 60 seconds)    
Step 2 - Add event listeners

The Remootio device emits various events. Add listeners to the events you need to:

The connecting event is called when the API client starts connecting to the Remootio device

garagedoor1.on('connecting',()=>{
    console.log('garage door 1 connecting ...')
})

The conencted event is called when the websocket connection is established with the Remootio device. You need to authenticate each session (connection) to be able to control your Remootio device or receive log events. This can be done using the .authenticate() method. It is recommended to call this in the connected event handler.

garagedoor1.on('connected',()=>{
    console.log('garage door 1 connected')
    garagedoor1.authenticate() //Authenticate the session (required)
})

The authenticated event is fired once the authentication was completed successfully. From this point on actions that require authentication can be sent to Remootio.

garagedoor1.on('authenticated',()=>{
    console.log('garage door 1 session authenticated')
    //From this point on actions (that require authentication) can be sent to Remootio
    //garagedoor1.sendQuery()
    //garagedoor1.sendTrigger()
    //garagedoor1.sendOpen()
    //garagedoor1.sendClose()
    //garagedoor1.sendRestart()
})

The disconnect event is fired if the websocket connection to Remootio is closed

garagedoor1.on('disconnect',()=>{
    console.log('garage door 1 disconnected')
})

The error event is fired if there was an error (e.g. the authentication process failed, there was an encryption error, and so on). If there is no response to a keepalive PING the connection is considered to be broken, and this will also fire an error event.

garagedoor1.on('error',(err)=>{
    console.log('error',err)
})

The incomingmessage event is fired for every incoming frame. Add your own code to process the messages here. Updating the lastActionId (a frame coutner needed to be incremented to every action sent to the Remootio device) is handled inside the RemootioDevice class.

garagedoor1.on('incomingmessage',(frame,decryptedPayload)=>{
    //log the incoming messages to the console
    console.log('Incoming message: ',frame)
    if (decryptedPayload){
        console.log('Decrypted payload: ',decryptedPayload)
    }
    //messages can be handled here:
    //use frame.type to determine the frame type
    //if frame.type == "ENCRYPTED": 
    //then if decryptedPayload.response!=undefined it's a reponse message to an action sent previously
    //and if decryptedPayload.event!=undefined it's a log message e.g. gate status changed
})

The outgoingmessage event is fired for every frame the API client has sent.

garagedoor1.on('outgoingmessage',(frame, unencryptedPayload)=>{
    console.log('Outgoing message: ',frame)
    if (unencryptedPayload){
        console.log('Unencrypted payload: ',unencryptedPayload)
    }
})
Step 3 - connect to the API

After you have created your device, added the necessary event listeners call the .connect() method to start connecting to your Remootio.

garagedoor1.connect(true) 
//if the parameter is true the client will try to reconnect to the Remootio device if the connection is lost (recommended)
Sending frames to Remootio

The RemootioDevice class provides the following methods to send frames

Checking the status of the device

The RemootioDevice class provides the following properties to check the current status of the connection to your Remootio:

Disconnecting

Call the .disconnect() method of the RemootioDevice class to close the current connection to your Remootio device.

Example 1 - Trigger Remootio's output

This example:

//Include the RemootioDevice module
const RemootioDevice = require('remootio-api-client')

//1) - Create a new instance for each Remootio device you have:
let garagedoor1 = new RemootioDevice(
    '192.168.1.115', //Change to the IP address of your device
    'EFD0E4BF75D49BDD4F5CD5492D55C92FE96040E9CD74BED9F19ACA2658EA0FA9', //Change to the API Secret Key of your device
    '7B456E7AE95E55F714E2270983C33360514DAD96C93AE1990AFE35FD5BF00A72', //Change to API Auth Key of your device
    )

//2) - Add listeners to various events:
garagedoor1.on('connected',()=>{
    console.log('garage door 1 connected')
    garagedoor1.authenticate()
})

garagedoor1.on('authenticated',()=>{
    console.log('garage door 1 session authenticated')
    garagedoor1.sendTrigger()
})

garagedoor1.on('error',(err)=>{
    console.log('error',err)
})

garagedoor1.on('disconnect',(err)=>{
    process.exit(0)
})

//The incomingmessage event is fired for every incoming frame
garagedoor1.on('incomingmessage',(frame,decryptedPayload)=>{
    //log the incoming messages to the console
    if (decryptedPayload){
        if (decryptedPayload.response != undefined){ //It's a response frame to one of our previous actions
            if (decryptedPayload.response.type == 'TRIGGER'){ //This is the response frame to the .sendTrigger() action
                console.log('The trigger action was '+(decryptedPayload.response.success == true?"successful":"not successful"))
                console.log('The status of the garage door when triggering was: '+(decryptedPayload.response.state))
                if (decryptedPayload.response.state == "no sensor"){
                    console.log('Since there is no sensor installed for the garage door we will not get any StateChange event, so we just disconnect now.')
                    console.log('Disconnecting...')
                    garagedoor1.disconnect()
                }
            }
        }
        if (decryptedPayload.event != undefined){ //It's an event frame containing a log entry from Remootio
            if (decryptedPayload.event.type == 'StateChange'){ //This event is sent by Remootio when the status of the garage door has changed
                console.log('The state of the garage door has changed to '+decryptedPayload.event.state);
                console.log('Disconnecting...')
                garagedoor1.disconnect()
            }
        }
    }
})

//Connect to the API
garagedoor1.connect(true)

Example output of the code: garage door 1 connected garage door 1 session authenticated The trigger action was successful The status of the garage door when triggering was: open The state of the garage door has changed to closed Disconnecting...

Example 2 - Log events from Remootio into a file

This example:

//Include the RemootioDevice module
const RemootioDevice = require('remootio-api-client')
const fs = require('fs');

const logFileName = './remootiolog.txt'

//1) - Create a new instance for each Remootio device you have:
let garagedoor1 = new RemootioDevice(
    '192.168.1.115', //Change to the IP address of your device
    'EFD0E4BF75D49BDD4F5CD5492D55C92FE96040E9CD74BED9F19ACA2658EA0FA9', //Change to the API Secret Key of your device
    '7B456E7AE95E55F714E2270983C33360514DAD96C93AE1990AFE35FD5BF00A72', //Change to API Auth Key of your device
    )

//2) - Add listeners to various events:
garagedoor1.on('connected',()=>{
    console.log('garage door 1 connected')
    garagedoor1.authenticate()
})

garagedoor1.on('authenticated',()=>{
    console.log('garage door 1 session authenticated')
})

garagedoor1.on('error',(err)=>{
    console.log('error',err)
})

//The incomingmessage event is fired for every incoming frame
garagedoor1.on('incomingmessage',(frame,decryptedPayload)=>{
    //log the incoming messages to the console
    if (decryptedPayload){
        //We are interested in events 
        if (decryptedPayload.event != undefined){ //It's an event frame containing a log entry from Remootio
            let rowToLog = new Date().toISOString() + ' ' + JSON.stringify(decryptedPayload) + '\r\n'
            console.log(rowToLog)
            fs.appendFile(logFileName, rowToLog, function (err) {
                if (err) console.log('ERROR: ', err);
            });
        }
    }
})

//Connect to the API
garagedoor1.connect(true)