Indoor Air Quality and Garbage Monitoring System

Healthy indoor environments system of smart commercial buildings Using Masked Authenticated Messaging (MAM) of the IOTA protocol.

AdvancedFull instructions provided5 days2,936

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
Arduino UNO & Genuino UNO
Arduino UNO & Genuino UNO
×1
NodeMCU ESP8266 Breakout Board
NodeMCU ESP8266 Breakout Board
×1
DHT11 Temperature & Humidity Sensor (4 pins)
DHT11 Temperature & Humidity Sensor (4 pins)
×1
Grove - Gas Sensor(MQ2)
Seeed Grove - Gas Sensor(MQ2)
×1
MQ-7 CO gas sensor (generic)
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
Raspberry Pi power supply
×1
HDMI cable
×1
USB-A to B Cable
USB-A to B Cable
×1
Jumper wires (generic)
Jumper wires (generic)
×1
5V battery (generic)
×1

Software apps and online services

IOTA Tangle
IOTA Tangle
Node.js
Raspbian
Raspberry Pi Raspbian
Arduino IDE
Arduino IDE
MQTT
MQTT

Story

Read more

Schematics

Indoor Air Quality Monitoring System v1

Schematic diagram

Indoor Air Quality Monitoring System v2

Schematic diagram

Garbage Monitoring System

Schematic diagram

Code

sensor.js

JavaScript
Indoor Air Quality Monitoring System v1
Code to test the DHT11 sensor
const sensor = require('node-dht-sensor');

const TIMEINTERVAL = 10; // SECONDS
const SENSORTYPE = 11; // 11=DHT11, 22=DHT22
const GPIOPIN = 4; // RASPBERRY GPIO PIN FROM THE DHT11 SENSOR

function readSensor(){
    sensor.read(SENSORTYPE, GPIOPIN, function(err, temperature, humidity) {
        if (!err) {
            console.log('temp: ' + temperature.toFixed(1) + 'C, ' + 'humidity: ' + humidity.toFixed(1) + '%');
        } else {
            console.log(err);
        }
    });
}

readSensor();

// AUTOMATICALLY UPDATE SENSOR VALUE EVERY 10 SECONDS
setInterval(readSensor, TIMEINTERVAL*1000);

mam_sensor.js

JavaScript
Indoor Air Quality Monitoring System v1
This code store the temperature and humidity data from the DHT11 sensor module to the Tangle
const sensor = require('node-dht-sensor');
const Mam = require('./lib/mam.client.js');
const IOTA = require('iota.lib.js');
const moment = require('moment');

//const iota = new IOTA({ provider: 'https://nodes.testnet.iota.org:443' });
const iota = new IOTA({ provider: 'https://potato.iotasalad.org:14265' });
//const iota = new IOTA({ provider: 'https://peanut.iotasalad.org:14265' });

const MODE = 'restricted'; // PUBLIC, PRIVATE OR RESTRICTED
const SIDEKEY = 'mysecret'; // USED ONLY IN RESTRICTED MODE
const SECURITYLEVEL = 3; 
const TIMEINTERVAL = 30; // SECONDS
const SENSORTYPE = 11; // 11=DHT11, 22=DHT22
const GPIOPIN = 14; // RASPBERRY GPIO PIN FROM DHT11 SENSOR

// INITIALIZE MAM STATE
let mamState = Mam.init(iota, undefined, SECURITYLEVEL);

// CHANNEL MODE
if (MODE == 'restricted') {
    const key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
} else {
    mamState = Mam.changeMode(mamState, MODE);
}

// PUBLISH TO TANGLE
const publish = async function(packet) {
    // CREATE MAM PAYLOAD
    const trytes = iota.utils.toTrytes(JSON.stringify(packet));
    const message = Mam.create(mamState, trytes);

    // SAVE NEW MAMSTATE
    mamState = message.state;
    console.log('Root: ', message.root);
    console.log('Address: ', message.address);

    // ATTACH THE PAYLOAD
    await Mam.attach(message.payload, message.address);

    return message.root;
}

function readSensor(){

    sensor.read(SENSORTYPE, GPIOPIN, async function(err, temperature, humidity) {
        if (!err) {
            const city = ('MEXICO');
            const building = ('65');
            const dateTime = moment().utc().format('YYYY/MM/DD hh:mm:ss'); 
            const data = `{Temperature: ${temperature.toFixed(1)}°C (${(temperature.toFixed(1)*1.8)+32}°F), Humidity: ${humidity.toFixed(1)}%}`;
            const json = {"data": data, "dateTime": dateTime, "building": building, "city": city};               

            const root = await publish(json);
            console.log(`City: ${json.city}, Building: ${json.building}, Time: ${json.dateTime} UTC, Data: ${json.data}, root: ${root}`);

        } else {
            console.log(err);
        }
    });
}

// START IT
readSensor();

// AUTOMATICALLY UPDATE SENSOR VALUE EVERY 30 SECONDS
setInterval(readSensor, TIMEINTERVAL*1000);

mam_receive.js

JavaScript
Indoor Air Quality Monitoring System v1
The stored sensor data is displayed.
const Mam = require('./lib/mam.client.js');
const IOTA = require('iota.lib.js');
//const iota = new IOTA({ provider: 'https://nodes.testnet.iota.org:443' });
const iota = new IOTA({ provider: 'https://potato.iotasalad.org:14265' });
//const iota = new IOTA({ provider: 'https://peanut.iotasalad.org:14265' });

const MODE = 'restricted'; // PUBLIC, PRIVATE OR RESTRICTED
const SIDEKEY = 'mysecret'; // USED ONLY IN RESTRICTED MODE

let root;
let key;

// CHECK THE ARGUMENTS
const args = process.argv;
if(args.length !=3) {
    console.log('Missing root as argument: node mam_receive.js <root>');
    process.exit();
} else if(!iota.valid.isAddress(args[2])){
    console.log('You have entered an invalid root: '+ args[2]);
    process.exit();
} else {
    root = args[2];
}

// INITIALISE MAM STATE
let mamState = Mam.init(iota);

// SET CHANNEL MODE
if (MODE == 'restricted') {
    key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
} else {
    mamState = Mam.changeMode(mamState, MODE);
}

// RECEIVE DATA FROM THE TANGLE
const executeDataRetrieval = async function(rootVal, keyVal) {
    let resp = await Mam.fetch(rootVal, MODE, keyVal, function(data) {
        let json = JSON.parse(iota.utils.fromTrytes(data));
        console.log(`City: ${json.city}, Building: ${json.building}, Time: ${json.dateTime} UTC, Data: ${json.data}`);
    });    

}

executeDataRetrieval(root, key);

sensorArduino.ino

Arduino
Indoor Air Quality Monitoring System v2
This code is to capture the data of the three sensors: DHT11 humidity and temperature sensor, MQ-2 LPG gas sensor, and MQ-7 CO gas sensor.
#include <MQ2.h>
#include "MQ7.h"
#include "DHT.h"   
#define DHTPIN 2     
 
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

int pin = A0;
int lpg;
MQ2 mq2(pin);
MQ7 mq7(A1,5.0); 

DHT dht(DHTPIN, DHTTYPE);  //PIN AND SENSOR TYPE
 
void setup()
{
  Serial.begin(9600);
  dht.begin();
  mq2.begin();
}
 
void loop()
{
  int h = dht.readHumidity();  //READ HUMIDITY
  int t = dht.readTemperature();  //READ TEMPERATURE

  float* values= mq2.read(true); //SET IT FALSE IF YOU DON'T WANT TO PRINT THE VALUES IN THE SERIAL
 
  if (isnan(t) || isnan(h)) // ARE THERE NUMBERS?
  {
    Serial.println("Fail to read the DHT sensor"); //FAILURE IF THERE ARE NOT NUMBERS
  } else {
    //lpg = values[0];
    lpg = mq2.readLPG();
    Serial.print("CO: ");
    Serial.print(mq7.getPPM());
    Serial.print("ppm, ");
    Serial.print("Temperature: ");
    Serial.print(t);
    Serial.print("°C, ");
    Serial.print("Humidity: ");
    Serial.print(h);
    Serial.println("%"); 
  }
  delay(30000);
}

listportsArduino.js

JavaScript
Indoor Air Quality Monitoring System v2
It shows us the available ports of the Arduino UNO board.
const SerialPort = require('serialport');

