×

行业市场上最聪明的设备开源

消耗积分:0 | 格式:zip | 大小:0.10 MB | 2022-12-16

李猛

分享资料个

描述

行业市场是一个自主和分散的平台,供人和机器买卖服务、数据和商品。它将 IOTA Tangle 与标准化的机器可读合约和集成的去中心化身份系统相结合,使参与者能够投标、投标和支付服务费用。

要在 Industry Marketplace 中投标、投标或付款,买方(服务请求者)首先请求使用 eCl@ss 属性指定要求的商品或服务提案。该市场中的所有服务提供商都会收到提案征集,并且可以将提案发送给请求者,询问是否符合要求的价格。发送提案后,服务请求者接受或拒绝该提案。

服务提供商可以同时收到多个提案请求,但所有服务都不相同,其中一项服务可能比其他服务更有利可图。如果服务提供商可以确定最有利可图的服务,它可以获得更多收益。

在这个概念验证项目中,我将展示 Industry Marketplace 和 eCl@ss 如何帮助您的设备作为服务提供商找到最佳客户,以提供最有利可图的商品或服务。我将为我的项目使用开源行业市场服务应用程序和 Python 语言。

要与 Industry Marketplace 连接,服务应用程序(基于 nodejs 的服务器)应该在您的服务器或设备中运行。在这个项目中,我将使用 Raspberry Pi 来托管服务应用程序以及运行客户端程序。

主要工作在第 7 步。如果您有工业市场的工作设置,您可以直接转到第 7 步。

树莓派入门

我假设您以前有使用 raspberry pi、Putty 和 Python 的经验。如果没有,你应该在继续这个项目之前阅读一些入门教程。

第 1 步:选择正确版本的 Raspberry Pi 和操作系统

Industry Marketplace 的技术文档推荐使用 Raspberry Pi 3 B+ 或更高版本,但以我的知识有限,我无法在 Raspberry Pi 3 B+ 上成功运行漏洞应用程序。经过几个失败的步骤后,我成功地在 Raspberry Pi 4、4GB 版本和带有桌面操作系统的 Raspbian Buster 中正常工作。您可以从这里下载操作系统

第 2 步:将 Nodejs 和 Yarn 安装到 Pi

运行服务应用需要 Nodejs 10 或更高版本。要在您的 Pi 中安装 Nodejs 10,请在 Raspberry Pi 的终端中运行以下命令:

curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -
sudo apt-get install nodejs

验证节点是否已成功安装并使用node -v命令(在撰写本文时,我得到 10.20.0)。

Yarn 是一个新的 node.js 包管理器。它是 Facebook、Exponent、Google 和 Tilde 等公司开发的常见项目。Yarn 比 NPM 更稳定、更快。使用以下命令在 Pi 中安装 yarn。

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

运行yarn -v验证(截至今天的版本 1.22.4)

第 3 步:将 Industry Marketplace ServerApp 下载到 Raspberry Pi

要获取 Industry Marketplace Server App 的最新副本,请使用以下命令克隆 GitHub 存储库:

git clone https://github.com/iotaledger/industry-marketplace.git marketplace

此命令将下载市场目录中的行业市场应用程序。

poYBAGOYCDWAPB3xAABez3XQzKA577.png
 

使用以下命令检查目录中的文件:

cd marketplace
ls

您将获得目录中下载的所有文件的列表:

poYBAGOYCDmAEEkCAAArocZdhz4389.png
 

因此,服务应用程序已成功下载。我们的下一步是下载客户端应用程序。但在此之前,我们会尝试快速检查以确保到目前为止一切正常。

第 4 步:运行 ServiceApp 进行检查

转到 ServiceApp 目录并运行以下命令:

cd ServiceApp
yarn run dev

此命令将下载所有依赖项并运行服务应用服务器。

poYBAGOYCDuAbZ1kAABLdRW2rTE036.png
 

等待几分钟,直到您在终端上看到以下输出。

pYYBAGOabOyANlVSAADlHdKNKWk917.png
 

如果您的 Pi 连接到监视器,您会发现一个浏览器窗口自动打开并获得以下视图。

poYBAGOabO6AYQpjAACm_36KbAA946.png
 

如果 Raspberry Pi 未连接到监视器,您可以从同一网络的任何浏览器通过 Pi 的 ip 地址访问服务器。在浏览器选项卡中键入 ip_address:3000。您将从浏览器获得以下输出。

pYYBAGOabPGAdR-wAADC-hXvgyU206.png
 

如果你得到这个,那么恭喜你!!!到目前为止,一切都运行良好。在下一步中,我们将客户端应用程序连接到服务器。继续关注...

第 5 步:下载 Python-Helper 客户端库

使用以下命令将 python 客户端库克隆到名为 helper 的目录。如果需要,您可以更改目录名称。

git clone https://github.com/iota-community/industry-marketplace-python-helper.git helper

检查以下文件是否已下载。

pYYBAGOabPSAdKIkAABqdowpmMc105.png
 

