邊緣計算開源框架EdgeXFoundry的部署應用開發
EdgeXFoundry的部署應用開發
EdgeX 歷史記錄和命名
EdgeXFoundry最初是戴爾物聯網營銷部特許的專案,由 CTO 戴爾客戶辦公室開發,於 2015 年 7 月作為名為"Fuse專案"的孵化專案開發。它最初建立為在戴爾的物聯網閘道器介紹行上作為 IoT 軟體應用程式執行。2017 年 4 月 24 日,戴爾通過 Linux 基金會將該專案引入開源。EdgeX 在 2017 年漢諾威展上正式宣佈並展示。漢諾威博覽會是世界上最大的工業貿易展覽會之一。在展會上,Linux基金會還宣佈了由50個創始成員組織(EdgeX生態系統)組成的協會,以幫助推進該專案和建立通用邊緣平臺的目標。
功能及流程簡介
EdgeX 的工作原理
說明中的一些名詞定義:
北向通訊(一般指上報資料)
南向通訊(一般指下發命令或者資料)
感測器資料收集
EdgeX 的主要工作是從感測器和裝置收集資料,使這些資料可供北端應用程式和系統使用。資料由表示該裝置協議的裝置服務從感測器收集資料。示例:Modbus 裝置服務將在 Modbus 中進行通訊,以便從 Modbus 泵裝置獲得壓力讀數。裝置服務將感測器資料轉換為 EdgeX 事件物件,並將事件物件通過 REST 通訊(步驟 1)傳送到核心資料服務。
核心資料將感測器資料保留在本地邊緣資料庫中。預設情況下,Redis 用作資料庫(其他資料庫可以替代使用)。事實上,永續性是不需要的,可以關閉。資料保留在邊緣的 EdgeX 中,原因有兩個:
- 邊緣節點並不總是連線。在斷開連線操作期間,必須儲存感測器資料,以便恢復連線時可以向北傳輸。這稱為儲存和轉發功能。
- 在某些情況下,感測器資料分析需要回顧歷史,以便了解趨勢,並基於該歷史記錄做出正確的決策。如果感測器報告現在溫度為 72° F,則在決定調整加熱或冷卻系統之前,您可能想知道 10 分鐘前的溫度是多少。如果溫度為 85° F,您可以決定調整以降低您十分鐘前的室溫足以冷卻房間。歷史資料的上下文對本地分析決策非常重要。
核心資料將感測器資料事件放在面向應用程式服務的訊息主題上。預設情況下,ZeroMQ 用作訊息傳遞基礎結構(步驟 2)。
應用程式服務根據需要轉換資料,並將資料推送到終結點。它還可以在將事件傳送到終結點之前對事件進行篩選、豐富、壓縮、加密或執行其他功能(步驟 3)。終結點可能是 HTTP/S 終結點、MQTT 主題、雲系統(雲主題)等。
邊緣分析和驅動
在邊緣計算中,簡單地收集感測器資料只是 EdgeX 等邊緣平臺工作的一部分。邊緣平臺的另一個重要工作是能夠:
- 本地分析傳入感測器資料
- 快速執行該分析邊緣或本地分析是執行對在邊緣收集的感測器資料(“本地”)進行評估並基於其看到內容觸發驅動或操作的處理。
Why edge analytics? Local analytics are important for two reasons:
- 某些決策無法等待感測器收集的資料反饋給企業或雲系統並返回響應。
- 此外,某些邊緣系統並不總是連線到企業或雲 - 它們具有間歇性的連線期。
本地分析允許系統獨立執行,至少在某些時間上是這樣。例如:當船舶在海上時,運輸集裝箱的冷卻系統必須能夠在本地做出決策,而無需長時間使用網際網路連線。本地分析還允許系統在系統操作關鍵時以低潛在方式快速行動。作為一個極端的情況,想象一下,你的車的安全氣囊發射的基礎上的資料被髮送到雲和分析碰撞。您的汽車有本地分析,以防止這種潛在的緩慢和容易出錯交付在您的汽車的安全驅動。
EdgeX 的構建是為了對從邊緣收集的資料進行本地操作。換句話說,事件由本地分析處理,可用於觸發感測器/裝置上的回工作。
正如應用程式服務準備資料供北端雲系統或應用程式使用一樣,應用程式服務可以處理和獲取 EdgeX 事件(及其包含的感測器資料)到任何分析包(參見步驟 4)。預設情況下,EdgeX 附帶一個簡單的規則引擎(預設 EdgeX 規則引擎是Kuiper - EMQ X 的開源規則引擎)。您自己的分析包(或 ML 代理)可以替換或增強本地規則引擎。
分析包可以探索感測器事件資料,並決定觸發裝置的驅動。例如,它可以檢查發動機的壓力讀數是否大於 60 PSI。當確定此規則為 true 時,分析包呼叫核心命令服務以觸發某些操作,例如在某些可控制的裝置上"開啟閥門"(參見步驟 5)。
核心命令服務獲取驅動請求,並確定它需要對哪個裝置執行該請求;然後呼叫擁有的裝置服務來執行啟用(請參閱步驟 6)。Core 命令允許開發人員在啟用之前設定其他安全措施或檢查。
裝置服務接收啟用請求,將其轉換為特定於協議的請求,並將請求轉發到所需的裝置(請參閱步驟 7)。
前提條件
需掌握的技術
- docker及docker-compose知道常用命令,瞭解Dockerfile的格式含義,知道docker-compose.yml格式含義
- Go瞭解編譯執行常用命令,如果跨平臺需要自己編譯原始碼
- 熟練使用一門語言C或者Go,方能基於SDK進行裝置服務的開發、跨平臺開發
- 瞭解相關主流通訊協議:modbus、mqtt,當然自定義亦可
- 非主要:熟悉git版本管理工具的使用
- 非必須:熟悉cmake、跨平臺ide工具
必須的軟體
cmake curl安裝
sudo apt update
sudo apt install cmake curl -y
docker安裝
IDE VScode的安裝
去VScode官網下載對應平臺的包安裝即可
我這裡使用Linux Mint發行版
下載xxx.deb包
sudo dpkg -i xxx.deb
部署框架
建個目錄EdgeXFoundry,在此執行部署的命令
mkdir EdgeXFoundry && cd EdgeXFoundry
- 在x86平臺部署
curl https://raw.githubusercontent.com/edgexfoundry/developer-scripts/master/releases/geneva/compose-files/docker-compose-geneva-redis-no-secty.yml -o docker-compose.yml; docker-compose up
- 在ARM64平臺部署
curl https://raw.githubusercontent.com/edgexfoundry/developer-scripts/master/releases/geneva/compose-files/docker-compose-geneva-redis-no-secty-arm64.yml -o docker-compose.yml; docker-compose up
驗證是否啟動
docker-compose ps
在目錄下有yaml的檔案,裡面官方預設遮蔽了虛擬的隨機數裝置服務,可以解除遮蔽自己去執行它,官網有相關教程步驟,這裡不多做介紹。
這裡給出一份帶ui控制檯的docker-compose.yml檔案
UI專案地址
UI使用介紹視訊:優酷、youtube
# /*******************************************************************************
# * Copyright 2020 Redis Labs Inc.
# * Copyright 2020 Intel Corporation.
# *
# * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# * in compliance with the License. You may obtain a copy of the License at
# *
# * http://www.apache.org/licenses/LICENSE-2.0
# *
# * Unless required by applicable law or agreed to in writing, software distributed under the License
# * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# * or implied. See the License for the specific language governing permissions and limitations under
# * the License.
# *
# * @author: Jim White, Dell
# * @author: Andre Srinivasan, Redis Labs
# * @author: Leonard Goodell, Intel
# * EdgeX Foundry, Geneva, version 1.2.0
# * added: May 14, 2020
# *******************************************************************************/
# NOTE: this Docker Compose file does not contain the security services - namely the API Gateway
# and Secret Store
version: '3.4'
# all common shared environment variables defined here:
x-common-env-variables: &common-variables
EDGEX_SECURITY_SECRET_STORE: "false"
Registry_Host: edgex-core-consul
Clients_CoreData_Host: edgex-core-data
Clients_Data_Host: edgex-core-data # For device Services
Clients_Notifications_Host: edgex-support-notifications
Clients_Metadata_Host: edgex-core-metadata
Clients_Command_Host: edgex-core-command
Clients_Scheduler_Host: edgex-support-scheduler
Clients_RulesEngine_Host: edgex-kuiper
Clients_VirtualDevice_Host: edgex-device-virtual
Databases_Primary_Host: edgex-redis
# Required in case old configuration from previous release used.
# Change to "true" if re-enabling logging service for remote logging
Logging_EnableRemote: "false"
# Clients_Logging_Host: edgex-support-logging # un-comment if re-enabling logging service for remote logging
volumes:
db-data:
log-data:
consul-config:
consul-data:
services:
consul:
image: edgexfoundry/docker-edgex-consul:1.2.0
ports:
- "127.0.0.1:8400:8400"
- "127.0.0.1:8500:8500"
container_name: edgex-core-consul
hostname: edgex-core-consul
networks:
- edgex-network
volumes:
- consul-config:/consul/config:z
- consul-data:/consul/data:z
environment:
- EDGEX_DB=redis
- EDGEX_SECURE=false
redis:
image: redis:5.0.8-alpine
ports:
- "127.0.0.1:6379:6379"
container_name: edgex-redis
hostname: edgex-redis
networks:
- edgex-network
environment:
<<: *common-variables
volumes:
- db-data:/data:z
# The logging service has been deprecated in Geneva release and will be removed in the Hanoi release.
# All services are configure to send logging to STDOUT, i.e. not remote which requires this logging service
# If you still must use remote logging, un-comment the block below, all the related depends that have been commented out
# and the related global override that are commented out at the top.
#
# logging:
# image: edgexfoundry/docker-support-logging-go:1.2.1
# ports:
# - "127.0.0.1:48061:48061"
# container_name: edgex-support-logging
# hostname: edgex-support-logging
# networks:
# - edgex-network
# environment:
# <<: *common-variables
# Service_Host: edgex-support-logging
# Writable_Persistence: file
# Databases_Primary_Type: file
# Logging_EnableRemote: "false"
# depends_on:
# - consul
system:
image: edgexfoundry/docker-sys-mgmt-agent-go:1.2.1
ports:
- "127.0.0.1:48090:48090"
container_name: edgex-sys-mgmt-agent
hostname: edgex-sys-mgmt-agent
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-sys-mgmt-agent
ExecutorPath: /sys-mgmt-executor
MetricsMechanism: executor
volumes:
- /var/run/docker.sock:/var/run/docker.sock:z
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- scheduler
- notifications
- metadata
- data
- command
notifications:
image: edgexfoundry/docker-support-notifications-go:1.2.1
ports:
- "127.0.0.1:48060:48060"
container_name: edgex-support-notifications
hostname: edgex-support-notifications
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-support-notifications
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- redis
metadata:
image: edgexfoundry/docker-core-metadata-go:1.2.1
ports:
- "127.0.0.1:48081:48081"
container_name: edgex-core-metadata
hostname: edgex-core-metadata
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-core-metadata
Service_Timeout: "20000"
Notifications_Sender: edgex-core-metadata
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- redis
- notifications
data:
image: edgexfoundry/docker-core-data-go:1.2.1
ports:
- "127.0.0.1:48080:48080"
- "127.0.0.1:5563:5563"
container_name: edgex-core-data
hostname: edgex-core-data
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-core-data
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- redis
- metadata
command:
image: edgexfoundry/docker-core-command-go:1.2.1
ports:
- "127.0.0.1:48082:48082"
container_name: edgex-core-command
hostname: edgex-core-command
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-core-command
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- redis
- metadata
scheduler:
image: edgexfoundry/docker-support-scheduler-go:1.2.1
ports:
- "127.0.0.1:48085:48085"
container_name: edgex-support-scheduler
hostname: edgex-support-scheduler
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-support-scheduler
IntervalActions_ScrubPushed_Host: edgex-core-data
IntervalActions_ScrubAged_Host: edgex-core-data
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- redis
app-service-rules:
image: edgexfoundry/docker-app-service-configurable:1.2.0
ports:
- "127.0.0.1:48100:48100"
container_name: edgex-app-service-configurable-rules
hostname: edgex-app-service-configurable-rules
networks:
- edgex-network
environment:
<<: *common-variables
edgex_profile: rules-engine
Service_Host: edgex-app-service-configurable-rules
Service_Port: 48100
MessageBus_SubscribeHost_Host: edgex-core-data
Binding_PublishTopic: events
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- data
rulesengine:
image: emqx/kuiper:0.4.2-alpine
ports:
- "127.0.0.1:48075:48075"
- "127.0.0.1:20498:20498"
container_name: edgex-kuiper
hostname: edgex-kuiper
networks:
- edgex-network
environment:
# KUIPER_DEBUG: "true"
KUIPER_CONSOLE_LOG: "true"
KUIPER_REST_PORT: 48075
EDGEX_SERVER: edgex-app-service-configurable-rules
EDGEX_SERVICE_SERVER: http://edgex-core-data:48080
EDGEX_TOPIC: events
EDGEX_PROTOCOL: tcp
EDGEX_PORT: 5566
depends_on:
- app-service-rules
ui:
image: edgexfoundry/docker-edgex-ui-go:1.2.1
ports:
- "127.0.0.1:4000:4000"
container_name: edgex-ui-go
hostname: edgex-ui-go
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-ui-go
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- scheduler
- notifications
- metadata
- data
- command
# Support RulesEngine has been deprecated in the Geneva (1.2.0) release
# If still required, simply uncomment the block below and comment out the block above.
#
# rulesengine:
# image: edgexfoundry/docker-support-rulesengine:1.2.1
# ports:
# - "127.0.0.1:48075:48075"
# container_name: edgex-support-rulesengine
# hostname: edgex-support-rulesengine
# networks:
# - edgex-network
# depends_on:
# - app-service-rules
#################################################################
# Device Services
#################################################################
device-virtual:
image: edgexfoundry/docker-device-virtual-go:1.2.2
ports:
- "127.0.0.1:49990:49990"
container_name: edgex-device-virtual
hostname: edgex-device-virtual
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-device-virtual
depends_on:
- consul
# - logging # uncomment if re-enabled remote logging
- data
- metadata
device-rest:
image: edgexfoundry/docker-device-rest-go:1.1.1
ports:
- "127.0.0.1:49986:49986"
container_name: edgex-device-rest
hostname: edgex-device-rest
networks:
- edgex-network
environment:
<<: *common-variables
Service_Host: edgex-device-rest
depends_on:
- data
- command
# - logging # uncomment if re-enabled remote logging
# device-random:
# image: edgexfoundry/docker-device-random-go:1.2.1
# ports:
# - "127.0.0.1:49988:49988"
# container_name: edgex-device-random
# hostname: edgex-device-random
# networks:
# - edgex-network
# environment:
# <<: *common-variables
# Service_Host: edgex-device-random
# depends_on:
# - data
# - command
# device-mqtt:
# image: edgexfoundry/docker-device-mqtt-go:1.2.1
# ports:
# - "127.0.0.1:49982:49982"
# container_name: edgex-device-mqtt
# hostname: edgex-device-mqtt
# networks:
# - edgex-network
# environment:
# <<: *common-variables
# Service_Host: edgex-device-mqtt
# depends_on:
# - data
# - command
#
# device-modbus:
# image: edgexfoundry/docker-device-modbus-go:1.2.1
# ports:
# - "127.0.0.1:49991:49991"
# container_name: edgex-device-modbus
# hostname: edgex-device-modbus
# networks:
# - edgex-network
# environment:
# <<: *common-variables
# Service_Host: edgex-device-modbus
# depends_on:
# - data
# - command
#
# device-snmp:
# image: edgexfoundry/docker-device-snmp-go:1.2.1
# ports:
# - "127.0.0.1:49993:49993"
# container_name: edgex-device-snmp
# hostname: edgex-device-snmp
# networks:
# - edgex-network
# environment:
# <<: *common-variables
# Service_Host: edgex-device-snmp
# depends_on:
# - data
# - command
networks:
edgex-network:
driver: "bridge"
Consul訪問地址:http://localhost:8500/ui
UI控制檯訪問地址:http://localhost:4000
裝置接入服務開發
登入看了下阿里雲的邊緣計算,驅動都有市場了,商機無限,相對於EdgeXFoundry的開發,簡直傻瓜式部署應用邊緣計算框架——一時感慨
安裝必須的庫檔案
sudo apt-get install libcurl4-openssl-dev libmicrohttpd-dev libyaml-dev libcbor-dev
需執行在其他平臺的,需要自行編譯對應平臺的庫
看下官網對版本的要求:
- A version of GCC supporting C11.
- CMake version 3 or greater and make.
- Development libraries and headers for:
- curl (version 7.32 or later)
- microhttpd (version 0.9)
- libyaml (version 0.1.6 or later)
- libcbor (version 0.5)
- libuuid (from util-linux v2.x)
獲取官方的SDK
這裡使用C
#指定分支版本
git clone -b 1.2.2 https://github.com/edgexfoundry/device-sdk-c.git
#或者直接下載最新版
git clone https://github.com/edgexfoundry/device-sdk-c.git
編譯SDK
進入原始碼目錄,直接make
cd device-sdk-c
make
順利無誤的情況下將得到x86_64平臺的sdk庫檔案(release目錄下
),這可能不是我們目標所需平臺,先進行測試可用。
生成的xx.deb不建議使用,開發的裝置服務一般情況下是非x86平臺,更多可能是ARM64、ARMHF、AARCH64等架構的平臺,安裝沒啥用。
SDK的使用測試
在原始碼目錄下src/c/example下有模板檔案template.c
- 按照官方說明,sdk提供了一些介面完善這些介面,即可完成裝置接入的開發,與阿里雲邊緣Link IoT Edge開發類似(裝置驅動開發即裝置接入)
- 需要完善的介面在
devsdk/devsdk.h
中,當然template.c就是完善後的樣版 - 在
src/c/example目錄下有較多的例程
,結合xx.yaml與xx.toml檔案看對應的原始碼
以下模板檔案可以看出只要完善以下回撥介面:
1、完善以下回撥介面
template_init, /* Initialize */
template_reconfigure, /* Reconfigure */
template_discover, /* Discovery */
template_get_handler, /* Get */
template_put_handler, /* Put */
template_stop /* Stop */
2、再定義裝置提供的資源,如溫溼度裝置,提供溫度、溼度資料資訊,提供裝置啟動關閉、資料採集週期等擴充套件控制資源
其實這些就類似於阿里雲LinkIoTEdge的物模型概念,阿里雲的是雲端介面配置自動生成json格式,這個就需要自己手寫了,而且是yaml格式的,不過提供了不少樣版,難度不是太大
3、編譯執行
/* template implementation of an Edgex device service using C SDK */
/*
* Copyright (c) 2018-2020
* IoTech Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include "devsdk/devsdk.h"
#include "edgex/edgex-base.h"
#include <unistd.h>
#include <signal.h>
#define ERR_CHECK(x) if (x.code) { fprintf (stderr, "Error: %d: %s\n", x.code, x.reason); devsdk_service_free (service); free (impl); return x.code; }
typedef struct template_driver
{
iot_logger_t * lc;
} template_driver;
static void dump_protocols (iot_logger_t *lc, const devsdk_protocols *prots)
{
iot_log_debug (lc, " [Other] protocol:");
for (const devsdk_nvpairs *nv = devsdk_protocols_properties (prots, "Other"); nv; nv = nv->next)
{
iot_log_debug (lc, " %s = %s", nv->name, nv->value);
}
}
static void dump_attributes (iot_logger_t *lc, const devsdk_nvpairs *attrs)
{
for (const devsdk_nvpairs *a = attrs; a; a = a->next)
{
iot_log_debug (lc, " %s = %s", a->name, a->value);
}
}
/* --- Initialize ---- */
/* Initialize performs protocol-specific initialization for the device
* service.
*/
static bool template_init
(
void *impl,
struct iot_logger_t *lc,
const iot_data_t *config
)
{
template_driver *driver = (template_driver *) impl;
iot_log_debug (lc, "Template Init. Driver Config follows:");
if (config)
{
iot_data_map_iter_t iter;
iot_data_map_iter (config, &iter);
while (iot_data_map_iter_next (&iter))
{
iot_log_debug (lc, " %s = %s", iot_data_map_iter_string_key (&iter), iot_data_map_iter_string_value (&iter));
}
}
driver->lc = lc;
iot_log_debug (lc, "Template Init done");
return true;
}
/* --- Reconfigure ---- */
/* Reconfigure is called if the driver configuration is updated.
*/
static void template_reconfigure
(
void *impl,
const iot_data_t *config
)
{
iot_data_map_iter_t iter;
template_driver *driver = (template_driver *) impl;
iot_log_debug (driver->lc, "Template Reconfiguration. New Config follows:");
iot_data_map_iter (config, &iter);
while (iot_data_map_iter_next (&iter))
{
iot_log_debug (driver->lc, " %s = %s", iot_data_map_iter_string_key (&iter), iot_data_map_iter_string_value (&iter));
}
}
/* ---- Discovery ---- */
/* Device services which are capable of device discovery should implement it
* in this callback. It is called in response to a request on the
* device service's discovery REST endpoint. New devices should be added using
* the devsdk_add_device() method
*/
static void template_discover (void *impl) {}
/* ---- Get ---- */
/* Get triggers an asynchronous protocol specific GET operation.
* The device to query is specified by the protocols. nreadings is
* the number of values being requested and defines the size of the requests
* and readings arrays. For each value, the commandrequest holds information
* as to what is being requested. The implementation of this method should
* query the device accordingly and write the resulting value into the
* commandresult.
*
* Note - In a commandrequest, the DeviceResource represents a deviceResource
* which is defined in the device profile.
*/
static bool template_get_handler
(
void *impl,
const char *devname,
const devsdk_protocols *protocols,
uint32_t nreadings,
const devsdk_commandrequest *requests,
devsdk_commandresult *readings,
const devsdk_nvpairs *qparams,
iot_data_t **exception
)
{
template_driver *driver = (template_driver *) impl;
/* Access the location of the device to be accessed and log it */
iot_log_debug(driver->lc, "GET on device:");
dump_protocols (driver->lc, protocols);
for (uint32_t i = 0; i < nreadings; i++)
{
/* Log the attributes for each requested resource */
iot_log_debug (driver->lc, " Requested reading %u:", i);
dump_attributes (driver->lc, requests[i].attributes);
/* Fill in a result regardless */
readings[i].value = iot_data_alloc_string ("Template result", IOT_DATA_REF);
}
return true;
}
/* ---- Put ---- */
/* Put triggers an asynchronous protocol specific SET operation.
* The device to set values on is specified by the protocols.
* nvalues is the number of values to be set and defines the size of the
* requests and values arrays. For each value, the commandresult holds the
* value, and the commandrequest holds information as to where it is to be
* written. The implementation of this method should effect the write to the
* device.
*
* Note - In a commandrequest, the DeviceResource represents a deviceResource
* which is defined in the device profile.
*/
static bool template_put_handler
(
void *impl,
const char *devname,
const devsdk_protocols *protocols,
uint32_t nvalues,
const devsdk_commandrequest *requests,
const iot_data_t *values[],
iot_data_t **exception
)
{
template_driver *driver = (template_driver *) impl;
/* Access the location of the device to be accessed and log it */
iot_log_debug (driver->lc, "PUT on device:");
dump_protocols (driver->lc, protocols);
for (uint32_t i = 0; i < nvalues; i++)
{
/* A Device Service again makes use of the data provided to perform a PUT */
/* Log the attributes */
iot_log_debug (driver->lc, " Requested device write %u:", i);
dump_attributes (driver->lc, requests[i].attributes);
switch (edgex_propertytype_data (values[i]))
{
case Edgex_String:
iot_log_debug (driver->lc, " Value: %s", iot_data_string (values[i]));
break;
case Edgex_Uint64:
iot_log_debug (driver->lc, " Value: %lu", iot_data_ui64 (values[i]));
break;
case Edgex_Bool:
iot_log_debug (driver->lc, " Value: %s", iot_data_bool (values[i]) ? "true" : "false");
break;
/* etc etc */
default:
iot_log_debug (driver->lc, " Value has unexpected type %s: %s", iot_data_type_name (values[i]), iot_data_to_json (values[i]));
}
}
return true;
}
/* ---- Stop ---- */
/* Stop performs any final actions before the device service is terminated */
static void template_stop (void *impl, bool force) {}
int main (int argc, char *argv[])
{
sigset_t set;
int sigret;
template_driver * impl = malloc (sizeof (template_driver));
memset (impl, 0, sizeof (template_driver));
devsdk_error e;
e.code = 0;
/* Device Callbacks */
devsdk_callbacks templateImpls =
{
template_init, /* Initialize */
template_reconfigure, /* Reconfigure */
template_discover, /* Discovery */
template_get_handler, /* Get */
template_put_handler, /* Put */
template_stop /* Stop */
};
/* Initalise a new device service */
devsdk_service_t *service = devsdk_service_new
("device-template", "1.0", impl, templateImpls, &argc, argv, &e);
ERR_CHECK (e);
int n = 1;
while (n < argc)
{
if (strcmp (argv[n], "-h") == 0 || strcmp (argv[n], "--help") == 0)
{
printf ("Options:\n");
printf (" -h, --help\t\t\tShow this text\n");
devsdk_usage ();
return 0;
}
else
{
printf ("%s: Unrecognized option %s\n", argv[0], argv[n]);
return 0;
}
}
/* Set default config */
iot_data_t *confparams = iot_data_alloc_map (IOT_DATA_STRING);
iot_data_string_map_add (confparams, "TestParam1", iot_data_alloc_string ("X", IOT_DATA_REF));
iot_data_string_map_add (confparams, "TestParam2", iot_data_alloc_string ("Y", IOT_DATA_REF));
/* Start the device service*/
devsdk_service_start (service, confparams, &e);
ERR_CHECK (e);
/* Wait for interrupt */
sigemptyset (&set);
sigaddset (&set, SIGINT);
sigprocmask (SIG_BLOCK, &set, NULL);
sigwait (&set, &sigret);
sigprocmask (SIG_UNBLOCK, &set, NULL);
/* Stop the device service */
devsdk_service_stop (service, true, &e);
ERR_CHECK (e);
devsdk_service_free (service);
free (impl);
iot_data_free (confparams);
return 0;
}
測試編譯
export CSDK_DIR=你下載sdk原始碼目錄路徑
export CSDK_LIB=你下載sdk編譯後生成的動態庫檔案路徑
gcc -I$CSDK_DIR/include -L$CSDK_LIB -o template template.c -lcsdk
執行
下圖只為說明介面獲取的方法,裝置名在哪看
#執行前,請先準備好configuration.toml服務配置檔案與xxx.yaml裝置配置檔案放置在同一個目錄下,如dir
./template -c dir
#讀取可用API介面
GET http://localhost:48082/api/v1/device/name/configuration.toml檔案中的裝置名
#獲得類似上圖中的資料即可
GET 獲取的url,例子如下
GET http://localhost:48082/api/v1/device/c5c93b51-226b-4b0f-a4e5-8bfbfa096382/command/2bb9992c-3b74-422a-b4c6-74b33492ca79
PUT 獲取的url 需設定的引數,例子如下
PUT http://localhost:48082/api/v1/device/59f51186-af23-4340-823f-0bbd8a65449f/command/db0dbed8-ad94-4706-9f34-6110e2b45797
{"Min_Int8":"-10", "Max_Int8":"10" }
#PUT與GET的資料不盡相同,皆是基於你所定義的裝置配置檔案中提供的裝置資源,而裝置配置檔案又是基於你依靠SDK編寫的裝置服務驅動
至此,皆是對官網的使用流程進行說明,下面進入正題。
使用SDK開發真實裝置接入服務
著手編寫一個溫溼度裝置接入
準備相關檔案及目錄
建立一個資料夾如:temperature-device-driver
mkdir temperature-device-driver && cd temperature-device-driver
建立device-temperature.c
檔案、建立res
目錄
在temperature-device-driver
目錄下建立build.sh
指令碼檔案,內容如下:
#!/bin/sh
#定義SDK原始碼標頭檔案目錄
SDK_INC_DIR=/home/aron566/Workspace/C_SDK/device-sdk-c/include
#定義SDK動態庫檔案目錄
SDK_LIB_DIR=/home/aron566/Workspace/C_SDK/device-sdk-c/build/release/_CPack_Packages/Linux/TGZ/csdk-1.3.0/lib
#定義編譯生成的APP名稱
TARGET_APP_NAME=device_driver
#定義原始碼檔名稱
SOURCE_FILE_NAME=device_driver.c
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_LIB_DIR
case "$1" in
make)
gcc -I$SDK_INC_DIR -L$SDK_LIB_DIR -o $TARGET_APP_NAME $SOURCE_FILE_NAME -lcsdk
;;
run)
./$TARGET_APP_NAME -c res
;;
*)
echo "Usage: $0 {make|run}"
exit 1
esac
新增可執行許可權
sudo chmod +x build.sh
編寫溫溼度裝置接入裝置服務
記住,完善介面即可
#include "devsdk/devsdk.h"
#include "edgex/edgex-base.h"
#include <unistd.h>
#include <signal.h>
#define ERR_CHECK(x) if (x.code) { fprintf (stderr, "Error: %d: %s\n", x.code, x.reason); devsdk_service_free (service); free (impl); return x.code; }
配置檔案xx.yaml和xx.toml
xx.yaml的修改需遵照裝置服務提供的裝置功能
官方對配置的介紹
其他配置的介紹
編譯
./build make
執行
執行可以使用指令碼,當然需要在指令碼中修改定義好變數
./build run
未完待續
相關文章
- 雲原生與邊緣計算的碰撞——邊緣原生應用實踐
- 史上最全的邊緣計算應用場景
- 打破邊界,邊緣計算有何應用場景?
- CES 2019 | 百度全球釋出智慧邊緣計算產品 BIE 和智慧邊緣計算開源版本 OpenEdge
- 邊緣雲端計算典型應用場景
- JuiceFS 在火山引擎邊緣計算的應用實踐UI
- 開發邊緣計算儲存策略的關鍵考慮因素
- 邊緣計算的發展歷程
- KubeEdge,一個Kubernetes原生邊緣計算框架框架
- 雲端計算開源產業聯盟:2019年雲端計算與邊緣計算協同九大應用場景(附下載)產業
- 5G邊緣計算:開源架起5G MEC生態發展新通路
- 邊緣計算系列科普(五)邊緣計算中的關鍵技術
- 重磅!阿里巴巴開源首個邊緣計算雲原生專案 OpenYurt阿里
- []AWS + 邊無際Shifu IoT開源開發框架助力十倍加速物聯網應用開發框架
- 【邊緣計算】邊緣計算時代已經到來,巨頭們新的敵人是資料邊界;邊緣計算、AI晶片、垂直應用,2018人工智慧怎麼投AI晶片人工智慧
- 邊緣計算|Hadoop——邊緣計算和Hadoop是什麼關係?Hadoop
- Cognita: 開源RAG框架助力生產級應用開發框架
- 邊緣計算與雲端計算
- 邊緣計算的最佳實踐
- 函式計算-HelloWorld應用開發函式
- 雲端計算開發-RPC應用RPC
- 雲端計算時代邊緣計算正蓬勃發展
- 邊緣計算2.0時代,“雲邊緣”與“邊緣雲”你分清了嗎?
- 邊緣計算與雲端計算的未來
- 邊緣計算 KubeEdge+EdgeMash
- 【邊緣計算】劉陽:邊緣計算髮展中的若干熱點問題及思考
- 蘇寧影片雲如何雲用邊緣計算擴充套件雲端計算的邊界的?套件
- Galileo:一款開源Web應用審計框架Web框架
- 【京東】【京東雲】【北京】邊緣計算資深測試開發工程師工程師
- 邊緣計算軟體的選擇
- 邊緣計算中的防雷網路卡
- Android示例應用:開源框架Glide的使用Android框架IDE
- 【從0到1學習邊緣容器系列1】之 邊緣計算與邊緣容器的起源
- MLOps模型部署的三種策略:批處理、實時、邊緣計算模型
- 邊緣計算與資料中心的發展趨勢
- 從雲端計算轉向邊緣計算
- 天翼雲邊緣函式、邊緣安全專案入選“可信邊緣計算推進計劃”函式
- 邊緣計算與物聯網