Simbiotes

The easy way to make your Rails application interact with IoT devices.

Installation

Add this line to your application's Gemfile:

gem "simbiotes"

Or install it yourself as:

$ gem install simbiotes

And then execute:

$ bundle
$ rails generate simbiotes:install

On the Simbiotes portal located at www.simbiotes.com, you can create a Hive for your project. Hives have Workers (each type of IoT device in your project will have a corresponding worker in the Hive). Workers have Drivers and, optionally, Scripts. Drivers and Scripts have interfaces. An example worker might be a Thermostat. The Thermostat has a Control Script with two interfaces: temperature and target temperature. If you set the target temperature to 72 and the temperature is 65, the Thermostat will turn the heat on. We'll use this example again and flesh it out below.

Once you have created a Hive, it will give you a public and a private API key. Best practice is to set environment variables in your development, test and production environments to equal these API keys. Then, set config.public_key and config.private_key in config/initializers/simbiotes.rb to those environment variables. You can enter the API keys directly into the configuration file, but you should only do this if you never plan to put your Rails application and Hive into production, as it is a significant security risk.

Simbiotes.configure do |config|
    config.public_key = ENV['SIMBIOTES_PUBLIC_API_KEY']
    config.private_key = ENV['SIMBIOTES_PRIVATE_API_KEY']
    config.local_port = 8001
    config.server_port = 8000
    config.local_logging = true
end

Usage

After you have installed the API keys, log in to the Simbiotes portal (www.simbiotes.com) to see that your Hive has Workers and that those Workers have Drivers and, if applicable, Scripts defined. Each Worker, Driver or Script will have one or more Interfaces. For example, if you are making a connected Thermostat, your Hive might have a Worker named 'Thermostat' and it might have the following Drivers/Scripts: Thermometer, Furnace and Control.

Each of the Drivers/Scripts has Interfaces (all of this would be viewable on the www.simbiotes.com portal). The Control script might have two interfaces: Temperature and Target Temperature.

We want to be able to interact with these interfaces easily through our Rails application for all of the Thermostats that we have out there in the field.

Models and Tables

To do this, we will create a model in our Rails application with attributes that correspond to the interfaces we want to interact with. We will then create records in our Rails database that correspond to our devices. Once we've done that, we can interact with a database record using ActiveRecord as usual, but the attribute values from our database records will be automatically synced to the corresponding device.

Because our model is going to sync with our IoT devices, we need to use the Simbiotes model generator that comes with the gem to create the model rather than the model generator that comes by default with Rails. To use it, we pass two arguments, the name of the Worker and the name of the Driver or Script that we want to interact with. In this case, our worker is Thermostat and we want to interact with Control, so we create the model as follows:

$ rails generate simbiotes:model Thermostat Control

This generator actually creates a model and a module. The module is in app/models/thermostat.rb and the model in app/models/thermostat/control.rb. If you create models that correspond to one or more of your Thermostat's other Drivers/Scripts, they will be placed in the app/models/thermostat directory as well.

Now you should migrate your database in order to create the database tables that correspond to your model.

$ rake db:migrate

The migration creates three tables: thermostat_controls, thermostat_control_temperature_logs and thermostat_control_target_temperature_logs. The thermostat_controls table holds the data for temperature and target temperature for all of the devices within your Hive.

Instances and Devices

Now that you have your models and database tables created, you can use them to communicate with the devices that are out in the field.

The first thing to do is to create database records that correspond to actual devices. On the Simbiotes Portal (www.simbiotes.com) you will see a list of Worker Instances (each Instance represents an individual device of that particular Worker type) on each Worker page. Each Worker Instance has an id, you'll see them as a long string of characters on the page, one for each Worker Instance.

Now, run:

$ rails console

This will open up an irb console with your Rails environment (including the Simbiotes gem) loaded.

In your console run:

> Thermostat.sync_device_instances

That will create a database record for each device instance you currently have defined in for your Thermostat worker. If you have no instances defined, create one on the Thermostat worker page in the simbiotes.com portal.

Next, exit your rails console by typing:

> exit

The next thing we need to do is establish a communications channel we can use to communicate between our Rails application and the devices in the field. To do this, we use a local server that handles sending communications to the remote devices and handles communications that we will receive from them.

To start it up in production:

$ rake comms:start

In development:

$ rake dev_comms:start

In test:

$ rake test_comms:start

This starts our communications server. If you want to stop the communications server for any reason simply:

In production:

$ rake comms:stop

In development:

$ rake dev_comms:stop

In test:

$ rake test_comms:stop

Note that you can only communicate with devices if the local communications server is running.

Communicating with Devices

Now that the preliminaries are out of the way, let's communicate with devices.

Open up your rails console again by typing:

$ rails c

In your console, type the following to get a device instance and assign it to the variable d:

> d = Thermostat::Control.first

The first thing to do is to synchronize the database's data with the data from the device. (This sends a get request for each Interface in the current Driver/Script) To do this type in your console:

> d.sync

Now that you are synced with the device, you can set the device's Interfaces easily right from Rails. Let's say you want to set the temperature of your thermostat to 68 degrees. Here's how you do it:

> d.target_temperature = 68
> d.save

All of the communications to the device are taken care of for you. If the value of these Interfaces changes (if the ambient temperature rises or falls for example) then your database will be kept up to date via the communications server without needing to sync the device instance going forward.

Building a Web Scaffold

Now that you can communicate with your devices from the rails console, let's create a web scaffold so that you can communicate with them via your web browser.

If you haven't done it already, run

> rails generate simple_form:install

Then at the top of the config/initializers/simple_form.rb file put

require 'simple_form'

To install the form helpers we will use to build forms to edit device interfaces via the browser.

Once you've done that, you can run the simbiotes scaffold controller generator to generate a scaffold and views for your device.

> rails generate simbiotes:controller Thermostat

This command installs a default controller and views for your Thermostat. Once they are installed, you can see them in your browser by starting up your development web server.

> rails server

Then in your web browser of choice, navigate to http://localhost:3000/thermostats. This page will show you a list of your Thermostat instances, as well as the current values of the different interfaces for your device. You can use the edit links for each device instance to change these values.

Adding Push Web Updates

Since we want to be able to see changes to our devices without refreshing our webpage manually, we can leverage Rails 5's ActionCable to push device updates to our page.

To do this, run:

> rails generate simbiotes:channel Thermostat

This command installs a configuration file, in this case app/channels/thermostat_channel.rb, to define an ActionCable channel for your Worker, in this case thermostat_channel, as well as a coffeescript file, in this case app/assets/javascripts/channels/thermostat.coffee, that defines how the browser will update information from the server on the page.

In order for the ActionCable messages to actually transmit to the browser, we need to install Redis. Redis is an open source in-memory data store that ActionCable uses to implement its PubSub messaging.

The easiest way to install Redis (if you are on a Mac) is:

> brew install redis

Then, once it is installed, run:

> redis-server

In your Rails application, edit your config/cable.yml file to look as follows:

development:
  adapter: redis

test:
  adapter: redis

production:
  adapter: redis

Add the following to your Gemfile:

gem 'jquery-rails'

And run

> bundle install

Next, open up your app/assets/javascripts/application.js file. Make sure you add the following lines to it above the require_tree . line, if you have it.

//= require jquery
//= require jquery_ujs

Then, restart your Rails server. Once you have done that, the values on the Thermostats page will update via push notifications.

Contributing

Contribution directions go here.

License

The gem is available as open source under the terms of the MIT License.