Currently, the modes of payment are credit cards, RFID tags, or membership apps. But all of the methods required user interaction. Can you imagine your devices can exchange data and service and can make the payment for the service automatically without bothering you? Yes, Industrial Marketplace & IOTA are going to make it possible!!!
The Industry Marketplace is a vendor and industry-neutral platform, automating the trading of physical and digital goods and services. Building on specifications developed by the Plattform Industrie 4.0 (Germany's central network for the advancement of digital transformation in manufacturing), it combines distributed ledger technology, immutable audit logs and standardized, machine-readable contracts to accelerate industrial automation and enable the "economy of things".
In this proof of the concept project, I will show how Industry Marketplace and eCl@ss can help your device to find and offer the best service according to you and your client's requirement, negotiate for a suitable price, and with the help of IOTA how your device can pay as service requester and receive payment as service provider digitally keeping it completely free from human guidance. I will use the open-source Industry Marketplace Service App and Python language for my project.
[Let me explain the whole thing in my words. Suppose you want to buy a product. So, you will go to the market to buy it. Another person who produces the product will also come to the market for selling the product. So, buyers and sellers meet one another in the market and negotiate to buy or sell a product. If they agreed with a price then the buyer pays the amount to the seller for the product. This is the real world case where we, the human do the thing.
If I compare the situation with the digital world, the different types of devices are buyers (service requester) and sellers (service provider) and Industry Marketplace is the digital market (a market for devices). Here data or service is the product and payments are made by IOTA token (digital money) instead of paper money or credit card.]
To connect with Industry Marketplace, the Service App (nodejs based server) should be running in your server or device. In this project, I will use Raspberry Pi to host the service app as well as to run the client program.
Getting Started with Raspberry PiI am assuming you have some previous experience of working with raspberry pi, Putty, and Python. If not, you should read some getting started tutorial before further proceeding this project.
Step 1: Choosing the right version of Raspberry Pi and OSThe technical documentation of Industry Marketplace recommends Raspberry Pi 3 B+ or higher but with my limited knowledge, I could not run the hole apps successfully on Raspberry Pi 3 B+. After several fail steps, I succeeded to get everything worked in Raspberry Pi 4, 4GB version with Raspbian Buster with desktop OS. You can download the OS from here.
Step 2: Installing Nodejs and Yarn to the PiFor running the service app Nodejs 10 or higher is required. To install Nodejs 10 in your Pi run the following commands in the terminal of Raspberry Pi :
curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -
sudo apt-get install nodejs
Verify the node is successfully installed and working with node -v command (as of this writing, I get 10.20.0).
Yarn is a new package manager for node.js. It is a common project developed by such companies as Facebook, Exponent, Google, and Tilde. Yarn is more stable and faster than NPM. Use the following commands to install yarn in Pi.
Install the Yarn dependency manager, which we’ll use to run our app:
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
Run yarn -v to verify (Version 1.22.4 as of today)
Step 3: Downloading Industry Marketplace ServerApp to Raspberry PiTo get the latest copy of Industry Marketplace Server App clone the GitHub repo using the following command:
git clone https://github.com/iotaledger/industry-marketplace.git marketplace
This command will download the Industry Marketplace App inside marketplace directory.
Check the files in directory using:
cd marketplace
ls
You will get the list of all files in downloaded in the directory:
So, the service app is successfully downloaded. Our next step is to download the client application. But before that we to try a quick check to sure that so far everything is working.
Step 4: Run the ServiceApp for a checkGo to ServiceApp directory and run the command:
cd ServiceApp
yarn run dev
This command will download all the dependencies and run the service app server.
Wait for a couple of minutes until you see the following output on the terminal.
If your Pi is connected to a monitor you will find a browser window automatically opened and get the following view.
If Raspberry Pi is not connected to a monitor you can access the server through the ip address of the Pi from any browser from the same network. In the browser tab type ip_address:3000. You will get the following output from the browser.
If you get this then a big Congratualtion!!! So far everything is working perfectly. In the next step we will connect the client app to the server. Keep following...
Step 5: Downloading Python-Helper Client LibraryClone the python client library to a directory named helper using the following command. You can change the directory name if you want.
git clone https://github.com/iota-community/industry-marketplace-python-helper.git helper
Check the following files are downloaded.
To run the python sample program we will create a Python3 virtual environment. Use the following commands to create and activate a Python3 virtual environment to the home directory of your Pi.
python3 -m venv ~/my_venv
source ~/my_venv/bin/activate
If successful you will see the result
Using pip install all the python 3 requirements with the following commands:
pip install -r requirements.txt
Wait for a moment while installing the packages...
When completed run the service_requester sample app came with the client library using the command below...
You will get the connection confirmation with the server app. But before that be sure server app is running in another terminal window.
You will also get a response from the service app window after connecting to the client.
Step 6: Checking Service Provider & Service Requester interactionDownload two copy of Industry Marketplace Service App by cloning github repo. Type the following commands:
git clone --depth=1 https://github.com/iotaledger/industry-marketplace.git provider
git clone --depth=1 https://github.com/iotaledger/industry-marketplace.git requester
The above commands save one copy of the app to provider directory and one copy to requester directory. Now we will run both the app. If you like to run both apps from the same device you need to change the port number for one app. Let's do it for the provider app. Run the following command from provider directory:
git apply ../helper/patches/different_ports.patch
Go to the directories from two different windows and run the app as you did in Step 4.
Go to helper directory and run service_requester.py and service_provider.py from two different windows as you did in step 5.
Now, go to the requester from the browser and make a manual service request like this:
From the terminal you will get "received call for proposal message" with the irdi.
If you now open the service provider tab from the browser you will see a proposal received from the requester. From here you can put a prise in IOTA token and send the request to the requester.
After sending the proposal the proposal will be received by the requester and the requester and either accept or reject the proposal.
The service provider will be informed if the requester accepts or rejects the proposal.
On fulfillment of the service, the requester can proceed with the payment.
The whole process will be completed by the completion of the payment.
All the steps and the related information can also be observed from the terminal as shown in the following screenshots.
Both the web client and the python program can work independently and do not depend on one another. But the service app server must be running.
So far we just check our tools and all are ready. Now let us use the tools and make something as our requirement.
Step 7: Making our own service provider and requester client as our requirementsIn this proof of concept project, I will use "Cell Tower Rent" service offered by Industry Marketplace for the demonstration. Here I will show how we can modify or develop our own client program to fulfill our own requirement. I will show both service provider case and service requester case in my demo and I am using Raspberry Pi for running the client program. I will use two different Raspberry Pi one as a service provider and another as service requester.
Let's start with the Industry Marketplace abstract class provided with the python helper library. Before going to that let's see the IRDI's and Attributes from the eCl@ss whitelist Industry Marketplace support for Cell Tower Rent.
"0173-1#01-BAF575#004": {
"submodelElements":[
{
"idShort":"range [km]",
"modelType":"Property",
"value":"",
"valueType":"decimal",
"semanticId":"0173-1#02-AAI957#004"
},
{
"idShort":"frequency [MHz]",
"modelType":"Property",
"value":"",
"valueType":"double",
"semanticId":"0173-1#07-AAL034#004"
},
{
"idShort":"energy consumption [kWh]",
"modelType":"Property",
"value":"",
"valueType":"decimal",
"semanticId":"0173-1#02-AAF090#005"
},
{
"idShort":"location [lat, lng]",
"modelType":"Property",
"value":"",
"valueType":"string",
"semanticId":"0173-1#02-BAF163#002"
},
{
"idShort":"price",
"modelType":"Property",
"value":"",
"valueType":"integer",
"semanticId":"0173-1#02-AAO739#001"
}
]
}
So, from the above json it is found that cell tower rent service has 5 attributes and each service provider and service requester should speak to each other using these attributes for the service.
In industry Marketplace service requester is the initiator and first sent a request for a proposal (call for proposal message) in the marketplace. For requesting a proposal service requester must mention the value of each property without price using the semanticId (irid). The format of the value will be as follows.
values = { # cell tower rent service
'0173-1#02-AAI957#004': 2, # range [km], decimal
'0173-1#07-AAL034#004': 10, # frequency [MHz], double
'0173-1#02-AAF090#005': 3, # energy consumption [kWh], decimal
'0173-1#02-BAF163#002': '54.4321, 4.5210', # location [lat, lng], string
}
After requesting for proposal all service providers of that marketplace will see that request. Every service provider must understand the properties before sending a proposal. This understanding is required either to know if it is capable to provide the mentioned service and also for providing the correct price for the service. So, for reading these four properties I added four methods in the abstract class (actually three because get_price was already there).
def get_price(self, irdi, submodels):
'''
Get the price for a irdi from the submodels
'''
try:
return [x['value'] for x in submodels.values() if x['idShort'] == 'price'][0]
except IndexError:
return None
######################################Added######################################
def get_location(self, irdi, submodels):
'''
Get the service location for a irdi from the submodels
'''
try:
return [x['value'] for x in submodels.values() if x['idShort'] == 'location [lat, lng]'][0]
except IndexError:
return None
def get_range(self, irdi, submodels):
'''
Get the cell tower range for a irdi from the submodels
'''
try:
return [x['value'] for x in submodels.values() if x['idShort'] == 'range [km]'][0]
except IndexError:
return None
def get_frequency(self, irdi, submodels):
'''
Get the cell tower frequency for a irdi from the submodels
'''
try:
return [x['value'] for x in submodels.values() if x['idShort'] == 'frequency [MHz]'][0]
except IndexError:
return None
def get_energy_consumption(self, irdi, submodels):
'''
Get the energy consumption of BTS for a irdi from the submodels
'''
try:
return [x['value'] for x in submodels.values() if x['idShort'] == 'energy consumption [kWh]'][0]
except IndexError:
return None
##################################################################################
The get_price method will be used by service requester and others will be called by the service provider to get the requested value for every attribute.
In the code for the service provider, these methods are used as follows:
location = self.get_location(irdi, submodels)
cell_range = self.get_range(irdi, submodels)
frequency = self.get_frequency(irdi, submodels)
energy_consumption = self.get_energy_consumption(irdi, submodels)
The attributes values are stored in four variables. Base on the values service provider will decide either it is capable to provide the requested service and set a price if capable.
if cell_range <= 1 and frequency <= 1000 and energy_consumption <= 2:
self.proposed_price = 20
elif cell_range <= 2 and frequency <= 1000 and energy_consumption <= 2:
self.proposed_price = 25
elif cell_range <= 3 and frequency <= 1000 and energy_consumption <= 4:
self.proposed_price = 30
elif cell_range <= 6 and frequency <= 1000 and energy_consumption <= 6:
self.proposed_price = 35
elif cell_range > 6 and frequency <= 1000 and energy_consumption > 6:
self.proposed_price = 40
elif cell_range <= 4 and frequency <= 3000 and energy_consumption <= 2:
self.proposed_price = 27
elif cell_range <= 4 and frequency <= 3000 and energy_consumption <= 4:
self.proposed_price = 33
elif cell_range <= 2 and frequency <= 3000 and energy_consumption <= 4:
self.proposed_price = 38
elif cell_range > 4 and frequency <= 3000 and energy_consumption > 4:
self.proposed_price = 43
else:
self.proposed_price = 50
In
our use case suppose the service provider rents the cell tower. In this case, the price may vary based on cell range, frequency and energy_consumption. The above code snippet shows how based on different eCl@ss property the price range can be set. Using this price service provider now sends the proposal.
After sending the proposal service requester automatically receive the proposal with the quoted price. Service requester now can read the price from the submodel and can take decesion either it will accept the proposal for the called price or not. If it thinks the price is not justified for the requested service it can reject the proposal.
def on_proposal(self, data, irdi, submodels):
'''
Accept only for cell tower rent request
'''
self.log('on proposal called!')
try:
price = self.get_price(irdi, submodels)
self.log('Received proposal for %si for irdi %s' % (price, irdi))
if not price:
self.log('Price not found, submodels: %s' % submodels)
if price <= 50:
self.log('Accepting proposal')
self.accept_proposal(data)
else:
self.log('Rejecting proposal')
self.reject_proposal(data)
except Exception as e:
self.log('Error on accepting: %s' % e)
The following code snippet helps to read the price from the proposal submodel and make a decision about accepting or rejecting the proposal based on the price. The on_proposal() method automatically called on the proposal received from the service provider.
If the service requester accepts the proposal on_accept_proposal() method is called automatically which is implemented in the service_provider program.
def on_accept_proposal(self, data, irdi, submodels):
self.log('Proposal accepted! Start fulfilling')
self.log('Sending inform confirm')
ret = self.inform_confirm(data)
# self.log(ret)
If the proposal is rejected then on_reject_proposal() method is called automatically. The service provider can stop here or it can send a new proposal reducing the prince. In the following code snippet, 20% discount is offered until it crosses the marginal price for the service.
def on_reject_proposal(self, data, irdi, submodels):
self.log('Proposal rejected!')
price = self.get_price(irdi, submodels)
marginal_price = 0.8*self.proposed_price
if price > marginal_price:
try:
ret = self.proposal(data, price_in_iota=price * 0.8)
self.log('20% Discount is offered!')
except Exception as e:
self.log('Unable to send proposal', e)
else:
self.log('Proposal rejected even after 20% discount!')
If the requester accept the proposal the service provider sent the confirmation message and agreed to provide the service. After getting confirmation requester makes the payment and the service provider receive the payment confirmation automatically. Within a few minutes required IOTA token for the service is transferred from the requester's wallet to the service provider's wallet.
Watch the demo video:
Comments