MQTT客户端(基于mosquitto库)上报温度到阿里云

前言

在上几篇文章中我们用MQTT.fx模拟客户端实现了与阿里云物联网平台的双向通信,接下来我们自己动手编程使用mosquitto库实现一个发布端

iniparser配置文件

iniparser简介
在上篇文章中阿里云配置文件另外之前发布和订阅的topic也要记下来:

[mqtt_server_addr]
host        =iot-06z00c6bu42mu5l.mqtt.iothub.aliyuncs.com
port        =1883

[user_passwd]
username    =ds18b20&i5oqviRE56z
passwd      =e84ffa7d0c4bf58c2d00bff75d222384f5400112c175917635339219021b9467

[client_id]
id          =i5oqviRE56z.ds18b20|securemode=2,signmethod=hmacsha256,timestamp=1673699121744|

[sub_topic]
topic       =/sys/i5oqviRE56z/ds18b20/thing/service/property/set

[pub_topic]
topic       =/sys/i5oqviRE56z/ds18b20/thing/event/property/post

[ali_json]
method      =thing.service.property.set
id          =244036390
identifier  =CurrentTemperature
version     =1.0.0"

这些都是我们在项目中要用到的配置信息,具体应用在:

#客户端id
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。

cJSON

cJSON学习参考博客

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

阿里云上payload must be json format 负载(消息)必须为cJSON格式。
因为使用的阿里云提供的标准物模型,所以消息格式应该遵循阿里云的规范。这就是我们要使用cJSON的原因。

要是已其他格式发送,阿里云收到了消息,但是因为参数不匹配,无法对消息进行解析,也就无法获取到温度消息

话不多说看项目实例

流程图

在这里插入图片描述

ini配置信息

mqtt_aliyun_conf_ini

[mqtt_server_addr]
host        =iot-06z00c6bu42mu5l.mqtt.iothub.aliyuncs.com
port        =1883

[user_passwd]
username    =ds18b20&i5oqviRE56z
passwd      =e84ffa7d0c4bf58c2d00bff75d222384f5400112c175917635339219021b9467

[client_id]
id          =i5oqviRE56z.ds18b20|securemode=2,signmethod=hmacsha256,timestamp=1673699121744|

[sub_topic]
topic       =/sys/i5oqviRE56z/ds18b20/thing/service/property/set

[pub_topic]
topic       =/sys/i5oqviRE56z/ds18b20/thing/event/property/post

[ali_json]
method      =thing.service.property.set
id          =244036390
identifier  =CurrentTemperature
version     =1.0.0"

[KEEP_ALIVE]
alive       =60

[ali_Qos]
Qos         =0

mqtt_aliyun_conf.c

/********************************************************************************
 *      Copyright:  (C) 2023 Yangpeng
 *                  All rights reserved.
 *
 *       Filename:  get_temperature.h
 *    Description:  This file 
 *
 *        Version:  1.0.0(2023年01月05日)
 *         Author:  Yangpeng <1023769078@qq.com>
 *      ChangeLog:  1, Release initial version on "2023年01月05日 17时02分31秒"
 *                 
 ********************************************************************************/
#include "iniparser.h"
#include "mqtt_aliyun_conf.h"
#include <stdio.h>
#include <string.h>

int get_mqtt_conf(char *ini_path,data_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;
}

mqtt_aliyun_conf.h

********************************************************************************
 *      Copyright:  (C) 2023 Yangpeng
 *                  All rights reserved.
 *
 *       Filename:  get_temperature.h
 *    Description:  This file 
 *
 *        Version:  1.0.0(20230105)
 *         Author:  Yangpeng <1023769078@qq.com>
 *      ChangeLog:  1, Release initial version on "2023年01月05日 17时02分31秒"
 *                 
 ********************************************************************************/
#ifndef MQTT_ALIYUN_CONF_H
#define MQTT_ALIYUN_CONF_H

#define  BUF_SIZE 512

#define DEFAULT_CLIENTID    "i5oqviRE56z.ds18b20|securemode=2,signmethod=hmacsha256,timestamp=1673699121744|"

#define DEFAULT_USERNAME    "ds18b20&i5oqviRE56z"
#define DEFAULT_PASSWD      "e84ffa7d0c4bf58c2d00bff75d222384f5400112c175917635339219021b9467"

