Skip to content

Clients

Rebecca Malamud edited this page Jan 3, 2014 · 23 revisions

Building clients which talk to the steward is pretty simple using Websockets. The steward provides two main API endpoints accessible using secure web socket protocol on port 8888, advertising this service via zero-configuration networking (mDNS), perhaps better known as Bonjour.

Authorized clients can connect to the,

 wss://steward.local:8888/console

resource in order to receive logging entries from the steward as well as state updates from things which talk to the steward. When a client first connects to this resource, most actors in the system will present a brief synopsis.

Alternatively they can connect to the,

 wss://steward.local:8888/manage

resource in order to manage activities, events, tasks and groups or to request the steward communicate with things to to perform and action (e.g. turn on a light) or observe an event such as an instantaneous measurement (e.g. take a measurement of temperature), or request notification from a thing of an event occurring (e.g. movement detected).

More complicated clients, one which monitor updates from the steward looking for changing conditions, and reacting to them on behalf of the user by asking the steward to perform actions, are entirely possible. Technically speaking these are intelligent agents working in a multi-agent system with shared goals of making life more convenient for the user. We like to think that we're implementing magic.

##Example clients, saying "Hello Lightbulbs"

There are a number of example clients available which illustrate how to use these two end points. However lets look at one type of interaction specifically, let's say "Hello Lightbulbs."

More examples can be found elsewhere in the documentation.

###Example using node.js

A simple client to control all the lights in your house can be constructed fairly easily. Using node.js the following example will bring up a web server on port 9999 which has two end points /on and /off which will turn all lighting devices associated with the steward on or off respectively.

var http = require("http");
var util = require("util");
var url = require("url");
var WebSocket = require('ws');

function onRequest(request, response) {    
    var ws;
    
    console.log("Request recieved.");
    var pathname = url.parse(request.url).pathname;
    response.writeHead(200, {"Content-Type":"text/html"});
    
    ws = new WebSocket('ws://127.0.0.1:8887/manage');
    console.log("Created websocket.");    
    
    ws.onopen = function(event) {
        console.log("Opened websocket to steward.");
        if ( pathname == "/on") {
            var json = JSON.stringify({ path      :'/api/v1/actor/perform/device/lighting', 
                                        requestID :'1', 
                                        perform   :'on', 
                                        parameter :JSON.stringify({ brightness: 100, color: { model: 'rgb', rgb: { r: 255, g: 255, b: 255 }}}) });
            ws.send(json);    
            console.log( json );
        
        } else if ( pathname == "/off") {
            var json = JSON.stringify({ path      :'/api/v1/actor/perform/device/lighting', 
                                        requestID :'2', 
                                        perform   :'off', 
                                        parameter :'' });            
            ws.send(json);
            console.log( json );
        
        } else {
            response.write("<h2>Unrecognised request</h2>");
            ws.close(); 
            response.end();
        }
      };

     ws.onmessage = function(event) {
        console.log("Socket message: " + util.inspect(event.data));
        response.write( "<h2>Turning lightbulb '" + pathname +"'</h2>" + util.inspect(event.data, {depth: null}));
        ws.close(); 
        response.end();

    };

    ws.onclose = function(event) {
          console.log("Socket closed: " + util.inspect(event.wasClean));

    };

    ws.onerror = function(event) {
          console.log("Socket error: " + util.inspect(event, {depth: null}));
          try { 
            ws.close(); 
            console.log("Closed websocket.");
          } catch (ex) {}
    };

}

var server = http.createServer(onRequest).listen(9999);
console.log("Server started on port 9999.");

###Example using Arduino

Similarly it's easy to build a physical remote control for your lights. Let's take a simple example of a button connected to an Arduino Ethernet board.

Wiring Diagram

Wiring up the button as shown in the above diagram, the following code will let you turn your house lights on and off directly from your Arduino.

#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <util.h>
#include <SPI.h>

#include <Base64.h>
#include <global.h>
#include <MD5.h>
#include <sha1.h>
#include <WebSocketClient.h>

const char *server = "192.168.1.91";

const int buttonPin = 7;
const int ledPin = 6;

int ledState = LOW;         
int buttonState;             
int lastButtonState = LOW;
int sentPacket = 0;

long lastDebounceTime = 0;  
long debounceDelay = 50; 

char *jsonOff = "{\"path\":\"/api/v1/actor/perform/device/lighting\",\"requestID\":\"2\",\"perform\":\"off\",\"parameter\":\"\"}";
char *jsonOn = "{\"path\":\"/api/v1/actor/perform/device/lighting\",\"requestID\":\"1\",\"perform\":\"on\",\"parameter\":\"{\\\"brightness\\\":100}\"}";
byte mac[] = { 0x0, 0xA2, 0xDA, 0x0D, 0x90, 0xE2 };  

EthernetClient client;
WebSocketClient webSocketClient;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);  
  
  Serial.begin(9600);
  while(!Serial) {  }

  if (Ethernet.begin(mac) == 0) {
    Serial.println("Error: Failed to configure Ethernet using DHCP");
    while(1) {  }
  } 
}

void loop() {
  String data;
  int reading = digitalRead(buttonPin);
  
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  } 
  if ((millis() - lastDebounceTime) > debounceDelay) {
    buttonState = reading;
    if ( buttonState && !sentPacket ) {
       if ( ledState ) {
          Serial.println( "Turning lights off.");
          Serial.println("Connecting to steward...");
          if( client.connect(server,8887) ) {
            Serial.println("Connected");
            webSocketClient.path = "/manage";
            webSocketClient.host = "dastardly.local";
            if (webSocketClient.handshake(client)) {
                Serial.println("Handshake successful");
            } else {
                Serial.println("Handshake failed.");
                while(1) {
                  // Hang on failure
                }  
            }
            webSocketClient.sendData(jsonOff);
          }          

       } else {       
          Serial.println( "Turning lights on.");
          Serial.println("Connecting to steward...");
          if( client.connect(server,8887) ) {
            Serial.println("Connected");
            webSocketClient.path = "/manage";
            webSocketClient.host = "dastardly.local";
            if (webSocketClient.handshake(client)) {
                Serial.println("Handshake successful");
            } else {
                Serial.println("Handshake failed.");
                while(1) {
                // Hang on failure
                }  
            }
            webSocketClient.sendData(jsonOn);
          }                    
       }
       sentPacket = 1;
    }
  }
  
  if (client.connected()) {
    data = webSocketClient.getData();
    if (data.length() > 0) {
      Serial.print("Received data: ");
      Serial.println(data);
      client.stop();
      if ( ledState ) {
          digitalWrite(ledPin, LOW);
          ledState = LOW;       
      } else {
          digitalWrite(ledPin, HIGH);
          ledState = HIGH;       
      }
    }
  }
  
  if ( lastButtonState != reading ) {
     sentPacket = 0; 
  }  
  lastButtonState = reading;
}

This example makes use of the Arduino WebSocket library which you'll need to install before using the sketch. After installing the library you'll need to restart the Arduino IDE if you already have it open. As before, we make use of multicast UDP. If you haven't already patched your Ethernet library, you should do so now (see above for more details).

###Example using iOS

Screen shot

We can also build the exact same example for iOS making use of Square's SocketRocket library.

Analytics