Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding devices on runtime. #357

Open
usmantahirr opened this issue Dec 6, 2016 · 1 comment
Open

Adding devices on runtime. #357

usmantahirr opened this issue Dec 6, 2016 · 1 comment

Comments

@usmantahirr
Copy link

usmantahirr commented Dec 6, 2016

I am using Cylon for my Smart Devices framework, I am using MQTT for this purpose. I've defined a driver for my AirConditionar let's say. I have an ESP8026 chip in each AC which may use the different driver, but let's stick to one for now and I am using MQTT for communication.

I've added MQTT device with a topic devices/events on which every device will send data. I am using this device inside ESP's custom driver.

Now I want to add more devices dynamically to this robot in my MQTT's onConnect event on broker side. How can I do that?

This is the way I am defining my driver

Cylon.robot({
  connections: {
    server: { adaptor: 'mqtt', host: 'mqtt://localhost:1883' }
  },

  devices: {
    deviceAdapter: { driver: 'mqtt', topic: 'device/event', adaptor: 'server' },
    ultron: { driver: 'orient-ultron', deviceId: '5CCF7F095FE9', topic: 'device/5CCF7F095FE9/command' }
  },

  work: function(my) {
    my.ultron.initDriver(null, () => {
      console.log('driver bootstraped');
    });

    my.deviceAdapter.on('message', function (data) {
      debug(data);
      my.ultron.setState(data);
      sendCommand();
    });

    my.ultron.on('state', function (data) {
      debug('inside state event', data.toString());
    });

    function sendCommand() {
      my.ultron.thermostatDrySetpoint(30);
    }
  }
}).start();

and this is the way I've defined my driver.

class Driver extends Cylon.Driver {
  constructor(opts, cb) {
    super(opts);

    this.setupCommands(Commands);
    this.deviceId = opts.deviceId || null;
    this.topic = opts.topic;
    this.commands = Commands;
    this.protobuf = {};

    this.state = {};

    this.initDriver(cb);

    debug(this.deviceId);
  }

  start(callback) {
    const events = ['state', 'measurement', 'alert', 'log', 'ack'];

    events.forEach(function(e) {
      this.defineDriverEvent(e);
    }.bind(this));
    
    if (this.robot.devices.deviceAdapter) {
      this.connection.robot.devices.deviceAdapter.on('message', function(data) {
        // TODO modify event based on type of data received
        debug('Got data inside driver throught adapter', data.toString());
        this.emit('state', data);
      }.bind(this));
    }
    
    callback()
  }
  halt(callback) { callback() }

  /**
   * Send standby command to OrientUltron
   * This capability is used to set standby mode of a device.
   * @param {String} value true | false
   */
  standby(value) {
    const action = this.protobuf.message.lookup('standby').name;
    this.sendToDevice(action, value || false);
  }

  /**
   * Send refresh command to OrientUltron
   * This capability is used to request all latest state values from a device.
   */
  refresh() {
    const action = this.protobuf.message.lookup('refresh').name;
    this.sendToDevice(action, true);
  }

  /**
   * This is the thermostat's setpoint value, when the thermostat mode is set to Auto. The value will be fixed on 24.
   */
  thermostatAutoSetpoint() {
    const action = this.protobuf.message.lookup('thermostatAutoSetpoint').name;
    this.sendToDevice(action, 24);
  }

  /**
   * This is the thermostat's setpoint value, when the thermostat mode is set to Cool. The default value will be 24. The values ranges from 16 to 32.
   * @param {Number} value  16-32
   */
  thermostatCoolingSetpoint(value) {
    const action = this.protobuf.message.lookup('thermostatCoolingSetpoint').name;
    this.sendToDevice(action, value || 24);
  }

  /**
   * This is the thermostat's setpoint value, when the thermostat mode is set to Dry. The default value will be 24. The values ranges from 16 to 32.
   * @param {Number} value  16-32
   */
  thermostatDrySetpoint(value) {
    const action = this.protobuf.message.lookup('thermostatDrySetpoint').name;
    this.sendToDevice(action, value);
  }

  /**
   * This is the thermostat's fan mode (speed). e.g. "4 = high", "3 = mid", "2 = low", "1 = auto". The default value will be "auto".
   * @param {Number} value  4 | 3 | 2 | 1
   */
  thermostatFanMode(value) {
    const action = this.protobuf.message.lookup('thermostatFanMode').name;
    this.sendToDevice(action, value);
  }

  /**
   * This is the thermostat's setpoint value, when the thermostat mode is set to Heat.
   * @param {Number} value
   */
  thermostatHeatingSetpoint(value) {
    const action = this.protobuf.message.lookup('thermostatHeatingSetpoint').name;
    this.sendToDevice(action, value);
  }

  /**
   * This is the thermostat's fan mode. e.g. "1 = auto", "2 = cool", "3 = dry", "4 = heat", "5 = fan"
   * @param {Number} value 1 | 2 | 3 | 4 | 5
   */
  thermostatMode(value) {
    const action = this.protobuf.message.lookup('thermostatMode').name;
    this.sendToDevice(action, value);
  }

  /**
   * Controls Vertical air flow direction of a device.
   * Send air flow change command to OrientUltron
   */
  verticalAirFlowDirection() {
    const action = this.protobuf.message.lookup('verticalAirFlowDirection').name;
    this.sendToDevice(action, true);
  }

  /**
   * Controls horizontal air flow direction of a device.
   * Send air flow change command to OrientUltron
   */
  horizontalAirFlowDirection() {
    const action = this.protobuf.message.lookup('horizontalAirFlowDirection').name;
    this.sendToDevice(action, true);
  }

  setState(state) {
    if (this.protobuf.message) {
      this.state = this.protobuf.decode(state);
      debug(this.state);
    } else {
      debug('state not updated');
    }
  }

  initDriver(filePath, cb) {
    if (!this.protobuf.message) {
      const path = filePath || './';
      this.protobuf = new ProtocolBuffer('format', path, 'ACDriver', 'ACActions', () => {
        debug('protobuf loaded');
        if (cb) cb(this);
      });
    } else {
      debug('protobuf already loaded');
    }
  }

  sendToDevice(key, value) {
    this.state[key] = value;
    this.connection.publish(this.topic, this.protobuf.encode(this.state));
  }
}

module.exports = Driver;
@kendemu
Copy link

kendemu commented Feb 11, 2017

Hello, I'm doing a dynamic driver configuration from electron UI & IPC by using require.
I think you can re-implement this code using Socket.io or MQTT. But probably you need to setup a different HTTP / MQTT port from the cylon-api-mqtt / http module.
:

electron IPC Code:

ipc.on('device', (event, arg) => {
    console.log("ipc called");
    const DeviceServer = new DeviceHttpServer(arg);
    DeviceServer.start();
});

Dynamic Server Code:

import http from "http";

class DeviceHttpServer{
    constructor(device){
        this.device = device;
        console.log("DeviceHttpServer object created");
    }
    
    start(){
        require( __dirname +"/" + this.device);
    }
}
export default DeviceHttpServer;

cylon module code called by require:

import Cylon from "cylon";

Cylon.api("http", {
    host: '127.0.0.1',
    port: '3001',
    ssl: false,
    auth: false
});

Cylon.robot({
    name: "hoge",
    connections: {
        bebop: { adaptor: 'hoge' }
    },

    devices: {
        drone: { driver : 'hoge' }
    },

    work: function(my){
        
    }
}).start();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants