EdgeX 2.0-Ireland 使用說明

一、安裝edgex 2.0

1.使用docker-compose.yml啟動[推薦]

參考:https://docs.edgexfoundry.org/2.0/getting-started/quick-start/

1)預(yù)裝docker及docker-compose

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容器可以被外部設(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è)備進行的操作蜜猾;

device-profile參數(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
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雄人,隨后出現(xiàn)的幾起案子从橘,更是在濱河造成了極大的恐慌,老刑警劉巖础钠,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恰力,死亡現(xiàn)場離奇詭異,居然都是意外死亡旗吁,警方通過查閱死者的電腦和手機踩萎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來很钓,“玉大人香府,你說我怎么就攤上這事÷刖耄” “怎么了企孩?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長袁稽。 經(jīng)常有香客問我勿璃,道長,這世上最難降的妖魔是什么推汽? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任补疑,我火速辦了婚禮,結(jié)果婚禮上歹撒,老公的妹妹穿的比我還像新娘莲组。我一直安慰自己,他們只是感情好栈妆,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布胁编。 她就那樣靜靜地躺著,像睡著了一般鳞尔。 火紅的嫁衣襯著肌膚如雪嬉橙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天寥假,我揣著相機與錄音市框,去河邊找鬼。 笑死糕韧,一個胖子當著我的面吹牛枫振,可吹牛的內(nèi)容都是我干的喻圃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼粪滤,長吁一口氣:“原來是場噩夢啊……” “哼斧拍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杖小,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤肆汹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后予权,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昂勉,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年扫腺,在試婚紗的時候發(fā)現(xiàn)自己被綠了岗照。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡笆环,死狀恐怖攒至,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咧织,我是刑警寧澤嗓袱,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站习绢,受9級特大地震影響渠抹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜闪萄,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一梧却、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧败去,春花似錦放航、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吓妆,卻和暖如春赊时,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背行拢。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工祖秒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓竭缝,卻偏偏與公主長得像房维,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子抬纸,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容