Datastorage

The data storage is though to use both blockchain and a database based on OpenBravo. OpenBravo will be the web service for the website to communicate with and blockchain will be the trust-machine.

Ethereum data storage

Once we have initialized our private node (explained in the echo server configuration) we have developed some smart contracts that allow us to store data on the blockchain via authorised entities. To do so we've decided to develop one contract per sensor to ease the understanding of non-tech stakeholders. This contracts can be found in: https://github.com/OpenVino/data-storage-solidity

To test the contracts you can follow the instructions given in the README file or check the javadoc written in the code. Once we have this contracts implemented we had to prepare a script to lead the deployment of the given contracts in our private network which is the following one:

 

import json import web3 from web3 import Web3, HTTPProvider from solc import compile_source def compile_source_file(file_path): with open(file_path, 'r') as f: source = f.read() return compile_source(source) print("\n 1) Connecting to the costaflores-node1 (http://10.112.48.25:8545) ...") w3 = Web3(HTTPProvider("http://10.112.48.25:8545")) print("\n 2) Preparing contracts (IoT, Datastorage)...") compiled_sol = compile_source_file('contracts.sol') IoT = w3.eth.contract(abi=compiled_sol['<stdin>:IoT']['abi'], bytecode=compiled_sol['<stdin>:IoT']['bin']); Datastorage = w3.eth.contract(abi=compiled_sol['<stdin>:Datastorage']['abi'], bytecode=compiled_sol['<stdin>:Datastorage']['bin']); print("\n 3) Deploying contracts (IoT, Datastorage)...") tx_hash = Datastorage.constructor(w3.eth.coinbase).transact({'from': w3.eth.coinbase, 'gas': 672197}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) print("\n - Contract Datastorage.sol was deployed at address: " + w3.toChecksumAddress(tx_receipt.contractAddress) + "on transaction " + w3.toHex(tx_hash)) datastorage = w3.eth.contract(address = w3.toChecksumAddress(tx_receipt.contractAddress), abi = compiled_sol['<stdin>:Datastorage']['abi'], ) tx_hash = IoT.constructor(tx_receipt.contractAddress, w3.toChecksumAddress("0xBD918Bf5d6A6DD2b6A7091f114d4382b8368Cc96")).transact({'from': w3.eth.coinbase, 'gas': 672197}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) print("\n - Contract IoT.sol was deployed at address " + w3.toChecksumAddress(tx_receipt.contractAddress) + "on transaction " + w3.toHex(tx_hash)) print("\n 4) Initializing contracts (IoT, Datastorage)...") tx_hash = datastorage.functions.setLogic(w3.toChecksumAddress(tx_receipt.contractAddress)).transact({'from': w3.eth.coinbase, 'gas': 672197}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash) tx_hash = datastorage.functions.transferOwnership(w3.toChecksumAddress("0xd8c897d27681bea0444474d9564f986d0ec864f1")).transact({'from': w3.eth.coinbase, 'gas': 672197}) tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)

 

We ran this script for the deployment and got the following result:

 

