EdgeX 2.0-Ireland 使用说明

一、安装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 
image
  • 注意:如果需要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
}

你可能感兴趣的:(EdgeX 2.0-Ireland 使用说明)