How to send sensor data from python to IOTA tangle with MAM
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.