// list serial ports:
SerialPort.list(function (err, ports) {
    ports.forEach(function(port) {
        console.log(port.comName);
    });
});

mam_sensorArduino.js

JavaScript
Indoor Air Quality Monitoring System v2
The DHT11, MQ-2, and MQ-7 sensors data are read and published to the Tangle using MAM.
const SerialPort = require('serialport');
const moment = require('moment');

const IOTA = require('iota.lib.js');
const Mam = require('./lib/mam.client.js');

//const iota = new IOTA({ provider: 'https://nodes.testnet.iota.org:443' });
const iota = new IOTA({ provider: 'https://potato.iotasalad.org:14265' });

const MODE = 'restricted'; // PUBLIC, PRIVATE, RESTRICTED
const SIDEKEY = 'mysecret'; // ONLY ASCII CHARACTERS
const SECURITYLEVEL = 3; // 1, 2, 3

const PORTNAME = '/dev/ttyACM1'; // ENTER VALID PORT 

const port = new SerialPort(PORTNAME, {
    baudRate: 9600,
    autoOpen: true
});

const Readline = SerialPort.parsers.Readline;
const parser = port.pipe(new Readline({ delimiter: '\r\n' }));

// INITIALIZE MAM STATE
let mamState = Mam.init(iota, undefined, SECURITYLEVEL);

// SET CHANNEL MODE
if (MODE == 'restricted') {
    const key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
} else {
    mamState = Mam.changeMode(mamState, MODE);
}

// PUBLISH TO TANGLE
const publish = async function(packet) {
    // CREATE MAM PAYLOAD
    const trytes = iota.utils.toTrytes(JSON.stringify(packet));
    const message = Mam.create(mamState, trytes);

    // SAVE NEW MAMSTATE
    mamState = message.state;
    console.log('Root: ', message.root);
    console.log('Address: ', message.address);

    // ATTACH THE PAYLOAD
    await Mam.attach(message.payload, message.address);

    return message.root;
}

// SERIAL PORT LIBRARY EVENTS
port.on('open', showPortOpen);
parser.on('data', readSerialData);
port.on('close', showPortClose);
port.on('error', showError);

// CALLBACK FUNCTIONS
function showPortOpen() {
    console.log('Serial port open. Data rate: ' + port.baudRate);
}

async function readSerialData(data){
    let json = {};

    const time = moment().utc().format('YYYY/MM/DD hh:mm:ss');
    const city = ('NY');
    const building = ('13');

    json['time'] = time;
        json['city'] = `${city}`;
        json['building'] = `${building}`;
	json['data'] = `{${data}}`;

    console.log('json = ',json);
    const root = await publish(json);
}

function showPortClose() {
    console.log('Serial port closed.');
}

function showError(error) {
   console.log('Serial port error: ' + error);
}

mam_receiveArduino.js

JavaScript
Indoor Air Quality Monitoring System v2
Extract the stored data from the Tangle using MAM and display the data.
const Mam = require('./lib/mam.client.js');
const IOTA = require('iota.lib.js');
//const iota = new IOTA({ provider: 'https://nodes.testnet.iota.org:443' });
const iota = new IOTA({ provider: 'https://potato.iotasalad.org:14265' });

const MODE = 'restricted'; // PUBLIC, PRIVATE OR RESTRICTED
const SIDEKEY = 'mysecret'; // ENTER ONLY ASCII CHARACTERS

let root;
let key;

// CHECK THE ARGUMENTS
const args = process.argv;
if(args.length !=3) {
    console.log('Missing root as argument: node mam_receive.js <root>');
    process.exit();
} else if(!iota.valid.isAddress(args[2])){
    console.log('You have entered an invalid root: '+ args[2]);
    process.exit();
} else {
    root = args[2];
}

// INITIALIZE MAM STATE
let mamState = Mam.init(iota);

// SET CHANNEL MODE
if (MODE == 'restricted') {
    key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
} else {
    mamState = Mam.changeMode(mamState, MODE);
}

// RECEIVE DATA FROM THE TANGLE
const executeDataRetrieval = async function(rootVal, keyVal) {
    let resp = await Mam.fetch(rootVal, MODE, keyVal, function(data) {
    let json = JSON.parse(iota.utils.fromTrytes(data));
    console.log(`City: ${json.city}, Building: ${json.building}, Time: ${json.time} UTC, Data: ${json.data}`);
    });

    executeDataRetrieval(resp.nextRoot, keyVal);
}

