温度上报到阿里云物联网平台
前言
在上篇文章中我们用MQTT.fx模拟客户端实现了与阿里云物联网平台的双向通信,接下来我们自己动手编程使用mosquitto库实现一个客户端来实现一个发布端。
一、iniparser 和 json
1、为什么要使用iniparser库
iniparser简介:https://blog.csdn.net/qq_47548559/article/details/120920002
与阿里云进行通信时,我们需要如下一些信息,例如在使用MQTT.fx时:
复制保存一下,另外之前发布和订阅的topic也要记下来:
这些都是我们在项目中要用到的配置信息,具体应用在:
clientid:struct mosquitto *mosquitto_new( const char * id, bool clean_session, void * obj )
brokeraddress and brokerport:int mosquitto_connect( struct mosquitto * mosq, const char * host, int port, int keepalive )
username and password:int mosquitto_username_pw_set(struct mosquitto * mosq, const char *username, const char *password )
topic:int mosquitto_publish( struct mosquitto * mosq, int * mid, const char * topic, int payloadlen, const void * payload, int qos, bool retain )
我们当然可以直接写死在代码里,但是这样一来,代码复用性不高,换一个设备那么就要改一次源码来更改设备配置信息。
所以我们写一个.ini文件,这样当我们更换设备的时候只需要修改这个.ini文件中的信息即可。然后在代码中使用iniparser库中API。
2.为什么要使用json
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
打个比方:如果我们发布的消息为:
那么在阿里云上:
payload must be json format 负载(消息)必须为json格式。
所以我们这样写:
再看一下阿里云:
这下就成功啦!
因为我们是使用的阿里云提供的标准物模型,所以我们的消息格式应该遵循阿里云的规范。这就是我们要使用json的原因。
其中:param 代表参数。参数有两个 一个 data 一个 CurrentTemperature (这两个参数就是我们之前定义功能中的标识符),你可以这样理解,阿里云可以接收到以json格式发送的任何消息,例如:
阿里云上
同一时间内显示 ture 和 false 你可以这样理解 接收到了,但是参数不匹配 无法解析,(tsl parse failed),我在网上搜不到tsl 相关知识,但是在这里我们可以粗略的认为,阿里云收到了消息,但是因为参数不匹配,无法对消息进行解析,也就无法获取到温度和测试消息(如有错误请指正)。详细请 参考:https://developer.aliyun.com/article/777052
为了验证我的猜测:我又测试了正常情况:
好了到这里我们应该清楚为什么要学习json了。json的学习参考这篇博客:
https://blog.csdn.net/qq_47548559/article/details/120922787
二、编程实现客户端
1、大致流程
2.配置信息处理
/********************************************************************************
* Copyright: (C) 2021 lastbreath<2631336290@qq.com>
* All rights reserved.
*
* Filename: configoperate.h
* Description: This head file
*
* Version: 1.0.0(10/18/2021)
* Author: lastbreath <2631336290@qq.com>
* ChangeLog: 1, Release initial version on "10/18/2021 06:12:09 PM"
*
********************************************************************************/
#ifndef CONFIGOPERATE_H
#define CONFIGOPERATE_H
#define SIZE 256
#define DEFAULT_CLIENTID "12345|securemode=3,signmethod=hmacsha1|"
#define DEFAULT_USERNAME "test&ghcey1O2Yxm"
#define DEFAULT_PASSWORD "D090FBDCC327200DAD3083684A891A1C7992FACB"
#define DEFAULT_BROKER_ADDRESS "ghcey1O2Yxm.iot-as-mqtt.cn-shanghai.aliyuncs.com"
#define DEFAULT_BROKER_PORT 1883
#define DEFAULT_SUB_TOPIC "/sys/ghcey1O2Yxm/test/thing/service/property/set"
#define DEFAULT_PUB_TOPIC "/sys/ghcey1O2Yxm/test/thing/event/property/post"
#define DEFAULT_METHOD "thing.event.property.post"
#define DEFAULT_JSONID "0801"
#define DEFAULT_IDENTIFIER "data"
#define DEFAULT_VERSION "1.0.0"
#define KEEP_ALIVE 60
enum mode
{
SUB,
PUB
};
typedef struct mqtt_user_data{
char clientid[SIZE];
char username[SIZE];
char password[SIZE];
char brokeraddress[SIZE];
int brokerport;
char topic[SIZE];
char method[SIZE];
char jsonid[SIZE];
char identifier[SIZE];
char version[SIZE];
}mqtt_user_data;
int set_config(char *ini,char *host,int port, char *clientid,char *uname,char *pwd,char *topic);
int get_config(char *path,mqtt_user_data *mqtt,int mode);
#endif
3.主要流程
/*********************************************************************************
* Copyright: (C) 2021 lastbreath<2631336290@qq.com>
* All rights reserved.
*
* Filename: clien.c
* Description: This file
*
* Version: 1.0.0(08/08/2021)
* Author:
*
* lastbreath <2631336290@qq.com>
* ChangeLog: 1, Reliease initial version on "21/10/2021 16:08:41 PM"
*
********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <netdb.h>
#include <signal.h>
#include <libgen.h>
#include "mosquitto.h"
#include "ds18b20.h"
#include "cJSON.h"
#include "iniparser.h"
#include "configoperate.h"
#define INI_PATH "./mqtt_aliyun_conf.ini"
#define KEEP_ALIVE 60
int g_stop = 0;
static inline void print_usage(char *progname);//内联函数,空间换时间。编译时期展开。
void sig_handler(int sig_num)
{
if(sig_num == SIGUSR1)
g_stop = 1;
}
void connect_callback(struct mosquitto *mosq,void *obj,int rc);
int main (int argc, char **argv)
{
char *progname = basename(argv[0]);
int brokerport = 0;
char *brokeraddress = NULL;
char *clientid = NULL;
char *username = NULL;
char *password = NULL;
char *topic = NULL;
struct mosquitto *mosq = NULL;
int daemon_run = 0;
int opt = -1;
int rv;
char buffer[BUF_SIZE];
int log_fd;
struct mqtt_user_data mqtt;
struct option options[] =
{
{"daemon",no_argument,NULL,'d'},
{"topic", required_argument,NULL,'t'},
{"brokeraddress", required_argument,NULL,'H'},
{"clientid", required_argument, NULL, 'i'},
{"brokerport",required_argument,NULL,'p'},
{"help",no_argument,NULL,'h'},
{"username",required_argument,NULL,'u'},
{"password",required_argument,NULL,'P'},
{NULL,0,NULL,0}
};
while((opt = getopt_long(argc,argv,"dhp:t:i:u:P:H:",options,NULL)) != -1)
{
switch(opt)
{
case 't':
topic = optarg;
break;
case 'i':
clientid = optarg;
break;
case 'H':
brokeraddress = optarg;
break;
case 'u':
username = optarg;
break;
case 'P':
password = optarg;
break;
case 'd':
daemon_run = 1;
break;
case 'p':
brokerport = atoi(optarg);
break;
case 'h':
print_usage(argv[0]);
return 0;
default:
break;
}
}
//set_config(INI_PATH,brokeraddress,brokerport,clientid,username,password,topic);
if(daemon_run)
{
printf("program %s running in backgrund\n", progname);
if( (log_fd = open("client.log", O_CREAT|O_RDWR, 0666)) < 0)
{
printf("open() failed:%s\n", strerror(errno)) ;
return -2;
}
dup2(log_fd, STDOUT_FILENO) ;
dup2(log_fd, STDERR_FILENO) ;
daemon(1,1);
}
signal(SIGUSR1,sig_handler);
memset(&mqtt,0,sizeof(mqtt));
rv = get_config(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));
mosquitto_lib_cleanup();
return -1;
}
if(mosquitto_username_pw_set(mosq,mqtt.username,mqtt.password) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_username_pw_set failed: %s\n",strerror(errno));
/*mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return -1;*/
goto cleanup;
}
printf("Create mosquitto successfully!\n");
mosquitto_connect_callback_set(mosq,connect_callback);
/*if(mosquitto_loop_start(mosq) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_loop_start() failed: %s\n",strerror(errno));
//mosquitto_destroy(mosq);
//mosquitto_lib_cleanup();
//return -1;
goto cleanup;
}
printf("mosquitto_loop_start() successfully!\n");*/
//printf("%s\n",brokeraddress);
//printf("%d\n",brokerport);
while(!g_stop)
{
printf("into while:\n");
if(mosquitto_connect(mosq, mqtt.brokeraddress,mqtt.brokerport,KEEP_ALIVE) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_connect() failed: %s\n",strerror(errno));
//continue;
goto cleanup;
}
printf("connect successfully\n");
mosquitto_loop_forever(mosq,-1,1);
sleep(30);
}
cleanup:
close(log_fd);
mosquitto_destroy(mosq);
mosquitto_lib_cleanup();
return 0;
}
void print_usage(char *progname)
{
printf("%s usage:\n",progname);
printf("Example: %s -h ${brokeraddress} -p ${brokerport} -i ${clientid} -u ${username} -p ${password} -t${topic} -h ${help} -d ${daemon}\n",progname);
printf("-h(--host): sepcify brokeraddress.\n");
printf("-p(--port): sepcify brokerport.\n");
printf("-h(--Help): print this help information.\n");
printf("-d(--daemon): set program running on background.\n");
printf("-i(--clientid): sepcify the clientid.\n");
printf("-u(--username): sepcify username of the client.\n");
printf("-p(--password): sepcify password of the username.\n");
printf("-t(--topic): sepcify topic of the client.\n");
printf("-d(--daemon): running in backgrund.\n");
}
void connect_callback(struct mosquitto *mosq,void *obj,int rc)
{
printf("get into connect_callback():\n");
float t = 27.000000;
if(ds18b20_get_temperature(&t) < 0)
{
printf("ds18b20_get_temperature failed.\n");
return;
}
cJSON *root = cJSON_CreateObject();
cJSON *item = cJSON_CreateObject();
if(!obj)
{
printf("invalid_argument in %s\n",__FUNCTION__);
return;
}
struct mqtt_user_data *mqtt = (mqtt_user_data *)obj;
cJSON_AddItemToObject(root,"method",cJSON_CreateString(mqtt->method));
cJSON_AddItemToObject(root,"id",cJSON_CreateString(mqtt->jsonid));
cJSON_AddItemToObject(root,"params",item);
cJSON_AddItemToObject(item,"CurrentTemperature",cJSON_CreateNumber(t));
cJSON_AddItemToObject(root,"version",cJSON_CreateString(mqtt->version));
char *msg = cJSON_Print(root);
printf("%s\n",msg);
if(!rc)
{
if(mosquitto_publish(mosq,NULL,mqtt->topic,strlen(msg),msg,0,NULL) != MOSQ_ERR_SUCCESS)
{
printf("mosquitto_publish failed: %s\n",strerror(errno));
return;
}
}
mosquitto_disconnect(mosq);
}
4.运行结果
打开阿里云可以看到温度在实时更新啦。
项目源码地址:https://gitee.com/lastbreath/apue/tree/master/