Guillermo Perez Guillen
Published © CC BY-NC-SA

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 days12,000

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
Arduino UNO
Arduino 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 Studio 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);

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);

Credits

Guillermo Perez Guillen

Guillermo Perez Guillen

57 projects • 63 followers
Electronics and Communications Engineer (ECE) & Renewable Energy: 14 prizes in Hackster / Hackaday Prize Finalist 2021-22-23

Comments