边缘计算开源框架EdgeXFoundry的部署应用开发(三)设备服务开发

  • 使用SDK开发真实设备接入服务
    • 着手编写一个温湿度设备接入
      • 准备相关文件及目录
      • 脚本可选,用于单文件编译测试
    • 编写温湿度设备接入设备服务
      • 功能框架
        • 设备名的解析
        • 配置文件xx.yaml和configuration.toml
        • 获取数据接口中的参数使用
        • 编译
        • 运行
      • 假定一个实际需求
      • 定义它设备配置文件
        • 设备配置文件定义的一些关系
        • 浮点数精度问题
      • 设备驱动

整个EdgeXFoundry框架整体功能来说是比较全面的,但是也只是框架而已,具体的边缘计算实现的功能:各类传感器数据的上报、各类算法的部署、各类数据的流转、各种场景的控制等等皆须要设备服务的实现

为了实现它,你需要考虑以下:

  • 设备驱动的扩展性
  • 数据的完整及安全性
  • 部署的简易性
  • 设备服务性能(容量、速度、兼容)

使用SDK开发真实设备接入服务

当然博客不会贴出全部代码,重在(个人理解下的)功能框架,然后按需开发!

着手编写一个温湿度设备接入

准备相关文件及目录

建立一个文件夹如:temperature-device-driver

mkdir temperature-device-driver && cd temperature-device-driver

建立device-temperature.c文件、建立res目录

脚本可选,用于单文件编译测试

temperature-device-driver目录下建立build.sh脚本文件,内容如下:

#!/bin/sh#定义SDK源码头文件目录
SDK_INC_DIR=/home/aron566/Workspace/C_SDK/device-sdk-c/include#定义SDK动态库文件目录
SDK_LIB_DIR=/home/aron566/Workspace/C_SDK/device-sdk-c/build/release/_CPack_Packages/Linux/TGZ/csdk-1.3.0/lib#定义编译生成的APP名称
TARGET_APP_NAME=device_driver#定义源码文件名称
SOURCE_FILE_NAME=device_driver.cexport LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_LIB_DIRcase "$1" inmake)gcc -I$SDK_INC_DIR -L$SDK_LIB_DIR -o $TARGET_APP_NAME $SOURCE_FILE_NAME -lcsdk;;run)./$TARGET_APP_NAME -c res;;*)echo "Usage: $0 {make|run}"exit 1
esac

添加可执行权限

sudo chmod +x build.sh

编写温湿度设备接入设备服务

功能框架