executeDataRetrieval(root, key);

trashcan.ino

Arduino
Garbage Monitoring System
This code is to capture the data of the SRF05 sensor. This file is located in the trashcan folder
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define MEASUREMENT_TIMEINTERVAL 30 // Seconds

const char* wifi_ssid = "ARRIS-WXYZ";
const char* wifi_password = "XXXXXXXXXXXX";

const char* mqtt_server = "192.168.0.12";
const int mqtt_port = 1883;
const char* mqtt_user = "willy";
const char* mqtt_password = "mysecret";

// DEFINE PINS NUMBERS
const int trigPin = 2;  //D4 SRF05
const int echoPin = 0;  //D3 SRF05

// DEFINE VARIABLES
long duration; // SRF05
int distance; // SRF05
int garbage; // SRF05
int trashcan = 25;// MY TRASHCAN HAS 25 CM OF LONGITUDE 

#define srf05_topic "sensor/srf05"
WiFiClient espClient;
PubSubClient client(espClient);

void callback(char* topic, byte* payload, unsigned int length) {
    // HANDLE MESSAGE ARRIVED
}

void setup() {
    pinMode(trigPin, OUTPUT); // SETS THE TRIGPIN AS AN OUTPUT
    pinMode(echoPin, INPUT); // SETS THE ECHOPIN AS AN INPUT
    Serial.begin(115200);
    setup_wifi();
    client.setServer(mqtt_server, mqtt_port);

}

void setup_wifi() {
    delay(10);
    // WE START BY CONNECTING TO A WIFI NETWORK
    Serial.println("Connecting to ");
    Serial.println(wifi_ssid);

    WiFi.begin(wifi_ssid, wifi_password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.println("Connecting to WiFi..");
    }

    Serial.println("Connected to the WiFi network");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
}

// THIS FUNCTIONS RECONNECTS YOUR NODEMCU TO YOUR MQQT BROKER
void reconnect() {
    // LOOP UNTIL WE´RE RECONNECTED
    while (!client.connected()) {
        Serial.println("Attempting MQTT connection...");

        if (client.connect("ESP8266Client", mqtt_user, mqtt_password)) {
            Serial.println("connected");

            // SUBSCRIBE OR RESUBSCRIBE TO A TOPIC
        } else {
            Serial.print("failed with state ");
            Serial.println(client.state());

            // WAIT 5 SECONDS BEFORE RETRYING
            delay(5000);
        }
    }
}

void loop() {
    if (!client.connected()) {
        reconnect();
    }

    if(!client.loop()) {
        client.connect("ESP8266Client");
    }

    // CLEARRS THE TRIGPIN
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);

    // SETS THE TRIGPIN ON HIGH STATE FOR 10 MICRO SECONDS
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);

    // READS THE ECHOPIN, RETURNS THE SOUND WAVE TRAVEL TIME IN MICROSECONDS
    duration = pulseIn(echoPin, HIGH);

    // CALCULATING THE DISTANCE AND THE GARBAGE PERCENTAGE
    distance= duration*0.034/2;
    garbage = 100-(distance*100)/trashcan;

    String data = "trashcan: "+String(garbage)+" %";
    Serial.println(data);

    client.publish(srf05_topic, data.c_str(), false);

    // WAIT N SECONDS BETWEEN MEASSUREMENTS
    delay(MEASUREMENT_TIMEINTERVAL * 1000);
}

nodemcu_mqtt_mam.js

JavaScript
Garbage Monitoring System
The SRF05 sensor data are read and published to the Tangle using MAM.
const mqtt = require('mqtt');
const moment = require('moment');
const Mam = require('./lib/mam.client.js');
const IOTA = require('iota.lib.js');

const MODE = 'restricted';  // PUBLIC, PRIVATE OR RESTRICTED
const SIDEKEY = 'mysecret'; // ENTER ONLY ASCII CHARACTERS. USED ONLY IN RSETRICTED MODE
const SECURITYLEVEL = 3; // 1, 2 or 3

const SRF05_TOPIC = "sensor/srf05";

const BROKER_URL = "mqtt://192.168.0.12";