为了运行 python 示例程序,我们将创建一个 Python3 虚拟环境。使用以下命令创建 Python3 虚拟环境并将其激活到 Pi 的主目录。

python3 -m venv ~/my_venv
source ~/my_venv/bin/activate

如果成功,您将看到结果

poYBAGOabPaASnFhAAAm7PDPw94228.png
 

使用 pip 使用以下命令安装所有 python 3 要求:

pip install -r requirements.txt

安装软件包时稍等片刻...

pYYBAGOabPiAb3VmAAEH_1cSANI012.png
 

完成运行后,service_requester 示例应用程序使用以下命令随客户端库一起提供...

poYBAGOabPuABXcHAAA4KnPkP5c000.png
 

您将获得与服务器应用程序的连接确认。但在此之前,请确保服务器应用程序正在另一个终端窗口中运行。

pYYBAGOabP2AT7xQAAC1-bD8Ktk355.png
 

连接到客户端后,您还将从服务应用程序窗口获得响应。

第 6 步:检查服务提供者和服务请求者交互

通过克隆 github repo 下载两个 Industry Marketplace Service App 副本。键入以下命令:

git clone --depth=1 https://github.com/iotaledger/industry-marketplace.git provider
git clone --depth=1 https://github.com/iotaledger/industry-marketplace.git requester

上述命令将应用程序的一份副本保存到提供者目录,将一份副本保存到请求者目录。现在我们将运行这两个应用程序。如果您想从同一设备运行这两个应用程序,则需要更改一个应用程序的端口号。让我们为提供者应用程序做这件事。从提供者目录运行以下命令:

git apply ../helper/patches/different_ports.patch

从两个不同的窗口转到目录并像在第 4 步中那样运行应用程序。

转到 helper 目录并从两个不同的窗口运行 service_requester.py 和 service_provider.py,就像在步骤 5 中所做的那样。

poYBAGOabP-APns_AAArQwmtFDc184.png
 
poYBAGOabQKAZcwOAAAoubvAXTE501.png
 

现在,从浏览器转到请求者并发出如下手动服务请求:

pYYBAGOabQSAEjecAABupOruACM150.png
 

从终端,您将收到带有 irdi 的“已收到提案消息”。

poYBAGOabQeASD4HAAA8wxlKJJY686.png
 

如果您现在从浏览器打开服务提供商选项卡,您将看到从请求者那里收到的建议。从这里您可以将奖品放入 IOTA 令牌并将请求发送给请求者。

pYYBAGOabQmAV-uSAABcwDBXTW0165.png
 

发送提案后,请求者和请求者将收到该提案,并接受或拒绝该提案。

poYBAGOabQyAXtLBAABjGkKkg04746.png
 

如果请求者接受或拒绝该提议,将通知服务提供商。

pYYBAGOabQ6AdetGAABoVqfK28w021.png
 

服务完成后,请求者可以继续付款。

poYBAGOabRGAGWL9AABn-EsWUhw298.png
 
pYYBAGOabROAOpb0AABiKX19kDQ707.png
 

整个过程将在付款完成后完成。

poYBAGOabRaAV0wRAABeirMaR3Q119.png
 

所有步骤和相关信息也可以从终端中观察到,如以下屏幕截图所示。

poYBAGOabRiAGwo3AAB7ayV2NRg385.png
 

web客户端和python程序都可以独立工作,互不依赖。但服务应用服务器必须正在运行。

pYYBAGOabRuAavy-AAByt-X7K6k149.png
 

到目前为止,我们只是检查了我们的工具,一切都准备好了。现在让我们使用这些工具并根据我们的要求制作一些东西。

7. 赋予您的设备魔力

当您成功执行所有前面的步骤时,您就可以展示您的创造力,现在您可以赋予您的设备超能力。在这一步中,我将向您展示如何使您的设备/机器能够从市场中选择合适的交易(最有利可图的服务请求)。

在工业市场中有两方(设备/机器)。一个充当服务请求者,即需要数据或服务的设备。另一方充当服务提供者。服务提供商可以具有提供多种服务的能力,但所有服务的利润可能并不相同。

pYYBAGOabR6AWNeuAAI3a9Mqz-g648.jpg
 

当服务提供商 (SP) 同时收到多个工作请求时,它应该选择最合适和最有利可图的请求来发送提案。因此,为了提供正确的服务,服务提供商应该能够正确理解所有 eCl@ss 属性,并且还应该知道如何计算要价和利润。为了正确读取服务的属性,使用 eCl@ss irdi。为了计算要价和利润,我只是使用一些随机方程。实际情况肯定比这更复杂。

为了读取某些特定服务的 eCl@ss 属性,我在行业市场 python helper github ripo提供的imp.py文件中添加了一些额外的方法

