Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagepy
titlePython code for starting the delivery and sending the measurements
collapsetrue
import json
from dotenv import load_dotenv
from security2go import Security2GoSigner
from web3.auto import w3
from web3_utils import sign_and_send_transaction
from eth_account import Account
from altimu import Altimu
import time
import os

class EnvironmentManager:
    def __init__(self):
        load_dotenv()

    def getenv_or_raise(self, key):
        value = os.getenv(key)
        if value is None:
            raise Exception(f'{key} variable not found in the env')
        return value

class ContractManager:

    def __init__(self, w3, envman):
        with open('abi.json') as f:
            abi = json.load(f)
            contract_address = env_manager.getenv_or_raise('CONTRACT_ADDRESS')
            self.contract = w3.eth.contract(address=contract_address, abi=abi)

    def get_contract(self):
        return self.contract

    def get_start_delivery(self):
        return self.contract.get_function_by_name('start_delivery')

    def get_contractor(self):
        contractor_func = self.contract.get_function_by_name('contractor')
        return contractor_func().call()
    
    def get_final_payment(self):
        payment_func = self.contract.get_function_by_name('final_payment')
        return payment_func().call()
    
    def has_ended(self):
        ended_func = self.contract.get_function_by_name('ended')
        return ended_func().call()

    def get_store_measurements(self):
        return self.contract.get_function_by_name('store_measurements')

    def start_delivery(self, signer, w3):
        start_func = self.get_start_delivery()
        tx = signer.sign_send_and_wait(start_func, w3)
        print("Delivery started, hash:", tx)

    def store_measurements(self, value, time, signer, w3):
        store_func = self.get_store_measurements()
        tx = signer.sign_send_and_wait(store_func, w3, value, time)
        print("Delivery started, hash:", tx)
    
class Signer:

    def __init__(self, key_id=1):
        self.signer = Security2GoSigner(key_id=1)
        self.address = self.signer.get_address()

    def sign_send_and_wait(self, func, w3, value=None, time=None):
        nonce = w3.eth.getTransactionCount(self.address)
        if(value is None):
            raw_tx = func().buildTransaction({'nonce': nonce, 'gasPrice': 0, 'gas': 210000, 'from': self.address})
        else:
            raw_tx = func(value, time).buildTransaction({'nonce': nonce, 'gasPrice': 0, 'gas': 210000, 'from': self.address})
        tx = sign_and_send_transaction(w3, self.signer, self.address, raw_tx, nonce)
        w3.eth.waitForTransactionReceipt(tx)
        return tx

env_manager = EnvironmentManager()
signer = Signer()

if not w3.isConnected():
    raise Exception(f'web3 connection failed')

alt = Altimu()
alt.configure()

contract_manager = ContractManager(w3, env_manager)

while contract_manager.get_contractor() == '0x0000000000000000000000000000000000000000':
    print("Waiting for a contractor to accept the conditions")
    time.sleep(10.0)

contract_manager.start_delivery(signer, w3)

while not contract_manager.has_ended():
    now = int(time.time())
    x = int(alt.read_temperature()*1000)
    print("Temperature:", x, "Time:", now)
    contract_manager.store_measurements(x, now, signer, w3)
    time.sleep(10.0)

print("The delivery has ended, final payment:", contract_manager.get_final_payment())
alt.close_connection()

Note that we have added a new field in the file with the environmental variable: CONTRACT_ADDRESS in .env file, which is the address where the contract is deployed. We have to create also a new file “abi.json” containing the Application Binary Interface (ABI) of our contract (which we can copy from Remix).

Once the contract is deployed on our Besu network, the program can be started. First, it waits until a contractor accepts the delivery conditions. When it's done, it starts the delivery (requiring use of the smart card) and continuously sends the subsequent temperature measurements to the contract. Once the contract is finished (which happens outside the program), we’ll not be able to send the measurements anymore, and an exception will be firedthe final payment will be shown along with the information about the fact that delivery has ended. This gives us the possibility to close the I2C connection with the sensing module. Once the transaction is finished, we are able to check the final payment calculated for the contractor (and the contractor is able to do it as well).

Summary

We have shown a full stack that can be useful while integrating enterprise blockchain solutions, based on the Hyperledger Besu, with IoT devices. To add some flavor to our development, we have also shown a smart contract designed and developed for a specific use case, where, in turn, we’ve injected measurements from temperature sensors. We have also included a smart card to sign the transactions to be sure that only authorized persons could trigger some functionality of the smart contract. Nevertheless, it was a very concrete use case, and it was only the tip of the iceberg. There’s much more, and the possibilities are endless. We hope that this tutorial will give you the thrill to build your own blockchain application.

...

Page properties
hiddentrue


Related issues