为了实现它,你需要考虑以下:
当然博客不会贴出全部代码,重在(个人理解下的)功能框架,然后按需开发!
建立一个文件夹如: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.c
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SDK_LIB_DIR
case "$1" in
make)
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
参考阿里云方式,控制台以每个边缘网关为首向下拓展
#include /**< need definition of uint8_t */
#include /**< need definition of NULL */
#include /**< need definition of BOOL */
#include /**< if need printf */
#include
#include
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 ///
xx.yaml的修改需遵照设备服务提供的设备功能
官方对配置的介绍
其他配置的介绍
设备服务配置文件
配置文件中,主要关注AutoEvents项,配置它可以实现主动上报功能,这个可以自行运行demo测试
[Service]
Port = 50001
Timeout = 5000
ConnectRetries = 10
Labels = [ '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 = false
Discovery = false
MaxCmdOps = 128
MaxCmdResultLen = 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 = 1883
User = ''
Password = ''
ClientId = 1
Topic = ''
SubTopic = 'subcribe_test'
PubTopic = 'publish_test'
[[DeviceList.AutoEvents]]
Resource = 'temperature'
OnChange = false
Frequency = '10s'
[[DeviceList.AutoEvents]]
Resource = 'run_state'
OnChange = true
Frequency = '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 = 9600
DataBits = 8
StopBits = 1
Parity = 'N'
UnitID = 1
[[DeviceList.AutoEvents]]
Resource = 'temperature'
OnChange = false
Frequency = '10s'
[[DeviceList.AutoEvents]]
Resource = 'humidity'
OnChange = true
Frequency = '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 = 9600
DataBits = 8
StopBits = 1
Parity = 'N'
UnitID = 2
[[DeviceList.AutoEvents]]
Resource = 'temperature'
OnChange = false
Frequency = '10s'
[[DeviceList.AutoEvents]]
Resource = 'humidity'
OnChange = true
Frequency = '15000ms'
/*获取 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);
上传设备配置文件即物模型,如遇以下情况,请检查:
./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.
控制台状态
设备服务,与下级温湿度设备存在
以上为建立一个新设备的过程
1
设备资源
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 解析二进制数据,然后根据设备资源属性中定义的值类型转换值。
name: humidity
description: "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: temperature
description: "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: humidity
description: "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: humiditymin
description: "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: temperaturemin
description: "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: humiditymax
description: "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: temperaturemax
description: "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: temperatureHI
description: "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: humidityHI
description: "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: temperatureLOW
description: "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: humidityLOW
description: "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_state
description: "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_device
get:
- { 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_all
get:
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: temperature
get:
path: "/api/v1/device/{deviceId}/temperature"
responses:
-
code: "200"
description: "Get the temperature reading."
expectedValues: ["temperature"]
-
code: "503"
description: "service unavailable"
expectedValues: []
-
name: humidity
get:
path: "/api/v1/device/{deviceId}/humidity"
responses:
-
code: "200"
description: "Get the humidity reading."
expectedValues: ["humidity"]
-
code: "503"
description: "service unavailable"
expectedValues: []
-
name: temperaturemin
get:
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: humiditymin
get:
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: temperaturemax
get:
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: humiditymax
get:
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: temperatureHI
get:
path: "/api/v1/device/{deviceId}/temperatureHI"
responses:
-
code: "200"
description: "Get the temperatureHI reading."
expectedValues: ["temperatureHI"]
-
code: "503"
description: "service unavailable"
expectedValues: []
-
name: humidityHI
get:
path: "/api/v1/device/{deviceId}/humidityHI"
responses:
-
code: "200"
description: "Get the humidityHI reading."
expectedValues: ["humidityHI"]
-
code: "503"
description: "service unavailable"
expectedValues: []
-
name: temperatureLOW
get:
path: "/api/v1/device/{deviceId}/temperatureLOW"
responses:
-
code: "200"
description: "Get the temperatureLOW reading."
expectedValues: ["temperatureLOW"]
-
code: "503"
description: "service unavailable"
expectedValues: []
-
name: humidityLOW
get:
path: "/api/v1/device/{deviceId}/humidityLOW"
responses:
-
code: "200"
description: "Get the humidityLOW reading."
expectedValues: ["humidityLOW"]
-
code: "503"
description: "service unavailable"
expectedValues: []
-
name: online_state
get:
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接口将调用设备驱动的接口
设备驱动你需要做的事:
其实边缘网关实现减轻云端压力,释放边缘端的计算能力,最终各种算法的部署(更多种情况数据分析那种利用云端处理例如阿里,你上报的数据在云端数据库存储,它提供云计算服务你缴费.!),计算对于我来说就是一种设备,这个设备可以是虚拟的、也可是真实的