const options = {
    port: 1883,
    clientId: 'nodemcu_mqtt_mam.js',
    username: 'willy',
    password: 'mysecret'
};

//const iota = new IOTA({ provider: 'https://nodes.testnet.iota.org:443' });
//const iota = new IOTA({ provider: 'https://potato.iotasalad.org:14265' });
const iota = new IOTA({ provider: 'https://durian.iotasalad.org:14265' });

// INITIALIZE MAMA STATE
let mamState = Mam.init(iota, undefined, SECURITYLEVEL);

// SET CHANNEL MODE
if (MODE == 'restricted') {
    const key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
} else {
    mamState = Mam.changeMode(mamState, MODE);
}

// PUBLISH TO TANGLE
const publish = async function(packet) {
    // CREATE MAM PAYLOAD
    const trytes = iota.utils.toTrytes(JSON.stringify(packet));
    const message = Mam.create(mamState, trytes);

    // SAVE NEW MAMSTATE
    mamState = message.state;
    console.log('Root: ', message.root);
    console.log('Address: ', message.address);

    // ATTACH THE PAYLOAD
    await Mam.attach(message.payload, message.address);

    return message.root;
}

const client = mqtt.connect(BROKER_URL, options);

client.on("connect", onConnected);
client.on("message", onMessageReceived)

function onConnected() {
    client.subscribe(SRF05_TOPIC);
}

async function onMessageReceived(topic, message) {
    if (topic == SRF05_TOPIC) {
        const city = ('BERLIN');
        const building = ('7');
        const dateTime = moment().utc().format('YYYY/MM/DD hh:mm:ss');
        const data = `{${message}}`;
        const json = {"data": data, "dateTime": dateTime, "building": building, "city": city};               

        const root = await publish(json);
        console.log(`City: ${json.city}, Building: ${json.building}, dateTime: ${json.dateTime} UTC, data: ${json.data}, root: ${root}`);
    }
}

nodemcu_mam_receive.js

JavaScript
Garbage Monitoring System
Extract the stored data from the Tangle using MAM and display the data.
const Mam = require('./lib/mam.client.js');
const IOTA = require('iota.lib.js');
//const iota = new IOTA({ provider: 'https://nodes.testnet.iota.org:443' });
//const iota = new IOTA({ provider: 'https://potato.iotasalad.org:14265' });
const iota = new IOTA({ provider: 'https://durian.iotasalad.org:14265' });   

const MODE = 'restricted'; // PUBLIC, PRIVATE OR RESTRICTED
const SIDEKEY = 'mysecret'; // ENTER ONLY ASCII CHARACTERS. USED ONLY IN RSETRICTED MODE

let root;
let key;

// CHECK THE ARGUMENTS
const args = process.argv;
if(args.length !=3) {
    console.log('Missing root as argument: node mam_receive.js <root>');
    process.exit();
} else if(!iota.valid.isAddress(args[2])){
    console.log('You have entered an invalid root: '+ args[2]);
    process.exit();
} else {
    root = args[2];
}

// INITIALIZE MAM STATE
let mamState = Mam.init(iota);

// SET CHANNEL MODE
if (MODE == 'restricted') {
    key = iota.utils.toTrytes(SIDEKEY);
    mamState = Mam.changeMode(mamState, MODE, key);
} else {
    mamState = Mam.changeMode(mamState, MODE);
}

// RECEIVE DATA FRON THE TANGLE
const executeDataRetrieval = async function(rootVal, keyVal) {
    let resp = await Mam.fetch(rootVal, MODE, keyVal, function(data) {
        let json = JSON.parse(iota.utils.fromTrytes(data));
    console.log(`City: ${json.city}, Building: ${json.building}, dateTime: ${json.dateTime} UTC, Data: ${json.data}`);
    });
    executeDataRetrieval(resp.nextRoot, keyVal);
}

executeDataRetrieval(root, key);

Indoor Air Quality and Garbage Monitoring System

Project repository: "Indoor Air Quality and Garbage Monitoring System"

Credits

Guillermo Alberto Perez Guillen

Guillermo Alberto Perez Guillen

27 projects • 24 followers
Communications and Electronics Engineering, and Writer... "Don´t Expect Different Results If Your Habits Are The Same" A Einstein

Comments

Add projectSign up / Login