1) Connecting to the costaflores-node1 (http://10.112.48.25:8545) ... 2) Preparing contracts (IoT, Datastorage)... 3) Deploying contracts (IoT, Datastorage)... - Contract Datastorage.sol was deployed at address: 0xe87eFa27A14ABD7f8b3f281a0EeeD692562886b8 on transaction 0x366d013aac5a8cb9ce945b36916c1d8027b54ab3f281190c1605923adc115bed - Contract IoT.sol was deployed at address 0x866d841A567d1D486CbD7ab0CDeD04479500BF25 on transaction 0x1ebda6eec19dba44cb2de053c97ce2c3a2ff4ac3766203a12905a121b6509ae0 4) Initializing contracts (IoT, Datastorage)...


We can check with the result that the contracts were deployed correctly and that the blockchain storage structure is prepared to receive the data.

 

Now it's just a matter of connecting the blockchain to the raspberry  pi to receive the input and to OpenBravo to emit the output. To begin with the input we have the following information being collected in the weatherstion and the vinduinos (data structure):

 

Source

Type

Name

Extra description

Show on Dailylog Site

Source

Type

Name

Extra description

Show on Dailylog Site

Weather station

String

timestamp

PK

No

Vinduino

String

id_vinduino

PK

No

Vinduino

int

sensor2

 

Yes

Vinduino

int

sensor1

 

Yes

Vinduino

int

sensor05

 

Yes

Vinduino

int

sensor005

 

Yes

Vinduino

float

battery

 

No

Vinduino

float

temperature_local

 

No

Vinduino

float

humidity

Not connected

No

Weather station

float

rain

 

Yes

Weather station

float

wind speed

 

No

Weather station

float

wind gust

 

No

Weather station

float

wind direction

 

No

Weather station

float

pressure

Not working

No

Weather station

float

temperature_global

 

Yes

Weather station

float

humidity

 

Yes

 

We have developed the following script to run and gather all the information from the sensors and redirect it to the blockchain (remember that previously we've set up the Weather Station to write its data to a file in: *******):

 

import sys import json import serial import time import web3 from web3 import Web3, HTTPProvider from time import localtime, strftime from datetime import datetime print("\nSetting up enviroment for the Vinduinos") ser = serial.Serial('/dev/ttyACM0', 9600, timeout=900) print("Connecting to the node... (http://10.112.48.25:8545)") print("\n ================================================== \n") w3 = Web3(HTTPProvider("http://10.112.48.25:8545")) with open('contracts.json') as json_file: compiled_sol = json.load(json_file) IoT = w3.eth.contract(address = w3.toChecksumAddress("0x866d841A567d1D486CbD7ab0CDeD04479500BF25") , abi = compiled_sol['contracts']['contracts.sol:IoT']['abi'], ); with open('keystore/UTC--2018-03-28T17-48-45.929617976Z--ff317bb0c816c449d6b5bb5085d71561fcb94a37') as keyfile: encrypted_key = keyfile.read() private_key = w3.eth.account.decrypt(encrypted_key,'*********') while True: print("\n1) Reading from serial port"); line = ser.readline(); if len(line)==0: print("1.1) Error: Time out") sys.exit() line=line.decode("utf-8") splitted_line = line.split(",") start_char = splitted_line[0] write_key = splitted_line[1] sensor2 = int(float(splitted_line[2]) * 100) sensor1 = int(float(splitted_line[3]) * 100) sensor05 = int(float(splitted_line[4]) * 100) sensor005 = int(float(splitted_line[5]) * 100) battery = int(float(splitted_line[6]) * 100) temperature = int(float(splitted_line[7]) * 100) humidity = int(float(splitted_line[8]) * 100) timestamp = strftime("%d/%m/%y %H:%M:%S", localtime()) data = [sensor2, sensor1, sensor05, sensor005, battery, temperature, humidity] print("2) Line was read and preprocessed {" + str(write_key) + ", " + str(sensor2) + ", " + str(sensor1) + ", " + str(sensor05) + ", " + str(sensor005) + ", " + str(battery) + ", " + str(temperature) + ", " + str(humidity) + "} at " + timestamp + ".") if(write_key == "********"): write_key = "pe"; if(write_key == "********"): write_key = "cs" if(write_key == "********"): write_key = "me" if(write_key == "********"): write_key = "mo" print("3) Reading from weatherstation"); file = open("/home/pi/sensor-forwarder-python/weatherstation.txt", "r") line = file.readline() splitted_line = line.split(",") wind_speed = int(float(splitted_line[0]) * 100) wind_gust = int(float(splitted_line[1]) * 100) wind_direction = int(float(splitted_line[2]) * 100) pressure = int(float(splitted_line[3]) * 100) rain = int(float(splitted_line[4]) * 100) temperature = int(float(splitted_line[5]) * 100) humidity = int(float(splitted_line[6]) * 100) data.extend([wind_speed, wind_gust, wind_direction, pressure, rain, temperature, humidity]) print("4) Line was read and preprocessed: {" + str(wind_speed) + ", " + str(wind_gust) + ", " + str(wind_direction) + ", " + str(pressure) + ", " + str(rain) + ", " + str(temperature) + ", " + str(humidity) + "}") print("5) Redirecting data from vinduino and weather station " + (timestamp + "$" + str(write_key)) + " to blockchain.") reference = (timestamp + "$" + str(write_key)).encode('utf-8') nonce = w3.eth.getTransactionCount(w3.toChecksumAddress('0xff317bb0c816c449d6b5bb5085d71561fcb94a37')) tx = IoT.functions.post(reference, data).buildTransaction({'chainId': 42, 'gas': 7034534, 'gasPrice': w3.toWei('1','gwei'), 'nonce': nonce,}) signed_tx = w3.eth.account.signTransaction(tx, private_key = private_key) tx_hash = w3.eth.sendRawTransaction(signed_tx.rawTransaction) w3.eth.waitForTransactionReceipt(tx_hash) print("6) Transaction " + w3.toHex(tx_hash) + " sent to remote node at http://10.112.48.25:8545");


Once we have implemented this script we need to run it in the background by executing the following command in the raspberry pi.

 

 

With this command the script will start writing the gathered data to the blockchain and will write into sensors-1.log the logs of its state so that we can check what's happening.

If python3 is not installed in the raspberry run the following commands:

 

 

Now we have our sensors connected to blockchain. We can check that it is running and the information being collected by using:

 

Now we have to collect the event generated in the blockchain once data is written to redirect it to OpenBravo. To do so we have implemented another python script that's going to run on ECHO:

 

forwarder-openbravo.py

 

Once it is implemented again we just have to executing by using the following command:

 

Check that everything is working properly

 

From raspberry:

 

From ECHO:

 

From browser:

Ethereum Network Status: http://10.112.48.25:3000/

OpenBravo: http://10.112.48.22:80/

 

  • First observe raspberry pi console until a data arrives. When a data arrives, it will read the data from both the vinduino and the weatherstation and send the transaction waiting for the step (6 - confirmation of the tx).

    At this moment we can see in Ethereum Network Status how a new bar appears in the transaction graph. (appears when a block is mined)

    Once it appears we can check in the ECHO console that the data inserted by the raspberry was read and redirected to OpenBravo.

    Finally we look at the record and check that it has been inserted correctly in OpenBravo.