Getting Started : Press Button

Goal

We will create a very simple system composed of a virtual button pressed periodically and a monitor which will display the state of the button in the Spinalcore admin interface and in the terminal.

System architecture:


The best way to use this tutorial is to follow each step as it happens, no code or step needed to make this example application has been left out, so you can literally follow along step by step. A the end of each section, we show the current system architecture.

Requirements

For this tutorial, you just need the basic requirements

Creating a new Spinal System

The first step is to create the project's directory. We will call it button-system. Then, install inside the “spinal-system-basic” template. We suggest that before running the following command you initialize an npm project (with npm init):

Install spinal-system-basic

~/$ mkdir button-system
~/$ cd button-system

~/button-system$ npm init -y
~/button-system$ npm i https://github.com/spinalcom/spinal-browser-admin.git

Launch spinal-system

That’s it. You have everything you need. You can check that everything is working by running the PM2 process file automatically generated:

~/button-system$ pm2 start launch.config.js

PM2 will automatically start the Spinal Hub and the organs.

After this installation, only SpinalHub is running on port 7777. SpinalHub contains a web server that provide his own Admin interface (spinal-browser-admin organ). Here is the architecture of the system you have after this first install:

Connect to Admin UI

The admin interface is a browser application. You need to access it via a browser. We suggest you use google chrome. (you may change the host/port and the password corresponding to your .config.json file):

http://127.0.0.1:7777/html/admin

The default admin account is :

Usernameclient IDPassword
admin168SPINAL_PASSWORD

SPINAL_PASSWORD : you will find it in th file .config.json  (spinalcom connection configuration file).


Admin interface views:


If you access the previous interface, then your system is running ! and you have access to the first organ (service) of your brand new spinal-system: its administration interface.

Now let’s create our first synchronized data model and our first organ.


Button-system Folder organization

Your button-system folder has been initialized with many folders and files that respect a spinal-system organization (see Framework & Best practices for more information). Apart from the node_modules folder which contains Node.js dependencies and the pm2 process file launch.config.js, a directory called nerve-center is generated which contains the database that will be stored and synchronized by using the Spinal System.

Spinalcom-system architecture:


  • .browser_organs : This is your web browser folder
  • .config_env : Your env configuration
  • nerve-center : The Spinalcom nerve center
  • node_modules : npm (node package manager) & spinal-package
  • .apps.json : installed package of your spinal system
  • .config.json : spinalcom connection configuration file
  • launch.config.js : Start your hub using pm2
  • package.json : config of your package
Create a data model

In the development of a Spinal System, one of the mains steps is to define the structure of the data (model) that will be synchronized. We are going to define this model in a specific library. In this quick start, we will create the model of a virtual button with a state attribute. The “virtualButton” organ will then modify the state of the model and we will monitor this state in the admin interface.


Create a folder named spinal-model-button at the root of your project and, inside it, create a file called model.js.

~/button-system$ mkdir spinal-model-button

spinal-model-button/model.js

class ButtonModel extends Model { // 1
  constructor() {
    super(); // 2
    this.add_attr({ // 3
      pressed: false
    });
  }
}
module.exports.ButtonModel = ButtonModel;

When creating a model, there are 2 things to take into account:

  1. Our ButtonModel class that inherits from the Model class in the SpinalCore library.
  2. The first instruction of the constructor is to call the super() method. As this function will inherit from a Model class inside the SpinalCore library, we need to call the parent constructor.
  3. Every argument that needs to be synchronized should be created using the add_attr() method like in the example above.

The model of the virtual button is now defined and contains its state (on/off) in an boolean attribute called pressed.

Create virtualButton organ

Now that we have our button model, we need to control its state by modifying its attribute “pressed”. To do this, we create an organ that interacts with the model.


Make a new folder called virtualButtonOrgan where we are going to define our process.

~/button-system$  mkdir virtualButtonOrgan

An organ has to be linked with the Spinalhub via a connector. For this tutorial, we use the Node.js connector, which has already been installed at the first step.

Inside the organ folder, create the file called index.js with the code below.


virtualButtonOrgan/index.js

// 1
const spinalCore = require('spinal-core-connectorjs');
const models = require('../spinal-model-button/model.js');

