Version: 0.2.0
Platform: Arduino ESP8266
Language: Arduino C/C++
License: MIT
- Manish Meganathan
- Mariyam A. Ghani
This repository contains the following:
-
An Arduino Library for the ESP8266
An Arduino library that contains firmware code for sensor nodes and control nodes that run on the FyrMesh Platfrom. Contains abstraction tools to support a modular sensor hardware configurations, callbacks to support the painlessMesh library, loop runtimes to check button statuses and a custom message delivery protocol. It is intended to be compatible with the ESP8266 NodeMCU boards. -
A Configuration Value Generation Tool
An interactive python script to generate the configuration variables for any custom FyrNode configuration.
An Arduino library that contains firmware code for sensor nodes and control nodes that run on the FyrMesh Platfrom. Contains abstraction tools to support a modular sensor hardware configurations, callbacks to support the painlessMesh library, loop runtimes to check button statuses and a custom message delivery protocol.
It is intended to be compatible with the ESP8266 NodeMCU boards.
The library is based on the painlessMesh library that implements a mesh network of nodes based on the ESP8266 and ESP32 platforms. This library combines this functionality along with its custom JSON-based command messaging protocol and modular hardware configuration support to abstract the FyrMesh platforms requirements into a simple collection classes that achieve all the required functionality behind the scenes.
This library operates with 2 mesh messaging protocols, IMC & ICC. Both of these systems do not use a request-response system. Instead, they employ an Remote Procedure Call based system by sending 'commands' and handling incoming 'messages'. Unique handlers are built for each type of message or command.
A distibuted communication protocol where all nodes on the mesh can communicate using messages. Each message follows a simple structure as illustrated below.
message: {
"type": "message",
"origin": <uint_32>,
"reach": {
"type": <str>,
"destination": <uint_32> (optional)
},
"data": {
"type": <str>,
<data/metadata>
}
}
The origin
is the nodeID of the node that sent the message and the data
field is a dicitionary with a key type
set to the type of message along with set of additional data/metadata. The reach
field is set with reach parameters. The type may be either unicast or broadcast. The reach destination field is ignored for broadcast messages and is a recipient nodeID for unicast messages.
Some of the current types of messages include the following, each of which have their own characteristic set of metadata embedded in the data
field.
- meshcommand
- handshake
- handshakeACK
- sensordata
- configdata
- connectionupdate
The meshcommand messages are always generated by the control node and follow the following structure.
meshcommand: {
"type": "message",
"origin": <uint_32>,
"reach": {
"type": <str>,
"destination": <uint_32> (optional)
},
"data": {
"type": "meshcommand",
"command": <str>,
<data/metadata>
}
}
The only real difference is the required command
field within the data
field. This string determines the command string and the sensor node calls the appropriate command handler to handle it.
When other recognized types of messages are recieved by the mesh, the appropriate message handler and if an unrecognized message type is recieved, it is ignored and logged to the Serial.
An asymmetric protocol that allows the control node and the controller to send 'controlcommands' and 'meshlogs' to each other. This 'meshlog' format is also used by sensor nodes to log data to their Serial.
meshlog: {
"type": "meshlog",
"nodeID": <uint_32>,
"nodetime": <uint64_t>,
"logdata": {
"type": <str>,
"message": <str>,
<data/metadata>
}
}
The nodeID
is the nodeID of the node that is generating the log and the nodetime
is the internal clock time of the node when the log is generated. The logdata
field is a dictionary with the a type
and message
key for the log type and log message and is often filled with other data/metadata for context.
Some of the current types of meshlogs include the following,
- meshsync
- nodesync
- handshake-rxack
- sensordata
- configdata
- controlconfigdata
- controlnodelist
- messagerx
'*' These meshlog types are only generated by the control node and handled by the controller using the FyrMesh orchestration runtimes.
'^' These meshlog types are only generated by sensor nodes and only used for logging.
Apart from meshlogs, the library currently supports the command interface for the controller to send commands to the control node. The reverse is not possible yet, as of v0.2.0. These control commands are structured as follows.
controlcommand: {
"type": "controlcommand",
"command": <str>
<data/metadata>
}
The command
field determines the command to be executed and is often passed with some additional metadata to help handle the command. Some of the current types of control commands are:
- connection-on
- connection-off
- readsensors-mesh
- readsensors-node
- readconfig-mesh
- readconfig-node
- readconfig-control
- readnodelist-control
The library contains two classes FyrNode and FyrNodeControl. They behave as the sensor nodes and the control node for the FyrMesh platform respectively. The hardware configuration of the node is specified using a collection of global values made available to the library using the extern
keyword.
This library while designed to be hackable and modular, is intended to be used as is on the nodes themselves. The only level of customization on the nodes is expected to be with the configuration value set to support different types of hardware configurations. New functionality must be implemented directly into the library and not on the sketch file of the node.
The modularity of the library is achieved using a set of special runtimes called handlers. There are few types of handlers, such as message handlers and command handlers that are responsible for handling incoming messages and commands. These are IMC commands
The FyrNode
object is initialised as mentioned below. The hardware configuration is not specfied at the time of intialisation of this object, but is rather accessed from the collection of global variables. See more in the Hardware Configuration Section.
FyrNode sensornode;
The FyrNode
object has the following member methods.
begin()
This method is used in thevoid setup()
function of the Arduino Sketch. It initialises all the sensors, buttons, interfaces and initiates the mesh.update()
This method is used in thevoid loop()
function of the Arduino Sketch. It runs themesh.update()
runtime in the backend along with checking for connection states, new messages and button states.
The FyrNodeControl
object is initialised as mentioned below. The hardware configuration is not specfied at the time of intialisation of this object, but is rather accessed from the collection of global variables. See more in the Hardware Configuration Section.
FyrNodeControl controlnode;
The FyrNode
object has the following member methods.
begin()
This method is used in thevoid setup()
function of the Arduino Sketch. It initialises all the buttons, interfaces and initiates the mesh.update()
This method is used in thevoid loop()
function of the Arduino Sketch. It runs themesh.update()
runtime in the backend along with checking for connection states, new messages and button states.
The FyrNode library supports a modular approach to node design i.e. every node can be built and configured differently and the mesh can still function as a whole. This is achieved by embedding some values as global constants in the Arduino Sketch, which is then accessed by the library using the extern
keyword that tells the linker to fetch the symbol from another part of the program.
The configuration values can either be manually filled in or the config-generator.py script can be used to interactively generate the values and their supporting comments. (This script is unavailable as of v0.2.0)
The configuration symbols are as follows:
MESH_SSID
ThisString
value determines the SSID name of the mesh AP configuration.MESH_PSWD
ThisString
value determines the password of the mesh AP configuration.MESH_PORT
Thisuint16_t
value determines the port on which the node has to listen to for mesh messages.DHTTYP
Thisint
value determines the sensor ID attached to the DHT interface. Refer to the Sensor Value Codes section for sensor values.DHTPIN
Thisint
value determines the pin on which the DHT sensor is attached. Refer to NodeMCU Pin Numbering section for pin values.GASTYP
Thisint
value determines the sensor ID attached to the GAS interface. Refer to the Sensor Value Codes section for sensor values.GASPIN
- This
int
value determines the pin on which the GAS sensor is attached. Refer to NodeMCU Pin Numbering section for pin values. FLMTYP
Thisint
value determines the sensor ID attached to the FLM interface. Refer to the Sensor Value Codes section for sensor values.FLMPIN
Thisint
value determines the pin on which the FLM sensor is attached. Refer to NodeMCU Pin Numbering section for pin values.PINGER
Thisbool
value determines whether a button is attached to the PINGER interface. Pressing this button broadcasts a pingresponse command to the mesh.PINGERPIN
Thisint
value determines the pin on which the PINGER button is attached. Refer to NodeMCU Pin Numbering section for pin values.SERIALBAUD
Thisuint32_t
value determines the baud rate of the Serial interface.CONNECTLEDPIN
Thisint
value determines the pin on which the connection indicator LED is attached. Defaults to the built-in LED at pin D0 (16).
0 = No Attachment
2 = MQ2 (GAS)
11 = DHT11 (DHT)
16 = SEN16 (FLM)
22 = DHT22 (DHT)
all other values are currently unassigned.
D0 = 16 D1 = 5 D2 = 4 D3 = 0
D4 = 2 D5 = 14 D6 = 12 D7 = 13
D8 = 15 D9 = 3 D10 = 1 A0 = 17
refer to this link for more information about NodeMCU pins
An example program that uses the FyrNodeControl
class to define a control node.
#include "fyrnode.h"
String MESH_SSID = "whateverYouLike";
String MESH_PSWD = "somethingSneaky";
uint16_t MESH_PORT = 5555;
int DHTTYP = 0; // DHT attached to None
int DHTPIN = 99; // DHT attached at None
int GASTYP = 0; // GAS attached to None
int GASPIN = 99; // GAS attached at None
int FLMTYP = 0; // FLM attached to None
int FLMPIN = 99; // FLM attached at None
bool PINGER = true; //PINGER attached = true
int PINGERPIN = 5; //PINGER attached at Pin D1 (GPIO5)
int CONNECTLEDPIN = 16; // CONNECTLEDPIN attached at Pin D0 (LED_BUILTIN)
uint32_t SERIALBAUD = 115200; // SERIALBAUD rate is 38400 bps
FyrNodeControl controlnode;
void setup()
{
controlnode.begin();
}
void loop()
{
controlnode.update();
}
An example program that uses the FyrNode
class to define a sensor node that has DHT11 sensor attached at pin D1.
#include "fyrnode.h"
String MESH_SSID = "whateverYouLike";
String MESH_PSWD = "somethingSneaky";
uint16_t MESH_PORT = 5555;
int DHTTYP = 11; // DHT attached to DHT11 Sensor
int DHTPIN = 5; // DHT attached at Pin D1 (GPIO5)
int GASTYP = 0; // GAS attached to None
int GASPIN = 99; // GAS attached at None
int FLMTYP = 0; // FLM attached to None
int FLMPIN = 99; // FLM attached at None
bool PINGER = false; //PINGER attached = false
int PINGERPIN = 99; //PINGER attached at None
int CONNECTLEDPIN = 16; // CONNECTLEDPIN attached at Pin D0 (LED_BUILTIN)
uint32_t SERIALBAUD = 115200; // SERIALBAUD rate is 38400 bps
FyrNode meshnode;
void setup()
{
meshnode.begin();
}
void loop()
{
meshnode.update();
}
More examples are available in the library's examples directory.