一.连接阿里云服务器测试
mqtt.fx测试与阿里云平台的连通。
可以参考博客 mqtt.fx实现与阿里云的通信 主要是记录一下mqtt连接参数和设备证书,mqtt.fx连接上云平台。并使用publish和subcribe进行订阅和发布具体实现参考上面博客。 记录下在云平台上的配置信息
客户ID
clientId
gv9vUe6QzX6.MQTT|securemode=2,signmethod=hmacsha256,timestamp=2524608000000|
用户名
username
MQTT&gv9vUe6QzX6
密码
passwd
34bde8763e13a25d2448e8594dc8a69650e05cf70c1fb8fa731ffeaedef95
mqtt的host
mqttHostUrl
iot-06z00gyvi020tfv.mqtt.iothub.aliyuncs.com
端口号
port
1883
ProductKey
gv9vUe6QzX6
DeviceName
MQTT
DeviceSecret
c6dd3dfb77d3f64b73475c7ee0880a74
发布主题
/sys/gv9vUe6QzX6/${deviceName}/thing/event/property/post
订阅主题
/sys/gv9vUe6QzX6/${deviceName}/thing/service/property/set
二.iniparser库介绍
为了实现代码复用性,我们把不同云平台的配置文件单独写成一个.ini配置文件,这样要解析配置文件中的信息就需要用到iniparser库函数。可以参考博客:iniparser库的安装和使用
三.CJSON库介绍
由于阿里云对消息的格式比较严格,需要打包成cJSON的格式才能正确获得数据,所以我们使用mosquito的APImosquitto库和mqtt介绍连接上阿里云后需要把数据打包成cJSON的格式再上传。这里需要用到cJSON库简介打包数据。
四.需要使用到的文件
首先是需要使用的到连接阿里云平台的配置信息.ini文件
[mqtt_server_addr]
host =iot-06z00gyvi020tfv.mqtt.iothub.aliyuncs.com
port =1883
[user_passwd]
username =MQTT&gv9vUe6QzX6
passwd =34bde8763e13a25d2448e8594dc8a69650e05cf70c1fb8fa731ffeaedef95
[client_id]
id =gv9vUe6QzX6.MQTT|securemode=2,signmethod=hmacsha256,timestamp=2524608000000|
[sub_topic]
topic =/sys/gv9vUe6QzX6/MQTT/thing/service/property/set
[pub_topic]
topic =/sys/gv9vUe6QzX6/MQTT/thing/event/property/post
[ali_json]
method =thing.service.property.set
id =1759550978
identifier =CurrentTemperature
version =1.0.0"
[KEEP_ALIVE]
alive =60
[ali_Qos]
Qos =0
由于需要解析配置文件我们自己写一个关于解析配置文件的头文件和c文件
#ifndef MQTT_CONF_H
#define MQTT_CONF_H
#define BUF_SIZE 512
/设置默认参数,假如没有传入参数就是用配置文件内的默认参数/
#define DEFAULT_CLIENTID "gv9vUe6QzX6.MQTT|securemode=2,signmethod=hmacsha256,timestamp=2524608000000|"
#define DEFAULT_USERNAME "MQTT&gv9vUe6QzX6"
#define DEFAULT_PASSWD "34bde8763e13a25d2448e8594dc8a69650e05cf70c1fb8fa731ffeaedd22ef95"
#define DEFAULT_HOSTNAME "iot-06z00gyvi020tfv.mqtt.iothub.aliyuncs.com"
#define DEFAULT_PORT 1883
#define DEFAULT_SUBTOPIC "/sys/gv9vUe6QzX6/MQTT/thing/service/property/set"
#define DEFAULT_PUBTOPIC "/sys/gv9vUe6QzX6/MQTT/thing/event/property/post"
#define DEFAULT_QOS 0
#define DEFAULT_METHOD "thing.service.property.set"
#define DEFAULT_JSONID "1759550978"
#define DEFAULT_IDENTIFIER "CurrentTemperature"
#define DEFAULT_VERSION "1.0.0.0"
#define KEEP_ALIVE 60
enum{
SUB,
PUB
};
typedef struct data_st_mqtt
{
char hostname[BUF_SIZE] ;
int port ;
char username[BUF_SIZE] ;
char passwd[BUF_SIZE] ;
char clientid[BUF_SIZE] ;
char topic[BUF_SIZE] ;
int Qos;
char method[BUF_SIZE] ;
char jsonid[BUF_SIZE] ;
char identifier[BUF_SIZE] ;
char version[BUF_SIZE] ;
}st_mqtt;
int gain_mqtt_conf(char *ini_path,st_mqtt *mqtt,int type);/获取配置参数的函数/
#include "iniparser.h"
#include "mqtt_conf.h"
#include <stdio.h>
#include <string.h>
int gain_mqtt_conf(char *ini_path,st_mqtt *mqtt,int type)
{
dictionary *ini=NULL;
const char *hostname;
const char *username;
int port;
const char *passwd;
const char *clientid;
const char *topic;
int Qos;
const char *method;
const char *jsonid;
const char *identifier;
const char *version;
if(!ini_path || !mqtt)
{
printf("invail input parameter in %s\n", __FUNCTION__) ;
return -1 ;
}
ini=iniparser_load(ini_path);
if( ini ==NULL)
{
printf("inipar_load failure\n");
return -1;
}
/这里我没有使用到参数解析,所以使用的全部是默认参数,也就是配置文件内的参数/
hostname =iniparser_getstring(ini, "mqtt_server_addr:host", DEFAULT_HOSTNAME);
port =iniparser_getint(ini,"mqtt_server_addr:port",DEFAULT_PORT);
username =iniparser_getstring(ini,"user_passwd:username",DEFAULT_USERNAME);
passwd =iniparser_getstring(ini,"user_passwd:passwd",DEFAULT_PASSWD);
clientid =iniparser_getstring(ini,"client_id:id",DEFAULT_CLIENTID);
identifier =iniparser_getstring(ini,"ali_json:identifier",DEFAULT_IDENTIFIER) ;
Qos =iniparser_getint(ini,"ali_Qos:Qos",DEFAULT_QOS);
if(type == SUB)
topic = iniparser_getstring(ini, "sub_topic:topic", DEFAULT_SUBTOPIC) ;
else if(type == PUB)
{
topic = iniparser_getstring(ini,"pub_topic:topic", DEFAULT_PUBTOPIC) ;
method = iniparser_getstring(ini,"json:method", DEFAULT_METHOD) ;
jsonid = iniparser_getstring(ini,"json:id", DEFAULT_JSONID) ;
version = iniparser_getstring(ini,"json:version", DEFAULT_VERSION) ;
}
mqtt->Qos=Qos;
strncpy(mqtt->hostname, hostname,BUF_SIZE);
mqtt->port = port;
strncpy(mqtt->username, username,BUF_SIZE);
strncpy(mqtt->passwd, passwd,BUF_SIZE);
strncpy(mqtt->clientid, clientid,BUF_SIZE);
strncpy(mqtt->topic, topic,BUF_SIZE);
if(type == PUB)
{
strncpy(mqtt->method, method,BUF_SIZE) ;
strncpy(mqtt->identifier, identifier,BUF_SIZE);
strncpy(mqtt->jsonid, jsonid,BUF_SIZE) ;
strncpy(mqtt->version, version,BUF_SIZE) ;
}
iniparser_freedict(ini);
return 0;
}
在文件夹下还需要包含解析配置文件的iniparser的.c和.h文件 还需要把获取到的数据打包成cJSON格式的.c和.h文件
五.流程图
做了上述准备,就可以开始构思整个流程了
六.代码实现测试
发布端代码
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <getopt.h>
#include <string.h>
#include <mosquitto.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <signal.h>
#include <time.h>
#include "mqtt_conf.h"
#include "cJSON.h"
#include "dictionary.h"
#include "iniparser.h"
#define PROG_VERSION "1.0.0"
#define INI_PATH "./mqtt_aliyun_conf.ini"
static int g_stop=0;
int get_temperature(float *temp);
int get_time(char *tim);
void pub_json_data(struct mosquitto *mosq,st_mqtt *mqt);
int main(int argc,char **argv)
{
int rv;
int port=1883;
char *hostname=NULL;
char *username=NULL;
char *clientid=NULL;
char *topic=NULL;
char *passwd=NULL;
char *program_name=basename(argv[0]);
int daemon_run=0;
st_mqtt mqtt;
struct mosquitto *mosq = NULL;
memset(&mqtt,0,sizeof(mqtt));
rv=gain_mqtt_conf(INI_PATH,&mqtt,PUB);
mosquitto_lib_init();
mosq = mosquitto_new(mqtt.clientid,true,(void *)&mqtt);
if(!mosq)
{
printf("mosquitto_new() failed: %s\n",strerror(errno));
goto cleanup;
return -1;
}
if(mosquitto_username_pw_set(mosq,mqtt.username,mqtt.passwd) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_username_pw_set failed: %s\n",strerror(errno));
goto cleanup;
}
if(mosquitto_connect(mosq, mqtt.hostname,mqtt.port,KEEP_ALIVE) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_connect() failed: %s\n",strerror(errno));
goto cleanup;
}
printf("connect successful\n");
while(!g_stop)
{
pub_json_data(mosq,&mqtt);
sleep(10);
}
cleanup:
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
int get_temperature(float *temp)
{
char w1_path[50]="/sys/bus/w1/devices/";
char f_name[50];
char buf[128];
char *data_p=NULL;
struct dirent *file=NULL;
DIR *dir=NULL;
int data_fd;
int found = -1;
if((dir=opendir(w1_path))<0)
{
printf("open w1_path failure:%s\n",strerror(errno));
return -1;
}
while((file=readdir(dir))!=NULL)
{
if(strstr(file->d_name,"28-"))
{
strncpy(f_name,file->d_name,sizeof(f_name));
found=1;
}
}
closedir(dir);
if(!found)
{
printf("can not found the folder\n");
return 0;
}
strncat(w1_path, f_name, sizeof(w1_path)-strlen(w1_path));
strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));
data_fd=open(w1_path,O_RDONLY);
if(data_fd<0)
{
printf("open file failure: %s\n",strerror(errno));
return -2;
}
memset(buf,0,sizeof(buf));
if(read(data_fd,buf,sizeof(buf))<0)
{
printf("read temperature from w1_path failure:%s\n",strerror(errno));
return -3;
}
data_p=strstr(buf, "t=");
data_p=data_p+2;
if(!data_p)
{
printf("can't get temperature :%s\n",strerror(errno));
return -4;
}
*temp=atof(data_p)/1000.0;
close(data_fd);
return 0;
}
int get_time(char *tim)
{
time_t time_val,time_mk;
struct tm *time_gm,*time_local;
time(&time_val);
time_gm=gmtime(&time_val);
sprintf(tim,"\tdate:%04d/%02d/%02d,time:%02d:%02d:%02d",time_gm->tm_year+1900,time_gm->tm_mon+1,time_gm->tm_mday,time_gm->tm_hour,time_gm->tm_min,time_gm->tm_sec);
return 0;
}
void pub_json_data(struct mosquitto *mosq,st_mqtt *mqt)
{
char buf[512];
float tem;
char tim[32];
char *msg;
cJSON * root = cJSON_CreateObject();
cJSON * item = cJSON_CreateObject();
memset(root,0,sizeof(root));
memset(item,0,sizeof(item));
if(get_temperature(&tem)<0)
{
printf("get_temperature failed:%s\n",strerror(errno));
return ;
}
if(get_time(tim)<0)
{
printf("get_time failured:%s\n",strerror(errno));
return ;
}
snprintf(buf,sizeof(buf),"%s/%s",tim,tem);
cJSON_AddItemToObject(root, "method", cJSON_CreateString(mqt->method));
cJSON_AddItemToObject(root, "id", cJSON_CreateString(mqt->jsonid));
cJSON_AddItemToObject(root, "params",item);
cJSON_AddItemToObject(root,"time",cJSON_CreateString(tim));
cJSON_AddItemToObject(item, "CurrentTemperature", cJSON_CreateNumber(tem));
cJSON_AddItemToObject(root, "version", cJSON_CreateString(mqt->version));
msg=cJSON_Print(root);
printf("%s\n",msg);
if(mosquitto_publish(mosq,NULL,mqt->topic,strlen(msg),msg,mqt->Qos,NULL) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_publish failed: %s\n",strerror(errno));
return;
}
printf("mqtt_publish successful!\n");
}
整个代码设计的是每10秒发布一次温度。make编译并运行 运行之后登录到阿里云平台查看发布的数据如下,跟发布端发布的温度相同 这只是初步的实现上报温度到阿里云,后续还需要添加参数解析来实现不同云平台的上报。对cJSON和mosquitto库函数的使用还不是很熟悉,后面在慢慢学习吧。 项目源码地址
|