Basic Equipment Tutorial

Goal

In this tutorial you will learn how to :

  1. Create a model or a Digital twin of your sensors equipment.
  2. Create organs that simulate your sensors behavior.
  3. Launch your organs with efficiently
System architecture:

Requirements

For this tutorial, you need the basic requirements

Create the models / Digital twins

In this part you’re going to create two sensor models:

  • Sensor, a model with 4 attributes:
    • id : unique integer
    • name : string 
    • hygrometry : integer
    • temperature : integer
  • SensorList, a model with 1 attribute:
    • sensors : array of sensors

Create your spinal system and digital twin by following these steps:

  1. Create a new spinal-system from the browser-admin template (explained in the section "Creating a new Spinal System" in the Getting Started tutorial).
  2. Create a folder called spinal-models to store the different models you are going to create. Within this folder create a file named model.js.
  3. Complete model.js:
    1. Create the sensor model.
    2. Extend the sensor model with the Model class from spinalCore.
    3. Export the sensor model.
    4. Create the sensor list.
    5. Extend the sensor list with the Model of spinalCore.
    6. Export the sensor list.

Your model file should look like this:

spinal-models/models.js

models.js
// SensorModel inherits from Model
class SensorModel extends Model {
  constructor() {
    super();
    // add attributes to the model
    this.add_attr({
      id: 0,
      name: "",
      hygrometry: 0,
      temperature: 0
    });
  }
}
module.exports.SensorModel = SensorModel;

// SensorListModel inherits from Model
class SensorListModel extends Model {
  constructor() {
    super();
    // Array of equipments
    this.add_attr({
      sensors: []
    });
  }
}
module.exports.SensorListModel = SensorListModel;
Instantiate a list of 2 Sensors

In this part your are going to instantiate a list of 2 virtual sensors in the database and create two "organs" of the system that will simulate the sensor behavior.

Each organ will simulate changes of hygrometry and temperature.


  1. Create a new folder spinal-organ-sensor1 and within it a file named index.js.
  2. in the index.js file:
    1. Require spinal-core.
    2. Get the connection parameter from the config.js file in the main folder
    3. Create a function addItem. This function create, set and add an item to the list given in argument.
    4. Create a function simulate. This function simulate the value of the sensor.
    5. Create a function onSuccess. This function will be executed if the loading of ‘List’ is successful. 
    6. Create a function onFaill. This function will be executed if the loading of ‘List’ fail.
    7. Load list from spinal-core.
  3. Create a new folder spinal-organ-sensor2 
  4. Copy paste the index.js into sensor2 folder and do the appropriate modifications.
  5.  Don't forget to install spinal-core-connectorjs from GitHub in the two folders


Note
  • If you have and API to retrieve the real data of your sensor use it to send real data to the graph.
  • You can run every sensor independently by running the corresponding index.js (node index.js)

Your file spinal-organ-sensor1/index.js should look like this.

spinal-organ-sensor1/index.js
// Requirements and connection
const spinalCore = require('spinal-core-connectorjs');
const models = require('../spinal-models/models.js');


process.env.SPINALHUB_PORT = 7777;
process.env.SPINALHUB_IP = "127.0.0.1";
process.env.SPINAL_USER_ID = 168;
process.env.SPINAL_PASSWORD = "JHGgcz45JKilmzknzelf65ddDadggftIO98P";

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

// Gives random values to the hygrometry and temperature of a sensor
function simulate(sensor) {
  const hydro = Math.floor(Math.random() * 100);
  const degrees = Math.floor(Math.random() * 30);
  sensor.hygrometry.set(hydro);
  sensor.temperature.set(degrees);
  // Repeats every second
  setTimeout(() => {
    console.log(sensor.name.get() + ": data has changed");
    simulate(sensor);
  }, 1000);
};

// Finds a Sensor in the SensorList, if it doesn't exist, creates it
function getSensorById(list, id) {
  let item;

  for (let i = 0; i < list.sensors.length; i++) {
    if (list.sensors[i].id.get() === id) {
      item = list.sensors[i];
      break;
    }
  }
  if (typeof item === "undefined") {
    item = new models.SensorModel();
    item.id.set(id);
    item.name.set("sensor" + id);
    list.sensors.push(item);
  }
  return item;
}

// This function will be called if the list is successfully loaded
function onSuccess(list) {
  simulate(getSensorById(list, 0));
};

// This function will be called if the list cannot be loaded
function onFailure() {
  const list = new models.SensorListModel();
  const item = getSensorById(list, 0);

  spinalCore.store(conn, list, "List", () => {
    simulate(item);
  });
};

spinalCore.load(conn, "List", onSuccess, onFailure);

Run spinal-organ-sensor1/index.js and go to the admin UI and put 'List' into the inspector and you should see the hygrometry and temperature of sensor0 change every second.

Your file spinal-organ-sensor2/index.js should look like this.

spinal-organ-sensor2/index.js
// Requirements and connection
const spinalCore = require('spinal-core-connectorjs');
const models = require('../spinal-models/models.js');

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 = "JHGgcz45JKilmzknzelf65ddDadggftIO98P";

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

// Gives random values to the hygrometry and temperature of a sensor
function simulate(sensor) {
  const hydro = Math.floor(Math.random() * 100);
  const degrees = Math.floor(Math.random() * 30);
  sensor.hygrometry.set(hydro);
  sensor.temperature.set(degrees);
  // Repeats every second
  setTimeout(() => {
    console.log(sensor.name.get() + ": data has changed");
    simulate(sensor);
  }, 1000);
};

// Finds a Sensor in the SensorList, if it doesn't exist, creates it
function getSensorById(list, id) {
  let item;

  for (let i = 0; i < list.sensors.length; i++) {
    if (list.sensors[i].id.get() === id) {
      item = list.sensors[i];
      break;
    }
  }
  if (typeof item === "undefined") {
    item = new models.SensorModel();
    item.id.set(id);
    item.name.set("sensor" + id);
    list.sensors.push(item);
  }
  return item;
}

// This function will be called if the list is successfully loaded
function onSuccess(list) {
  simulate(getSensorById(list, 1));
};

// This function will be called if the list cannot be loaded
function onFailure() {
  const list = new models.SensorListModel();
  const item = getSensorById(list, 1);

  spinalCore.store(conn, list, "List", () => {
    simulate(item);
  });
};

spinalCore.load(conn, "List", onSuccess, onFailure); 


Launch efficiently your organs

You might have noticed that you are running every organ independently.

In a system where all the organs run on the same server, you can simplify this process and monitor your organs using pm2.

  1. Take a look at .app.json.
  2. add dependency to your organs.
    1. name: The name they will be identified by pm2
    2. script: The name of the script to be executed to launch the organ
    3. cwd: The location of the script (relative to the root of the project)
  3. run the commande pm2 restart launch.config.json.

Your .app.json should look like this:

{
  "apps": [
    {
      "name": "spinal-core-hub",
      "script": "spinalhub.js",
      "cwd": "./nerve-center/"
    },
    {
      "name": "sensor1",
      "script": "index.js",
      "cwd": "./spinal-organ-sensor1/"
    },
    {
      "name": "sensor2",
      "script": "index.js",
      "cwd": "./spinal-organ-sensor2/"
    }
  ]
}

pm2 will now show you sensor 1 and 2 along with spinal-core-hub.

Conclusion


In this tutorial you learned:

  • how to create complex models
  • how to organize your data coming from multiple organs
  • how to launch you your organs efficiently


This tutorial will be continued in Basic Automate Tutorial.