// 2

process.env.SPINALHUB_PORT = 7777;
process.env.SPINALHUB_IP = "127.0.0.1";
process.env.SPINAL_USER_ID = 168;
process.env.SPINAL_PASSWORD = "SPINAL_PASSWORD"; // you will find it in th file .config.json  (spinalcom connection configuration file)

const conn = spinalCore.connect(`http://${process.env.SPINAL_USER_ID}:${process.env.SPINAL_PASSWORD}@${process.env.SPINALHUB_IP}:${process.env.SPINALHUB_PORT}/`);

// 3: Create and store button
spinalCore.load(conn, "myButton",
  function (myButton) { //success callback
    console.log('load & sync existing model if it exists');
    press(myButton);
  },
  function (myButton) { //error callback
    myButton = new models.ButtonModel();
    spinalCore.store(conn, myButton, "myButton", function () {
      console.log('store & sync new model, first connection');
      press(myButton);
    });
  }
);

// 4:  Simulate that a button is being pressed
function press(button) {
  // Toggle pressed
  button.pressed.set(!button.pressed.get());
  // Call the function every second
  setTimeout(function () {
    console.log("button has been pressed");
    press(button);
  }, 1000);
}

These are the steps that the code is following:

  1. Requires connector and model.
  2. Establishes a connection with the hub, with write/read rights, using a user, password and environment variables. To understand more about configuration, please head to the configuration docs.
  3. Creates and synchronizes an instance of our button model and stores it in the hub. We first try to load and sync an existing instance from the hub, if no instance is found we create a new one
  4. Changes the data periodically through the press() function.

The current system folder organization so far is:

Launch the system

Run your organ


Run your organ with node:

~/button-system$ node virtualButtonOrgan/index.js

We should have the following system running by now:

Results: Monitor the value in the admin UI

Now we will check if everything is fine. Let’s open the admin dashboard and see modification in real time.

We see the file “mybutton”, to access to the real time value, check db inspector.


Create our second organ : virtualButtonMonitor

Now that our virtual button works, we are going to create a monitoring organ that subscribe to the virtualButton data and display its state in real time in the terminal.


Make a new folder called virtualButtonMonitorOrgan where we are going to define our process.

~/button-system$ mkdir virtualButtonMonitorOrgan 

We will use the Node.js connector in the same way then we did before in the file index.js

virtualButtonMonitorOrgan/index.js

// 1
const spinalCore = require('spinal-core-connectorjs');

// 2
console.log("Configuration Environment not found, using default config");
process.env.SPINALHUB_PORT = 7777;
process.env.SPINALHUB_IP = "127.0.0.1";
process.env.SPINAL_USER_ID = 168;
process.env.SPINAL_PASSWORD = "SPINAL_PASSWORD"; // you will find it in th file .config.json  (spinalcom connection configuration file)

const conn = spinalCore.connect(`http://${process.env.SPINAL_USER_ID}:${process.env.SPINAL_PASSWORD}@${process.env.SPINALHUB_IP}:${process.env.SPINALHUB_PORT}/`);

// 3: Create and store button
spinalCore.load(conn, "myButton",
    function (myButton) { //success callback        
        printState(myButton);
    }
);

// 4:  print the state when pressed
function printState(button) {
    button.bind(function  () {
        if (button.pressed.get() === true )
            console.log("Button has been pressed!");
    });
}

These are the steps that the code is following:

  1. Requires connector and model.
  2. Establishes a connection with the hub, with write/read rights, using a user, password and environment variables. To understand more about configuration, please head to the configuration docs.
  3. Load and sync the existing instance of the button from the hub.
  4. bind the display function that print the data periodically through the printState() function.

The current system folder organization so far is:



Run your organ

We assume that all your precedent organs are still running.

Run your monitoring organ with node:

~/button-system$ node virtualButtonMonitorOrgan/index.js

We should have the following system running by now:

Results

Conclusion

This first tutorial showed you three things :

  • how to install & launch a basic spinal system
  • how to create and store your own synchronized data model
  • how to store subscribe, monitor and assign events to modification of one data

This tutorial will be continued in Basic Equipment Tutorial.