How to send sensor data from python to IOTA tangle with MAM

in #iota6 years ago (edited)

Currently, the client APIs for IOTA are still under heavy development. The most stable client for the masked authenticated messaging API (See e.g. https://blog.iota.org/introducing-masked-authenticated-messaging-e55c1822d50e) is in javascript here: https://github.com/iotaledger/mam.client.js/
There might be a major update in the near future, called mam+ or mam2.0.
Let's say we have now already written a python module reading a sensor connected to a raspberry pi. How can we get this data now onto the IOTA tangle when we are missing a python IOTA MAM client? A possible solution is to serialize the data in json object and send this json object to a IOTA MAM client written in javascript. In the internet of things world, there is already infrastructure for sending around small amount of data from IOT devices, for example mosquitto with the mqtt protocol. Compared to IOTA, mqtt needs a central broker (a central server), where data publisher and data subscriber connect to. Publisher can publish data on a topic, subscriber can subscribe to a topic. This already sounds very similar to IOTA MAM, only that mosquitto is not decentralized.

Software Installation

You find all the example node.js and python files in the git repository:

git clone https://github.com/magictimelapse/mqtt-iota

Installing a mosquitto broker on a raspberry pi is very simple:

sudo apt update
sudo apt upgrade
sudo apt install mosquitto mosquitto-clients

The mosquitto broker will conveniently start immediately as a service after installing the apt module:

sudo service mosquitto status

● mosquitto.service - LSB: mosquitto MQTT v3.1 message broker
   Loaded: loaded (/etc/init.d/mosquitto; generated; vendor preset: enabled)
   Active: active (running) since Tue 2019-01-01 23:42:51 CET; 25min ago
     Docs: man:systemd-sysv-generator(8)
   CGroup: /system.slice/mosquitto.service
           └─20726 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf

We can now subscribe to some topic on the local mosquitto broker:

mosquitto_sub -d sensors/data

sensors/data is the topic we subscribe to. For further information, you can check here: http://www.steves-internet-guide.com/understanding-mqtt-topics/
In a separate terminal we write data to the same topic:

mosquitto_pub -d -t sensors/data  -m "{temperature: 23}"

In the subscriber terminal you see that the data arrived. We can send any data that serializes to strings, so a stringified json object is perfectly ok.

Python Sensor Part

We will now send randomly generated data from python via mqtt to a iota mam client in javascript. Let's start with the python side. We will need a mqtt client in python, for example paho-mqtt. As is good practice in python, we will install the packages in virtual environment. Here we use python 2.7:

cd /home/pi
mkdir -p venv
cd venv
virtualenv mqtt-to-iota

Then we need to activate the virtual environment:

source /home/pi/venv/mqtt-to-iota/bin/activate

And install paho-mqtt:

pip install paho-mqtt

Alternatively, you can also install all dependencies by using pip with the requirements.txt file in the python directory of the mqtt-iota repository:

pip install -r requirements.txt

Let's try it out with a simple script, called example_publish.py:

#!/usr/bin/env python
import paho.mqtt.client as paho
import json
import random
import time
def create_data():
    humidity = random.random()*100.
    temperature = random.random()*50-30.
    radon_activity = random.random()*200
    data = {'humidity'   : {'value': humidity, 'unit':'%RH'},
            'temperature': {'value': temperature, 'unit':'C'},
            'radon_activity': {'value':radon_activity, 'unit':'Bq'}}
    return data

def create_location():
    latitude = 2*(random.random()-0.5)*90.
    longitude = 2*(random.random()-0.5)*180.
    location = {'latitude' :{'value':latitude , 'unit':'deg'},
                'longitude':{'value':longitude, 'unit':'deg'}}
    return location

def get_timestamp():
    return time.time() # unix timestamp in utc

if __name__ == "__main__":
    broker = 'localhost'
    port = 1883
    client = paho.Client()
    client.connect(broker,port)
    location = create_location()
    sensor_id = 'radon sensor'
    while True:
        data = create_data()
        timestamp = get_timestamp()
        json_object = {'id': sensor_id,
                       'location': location,
                       'timestamp': timestamp,
                       'data': data}
        # stringify the json data:
        stringified_json_object = json.dumps(json_object, separators=(',',':'))
        ret = client.publish('sensors/data',stringified_json_object)
        time.sleep(30.)

Now we need to write the counterpart in the javascript world, which subscribes to our topic sensors/data and re-publishes the data to the IOTA tangle.

Software Installation: Node.js

First change the directory to the js directory of the git repository, and install the node.js dependencies with:

npm install

Additionally, we need a special (stable) version of the mam client. which you can get from rckey's github repository:

cd node_modules
git clone https://github.com/rckey/mam.node.js

Implementing the mqtt subscriber is pretty straightforward:

/// mqtt part ///
MQTT = require('mqtt');
var mqtt_subscriber = MQTT.connect({
    host: 'localhost',
    port: 1883})

mqtt_subscriber.on('connect', function() {
    mqtt_subscriber.subscribe('sensors/data', function(err) {
        if(!err) {
            console.log('connected and subscribed to mqtt sensors/data stream');
        }
    })
})

mqtt_subscriber.on('message', function(topic, message) {
    obj = JSON.parse(message);
    const root = publish(obj);
})

process.on('uncaughtException', function (exception) {
    console.log(exception);
});

We connect again to our local mosquitto broker. There are two callback function, which react to the events "connect" and "message". "connect" happens, when the mqtt_subscriber has connected to the broker. After connecting, it will subscribe to our data stream with topic 'sensors/data'. In case a message is received, the received stringified json object is deserialized with JSON.parse(message). Then we use the async function 'publish'(), which publishes the message on the tangle with MAM, similar as we already did directly with the ruuvitag data (https://steemit.com/iota/@mragic/how-to-send-ruuvitag-sensor-data-to-the-iota-tangle-with-mam-using-a-raspberry-pi-3):

const MAM = require('mam.node.js')
const IOTA = require('iota.lib.js')
const moment = require('moment')

/// iota part ///
//const iota_host = 'http://localhost:14265'
const iota_host = 'https://durian.iotasalad.org:14265'
const MODE = 'public' // set to public, restricted or private
const SIDEKEY = ''
const iota = new IOTA({provider: iota_host})
const SECURITYLEVEL = 2 // 1, 2 or 3

let mamState = MAM.init(iota, undefined, SECURITYLEVEL)

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


const publish = async function(packet) {
    console.log('publishing message... ')
    console.log(packet)
    const trytes = iota.utils.toTrytes(JSON.stringify(packet));
    const message = MAM.create(mamState, trytes);
    console.log("root: ", message.root)
    mamState = message.state;
    transaction = MAM.attach(message.payload, message.address);
    await transaction;
    return message.root;
}

You find all the code in the repository as mqtt_to_mam_tangle.js.




Coin Marketplace

STEEM 0.19
TRX 0.14
JST 0.030
BTC 61240.20
ETH 3247.86
USDT 1.00
SBD 2.45