一、安裝edgex 2.0
1.使用docker-compose.yml啟動[推薦]
參考:https://docs.edgexfoundry.org/2.0/getting-started/quick-start/
1)預(yù)裝docker及docker-compose
- Docker https://docs.docker.com/install/
- Docker Compose https://docs.docker.com/compose/install/
2)安裝運行EdgeX
下載非加密版本的edgex
方法1
# 86版本
curl https://raw.githubusercontent.com/edgexfoundry/edgex-compose/ireland/docker-compose-no-secty.yml -o docker-compose.yml
sudo docker-compose up -d
# ARM64版本
curl https://raw.githubusercontent.com/edgexfoundry/edgex-compose/ireland/docker-compose-no-secty-arm64.yml -o docker-compose.yml
sudo docker-compose up -d
方法2
git clone -b ireland https://github.com/edgexfoundry/edgex-compose
# X86運行
make run
# ARM64運行
make run arm64
驗證安裝
docker-compose ps
- 注意:如果需要edgex容器可以被外部設(shè)備訪問,需要把docker-compose.yml中的"127.0.0.1:"去掉另玖,然后重新啟動。
2.使用edgex-go 編譯容器運行
官方提供go和c兩種開發(fā)方式,EdgeX Foundry 的開源微服務(wù)是用 Go 1.16 編寫的目养,推薦使用golang進行開發(fā)呐籽。
1)安裝依賴
-
安裝Go環(huán)境
- 推薦安裝 Go 1.16 及其更新,較舊版本的 Go(尤其是 1.10 或更早版本)裕照,可能會導致問題。
-
安裝build-essential
- 一般系統(tǒng)自帶
-
ZeroMQ
有幾個edgex 服務(wù)默認使用zmq通信
-
使用腳本[setup-zeromq.sh]安裝(https://gist.github.com/katopz/8b766a5cb0ca96c816658e9407e83d00#file-setup-zeromq-sh)壁熄,實測適用Ubuntu 16.04及18.04
#!/bin/bash # Download zeromq # Ref http://zeromq.org/intro:get-the-software wget https://github.com/zeromq/libzmq/releases/download/v4.2.2/zeromq-4.2.2.tar.gz # Unpack tarball package tar xvzf zeromq-4.2.2.tar.gz # Install dependency sudo apt-get update && \ sudo apt-get install -y libtool pkg-config build-essential autoconf automake uuid-dev # Create make file cd zeromq-4.2.2 ./configure # Build and install(root permission only) sudo make install # Install zeromq driver on linux sudo ldconfig # Check installed ldconfig -p | grep zmq # Expected ############################################################ # libzmq.so.5 (libc6,x86-64) => /usr/local/lib/libzmq.so.5 # libzmq.so (libc6,x86-64) => /usr/local/lib/libzmq.so ############################################################
-
命令安裝耻台,實測適用raspberry pi 4b ubuntu 20.10
sudo apt-get update && \ sudo apt-get install -y libtool pkg-config build-essential autoconf automake uuid-dev sudo apt-get install -y libzmq3-dev $ ldconfig -p | grep zmq libzmq.so.5 (libc6,AArch64) => /lib/aarch64-linux-gnu/libzmq.so.5 libzmq.so (libc6,AArch64) => /lib/aarch64-linux-gnu/libzmq.so
-
下載edgex-go倉庫,作為設(shè)備微服務(wù)開發(fā)示例
export GO111MODULE=on go get github.com/edgexfoundry/edgex-go # 代碼下載到$GOPATH/pkg/mod/cache/download/github.com/edgexfoundry/edgex-go mkdir -p ~/go/src/github.com/edgexfoundry git clone https://github.com/edgexfoundry/edgex-go.git
2)edgex-go目錄說明
~/go/src/github.com/edgexfoundry/edgex-go$ tree -L 2
.
├── ADOPTERS.md
├── Attribution.txt
├── bin
│ └── test-attribution-txt.sh
├── CHANGELOG.md
├── cmd
│ ├── core-command
│ ├── core-data
│ ├── core-metadata
│ ├── secrets-config
│ ├── security-bootstrapper
│ ├── security-file-token-provider
│ ├── security-proxy-setup
│ ├── security-secretstore-setup
│ ├── support-notifications
│ ├── support-scheduler
│ ├── sys-mgmt-agent
│ └── sys-mgmt-executor
├── CONTRIBUTING.md
├── go.mod
├── GOVERNANCE.md
├── internal
│ ├── constants.go
│ ├── core
│ ├── interface.go
│ ├── io
│ ├── pkg
│ ├── security
│ ├── support
│ └── system
├── Jenkinsfile
├── LICENSE
├── Makefile
├── openapi
│ └── v2
├── OWNERS.md
├── README.md
├── SECURITY.md
├── snap
│ ├── hooks
│ ├── local
│ ├── README.md
│ └── snapcraft.yaml
├── version.go
└── ZMQWindows.md
3)編譯工程
make docker
二紫皇、EdgeX服務(wù)組件
https://docs.edgexfoundry.org/2.0/api/Ch-APIIntroduction/
1.核心組件
1)Core Command
提供了一個 API 來獲取可以為所有設(shè)備或單個設(shè)備發(fā)出的命令列表慰安。
- 向設(shè)備或傳感器發(fā)出 GET 命令以獲取設(shè)備上特定屬性的當前值
- 向設(shè)備或傳感器發(fā)出 SET 命令以更改設(shè)備的當前狀態(tài)或狀態(tài)或其屬性之一
2)Core Data
包含從設(shè)備/傳感器收集的Events/Readings數(shù)據(jù)庫 ,并將此數(shù)據(jù)庫公開給其他服務(wù)聪铺。通過API可以對Add, Query 和 Delete Events/Readings的訪問
3)Core Metadata
包含設(shè)備/傳感器的元數(shù)據(jù)庫 化焕,并將此數(shù)據(jù)庫公開給其他服務(wù)×逄蓿可以通過服務(wù)提供的API 存儲和管理設(shè)備元數(shù)據(jù)撒桨。
4)Configuration and Registry
使用第三方的Consul 微服務(wù)作為配置和注冊表的實現(xiàn)查刻,RESTful API 由 Consul 直接提供。提供配置管理凤类、服務(wù)注冊穗泵、服務(wù)注銷、服務(wù)發(fā)現(xiàn)谜疤、consul ui等功能
2.支持組件
1)Support Notifications
2)Support Scheduler
支持調(diào)度程序微服務(wù)提供一個內(nèi)部 EdgeX“時鐘”佃延,可以啟動任何 EdgeX 服務(wù)中的操作。在配置指定的時間夷磕,服務(wù)通過 REST 調(diào)用任何 EdgeX 服務(wù) API URL 以觸發(fā)操作履肃。
3.管理組件
1)System Management Agent
向第三方系統(tǒng)公開 EdgeX 管理服務(wù) API。
4.設(shè)備組件
1)Device Services
5.應(yīng)用組件
1)Application Services
2)Rules Engine
三企锌、使用edgex 2.0
1)EdgeX 服務(wù)的狀態(tài)
訪問consul http://localhost:8500/
2)本地讀取設(shè)備微服務(wù)信息
Edgex Foundry - Core Command API 2.0.0:59882端口
Edgex Foundry - Core Metadata API 2.0.0:59881端口
# 查詢微服務(wù)是否正常運行
curl http://localhost:[port]/api/v2/ping
# 查詢微服務(wù)當前configuration配置
curl http://localhost:[port]/api/v2/config
# 查詢設(shè)備微服務(wù)的事件(deviceName榆浓、profileName、sourceName撕攒、valueType等)
# Random-Integer-Device是預(yù)定義設(shè)備陡鹃,在cmd/device-xxx/res/devices/xxx.toml中定義
curl http://localhost:59880/api/v2/event/device/name/Random-Integer-Device
# 查詢所有設(shè)備
curl http://localhost:59882/api/v2/device/all
# 查詢設(shè)備的coreCommands(name、url抖坪、path萍鲸、parameters、get or set等)
curl http://localhost:59882/api/v2/device/name/Random-Integer-Device
# 讀取deviceName的coreCommands的值
curl -X GET http://localhost:59882/api/v2/device/name/Random-Integer-Device/Int16
# 設(shè)置deviceName的coreCommands的值
curl -X PUT -d '{"Int16":"42", "EnableRandomization_Int16":"false"}' http://localhost:59882/api/v2/device/name/Random-Integer-Device/WriteInt16Value
# 刪除設(shè)備
curl -X DELETE http://localhost:59881/api/v2/device/name/Random-Integer-Device
# 刪除設(shè)備profile
curl -X DELETE http://localhost:59881/api/v2/deviceprofile/name/Random-Integer-Device
3)導出設(shè)備微服務(wù)的數(shù)據(jù)到MQTT broker
社區(qū)提供的“可配置應(yīng)用程序服務(wù)”將 EdgeX 數(shù)據(jù)發(fā)送到由 HiveMQ 托管的公共 MQTT 代理擦俐。然后可以通過 HiveMQ 提供的 MQTT 瀏覽器客戶端查看 EdgeX 事件數(shù)據(jù)脊阴。
將以下應(yīng)用程序服務(wù)添加到 docker-compose.yml 文件中,緊跟在“app-service-rules”服務(wù)蚯瞧。
app-service-mqtt:
container_name: edgex-app-mqtt
depends_on:
- consul
- data
environment:
CLIENTS_CORE_COMMAND_HOST: edgex-core-command
CLIENTS_CORE_DATA_HOST: edgex-core-data
CLIENTS_CORE_METADATA_HOST: edgex-core-metadata
CLIENTS_SUPPORT_NOTIFICATIONS_HOST: edgex-support-notifications
CLIENTS_SUPPORT_SCHEDULER_HOST: edgex-support-scheduler
DATABASES_PRIMARY_HOST: edgex-redis
EDGEX_PROFILE: mqtt-export
EDGEX_SECURITY_SECRET_STORE: "false"
MESSAGEQUEUE_HOST: edgex-redis
REGISTRY_HOST: edgex-core-consul
SERVICE_HOST: edgex-app-mqtt
TRIGGER_EDGEXMESSAGEBUS_PUBLISHHOST_HOST: edgex-redis
TRIGGER_EDGEXMESSAGEBUS_SUBSCRIBEHOST_HOST: edgex-redis
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_BROKERADDRESS: tcp://broker.mqttdashboard.com:1883
WRITABLE_PIPELINE_FUNCTIONS_MQTTEXPORT_PARAMETERS_TOPIC: EdgeXEvents # 可以修改主題
hostname: edgex-app-mqtt
image: edgexfoundry/app-service-configurable:2.0.0
networks:
edgex-network: {}
ports:
- 127.0.0.1:59702:59702/tcp
read_only: true
security_opt:
- no-new-privileges:true
user: 2002:2001
公共MQTT代理接收到數(shù)據(jù)
{"apiVersion":"v2","id":"83d86ea1-edfd-4c14-a69e-b8d7dfec3965","deviceName":"Random-UnsignedInteger-Device","profileName":"Random-UnsignedInteger-Device","sourceName":"Uint8","origin":1630311152846053399,"readings":[{"id":"891df7ab-7822-46e8-9cd8-8b8f8de8629d","origin":1630311152846053399,"deviceName":"Random-UnsignedInteger-Device","resourceName":"Uint8","profileName":"Random-UnsignedInteger-Device","valueType":"Uint8","binaryValue":null,"mediaType":"","value":"207"}]}
四嘿期、Device Service開發(fā)
https://docs.edgexfoundry.org/2.0/getting-started/Ch-GettingStartedSDK-Go/
EdgeX Foundry - Device Service API 2.0.0
1.基于device-sdk-go開發(fā)
device-sdk-go is a set of Go packages that can be used to build Go-based device services for use within the EdgeX framework.
device service主要依賴以下兩個包來實現(xiàn)
- github.com/edgexfoundry/device-sdk-go/v2 v2.0.0
- github.com/edgexfoundry/go-mod-core-contracts/v2 v2.0.0
1)獲取device-sdk-go
cd ~/go/src/github.com/edgexfoundry
git clone --depth 1 --branch v2.0.0 https://github.com/edgexfoundry/device-sdk-go.git
工程目錄
├── bin
│ ├── test-attribution-txt.sh
│ └── test-go-mod-tidy.sh
├── CHANGELOG.md
├── Dockerfile.build
├── example # device-simple
│ ├── cmd
│ │ └── device-simple
│ ├── config
│ │ └── configuration.go
│ ├── driver
│ │ └── simpledriver.go
│ └── README.md
├── go.mod
├── internal
│ ├── application
│ │ ├── callback.go
│ │ ├── command.go
│ │ └── command_test.go
│ ├── autodiscovery
│ │ ├── autodiscovery.go
│ │ └── discovery.go
│ ├── autoevent
│ │ ├── executor.go
│ │ ├── executor_test.go
│ │ └── manager.go
│ ├── cache
│ │ ├── const_test.go
│ │ ├── devices.go
│ │ ├── devices_test.go
│ │ ├── init.go
│ │ ├── profiles.go
│ │ ├── profiles_test.go
│ │ ├── provisionwatcher.go
│ │ └── provisionwatcher_test.go
│ ├── clients
│ │ ├── clients.go
│ │ ├── init.go
│ │ └── init_test.go
│ ├── common
│ │ ├── consts.go
│ │ └── utils.go
│ ├── config
│ │ ├── config.go
│ │ └── types.go
│ ├── container
│ │ ├── client.go
│ │ ├── config.go
│ │ └── deviceservice.go
│ ├── controller
│ │ └── http
│ ├── messaging
│ │ ├── messaging.go
│ │ └── messaging_test.go
│ ├── provision
│ │ ├── devices.go
│ │ └── profiles.go
│ ├── telemetry
│ │ ├── linux_cpu.go
│ │ ├── telemetry.go
│ │ ├── unimplemented_cpu.go
│ │ └── windows_cpu.go
│ └── transformer
│ ├── checkNaN.go
│ ├── checkNaN_test.go
│ ├── transform.go
│ ├── transformparam.go
│ ├── transformparam_test.go
│ ├── transformresult.go
│ ├── transformresult_test.go
│ ├── transform_test.go
│ ├── transformvaluechecker.go
│ └── transformvaluechecker_test.go
├── Jenkinsfile
├── LICENSE
├── Makefile
├── openapi
│ ├── v1
│ │ └── device-sdk.yaml
│ └── v2
│ ├── changes.txt
│ └── device-sdk.yaml
├── pkg # golang依賴包
│ ├── models # driver相關(guān)
│ │ ├── asyncvalues.go
│ │ ├── commandrequest.go
│ │ ├── commandvalue.go
│ │ ├── commandvalue_test.go
│ │ ├── manager.go
│ │ ├── mocks
│ │ ├── protocoldiscovery.go
│ │ └── protocoldriver.go
│ ├── service # 服務(wù)管理相關(guān)
│ │ ├── async.go
│ │ ├── async_test.go
│ │ ├── init.go
│ │ ├── main.go
│ │ ├── managedautoevents.go
│ │ ├── manageddevices.go
│ │ ├── managedprofiles.go
│ │ ├── managedwatchers.go
│ │ └── service.go
│ └── startup # 啟動相關(guān)
│ └── bootstrap.go
├── README.md
├── snap
│ ├── hooks
│ │ └── install
│ ├── local
│ └── snapcraft.yaml
└── version.go
2)構(gòu)建新的device-service工程
cd ~/go/src/github.com/edgexfoundry
mkdir device-simple
cp -rf ./device-sdk-go/example/* ./device-simple/
cp ./device-sdk-go/Makefile ./device-simple
cp ./device-sdk-go/version.go ./device-simple/
$ tree device-simple/
device-simple/
├── cmd
│ └── device-simple
│ ├── Attribution.txt
│ ├── Dockerfile
│ ├── main.go
│ └── res
│ ├── configuration.toml # 微服務(wù)配置文件
│ ├── devices
│ │ ├── simple-device.json.example
│ │ └── simple-device.toml
│ ├── off.jpg
│ ├── on.png
│ ├── profiles
│ │ ├── Simple-Driver.json.example
│ │ └── Simple-Driver.yaml
│ └── provisionwatcher.json
├── config
│ └── configuration.go
├── driver
│ └── simpledriver.go
├── Makefile
├── README.md
└── version.go
修改device-simple/cmd/device-simple/main.go文件
import (
- "github.com/edgexfoundry/device-sdk-go/v2"
- "github.com/edgexfoundry/device-sdk-go/v2/example/driver"
+ "github.com/edgexfoundry/device-simple"
+ "github.com/edgexfoundry/device-simple/driver"
"github.com/edgexfoundry/device-sdk-go/v2/pkg/startup"
)
修改device-simple/Makefile文件
@@ -3,13 +3,13 @@
GO=CGO_ENABLED=0 GO111MODULE=on go
GOCGO=CGO_ENABLED=1 GO111MODULE=on go
-MICROSERVICES=example/cmd/device-simple/device-simple
+MICROSERVICES=cmd/device-simple/device-simple
.PHONY: $(MICROSERVICES)
VERSION=$(shell cat ./VERSION 2>/dev/null || echo 0.0.0)
DOCKER_TAG=$(VERSION)-dev
-GOFLAGS=-ldflags "-X github.com/edgexfoundry/device-sdk-go/v2.Version=$(VERSION)"
+GOFLAGS=-ldflags "-X github.com/edgexfoundry/device-simple.Version=$(VERSION)"
GOTESTFLAGS?=-race
GIT_SHA=$(shell git rev-parse HEAD)
@@ -17,13 +17,13 @@ GIT_SHA=$(shell git rev-parse HEAD)
build: $(MICROSERVICES)
$(GOCGO) install -tags=safe
-example/cmd/device-simple/device-simple:
+cmd/device-simple/device-simple:
go mod tidy
- $(GOCGO) build $(GOFLAGS) -o $@ ./example/cmd/device-simple
+ $(GOCGO) build $(GOFLAGS) -o $@ ./cmd/device-simple
docker:
docker build \
- -f example/cmd/device-simple/Dockerfile \
+ -f cmd/device-simple/Dockerfile \
--label "git_sha=$(GIT_SHA)" \
-t edgexfoundry/device-simple:$(GIT_SHA) \
-t edgexfoundry/device-simple:$(DOCKER_TAG) \
初始化工程go module
GO111MODULE=on go mod init github.com/edgexfoundry/device-simple
# 為工程補齊module
go mod tidy
3)為微服務(wù)添加設(shè)備驅(qū)動
修改driver/simpledriver.go,其導入device-sdk-go/v2/pkg/models包埋合,xxxdriver.go需要基于驅(qū)動實現(xiàn)其函數(shù)备徐。
//github.com/edgexfoundry/device-sdk-go/pkg/models
func (cv *CommandValue) ValueToString() string
func (cv *CommandValue) String() string
func (cv *CommandValue) BoolValue() (bool, error)
func (cv *CommandValue) BoolArrayValue() ([]bool, error)
func (cv *CommandValue) StringValue() (string, error)
func (cv *CommandValue) Uint8Value() (uint8, error)
func (cv *CommandValue) Uint8ArrayValue() ([]uint8, error)
func (cv *CommandValue) Uint16Value() (uint16, error)
func (cv *CommandValue) Uint16ArrayValue() ([]uint16, error)
func (cv *CommandValue) Uint32Value() (uint32, error)
func (cv *CommandValue) Uint32ArrayValue() ([]uint32, error)
func (cv *CommandValue) Uint64Value() (uint64, error)
func (cv *CommandValue) Uint64ArrayValue() ([]uint64, error)
func (cv *CommandValue) Int8Value() (int8, error)
func (cv *CommandValue) Int8ArrayValue() ([]int8, error)
func (cv *CommandValue) Int16Value() (int16, error)
func (cv *CommandValue) Int16ArrayValue() ([]int16, error)
func (cv *CommandValue) Int32Value() (int32, error)
func (cv *CommandValue) Int32ArrayValue() ([]int32, error)
func (cv *CommandValue) Int64Value() (int64, error)
func (cv *CommandValue) Int64ArrayValue() ([]int64, error)
func (cv *CommandValue) Float32Value() (float32, error)
func (cv *CommandValue) Float32ArrayValue() ([]float32, error)
func (cv *CommandValue) Float64Value() (float64, error)
func (cv *CommandValue) Float64ArrayValue() ([]float64, error)
func (cv *CommandValue) BinaryValue() ([]byte, error)
4)配置Device Profile
Profile.yml是用來定義Device的數(shù)據(jù)類型以及EdgeX如何通過core-Command來對device發(fā)送命令。
- deviceResources的值是定義Device上傳到deviceService中數(shù)據(jù)的類型甚颂;
- deviceCommands定義核心服務(wù)core-command能對設(shè)備進行的操作蜜猾;
type DeviceProfile struct {
DBTimestamp
Description string
Id string
Name string
Manufacturer string
Model string
Labels []string
DeviceResources []DeviceResource
DeviceCommands []DeviceCommand
}
type DeviceResource struct {
Description string
Name string
IsHidden bool
Tag string
Properties ResourceProperties
Attributes map[string]interface{}
}
type DeviceCommand struct {
Name string
IsHidden bool
ReadWrite string
ResourceOperations []ResourceOperation
}
// https://github.com/edgexfoundry/go-mod-core-contracts/blob/main/common/utils.go
var valueTypes = []string{
ValueTypeBool, ValueTypeString,
ValueTypeUint8, ValueTypeUint16, ValueTypeUint32, ValueTypeUint64,
ValueTypeInt8, ValueTypeInt16, ValueTypeInt32, ValueTypeInt64,
ValueTypeFloat32, ValueTypeFloat64,
ValueTypeBinary,
ValueTypeBoolArray, ValueTypeStringArray,
ValueTypeUint8Array, ValueTypeUint16Array, ValueTypeUint32Array, ValueTypeUint64Array,
ValueTypeInt8Array, ValueTypeInt16Array, ValueTypeInt32Array, ValueTypeInt64Array,
ValueTypeFloat32Array, ValueTypeFloat64Array,
}
路徑:cmd/device-xxx/res/profiles/Simple-Driver.yaml,示例如下:
# Identification部分
apiVersion: "v2"
name: "Simple-Device" # 唯一的ProfileName
manufacturer: "Simple Corp."
model: "SP-01"
labels:
- "modbus"
description: "Example of Simple Device"
# deviceResources部分
deviceResources: # 資源屬性
-
name: "SwitchButton"
isHidden: false
description: "Switch On/Off."
properties:
valueType: "Bool"
readWrite: "RW"
defaultValue: "true"
# deviceCommands部分
deviceCommands: # restful api command
-
name: "Switch"
isHidden: false
readWrite: "RW"
resourceOperations:
- { deviceResource: "SwitchButton", defaultValue: "false" }
5)添加預(yù)定義設(shè)備
可以支持TOML或JSON格式的配置文件
type Device struct {
DBTimestamp
Id string
Name string
Description string
AdminState AdminState
OperatingState OperatingState
Protocols map[string]ProtocolProperties
LastConnected int64
LastReported int64
Labels []string
Location interface{}
ServiceName string
ProfileName string
AutoEvents []AutoEvent
Notify bool
}
路徑:cmd/device-xxx/res/devices/simple-device.toml
[[DeviceList]]
# 這里DeviceList的Name和Profile的值對應(yīng)Simple-Driver.yaml的name: "Simple-Device"
Name = "Simple-Device01"
ProfileName = "Simple-Device"
Description = "Example of Simple Device"
Labels = [ "industrial" ]
[DeviceList.Protocols]
[DeviceList.Protocols.other]
Address = "simple01"
Port = "300"
[[DeviceList.AutoEvents]] # 自動請求事件
Interval = "10s" # 10秒發(fā)送一次
OnChange = false
SourceName = "Switch" # 對應(yīng)deviceCommands
配置文件的處理代碼:https://github.com/edgexfoundry/go-mod-core-contracts/tree/main/models
6)修改device service配置文件
路徑:cmd/device-xxx/res/configuration.toml
功能
- 定義設(shè)備微服務(wù)的host振诬、port等
- 定義使用Registry的host蹭睡、port
- 定義edgex core-data和core-metadata等服務(wù)的host、port
- 定義MessageQueue的配置赶么,基于redis
- 定義Device的ProfilesDir肩豁、DevicesDir和Discovery等
[Writable]
LogLevel = "INFO"
# Example InsecureSecrets configuration that simulates SecretStore for when EDGEX_SECURITY_SECRET_STORE=false
# InsecureSecrets are required for when Redis is used for message bus
[Writable.InsecureSecrets]
[Writable.InsecureSecrets.DB]
path = "redisdb"
[Writable.InsecureSecrets.DB.Secrets]
username = ""
password = ""
[Service]
HealthCheckInterval = "10s"
Host = "localhost"
Port = 59999 # Device serivce are assigned the 599xx range
ServerBindAddr = "" # blank value defaults to Service.Host value
StartupMsg = "device simple started"
# MaxRequestSize limit the request body size in byte of put command
MaxRequestSize = 0 # value 0 unlimit the request size.
RequestTimeout = "20s"
[Registry]
Host = "localhost"
Port = 8500
Type = "consul"
[Clients]
[Clients.core-data]
Protocol = "http"
Host = "localhost"
Port = 59880
[Clients.core-metadata]
Protocol = "http"
Host = "localhost"
Port = 59881
[MessageQueue]
Protocol = "redis"
Host = "localhost"
Port = 6379
Type = "redis"
AuthMode = "usernamepassword" # required for redis messagebus (secure or insecure).
SecretName = "redisdb"
PublishTopicPrefix = "edgex/events/device" # /<device-profile-name>/<device-name>/<source-name> will be added to this Publish Topic prefix
[MessageQueue.Optional]
# Default MQTT Specific options that need to be here to enable environment variable overrides of them
# Client Identifiers
ClientId = "device-simple"
# Connection information
Qos = "0" # Quality of Sevice values are 0 (At most once), 1 (At least once) or 2 (Exactly once)
KeepAlive = "10" # Seconds (must be 2 or greater)
Retained = "false"
AutoReconnect = "true"
ConnectTimeout = "5" # Seconds
SkipCertVerify = "false" # Only used if Cert/Key file or Cert/Key PEMblock are specified
# Example SecretStore configuration.
# Only used when EDGEX_SECURITY_SECRET_STORE=true
# Must also add `ADD_SECRETSTORE_TOKENS: "device-simple"` to vault-worker environment so it generates
# the token and secret store in vault for "device-simple"
[SecretStore]
Type = "vault"
Host = "localhost"
Port = 8200
Path = "device-simple/"
Protocol = "http"
RootCaCertPath = ""
ServerName = ""
TokenFile = "/tmp/edgex/secrets/device-simple/secrets-token.json"
[SecretStore.Authentication]
AuthType = "X-Vault-Token"
[Device]
DataTransform = true
MaxCmdOps = 128
MaxCmdValueLen = 256
ProfilesDir = "./res/profiles"
DevicesDir = "./res/devices"
UpdateLastConnected = false
AsyncBufferSize = 1
EnableAsyncReadings = true
Labels = []
UseMessageBus = true
[Device.Discovery]
Enabled = false
Interval = "30s"
# Example structured custom configuration
[SimpleCustom]
OnImageLocation = "./res/on.png"
OffImageLocation = "./res/off.jpg"
[SimpleCustom.Writable]
DiscoverSleepDurationSecs = 10
7)編譯及執(zhí)行工程
$ make build
go mod tidy
CGO_ENABLED=1 GO111MODULE=on go build -ldflags "-X github.com/edgexfoundry/device-simple.Version=0.0.0" -o cmd/device-simple/device-simple ./cmd/device-simple
CGO_ENABLED=1 GO111MODULE=on go install -tags=safe
# 執(zhí)行文件為cmd/device-simple/device-simple
運行可執(zhí)行文件
# 關(guān)閉安全模式
$ export EDGEX_SECURITY_SECRET_STORE=false
# 由于edgex服務(wù)組件使用容器以bridge網(wǎng)絡(luò)啟動,因此需要修改SERVICE_HOST為docker0 ip,否則會綁定127.0.0.1
$ export SERVICE_HOST="172.17.0.1"
$ cd ~/go/src/github.com/edgexfoundry/device-simple/cmd/device-simple
$ ./device-simple
msg="Loaded service configuration from ./res/configuration.toml" # 加載服務(wù)配置文件
msg="Using local configuration from file (0 envVars overrides applied)"
msg="Web server starting (localhost:59999)" # 微服務(wù)開啟webserver
msg="Setting options for secure MessageBus with AuthMode='usernamepassword' and SecretName='redisdb"
msg="Connected to redis Message Bus @ redis://localhost:6379 publishing on 'edgex/events/device' prefix topic with AuthMode='usernamepassword'" # 連接到redis
msg="Check core-metadata service's status by ping..."
msg="Service clients initialize successful."
msg="Registering v2 routes..."
msg="Skipping use of Configuration Provider for custom configuration: Provider not available"
msg="Loaded custom configuration from ./res/configuration.toml"
msg="Loaded custom configuration from file (0 envVars overrides applied)"
msg="Custom config is: {./res/off.jpg ./res/on.png {10}}"
msg="unable to watch custom configuration for changes: Configuration Provider not enabled"
msg="device service device-simple doesn't exist, creating a new one"
msg="Loading pre-defined profiles from /home/ubuntu/go/src/github.com/edgexfoundry/device-simple/cmd/device-simple/res/profiles"
msg="Profile Simple-Device not found in Metadata, adding it ..." # Metadata添加設(shè)備
msg="Loading pre-defined devices from /home/ubuntu/go/src/github.com/edgexfoundry/device-simple/cmd/device-simple/res/devices"
msg="Device Simple-Device01 not found in Metadata, adding it ..."
msg="AutoDiscovery stopped: disabled by configuration"
msg="Service dependencies resolved..."
msg="Starting device-simple 0.0.0 "
msg="device simple started"
msg="Service started in: 19.572988ms"
RESTFul API測試
// curl http://localhost:59882/api/v2/device/name/Simple-Device01
{
"apiVersion": "v2",
"statusCode": 200,
"deviceCoreCommand": {
"deviceName": "Simple-Device01",
"profileName": "Simple-Device",
"coreCommands": [
{
"name": "SwitchButton",
"get": true,
"set": true,
"path": "/api/v2/device/name/Simple-Device01/SwitchButton",
"url": "http://edgex-core-command:59882",
"parameters": [
{
"resourceName": "SwitchButton",
"valueType": "Bool"
}
]
},
...
{
"name": "Image",
"get": true,
"path": "/api/v2/device/name/Simple-Device01/Image",
"url": "http://edgex-core-command:59882",
"parameters": [
{
"resourceName": "Image",
"valueType": "Binary"
}
]
},
...
]
}
}
8)構(gòu)建鏡像
cd ~/edgexfoundry/device-simple
make build
make docker
# 在docker-compose-no-secty.yml中添加微服務(wù)蓖救,并執(zhí)行
docker-compose -f docker-compose-no-secty.yml up -d
docker-compose.yml樣例
- 添加到edgex核心服務(wù)的yml文件中
...
device-xxx:
container_name: edgex-device-xxx
depends_on:
- consul
- data
- metadata
environment:
CLIENTS_CORE_COMMAND_HOST: edgex-core-command
CLIENTS_CORE_DATA_HOST: edgex-core-data
CLIENTS_CORE_METADATA_HOST: edgex-core-metadata
CLIENTS_SUPPORT_NOTIFICATIONS_HOST: edgex-support-notifications
CLIENTS_SUPPORT_SCHEDULER_HOST: edgex-support-scheduler
DATABASES_PRIMARY_HOST: edgex-redis
EDGEX_SECURITY_SECRET_STORE: "false"
MESSAGEQUEUE_HOST: edgex-redis
REGISTRY_HOST: edgex-core-consul
SERVICE_HOST: edgex-device-xxx
hostname: edgex-device-xxx
image: edgexfoundry/device-xxx:0.0.0-dev
networks:
edgex-network: {}
ports:
- 49994:49994/tcp
read_only: false
privileged: true
volumes:
- "/sys:/sys"
- "/dev:/dev"
security_opt:
- no-new-privileges:false
user: root:root
...
2.device-sdk-go核心Package
1)pkg/startup
用于微服務(wù)的啟動
// bootstrap.go
package startup
import (
"context"
"github.com/edgexfoundry/device-sdk-go/v2/pkg/service"
"github.com/gorilla/mux"
)
func Bootstrap(serviceName string, serviceVersion string, driver interface{}) {
ctx, cancel := context.WithCancel(context.Background())
service.Main(serviceName, serviceVersion, driver, ctx, cancel, mux.NewRouter()) // 調(diào)用pkg/service/main.go的Main函數(shù)
}
2)pkg/service
// main.go
func Main(serviceName string, serviceVersion string, proto interface{}, ctx context.Context, cancel context.CancelFunc, router *mux.Router) {
...
bootstrap.Run( // 執(zhí)行g(shù)ithub.com/edgexfoundry/go-mod-bootstrap/bootstrap/bootstrap.go的Run函數(shù)
ctx,
cancel,
sdkFlags,
ds.ServiceName,
common.ConfigStemDevice,
ds.config,
startupTimer,
ds.dic,
true,
[]interfaces.BootstrapHandler{
httpServer.BootstrapHandler,
messaging.BootstrapHandler,
clients.BootstrapHandler,
autoevent.BootstrapHandler,
NewBootstrap(router).BootstrapHandler,
autodiscovery.BootstrapHandler,
handlers.NewStartMessage(serviceName, serviceVersion).BootstrapHandler,
})
...
}
// service.go
type UpdatableConfig interface {
interfaces.UpdatableConfig
}
type DeviceService struct {
ServiceName string
LoggingClient logger.LoggingClient
RegistryClient registry.Client
SecretProvider interfaces.SecretProvider
edgexClients clients.EdgeXClients
controller *restController.RestController
config *config.ConfigurationStruct
deviceService *models.DeviceService
driver sdkModels.ProtocolDriver
discovery sdkModels.ProtocolDiscovery
manager sdkModels.AutoEventManager
asyncCh chan *sdkModels.AsyncValues
deviceCh chan []sdkModels.DiscoveredDevice
initialized bool
dic *di.Container
flags flags.Common
configProcessor *bootstrapConfig.Processor
ctx context.Context
wg *sync.WaitGroup
}
func (s *DeviceService) Initialize(serviceName, serviceVersion string, proto interface{})
func (s *DeviceService) Name() string {
return s.ServiceName
}
// Version returns the version number of this Device Service
func (s *DeviceService) Version() string {
return sdkCommon.ServiceVersion
}
// AsyncReadings returns a bool value to indicate whether the asynchronous reading is enabled.
func (s *DeviceService) AsyncReadings() bool {
return s.config.Device.EnableAsyncReadings
}
func (s *DeviceService) DeviceDiscovery() bool {
return s.config.Device.Discovery.Enabled
}
// AddRoute allows leveraging the existing internal web server to add routes specific to Device Service.
func (s *DeviceService) AddRoute(route string, handler func(http.ResponseWriter, *http.Request), methods ...string) error {
return s.controller.AddRoute(route, handler, methods...)
}
// Stop shuts down the Service
func (s *DeviceService) Stop(force bool) {
if s.initialized {
err := s.driver.Stop(force)
if err != nil {
s.LoggingClient.Error(err.Error())
}
}
}
// LoadCustomConfig uses the Config Processor from go-mod-bootstrap to attempt to load service's
// custom configuration. It uses the same command line flags to process the custom config in the same manner
// as the standard configuration.
func (s *DeviceService) LoadCustomConfig(customConfig UpdatableConfig, sectionName string) error {
if s.configProcessor == nil {
s.configProcessor = bootstrapConfig.NewProcessorForCustomConfig(s.flags, s.ctx, s.wg, s.dic)
}
return s.configProcessor.LoadCustomConfigSection(customConfig, sectionName)
}
3)pkg/models
實現(xiàn)coreCommand洪规、protocoldriver與protocoldiscovery的相關(guān)接口印屁,負責設(shè)備驅(qū)動與coreCommand的中間層交互循捺。
// protocoldriver.go
package models
import (
"github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger"
"github.com/edgexfoundry/go-mod-core-contracts/v2/models"
)
type ProtocolDriver interface {
// Initialize performs protocol-specific initialization for the device service.
// The given *AsyncValues channel can be used to push asynchronous events and
// readings to Core Data. The given []DiscoveredDevice channel is used to send
// discovered devices that will be filtered and added to Core Metadata asynchronously.
Initialize(lc logger.LoggingClient, asyncCh chan<- *AsyncValues, deviceCh chan<- []DiscoveredDevice) error
// HandleReadCommands passes a slice of CommandRequest struct each representing
// a ResourceOperation for a specific device resource.
HandleReadCommands(deviceName string, protocols map[string]models.ProtocolProperties, reqs []CommandRequest) ([]*CommandValue, error)
// HandleWriteCommands passes a slice of CommandRequest struct each representing
// a ResourceOperation for a specific device resource.
// Since the commands are actuation commands, params provide parameters for the individual
// command.
HandleWriteCommands(deviceName string, protocols map[string]models.ProtocolProperties, reqs []CommandRequest, params []*CommandValue) error
// Stop instructs the protocol-specific DS code to shutdown gracefully, or
// if the force parameter is 'true', immediately. The driver is responsible
// for closing any in-use channels, including the channel used to send async
// readings (if supported).
Stop(force bool) error
// AddDevice is a callback function that is invoked
// when a new Device associated with this Device Service is added
AddDevice(deviceName string, protocols map[string]models.ProtocolProperties, adminState models.AdminState) error
// UpdateDevice is a callback function that is invoked
// when a Device associated with this Device Service is updated
UpdateDevice(deviceName string, protocols map[string]models.ProtocolProperties, adminState models.AdminState) error
// RemoveDevice is a callback function that is invoked
// when a Device associated with this Device Service is removed
RemoveDevice(deviceName string, protocols map[string]models.ProtocolProperties) error
}
// protocoldiscovery.go
package models
import (
"github.com/edgexfoundry/go-mod-core-contracts/v2/models"
)
// ProtocolDiscovery is a low-level device-specific interface implemented
// by device services that support dynamic device discovery.
type ProtocolDiscovery interface {
// Discover triggers protocol specific device discovery, asynchronously
// writes the results to the channel which is passed to the implementation
// via ProtocolDriver.Initialize(). The results may be added to the device service
// based on a set of acceptance criteria (i.e. Provision Watchers).
Discover()
}
// DiscoveredDevice defines the required information for a found device.
type DiscoveredDevice struct {
Name string
Protocols map[string]models.ProtocolProperties
Description string
Labels []string
}