参考阿里云方式,控制台以每个边缘网关为首向下拓展

  • 边缘网关,运行设备服务,并预先编写好设备配置文件与服务配置文件部署到网关并建立服务
  • 控制台中设备服务列表代表着不同功能的边缘网关,实际就是多协议支持的网关服务
  • 遵照驱动中支持的通讯协议设备,由控制台端编写不同的设备配置文件(modbus温度传感器、光照等各类型传感器或者其他自定义协议设备)
  • 动态部署使用,在控制台的上级网关的设备服务下建立设备,为其配置特定设备配置文件及其他参数,特别指定设备名(协议-位置信息(应包含上级网关信息+地理位置)-设备名(可重复)-地址号或者序号(同名设备不可重复),这里设备配置即物模型可以下发给网关也可以不下发由设备服务自动获取控制台端的设备配置文件
  • 控制台创建号设备信息后,通过已正常通讯的上级网关设备服务下发更新后的设备驱动库文件到远程网关,给设备服务调用,完成动态加载设备驱动。
  • 完成驱动的更新下发后,下发新增设备后的服务配置文件即configuration.toml文件
    这样后台浏览设备易于查看:物理通讯TOPO关系、通讯地址及协议、地理区域信息。

设备名的解析

#include <stdint.h> /**< need definition of uint8_t */
#include <stddef.h> /**< need definition of NULL    */
#include <stdbool.h>/**< need definition of BOOL    */
#include <stdio.h>  /**< if need printf             */
#include <stdlib.h>
#include <string.h>  typedef struct
{char protocol_str[64];      /**< 协议名*/char location_str[128];     /**< 设备位置信息*/char dev_type_name[64];     /**< 设备类型名称*/char dev_address[16];       /**< 设备地址号*/
}DEV_INFO_Typedef_t;int main(int argc ,char *argv[])
{DEV_INFO_Typedef_t dev_info;int ret = sscanf(argv[1], "'%[^-]-%[^-]-%[^-]-%[^']'", dev_info.protocol_str, dev_info.location_str, dev_info.dev_type_name, dev_info.dev_address);if(ret != 4){printf("parse dev_name error.\r\n");return -1;}else{printf("proto:%s\t\t location_str:%s\t\tdev_type_name:%s\t\tdev_address:%s\n",dev_info.protocol_str, dev_info.location_str, dev_info.dev_type_name, dev_info.dev_address);return 0;}
}

测试

#编译运行测试
gcc test.c
sudo chmod +x a.out
./a.out "'modbus_rtu-01_hangzhou-temperature_device-1'"

记住,完善接口即可
以下代码中,我已将设备服务设备驱动分离,即设备驱动为动态库方式存在
设备服务的需求:获取设备数据、控制设备、更新设备
设备驱动的功能:提供数据获取接口、提供控制设备接口、提供更新设备接口

/**                                                                            *  @file main_device_service.c                                                   *                                                                              *  @date 2020年11月08日 11:14:06 星期天**  @author aron566**  @copyright None**  @brief EdgeXFoudry 设备服务驱动.**  @details Pseudo-device service illustrating resource aggregation using C SDK .**  @version V1.0*/
#ifdef __cplusplus ///<use C compiler
extern "C" {#endif
/** Includes -----------------------------------------------------------------*/
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/inotify.h>
#include <sys/select.h>
#include <sys/stat.h>
/* Private includes ----------------------------------------------------------*/
#include "devsdk/devsdk.h"
#include "main_device_service.h"
/** Private typedef ----------------------------------------------------------*/typedef struct custom_device_driver
{iot_logger_t * lc;
} custom_device_driver;
/** Private macros -----------------------------------------------------------*/
#define ERR_CHECK(x) if(x.code){fprintf(stderr, "Error: %d: %s\n", x.code, x.reason); devsdk_service_free (service); free (impl); return x.code;}
#define ERR_BUFSZ 1024
#define ERR_CUSTOM_DEVICE_WRITE "PUT called for custom_device device. This is a read-only device."
#define ERR_CUSTOM_DEVICE_NO_PARAM "No parameter attribute in GET request."/** Private constants --------------------------------------------------------*/
/** Public variables ---------------------------------------------------------*/
/** Private variables --------------------------------------------------------*//** Private function prototypes ----------------------------------------------*/
/*初始化设备服务*/
static bool custom_device_init(void * impl, struct iot_logger_t * lc, const iot_data_t * config);
/*响应GET请求*/
static bool custom_device_get_handler(void * impl, const char * devname,const devsdk_protocols * protocols,uint32_t nreadings,const devsdk_commandrequest * requests,devsdk_commandresult * readings,const devsdk_nvpairs * qparams,iot_data_t ** exception);
/*响应PUT请求*/
static bool custom_device_put_handler(void * impl, const char * devname, const devsdk_protocols * protocols,uint32_t nvalues,const devsdk_commandrequest * requests,const iot_data_t * values[],iot_data_t ** exception);
/*响应重置请求*/
static void custom_device_reconfigure(void *impl, const iot_data_t *config);
/*响应发现请求*/
static void custom_device_discover(void *impl);
/*响应停止请求*/
static void custom_device_stop(void * impl, bool force);
/** Private user code --------------------------------------------------------*/
/** Private application code -------------------------------------------------*/
/*******************************************************************************
*
*       Static code
*
********************************************************************************
*/
/*** @brief Function called during service start operation.* @param impl The context data passed in when the service was created.* @param lc A logging client for the device service.* @param config A string map containing the configuration specified in the service's "Driver" section.* @return true if the operation was successful, false otherwise.*/
static bool custom_device_init(void * impl, struct iot_logger_t * lc, const iot_data_t * config)
{custom_device_driver * driver = (custom_device_driver *)impl;driver->lc = lc;/*初始化设备驱动*/device_driver_opt_init(lc, config);return true;
}/*** @brief Callback issued to handle GET requests for device readings.* @param impl The context data passed in when the service was created.* @param devname The name of the device to be queried.* @param protocols The location of the device to be queried.* @param nreadings The number of readings requested.* @param requests An array specifying the readings that have been requested.* @param readings An array in which to return the requested readings.* @param qparams Query Parameters which were set for this request.* @param exception Set this to an IOT_DATA_STRING to give more information if the operation fails.* @return true if the operation was successful, false otherwise.*/
static bool custom_device_get_handler(void * impl,                            /**< 自定义数据*/const char * devname,                   /**< 设备名称*/const devsdk_protocols * protocols,     /**< 请求设备所归属的协议*/uint32_t nreadings,                     /**< 请求类型的数量*/const devsdk_commandrequest * requests, /**< 请求参数列表*/devsdk_commandresult * readings,        /**< 返回结果给Edge控制台*/const devsdk_nvpairs * qparams,         /**< 请求的附加参数*/iot_data_t ** exception)                /**< 返回请求结果说明信息*/
{int ret = 0;const char *param;custom_device_driver * driver = (custom_device_driver *) impl;for(uint32_t i = 0; i < nreadings; i++){/*获取GET参数*//*参数来自.yaml中deviceResources列表中attributes项parameter键值*/param = devsdk_nvpairs_value (requests[i].attributes, "parameter");if(param == NULL){iot_log_error (driver->lc, ERR_CUSTOM_DEVICE_NO_PARAM);* exception = iot_data_alloc_string (ERR_CUSTOM_DEVICE_NO_PARAM, IOT_DATA_REF);return false;}ret = device_driver_opt_get(devname, param, &readings[i], driver->lc);if(ret != 0){iot_log_error(driver->lc, "get dev: %s par: error.", devname, param);}}return true;
}/*** @brief Callback issued to handle PUT requests for setting device values.* @param impl The context data passed in when the service was created.* @param devname The name of the device to be queried.* @param protocols The location of the device to be queried.* @param nvalues The number of set operations requested.* @param requests An array specifying the resources to which to write.* @param values An array specifying the values to be written.* @param exception Set this to an IOT_DATA_STRING to give more information if the operation fails.* @return true if the operation was successful, false otherwise.*/
static bool custom_device_put_handler(void * impl,const char * devname,const devsdk_protocols * protocols,uint32_t nvalues,const devsdk_commandrequest * requests,const iot_data_t * values[],iot_data_t ** exception)
{int ret = 0;const char *param;custom_device_driver * driver = (custom_device_driver *) impl;for(uint32_t i = 0; i < nvalues; i++){param = devsdk_nvpairs_value (requests[i].attributes, "parameter");if(param == NULL){iot_log_error (driver->lc, ERR_CUSTOM_DEVICE_NO_PARAM);* exception = iot_data_alloc_string (ERR_CUSTOM_DEVICE_NO_PARAM, IOT_DATA_REF);continue;}/*设置请求*/ret = device_driver_opt_set(devname, param, values[i], driver->lc);if(ret != 0){iot_log_error(driver->lc, "set dev: %s par: error.", devname, param);}}return true;
}/*** @brief Function called when configuration is updated.* @param impl The context data passed in when the service was created.* @param config A string map containing the new configuration.*/
static void custom_device_reconfigure(void *impl, const iot_data_t *config)
{custom_device_driver * driver = (custom_device_driver *) impl;device_driver_opt_reconfigure(driver->lc, config);
}/*** @brief Optional callback for dynamic discovery of devices. The implementation should detect devices and register them using*        the devsdk_add_device API call.* @param impl The context data passed in when the service was created.*/
static void custom_device_discover(void *impl)
{custom_device_driver * driver = (custom_device_driver *) impl;device_driver_opt_discover(driver->lc);
}/*** @brief Callback issued during device service shutdown. The implementation should stop processing and release any resources that were being used.* @param impl The context data passed in when the service was created.* @param force A 'force' stop has been requested. An unclean shutdown may be performed if necessary.*/
static void custom_device_stop(void *impl, bool force)
{/* Stop performs any final actions before the device service is terminated */custom_device_driver * driver = (custom_device_driver *) impl;device_driver_opt_stop(driver->lc, force);
}/** Public application code --------------------------------------------------*/
/*******************************************************************************
*
*       Public code
*
********************************************************************************
*/
/*** @brief 设备服务驱动入口*/
int main (int argc, char * argv[])
{sigset_t set;int sigret;custom_device_driver * impl = malloc (sizeof (custom_device_driver));impl->lc = NULL;devsdk_error e;e.code = 0;devsdk_callbacks custom_deviceImpls ={custom_device_init,         /* Initialize */custom_device_reconfigure,  /* Reconfigure */custom_device_discover,     /* Discovery */custom_device_get_handler,  /* Get */custom_device_put_handler,  /* Put */custom_device_stop          /* Stop */};devsdk_service_t * service = devsdk_service_new("device-custom_device", "1.0", impl, custom_deviceImpls, &argc, argv, &e);ERR_CHECK (e);int n = 1;while (n < argc){if (strcmp (argv[n], "-h") == 0 || strcmp (argv[n], "--help") == 0){printf ("Options:\n");printf ("  -h, --help\t\t\tShow this text\n");return 0;}else{printf ("%s: Unrecognized option %s\n", argv[0], argv[n]);return 0;}}devsdk_service_start (service, NULL, &e);ERR_CHECK (e);sigemptyset (&set);sigaddset (&set, SIGINT);sigprocmask (SIG_BLOCK, &set, NULL);sigwait (&set, &sigret);sigprocmask (SIG_UNBLOCK, &set, NULL);devsdk_service_stop (service, true, &e);ERR_CHECK (e);devsdk_service_free (service);free (impl);return 0;
}#ifdef __cplusplus ///<end extern c
}
#endif
/******************************** End of file *********************************/

配置文件xx.yaml和configuration.toml

xx.yaml的修改需遵照设备服务提供的设备功能
官方对配置的介绍
其他配置的介绍

设备服务配置文件
配置文件中,主要关注AutoEvents项,配置它可以实现主动上报功能,这个可以自行运行demo测试

[Service]Port = 50001Timeout = 5000ConnectRetries = 10Labels = [ 'MQTT_Protocol' ,'MODBUS_Protocol' ]StartupMsg = 'mqtt modbus device service started'CheckInterval = '10s'[Clients][Clients.Data]Host = 'localhost'Port = 48080[Clients.Metadata]Host = 'localhost'Port = 48081[Device]DataTransform = falseDiscovery = falseMaxCmdOps = 128MaxCmdResultLen = 256[Logging]LogLevel = 'DEBUG'[[DeviceList]]Name = 'mqtt-gateway_01_hangzhou-gateway_device-1'Profile = 'mqtt_gateway_device_profile'Description = 'An gatway device'[DeviceList.Protocols][DeviceList.Protocols.mqtt]Schema = 'tcp'Host = 'localhost'Port = 1883User = ''Password = ''ClientId = 1Topic = ''SubTopic = 'subcribe_test'PubTopic = 'publish_test'[[DeviceList.AutoEvents]]Resource = 'temperature'OnChange = falseFrequency = '10s'[[DeviceList.AutoEvents]]Resource = 'run_state'OnChange = trueFrequency = '15000ms'[[DeviceList]]Name = 'modbus_rtu-gateway_01_hangzhou-temperature_device-1'Profile = 'modbus_temperature_device_profile'Description = 'An temperature device'[DeviceList.Protocols][DeviceList.Protocols.modbus-rtu]Address = '/tmp/slave'BaudRate = 9600DataBits = 8StopBits = 1Parity = 'N'UnitID = 1[[DeviceList.AutoEvents]]Resource = 'temperature'OnChange = falseFrequency = '10s'[[DeviceList.AutoEvents]]Resource = 'humidity'OnChange = trueFrequency = '15000ms'[[DeviceList]]Name = 'modbus_rtu-gateway_01_hangzhou-temperature_device-2'Profile = 'modbus_temperature_device_profile'Description = 'An temperature device'[DeviceList.Protocols][DeviceList.Protocols.modbus-rtu]Address = '/tmp/slave'BaudRate = 9600DataBits = 8StopBits = 1Parity = 'N'UnitID = 2[[DeviceList.AutoEvents]]Resource = 'temperature'OnChange = falseFrequency = '10s'[[DeviceList.AutoEvents]]Resource = 'humidity'OnChange = trueFrequency = '15000ms'

获取数据接口中的参数使用

如下是一个温湿度的设备配置文件,当一个get请求过来

/*获取 parameter: "temperature" 中temperature字符串*/
const char *param = devsdk_nvpairs_value (requests[i].attributes, "parameter");/*获取 name: temperature 中temperature字符串*/
const char *name = requests[i].resname;/*获取数据类型*/
const iot_typecode_t type = *(requests[i].type);

上传设备配置文件即物模型,如遇以下情况,请检查:

  • 网络
  • 文件内容是否标准,因为是yaml格式特别注意空格对齐问题

编译

./build make

运行

运行可以使用脚本,当然需要在脚本中修改定义好变量

./build run

输出内容如下

aron566@MinT-machine:~/Workspace/custom_device_driver/build/devices_service$ ./custom-device -c res
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="iot_threadpool_alloc (threads: 8 max_jobs: 0 default_priority: -1 affinity: -1)"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-0 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-1 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-2 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-3 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-5 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-6 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-4 starting"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-0-7 starting"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="iot_scheduler_alloc (priority: -1 affinity: -1)"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="iot_threadpool_start()"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=TRACE ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread waiting for new job"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Setting LogLevel to DEBUG"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Starting device-custom_device device service, version 1.0"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="EdgeX device SDK for C, version 1.3.0"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service configuration follows:"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/Host="MinT-machine""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/Port=50000"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/Timeout=5000"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/ConnectRetries=10"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/StartupMsg="mqtt modbus device service started""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/CheckInterval="10s""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/Labels="""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Service/ServerBindAddr="""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/DataTransform=false"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/Discovery/Enabled=true"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/Discovery/Interval=0"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/MaxCmdOps=128"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/MaxCmdResultLen=256"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/ProfilesDir="res""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/UpdateLastConnected=false"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device/EventQLength=0"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Logging/LogLevel="DEBUG""
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Logging/EnableRemote=false"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Logging/File="""
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="iot_threadpool_alloc (threads: 1 max_jobs: 0 default_priority: -1 affinity: -1)"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Thread iot-1-0 starting"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Found core-data service at localhost:48080"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Found core-metadata service at localhost:48081"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Processing Device Profiles from res"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Checking existence of DeviceProfile mqtt_gateway_device_profile"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="DeviceProfile mqtt_gateway_device_profile already exists: skipped"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Checking existence of DeviceProfile modbus_temperature_device_profile"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="DeviceProfile modbus_temperature_device_profile already exists: skipped"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Starting HTTP server on interface MinT-machine, port 50000"
level=DEBUG ts=2020-11-28T16:49:17Z app=device-custom_device msg="Resolved interface is 2408:823c:815:3a8:5351:4fa2:768d:cd1c"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Processing DeviceList from configuration"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device mqtt-gateway_01_hangzhou-gateway_device-1 already exists: skipped"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device modbus_rtu-gateway_01_hangzhou-temperature_device-1 already exists: skipped"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="Device modbus_rtu-gateway_01_hangzhou-temperature_device-2 already exists: skipped"
level=INFO ts=2020-11-28T16:49:17Z app=device-custom_device msg="start device driver now."
Name = mqtt-gateway_01_hangzhou-gateway_device-1
gatway device register.
Name = modbus_rtu-gateway_01_hangzhou-temperature_device-1
temperature device register.
Name = modbus_rtu-gateway_01_hangzhou-temperature_device-2
temperature device register.

控制台状态
设备服务,与下级温湿度设备存在

以上为建立一个新设备的过程

假定一个实际需求

  • 协议:modbus-rtu,很常见
  • 设备:温湿度设备,很常见
  • 设备自身可提供的数值信息:温度、湿度
  • 设备地址:modbus地址1
  • 读取数据发送:0x01,0x03,0x00,0x00,0x00,0x02,0xc4,0x0b
  • 需要提供的功能:1、读取设备温湿度数据2、可设定温湿度数值的上下限3、可提供报警功能(掉线报警、高低温、高低湿度报警)

定义它设备配置文件

设备资源

  • 温度参数
  • 湿度参数
  • 温度报警值设定(分高低)
  • 湿度报警值设定(分高低)
  • 设备在线状态
  • 设备事件(高低温事件和高低湿度事件)

设备配置文件定义的一些关系

coreCommands 里面的name就是UI平台上的标签,并无多大意义
定义coreCommands 的path: “/api/v1/device/{deviceId}/modbus_temperature_device” modbus_temperature_device必须是个资源名称
可以是deviceResources里面的name的值
也可以是deviceCommands里面name的值
deviceCommands里面get/set 只能是deviceResources里面的name

浮点数精度问题

如果 rawType 属性存在,设备服务将根据定义的 rawType 解析二进制数据,然后根据设备资源属性中定义的值类型转换值。

  • 比如设备读取的湿度寄存器值为52,实际为52%
  • 依据下面配置则,52 以二进制数读取,存储类型为INT16,之后转为浮点数乘上0.01给设备服务

    name: humiditydescription: "humidity realtime value"attributes:{ parameter: "humidity", rawType: "INT16" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00", scale: "0.01"}units:{ type: "String", readWrite: "R", defaultValue: "%RH"}

我的温湿度设备配置文件如下,其实还是可以写寄存器地址给设备驱动读取

name: "modbus_temperature_device_profile"
manufacturer: "IoTechSystems"
model: "IoT6"
description: "Temperature & Humidity Device Profile"
labels:- "temperature_sensor"- "modbus_protocol"deviceResources:-name: temperaturedescription: "temperature realtime value"attributes:{ parameter: "temperature" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "degrees Celsius"}-name: humiditydescription: "humidity realtime value"attributes:{ parameter: "humidity" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "%RH"}-name: humiditymindescription: "humidity min value"attributes:{ parameter: "humiditymin" }properties:value:{ type: "Float32", size: "4", readWrite: "RW", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "%RH"}-name: temperaturemindescription: "temperature min value"attributes:{ parameter: "temperaturemin" }properties:value:{ type: "Float32", size: "4", readWrite: "RW", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "degrees Celsius"}-name: humiditymaxdescription: "humidity max value"attributes:{ parameter: "humiditymax" }properties:value:{ type: "Float32", size: "4", readWrite: "RW", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "%RH"}-name: temperaturemaxdescription: "temperature max value"attributes:{ parameter: "temperaturemax" }properties:value:{ type: "Float32", size: "4", readWrite: "RW", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "degrees Celsius"}-name: temperatureHIdescription: "temperature max value is arrived"attributes:{ parameter: "temperatureHI" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "degrees Celsius"}-name: humidityHIdescription: "humidity max value is arrived"attributes:{ parameter: "humidityHI" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "%RH"}-name: temperatureLOWdescription: "temperature low value is arrived"attributes:{ parameter: "temperatureLOW" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "degrees Celsius"}-name: humidityLOWdescription: "humidity low value is arrived"attributes:{ parameter: "humidityLOW" }properties:value:{ type: "Float32", size: "4", readWrite: "R", defaultValue: "0.00", minimum: "-1000.00", maximum: "1000.00" }units:{ type: "String", readWrite: "R", defaultValue: "%RH"}-name: online_statedescription: "device online state"attributes:{ parameter: "online_state" }properties:value:{ type: "int32", size: "4", readWrite: "R", defaultValue: "0", minimum: "0", maximum: "1" }units:{ type: "String", readWrite: "R", defaultValue: "leave time"}deviceCommands:-name: modbus_temperature_deviceget:- { deviceResource: "temperature" }- { deviceResource: "humidity" }- { deviceResource: "temperaturemin" }- { deviceResource: "humiditymin" }- { deviceResource: "temperaturemax" }- { deviceResource: "humiditymax" }- { deviceResource: "online_state" }set:- { deviceResource: "temperaturemin" }- { deviceResource: "humiditymin" }- { deviceResource: "temperaturemax" }- { deviceResource: "humiditymax" }
coreCommands:-name: get_temperature_device_allget:path: "/api/v1/device/{deviceId}/modbus_temperature_device"responses:- code: "200"description: "Successfully read the modbus_temperature_device sensors."expectedValues: [ "modbus_temperature_device" ]#expectedValues: [ "temperature", "humidity", "temperaturemin", "humiditymin", "temperaturemax", "humiditymax", "online_state" ]- code: "503"description: "service unavailable"expectedValues: []put:path: "/api/v1/device/{deviceId}/modbus_temperature_device"parameterNames: [ "temperaturemin", "humiditymin", "temperaturemax", "humiditymax" ]responses:- code: "200"description: "Successfully set the temperaturemin and humiditymin."expectedValues: []- code: "503"description: "service unavailable"expectedValues: []-name: temperatureget:path: "/api/v1/device/{deviceId}/temperature"responses:-code: "200"description: "Get the temperature reading."expectedValues: ["temperature"]-code: "503"description: "service unavailable"expectedValues: []-name: humidityget:path: "/api/v1/device/{deviceId}/humidity"responses:-code: "200"description: "Get the humidity reading."expectedValues: ["humidity"]-code: "503"description: "service unavailable"expectedValues: []-name: temperatureminget:path: "/api/v1/device/{deviceId}/temperaturemin"responses:- code: "200"description: "Get the temperaturemin value."expectedValues: ["temperaturemin"]- code: "503"description: "service unavailable"expectedValues: []put:path: "/api/v1/device/{deviceId}/temperaturemin"parameterNames: ["temperaturemin"]responses:- code: "200"description: "Successfully set the temperaturemin value."expectedValues: []- code: "503"description: "service unavailable"expectedValues: []-name: humidityminget:path: "/api/v1/device/{deviceId}/humiditymin"responses:- code: "200"description: "Get the humiditymin value."expectedValues: ["humiditymin"]- code: "503"description: "service unavailable"expectedValues: []put:path: "/api/v1/device/{deviceId}/humiditymin"parameterNames: ["humiditymin"]responses:- code: "200"description: "Successfully set the humiditymin value."expectedValues: []- code: "503"description: "service unavailable"expectedValues: []-name: temperaturemaxget:path: "/api/v1/device/{deviceId}/temperaturemax"responses:- code: "200"description: "Get the temperaturemax value."expectedValues: ["temperaturemax"]- code: "503"description: "service unavailable"expectedValues: []put:path: "/api/v1/device/{deviceId}/temperaturemax"parameterNames: ["temperaturemax"]responses:- code: "200"description: "Successfully set the temperaturemax value."expectedValues: []- code: "503"description: "service unavailable"expectedValues: []-name: humiditymaxget:path: "/api/v1/device/{deviceId}/humiditymax"responses:- code: "200"description: "Get the humiditymax value."expectedValues: ["humiditymax"]- code: "503"description: "service unavailable"expectedValues: []put:path: "/api/v1/device/{deviceId}/humiditymax"parameterNames: ["humiditymax"]responses:- code: "200"description: "Successfully set the humiditymax value."expectedValues: []- code: "503"description: "service unavailable"expectedValues: []-name: temperatureHIget:path: "/api/v1/device/{deviceId}/temperatureHI"responses:-code: "200"description: "Get the temperatureHI reading."expectedValues: ["temperatureHI"]-code: "503"description: "service unavailable"expectedValues: []-name: humidityHIget:path: "/api/v1/device/{deviceId}/humidityHI"responses:-code: "200"description: "Get the humidityHI reading."expectedValues: ["humidityHI"]-code: "503"description: "service unavailable"expectedValues: []-name: temperatureLOWget:path: "/api/v1/device/{deviceId}/temperatureLOW"responses:-code: "200"description: "Get the temperatureLOW reading."expectedValues: ["temperatureLOW"]-code: "503"description: "service unavailable"expectedValues: []-name: humidityLOWget:path: "/api/v1/device/{deviceId}/humidityLOW"responses:-code: "200"description: "Get the humidityLOW reading."expectedValues: ["humidityLOW"]-code: "503"description: "service unavailable"expectedValues: []-name: online_stateget:path: "/api/v1/device/{deviceId}/online_state"responses:-code: "200"description: "Get the online state reading."expectedValues: ["online_state"]-code: "503"description: "service unavailable"expectedValues: []

出现如下错误请先检查参数配置文件中是否有问题

设备驱动

以上贴出的main_device_service.c实则实现设备服务,其内部get、put接口将调用设备驱动的接口
设备驱动你需要做的事:

  • 设备硬件初始化
  • 实现解析网关下挂载的设备类型信息
  • 实现取对应不同类型的硬件设备数据
  • 实现对不同硬件设备的控制
  • 实现事件功能(功能的延申)
  • 实现驱动更新功能(动态扩展)

其实边缘网关实现减轻云端压力,释放边缘端的计算能力,最终各种算法的部署(更多种情况数据分析那种利用云端处理例如阿里,你上报的数据在云端数据库存储,它提供云计算服务你缴费.!),计算对于我来说就是一种设备,这个设备可以是虚拟的、也可是真实的

边缘计算开源框架EdgeXFoundry的部署应用开发(三)设备服务开发相关推荐

  1. 边缘计算简介以及几款边缘计算开源平台

    边缘计算中的边缘(edge)指的是网络边缘上的计算和存储资源,这里的网络边缘与数据中心相对,无论是从地理距离还是网络距离上来看都更贴近用户.作为一种新的计算范式,边缘计算将计算任务部署于接近数据产生源 ...

  2. 2020十大边缘计算开源项目

    2020 年是非常特别的一年,各行各业都非常艰难,但是有一股力量逆势增长,不断迎来新的突破,那就是开源.即使是资本寒冬,一些开源公司如EMQ也能逆势融资,Rancher也能和SUSE强强联合,开源充满 ...

  3. 中国首个!百度云宣布边缘计算开源,发布智能边缘开源平台OpenEdge

    12月6日,在2018 ABC Inspire企业智能大会上,百度云正式发布百度智能边缘(Baidu IntelliEdge,BIE)开源版本OpenEdge,为中国第一个宣布边缘计算开源. 12月6 ...

  4. 5G边缘计算与电力设施融合部署模式探析

      摘要:  5G的频率高.波长短,单个5G基站的覆盖范围小,而5G边缘计算需靠近最终用户部署,意味5G边缘计算节点的建设数量将快速增长,建设成本高.运维管理难度大,电力设施要求靠近负荷中心的建设特点 ...

  5. 每日新闻:百度云宣布边缘计算开源,发布智能边缘开源平台;英特尔和华为成功完成SA架构的5G互操作性测试;优信淘宝打造二手车供应链...

    关注中国软件网 最新鲜的企业级干货聚集地 趋势洞察 周亮:支持利用大数据.云计算.人工智能等金融科技 银保监会副主席周亮在第九届财新峰会上表示:对金融创新既要积极鼓励,又要审慎对待,要及时弥补监管短板 ...

  6. 真香!全场景AI计算开源框架MindSpore,我爱了

    [摘要] 本文主要通过两个实际应用案例:一是基于本地 Jupyter Notebook 的 MNIST 手写数据识别:二是基于华为云服务器的 CIFAR-10 图像分类,对开源框架 MindSpore ...

  7. 云计算的五个基本特征、四种部署模型和三种服务模式

    五个基本特征 自助服务 使用者可以按需要获取云端的计算资源 广泛的网络访问 使用者可以随时随地使用云终端设备接入网络并使用云端的计算资源. 资源池化 计算资源汇集在一起,形成一个个CPU池.内存池等, ...

  8. 边缘计算框架_黑科技 | 英特尔发布边缘计算加速框架最新版本 | OpenVINO 2019R02...

    点击上方↑↑↑"OpenCV学堂"关注我 最新版本OpenVINO特性黑科技 概述 英特尔自从发布OpenVINO开发框架以来,因为其强大的模型转换与模型推理加速性能,迅速得了广大 ...

  9. 神级开源框架发布!Github排名前三,连Spring Cloud 都被干掉了!

    目前,但凡谈及微服务技术选型,就必然会遇到一个两难的抉择,到底该采用Dubbo,还是该选择Spring Cloud呢? 当初阿里于2017年宣布重新开源Dubbo,近年来Dubbo发展速度和势头可谓是 ...

最新文章

  1. Mybatis用#{}从传递过来的参数中取值
  2. v-charts加载动画_加载动画-用户体验写作练习
  3. modelsim 编译 xilinx库
  4. set和map去重调用什么方法_你真的了解ES6的Set,WeakSet,Map和WeakMap吗?
  5. office选项-》高级-》显示 中, 显示此数目的“最近使用的文档” 为灰色,无法更改
  6. mysql找不到sys_解决方法:①MySQL 闪退 ②服务列表里找不到MySQL ③MySQL服务无法启动...
  7. 开源操作系统年度盛会最新日程曝光,邀您一同开启烧脑模式!
  8. ue4渲染速度太慢_技术汇丨如何在UE4中实现最佳性能和高质量视觉效果
  9. 经典书单 —— 机器学习/深度学习/AI/CV/PGM
  10. verilog之编程应该注意的事项
  11. Java命名和java图标来由
  12. 机器心理学家:可能是未来唯一不会被AI取代的职业
  13. mysql红黑联盟_MySQL在Centos的卸载和安装 - MySQL - 红黑联盟
  14. idb 怎么回复mysql_MySQL删除idb文件引发的思考
  15. 1124 Raffle for Weibo Followers
  16. <一>Android Audio音频框架
  17. webQQ迷你版协议(基于http://w.qq.com)
  18. 三次握手四次挥手详解
  19. RPA机器人流程自动化(Robotic process automation)
  20. 特岗计算机老师年度总结,特岗教师工作总结

热门文章

  1. 记一次Kafka warning排查过程
  2. 软著申请时提取60页代码shell命令解析
  3. 使用 VMware 16 RHEL7.7 虚拟机静默安装 Oracle 19c RAC
  4. Muli3D 7 判断Ray与Sphere的关系
  5. STM32超低功耗入门之停止模式
  6. IOS 开发 iPhone屏幕尺寸、分辨率及适配
  7. python暴力破解zip加密文件
  8. 苹果平板可以用html么,哪些苹果平板可以用苹果笔
  9. springboot 集成 actuator
  10. Linux系统:我们的征途是星辰大海!