一、安装edgex 2.0
1.使用docker-compose.yml启动[推荐]
参考:https://docs.edgexfoundry.org/2.0/getting-started/quick-start/
1)预装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容器可以被外部设备访问,需要把docker-compose.yml中的"127.0.0.1:"去掉,然后重新启动。
2.使用edgex-go 编译容器运行
官方提供go和c两种开发方式,EdgeX Foundry 的开源微服务是用 Go 1.16 编写的,推荐使用golang进行开发。
1)安装依赖
-
安装Go环境
- 推荐安装 Go 1.16 及其更新,较旧版本的 Go(尤其是 1.10 或更早版本),可能会导致问题。
-
安装build-essential
- 一般系统自带
-
ZeroMQ
有几个edgex 服务默认使用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仓库,作为设备微服务开发示例
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服务组件
https://docs.edgexfoundry.org/2.0/api/Ch-APIIntroduction/
1.核心组件
1)Core Command
提供了一个 API 来获取可以为所有设备或单个设备发出的命令列表。
- 向设备或传感器发出 GET 命令以获取设备上特定属性的当前值
- 向设备或传感器发出 SET 命令以更改设备的当前状态或状态或其属性之一
2)Core Data
包含从设备/传感器收集的Events/Readings数据库 ,并将此数据库公开给其他服务。通过API可以对Add, Query 和 Delete Events/Readings的访问
3)Core Metadata
包含设备/传感器的元数据库 ,并将此数据库公开给其他服务。可以通过服务提供的API 存储和管理设备元数据。
4)Configuration and Registry
使用第三方的Consul 微服务作为配置和注册表的实现,RESTful API 由 Consul 直接提供。提供配置管理、服务注册、服务注销、服务发现、consul ui等功能
2.支持组件
1)Support Notifications
2)Support Scheduler
支持调度程序微服务提供一个内部 EdgeX“时钟”,可以启动任何 EdgeX 服务中的操作。在配置指定的时间,服务通过 REST 调用任何 EdgeX 服务 API URL 以触发操作。
3.管理组件
1)System Management Agent
向第三方系统公开 EdgeX 管理服务 API。
4.设备组件
1)Device Services
5.应用组件
1)Application Services
2)Rules Engine
三、使用edgex 2.0
1)EdgeX 服务的状态
访问consul http://localhost:8500/
2)本地读取设备微服务信息
Edgex Foundry - Core Command API 2.0.0:59882端口
Edgex Foundry - Core Metadata API 2.0.0:59881端口
# 查询微服务是否正常运行
curl http://localhost:[port]/api/v2/ping
# 查询微服务当前configuration配置
curl http://localhost:[port]/api/v2/config
# 查询设备微服务的事件(deviceName、profileName、sourceName、valueType等)
# Random-Integer-Device是预定义设备,在cmd/device-xxx/res/devices/xxx.toml中定义
curl http://localhost:59880/api/v2/event/device/name/Random-Integer-Device
# 查询所有设备
curl http://localhost:59882/api/v2/device/all
# 查询设备的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
# 设置deviceName的coreCommands的值
curl -X PUT -d '{"Int16":"42", "EnableRandomization_Int16":"false"}' http://localhost:59882/api/v2/device/name/Random-Integer-Device/WriteInt16Value
# 删除设备
curl -X DELETE http://localhost:59881/api/v2/device/name/Random-Integer-Device
# 删除设备profile
curl -X DELETE http://localhost:59881/api/v2/deviceprofile/name/Random-Integer-Device
3)导出设备微服务的数据到MQTT broker
社区提供的“可配置应用程序服务”将 EdgeX 数据发送到由 HiveMQ 托管的公共 MQTT 代理。然后可以通过 HiveMQ 提供的 MQTT 浏览器客户端查看 EdgeX 事件数据。
将以下应用程序服务添加到 docker-compose.yml 文件中,紧跟在“app-service-rules”服务。
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代理接收到数据
{"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开发
https://docs.edgexfoundry.org/2.0/getting-started/Ch-GettingStartedSDK-Go/
EdgeX Foundry - Device Service API 2.0.0
1.基于device-sdk-go开发
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主要依赖以下两个包来实现
- 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相关
│ │ ├── asyncvalues.go
│ │ ├── commandrequest.go
│ │ ├── commandvalue.go
│ │ ├── commandvalue_test.go
│ │ ├── manager.go
│ │ ├── mocks
│ │ ├── protocoldiscovery.go
│ │ └── protocoldriver.go
│ ├── service # 服务管理相关
│ │ ├── async.go
│ │ ├── async_test.go
│ │ ├── init.go
│ │ ├── main.go
│ │ ├── managedautoevents.go
│ │ ├── manageddevices.go
│ │ ├── managedprofiles.go
│ │ ├── managedwatchers.go
│ │ └── service.go
│ └── startup # 启动相关
│ └── bootstrap.go
├── README.md
├── snap
│ ├── hooks
│ │ └── install
│ ├── local
│ └── snapcraft.yaml
└── version.go
2)构建新的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 # 微服务配置文件
│ ├── 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)为微服务添加设备驱动
修改driver/simpledriver.go,其导入device-sdk-go/v2/pkg/models包,xxxdriver.go需要基于驱动实现其函数。
//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的数据类型以及EdgeX如何通过core-Command来对device发送命令。
- deviceResources的值是定义Device上传到deviceService中数据的类型;
- deviceCommands定义核心服务core-command能对设备进行的操作;
device-profile参数说明
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)添加预定义设备
可以支持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的值对应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秒发送一次
OnChange = false
SourceName = "Switch" # 对应deviceCommands
配置文件的处理代码:https://github.com/edgexfoundry/go-mod-core-contracts/tree/main/models
6)修改device service配置文件
路径:cmd/device-xxx/res/configuration.toml
功能
- 定义设备微服务的host、port等
- 定义使用Registry的host、port
- 定义edgex core-data和core-metadata等服务的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" # /// 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)编译及执行工程
$ 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
# 执行文件为cmd/device-simple/device-simple
运行可执行文件
# 关闭安全模式
$ export EDGEX_SECURITY_SECRET_STORE=false
# 由于edgex服务组件使用容器以bridge网络启动,因此需要修改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" # 加载服务配置文件
msg="Using local configuration from file (0 envVars overrides applied)"
msg="Web server starting (localhost:59999)" # 微服务开启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添加设备
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)构建镜像
cd ~/edgexfoundry/device-simple
make build
make docker
# 在docker-compose-no-secty.yml中添加微服务,并执行
docker-compose -f docker-compose-no-secty.yml up -d
docker-compose.yml样例
- 添加到edgex核心服务的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
用于微服务的启动
// 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()) // 调用pkg/service/main.go的Main函数
}
2)pkg/service
// main.go
func Main(serviceName string, serviceVersion string, proto interface{}, ctx context.Context, cancel context.CancelFunc, router *mux.Router) {
...
bootstrap.Run( // 执行github.com/edgexfoundry/go-mod-bootstrap/bootstrap/bootstrap.go的Run函数
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
实现coreCommand、protocoldriver与protocoldiscovery的相关接口,负责设备驱动与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
}