为了充分利用domoticz平台的对MQTT客户端的控制功能,现在,受控设备端代码的核心任务转移到了对domoticz/out主题的MQTT消息解析上。本文将设计一个简单框架来实现对其消息的解析和功能回调。
一、对消息参数名字稍作研究。
domoticz/out的MQTT消息格式参考:
https://www.domoticz.com/wiki/MQTT
根据官方资料,并没有指明参数个数。
实际上看domoticz-3.5877版本源代码,可以在domoticz-3.5877/hardware/MQTT.cpp中看出,
domoticz/out消息大概有两类:
1、普通设备信息。
在void MQTT::SendDeviceInfo(const int m_HwdID, const unsigned long long DeviceRowIdx, const std::string &DeviceName, const unsigned char *pRXCommand)
中进行封装。
我们的开关设备也就在这里封装的。
从这段代码中可以看到:
有10个参数名字是固定的
["idx"]
["id"]
["unit"]
["name"]
["dtype"]
["stype"]
["switchType"]
["RSSI"]
["Battery"]
["nvalue"]
还有个参数名字不固定:
"svalue"
它可以是以后缀1为开头:"svalue1" 或者"svalue2"、……"svalue(n)"
这意味着参数数量总体是不固定的。
我们实际的开关量收到的消息如下:
{
"Battery" : 255,
"RSSI" : 12,
"dtype" : "Light/Switch",
"id" : "00014051",
"idx" : 1,
"name" : "LED鐏,
"nvalue" : 1,
"stype" : "Switch",
"svalue1" : "0",
"switchType" : "On/Off",
"unit" : 1
}
收到了"svalue1"。
要写出一个灵活的框架来适应svalue数量可变,还是有点难度的,先不做这么复杂的。
后文中将写一个能够接收名字固定的参数,再加上"svalue1" 、"svalue2" ,共处理12个参数类型。(或许有时间写个对"svalue"参数数量可变的处理函数?)
当然,domoticz源码是公开的,我们也可以在c++级别源代码上添加自己所需要的参数。
2、场景消息。
在
void MQTT::SendSceneInfo(const unsigned long long SceneIdx, const std::string &SceneName)
中进行封装的。
暂时没用到,暂不分析。
详情请参考相关资料和源代码。
二、编写一个简单的消息解析框架。
框架设计如下:
图中红色箭头的过程就是我们主要要实现的过程。
右边两个虚边框就是我们设计的框架。
具体实现代码如下:
CommonTypes.h:
/******************************************************************************
*filename: CommonTypes.h
******************************************************************************/
#ifndef COMMON_TYPES_H
#define COMMON_TYPES_H
#ifdef __cplusplus
extern "C"
{
#endif
//------------------------------------------------------------------------------
//common defines
#define KEY_IDX 0
#define KEY_NAME 1
#define KEY_ID 2
#define KEY_UINT 3
#define KEY_DTYPE 4
#define KEY_STYPE 5
#define KEY_NVALUE 6
#define KEY_SVALUE1 7
#define KEY_SVALUE2 8
#define KEY_BATTERY 9
#define KEY_RSSI 10
#define KEY_SWITCH_TYPE 11
#define MSG_MAX_LEN 128
#define KEY_WORDS_NUM 12
//------------------------------------------------------------------------------
//common types
typedef enum
{
STRING=0,
INT=1,
UINT=2
}ARG_TYPE_t;
#ifdef __cplusplus
}
#endif
#endif /* #ifndef COMMON_TYPES_H */
/*-- File end --*/
/******************************************************************************
*filename: HardwareInterface.h
******************************************************************************/
#ifndef HARDWARE_INTERFACE_H
#define HARDWARE_INTERFACE_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "CommonTypes.h"
//------------------------------------------------------------------------------
//common Hardware interface
typedef struct
{
//解析出来的消息参数类型(STRING、INT、UINT中的一种)
ARG_TYPE_t type;
//下面是解析出来的具体消息参数数据
union
{
char strArg[MSG_MAX_LEN];
int iVar;
unsigned int uiVar;
};
}ParserArg;
typedef struct
{
//----------------respons parser interface----------------------------------
//int(*IDX_ParserCallback)(ParserArg* arg);//无需处理idx
int(*NAME_ParserCallback)(ParserArg* arg);
int(*ID_ParserCallback)(ParserArg* arg);
int(*UINT_ParserCallback)(ParserArg* arg);
int(*DTYPE_ParserCallback)(ParserArg* arg);
int(*STYPE_ParserCallback)(ParserArg* arg);
int(*NVALUE_ParserCallback)(ParserArg* arg);
int(*SVALUE1_ParserCallback)(ParserArg* arg);
int(*SVALUE2_ParserCallback)(ParserArg* arg);
int(*BATTERY_ParserCallback)(ParserArg* arg);
int(*RSSI_ParserCallback)(ParserArg* arg);
int(*SWITCH_TYPE_ParserCallback)(ParserArg* arg);
ParserArg parseArg;
int RegisterIDX;
//--------------device base operation---------------------------------------
//must be implement
int (*Open)();
void (*Init)();
void (*Close)();
}Hardware;
typedef int(*ParserCallback)(ParserArg* arg);
#ifdef __cplusplus
}
#endif
#endif /* #ifndef HARDWARE_INTERFACE_H */
/*-- File end --*/
HardwareControl.h:
/******************************************************************************
* filename: HardwareControl.h
*****************