#define DEFAULT_HOSTNAME    "iot-06z00c6bu42mu5l.mqtt.iothub.aliyuncs.com"
#define DEFAULT_PORT        1883

#define DEFAULT_SUBTOPIC    "/sys/i5oqviRE56z/ds18b20/thing/service/property/set"
#define DEFAULT_PUBTOPIC    "/sys/i5oqviRE56z/ds18b20/thing/event/property/post"

#define DEFAULT_QOS         0

#define DEFAULT_METHOD      "thing.service.property.set"
#define DEFAULT_JSONID      "244036390"
#define DEFAULT_IDENTIFIER  "CurrentTemperature"
#define DEFAULT_VERSION     "1.0.0"

#define KEEP_ALIVE          60

enum{
    SUB,
    PUB
};

typedef struct data_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] ;
}data_mqtt;

int get_mqtt_conf(char *ini_path,data_mqtt *mqtt,int type);

#endif

ds18b20获取温度模块

/*********************************************************************************
 *      Copyright:  (C) 2023 Yangpeng
 *                  All rights reserved.
 *
 *       Filename:  get_temperature.c
 *    Description:  This file get temperature
 *                 
 *        Version:  1.0.0(2023年01月05日)
 *         Author:  Yangpeng <1023769078@qq.com>
 *      ChangeLog:  1, Release initial version on "2023年01月05日 16时39分48秒"
 *                 
 ********************************************************************************/

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<dirent.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#include"get_temperature.h"


int get_temperature(float *temp)
{
	char             path[64]="/sys/bus/w1/devices/";
	char             buf[128];
    	char             chip[32];
    	DIR             *dirp=NULL;
    	struct dirent   *direntp=NULL;
    	int              fd=-1;
    	char            *ptr=NULL;
    	int              found=0;

	if(NULL==(dirp=opendir(path)))
	{
    		printf("opendir failure:%s\n",strerror(errno));
    		return -1;
	}

	memset(chip,0,sizeof(chip));
	while((direntp=readdir(dirp))!=NULL)
	{
    		if(strstr(direntp->d_name,"28-"))
    		{
        		strcpy(chip,direntp->d_name);
            		found=1; 
    		}
	}
     
	closedir(dirp);

	if(!found)
	{
    		printf("readdir failure\n");
    		return -2;
    	}
  

                             
	strncat(path,chip,sizeof(path)-strlen(path));
	strncat(path,"/w1_slave",sizeof(path)-strlen(path));

	if((fd=open(path,O_RDONLY))<0)
	{
    		printf("open file failure:%s\n",strerror(errno));
    		return -3;
	} 

	memset(buf,0,sizeof(buf));
	if(read(fd,buf,sizeof(buf))<0)
	{
    		printf("read file failure:%s\n",strerror(errno));
    		return -4;
	} 

	ptr=strstr(buf,"t=");
	ptr+=2;
 
	if(!ptr)
	{
    		printf("error:can not ptr\n");
    		return -5;
	} 

	*temp=atof(ptr)/1000;
	printf("temprature:%f\n",*temp);
	close(fd);

	return 0;
}

/********************************************************************************
 *      Copyright:  (C) 2023 Yangpeng
 *                  All rights reserved.
 *
 *       Filename:  get_temperature.h
 *    Description:  This file 
 *
 *        Version:  1.0.0(2023年01月05日)
 *         Author:  Yangpeng <1023769078@qq.com>
 *      ChangeLog:  1, Release initial version on "2023年01月05日 17时02分31秒"
 *                 
 ********************************************************************************/

#ifndef  _GET_TEMPERATURE_H_
#define  _GET_TEMPERATURE_H_

int get_temperature(float *temp);

#endif

发布端代码

/********************************************************************************
 *      Copyright:  (C) 2023 Yangpeng
 *                  All rights reserved.
 *
 *       Filename:  get_temperature.h
 *    Description:  This file 
 *
 *        Version:  1.0.0(2023年01月05日)
 *         Author:  Yangpeng <1023769078@qq.com>
 *      ChangeLog:  1, Release initial version on "2023年01月05日 17时02分31秒"
 *                 
 ********************************************************************************/
#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 "get_temperature.h"
#include "mqtt_aliyun_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;

/* 调用信号 */
void sig_handler(int sig_num)
{
    if(sig_num == SIGUSR1)
    g_stop = 1;

}

int get_time(char *tim);
void connect_callback(struct mosquitto *mosq,void *obj,int rc);
static inline void print_usage(char *progname);


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;
    int    		opt = -1;
    int			log_fd;

    data_mqtt 		mqtt;    
    struct mosquitto	*mosq = NULL;

   
    struct option options[] = 
    {
        {"daemon",no_argument,NULL,'d'},
        {"topic", required_argument,NULL,'t'},
        {"hostname", required_argument,NULL,'H'},
        {"clientid", required_argument, NULL, 'i'},
        {"port",required_argument,NULL,'p'},
        {"help",no_argument,NULL,'h'},
        {"username",required_argument,NULL,'u'},
        {"passwd",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':
                hostname = optarg;
                break;
            case 'u':
                username = optarg;
                break;
            case 'P':
                passwd = optarg;
                break;
            case 'd':
                daemon_run = 1;
                break;
            case 'p':
                port = atoi(optarg);
                break;
            case 'h':
                print_usage(argv[0]);
                return 0;
            default:
                break;
        }
    }   

      /* 创建日志 */
    if(daemon_run)
    {
        printf("program %s running in backgrund\n", program_name);
        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_mqtt_conf(INI_PATH,&mqtt,PUB);

    /* MQTT 初始化 */
    mosquitto_lib_init();

    /* 创建MQTT 客户端 */
    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;
    }

     /* 设置回调函数 */
    mosquitto_connect_callback_set(mosq,connect_callback);

    
    while(!g_stop)
    {
        /* 连接MQTT服务器,ip,端口,时间 */
        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");

        /*无阻塞 断线连接 */
        mosquitto_loop_forever(mosq,-1,1);        

        sleep(3);
    }
    
            
/* 释放客户端,清除 */
cleanup:
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();                
    return 0;
}


/* 获取时间 */
int get_time(char *tim)
{
    time_t          t;
    struct tm       *p;

    time(&t);
    p = gmtime(&t);

    snprintf(tim, 32, "%04d-%02d-%02d %02d:%02d:%02d", 1900+p->tm_year,1+p->tm_mon, p->tm_mday, (p->tm_hour + 8), p->tm_min, p->tm_sec);
    return 0 ;
}

/* 回调函数*/
void connect_callback(struct mosquitto *mosq,void *obj,int rc)
{
    float   tem = 0.00000000;
    char   tim[64];
    char *msg;

    cJSON   * root =  cJSON_CreateObject();
    cJSON   * item =  cJSON_CreateObject();

    memset(root,0,sizeof(root));
    memset(item,0,sizeof(item));
    memset(tim,0,sizeof(tim));

    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 ;
    }

    
    if(!obj)
    {
        printf("invalid_argument in %s\n",__FUNCTION__);
        return;
    }

     struct data_mqtt *mqtt = (data_mqtt *)obj;

    cJSON_AddItemToObject(root, "method", cJSON_CreateString(mqtt->method));
    cJSON_AddItemToObject(root, "id", cJSON_CreateString(mqtt->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(mqtt->version));
   
    msg=cJSON_Print(root);
    printf("%s\n",msg);

    if(!rc)
    {
         if(mosquitto_publish(mosq,NULL,mqtt->topic,strlen(msg),msg,mqtt->Qos,NULL) != MOSQ_ERR_SUCCESS)
         {
             printf("mosquitto_publish failed: %s\n",strerror(errno));
             return;
         }
     }    
    printf("mqtt_publish successful!\n");
   
    mosquitto_disconnect(mosq);

}

/* 帮助信息 */
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 hostname.\n");
    printf("-p(--port): sepcify port.\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(--passwd): sepcify password of the username.\n");
    printf("-t(--topic): sepcify topic of the client.\n");
    printf("-d(--daemon): running in backgrund.\n");
}


makefile

CC = gcc



LDFLAGS+=-lm -lmosquitto -lcjson 
COMPILE=*.c

all:${COMPILE}
	${CC} ${COMPILE} -o mqtt_pub ${LDFLAGS}
clean:
	rm -rf mqtt_pub

运行结果展示

在这里插入图片描述

项目gitee地址

希望这篇博客能帮助到你

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值