#######################################Added##########################################
    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

    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_total_weight(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'] == 'total weight (freight) [kg]'][0]
        except IndexError:
            return None

    def get_starting_point(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'] == 'starting point [lat, lng]'][0]
        except IndexError:
            return None

    def get_destination(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'] == 'destination [lat, lng]'][0]
        except IndexError:
            return None

    def get_number_of_photo(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'] == 'number of photos that can be stored'][0]
        except IndexError:
            return None

    def get_reliability_duration(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'] == 'reliability duration [min]'][0]
        except IndexError:
            return None

    def get_target_location(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'] == 'target location [lat, lng]'][0]
        except IndexError:
            return None

    def get_autonomous(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'] == 'autonomous'][0]
        except IndexError:
            return None

    def get_max_persons(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'] == 'max. number of persons'][0]
        except IndexError:
            return None

    def get_duration(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'] == 'duration[min]'][0]
        except IndexError:
            return None

    def get_max_valocity(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'] == 'maximum velocity at rated value [km/h]'][0]
        except IndexError:
            return None

    def get_max_radius(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'] == 'max. monitoring radius [m]'][0]
        except IndexError:
            return None

    def get_2_4_value(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'] == '2,4 GHz'][0]
        except IndexError:
            return None

    def get_5_value(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'] == '5 GHz'][0]
        except IndexError:
            return None

    def get_energy_consumption(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'] == 'energy consumption [kW/h]'][0]
        except IndexError:
            return None
    ####################################################################################################

现在,让我们来看看服务提供者-客户程序。这是您在设备上运行的主要程序,用于检查和响应提案征集。对于这个演示项目,我的主要目标是从多个服务请求中选择最有利可图的提案调用,并为最有利可图的请求发送提案。对于演示代码,我正在等待三个提案调用,然后再发送任何提案。等待也可以基于时间,例如,在发送提案之前,服务请求者将等待最多 5 分钟,并将从这 5 分钟内收到的所有呼叫中确定最佳呼叫。

在收到每个请求后,我正在检查我的设备是否能够提供维护请求中提到的所有属性的服务。如果它不符合任何标准,则忽略提案请求。如果它满足所有要求,那么提案数据将存储在一个文本文件中,将 irdi 设置为文件名。

然后,设备会考虑上述属性来计算服务的价格。它还计算服务的利润。在 irdi 之后,计算出的价格和利润存储在三个单独的列表中。

"""Reads the irdi attributes from the call for proposal and check the capability and calculate price."""
                starting_point = self.get_starting_point(irdi, submodels)
                destination = self.get_destination(irdi, submodels)
                total_weight = self.get_total_weight(irdi, submodels)
                """This portion is used to check the capability of providing service mentioned to the call for proposal
                and return if does not meet."""
                if total_weight>5:
                    return   #assuming it only can carry 5 Kg
                """This portion is used to write the received data and written to a text file with irdi number so 
                that it can be used when sending proposal."""
                with open(irdi + '.txt', 'w') as json_file:
                    json.dump(data, json_file)
                """After getting starting point and destination I am calculating distance and from that distance 
                and weight I am calculating the price just using a random equation. I also calculating the profit
                assuming 35% of the total price."""
                lat1 = starting_point.split(',')[0]
                lon1 = starting_point.split(',')[1]
                lat2 = destination.split(',')[0]
                lon2 = destination.split(',')[1]
                dlon = float(lon2) - float(lon1)
                dlat = float(lat2) - float(lat1)
                a = (sin(float(dlat) / 2)) ** 2 + cos(float(lat1)) * cos(float(lat2)) * (sin(float(dlon) / 2)) ** 2
                c = 2 * atan2(sqrt(a), sqrt(1 - a))
                distance = self.R * c
                price = distance * 1.2 + total_weight * 1.2
                self.log('price')
                self.log(price)
                profit = 0.35 * price
                self.irdi_list.append(irdi)
                self.price_list.append(price)
                self.profit_list.append(profit)

                print('Received proposal request to carry = %s Kg for %s Km, for irdi %s' % (
                    total_weight, distance, irdi))
                """Wait for three proposal requests before sending the proposal to determine most profitable one."""
                if len(self.irdi_list) >= 3:
                    self.sent_proposal()

在收到每个提案请求时,设备都会检查它收到的提案总数。如果是三个或三个以上,则从利润列表中确定最大利润的建议请求。

在确定有利可图的请求后,读取该请求的所有相关信息(irdi、价格、数据、子模型),并且设备将提案发送给该特定请求者。

def sent_proposal(self):
        """This function is used to identify the most profitable request for the multiple requesters
        and send the proposal to that request only."""
        index_max = self.profit_list.index(max(self.profit_list))
        proposed_irdi = self.irdi_list[index_max]
        proposed_price = int(self.price_list[index_max])
        with open(proposed_irdi + '.txt') as json_file:
            data = json.load(json_file)
            try:
                ret = self.proposal(data, price_in_iota = proposed_price)
            except Exception as e:
                self.log('Unable to send proposal', e)

            self.log('proposal sent! Requesting %si for this service' % self.proposed_price)

如果提议被服务请求者拒绝,则可以考虑下一个有利可图的请求,或者设备可以提供有利可图的折扣。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !