基于Node-RED下的物联网环境监测系统(纯软件模拟)


前言

本文在Ubuntu操作系统下实现一个物联网系统,该系统能够实现生成两个随机数来模拟传感器采集到的数据,利用node-red监测emqx上的数据情况。

其主要可以完成以下功能要求

  • 由一个父线程创建两个子线程。
  • 由父线程统一将感知 (模拟) 数据发布到 MQTT Broker。
  • 温度和湿度均由随机数生成。温度范围:0-40,湿度范围:10-100。
  • 由父线程统一将感知 (模拟) 数据发布到 MQTT Broker。
  • 在 Node-Red 上接收数据并分别显示温度和湿度。

一、目的

  1. 基于MQTT通信协议实现物联网各层的数据传输。
  2. 理解和掌握物联网各层之间数据通信、数据处理、数据显示。

二、背景

  1. 理论研究基础
    (1) MQTT是基于TCP/IP协议栈而构建的,已成为IoT通信的标准。
    (2) MQTT的灵活性使得为IoT设备和服务的多样化应用场景提供支持成为可能。
    (3) NodeRED是构建物联网应用程序的一个强大工具,其重点是简化代码块的“连接”以执行任务。使用可视化编程方法,允许开发人员将预定义的节点连接起来执行任务。

  2. 技术层面支持
    (1) 一台装有Windows、VirtuaBox和Ubuntu虚拟机的计算机。
    (2) MQTT Broker服务器——emqx服务器。
    (3) NodeRED可视化程序设计。

三、主要步骤

  1. MQTT 服务器在 Linux 上的搭建
  2. 安装 MQTT 开发环境
  3. 安装 Node-Red
  4. Node-Red 可视化程序设计
  5. MQTT客户端程序编写
  6. 编译执行客户端程序,并在浏览器上查看运行结果

四、操作流程

1.emqx的安装与配置

下载 emqx-ubuntu18.04-4.3.11-amd64.zip

wget https://www.emqx.com/zh/downloads/broker/4.3.11/emqx-ubuntu18.04-4.3.11-amd64.zip

安装

unzip emqx-ubuntu18.04-4.3.11-amd64.zip

运行

./bin/emqx start

2.MQTT库安装

安装 git

∼/emqx$ sudo apt install git libssl‐dev openssl

从 Git 中下载 paho C 库。注意:该下载文件将会下载到当前的路径中。

∼/emqx$ git clone https://github.com/eclipse/paho.mqtt.c.git

安装 Paho C库

∼/emqx$ cd paho.mqtt.c
∼/emqx$ make
∼/emqx$ sudo make install

3.客户端源码

#include<stdio.h> 
#include<string.h> 
#include<stdlib.h>
#include<errno.h> 
#include<unistd.h> 
#include"MQTTClient.h" 
#include <sys/wait.h>
#include <time.h> 
#include <pthread.h>  
#include <semaphore.h> 
char buf[1024];
char suf[1024];
sem_t sem_empty;
sem_t sem_full;
pthread_mutex_t mutex_shidu;
pthread_mutex_t mutex_wendu;
void *thread_funb(void *p) {
    int temperature;
    while(1) {
        srand((unsigned int)time(0));
        temperature=(rand()%41);
        sem_wait(&sem_empty);
        pthread_mutex_lock(&mutex_wendu);
        printf("监测到的温度是:%d\n",temperature);
        sprintf(suf,"%.3d",temperature);
        sleep(2);
        pthread_mutex_unlock(&mutex_wendu);
        sem_post(&sem_full);
    }
}
void *thread_funa(void *p) {
    int humidity=0;
    while(1) {
        srand((unsigned int)time(0));
        humidity=(rand()%91)+10;
        sem_wait(&sem_empty);
        pthread_mutex_lock(&mutex_shidu);
        printf("监测到的湿度是:%d\n",humidity);
        sprintf(buf,"%.3d",humidity);
        sleep(2);
        pthread_mutex_unlock(&mutex_shidu);
        sem_post(&sem_full);
    }
}
int main(int argc,char **argv) {
    sem_init(&sem_empty, 0, 2);
    sem_init(&sem_full, 0, 0);
    char *address="tcp://localhost:1883";
    char *client_id="publish_client";
    char *topic1="shidu";
    char *topic2="wendu";
    const int time_out=10000;
    int rv;
    int QOS=2;
    MQTTClient client;
    MQTTClient_connectOptions conn_opts=MQTTClient_connectOptions_initializer;
    MQTTClient_message publish_msg=MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    conn_opts.keepAliveInterval=60;
    conn_opts.cleansession=1;
    MQTTClient_create(&client,address,client_id,MQTTCLIENT_PERSISTENCE_NONE ,NULL);
    if((rv=MQTTClient_connect(client,&conn_opts))!=MQTTCLIENT_SUCCESS) {
        printf("MQTTClient_connect failure:%s\n",strerror(errno));
        return 0;
    }
    publish_msg.qos=QOS;
    publish_msg.retained=0;
    pthread_t t1, t2;
    pthread_create(&t1, 0, thread_funa, (void *)1);
    pthread_create(&t2, 0, thread_funb, (void *)2);
    while(1) {
        sem_wait(&sem_full);
        pthread_mutex_lock(&mutex_shidu);
        pthread_mutex_lock(&mutex_wendu);
        publish_msg.payload=(void *)buf;
        publish_msg.payloadlen=strlen(buf);
        int payloadlen;
        MQTTClient_publishMessage(client,topic1,&publish_msg ,&token);
        rv=MQTTClient_waitForCompletion(client,token,time_out);
        printf("上传时间 %d 上传湿度 %s\n",rv,buf);
        publish_msg.payload=(void *)suf;
        publish_msg.payloadlen=strlen(suf);
        MQTTClient_publishMessage(client,topic2,&publish_msg ,&token);
        rv=MQTTClient_waitForCompletion(client,token,time_out);
        printf("上传时间 %d 上传温度 %s\n",rv,suf);
        sleep(1);
        pthread_mutex_unlock(&mutex_wendu);
        pthread_mutex_unlock(&mutex_shidu);
        sem_post(&sem_empty);
    }
}

4.NodeRed节点信息

[
    {
        "id": "f3db3f27.cba5c", 
        "type": "tab", 
        "label": "Flow1", 
        "disabled": false, 
        "info": ""
    }, 
    {
        "id": "d8c8d735.0b48a", 
        "type": "debug", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "active": true, 
        "tosidebar": true, 
        "console": false, 
        "tostatus": false, 
        "complete": "payload", 
        "targetType": "msg", 
        "statusVal": "", 
        "statusType": "auto", 
        "x": 440, 
        "y": 160, 
        "wires": [ ]
    }, 
    {
        "id": "fa39b2f.0c3eb5", 
        "type": "ui_gauge", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "group": "6e9b4b3d.5f0a14", 
        "order": 0, 
        "width": "8", 
        "height": "8", 
        "gtype": "donut", 
        "title": "温度", 
        "label": "℃", 
        "format": "{{value}}", 
        "min": 0, 
        "max": "40", 
        "colors": [
            "#00b500", 
            "#e6e600", 
            "#ca3838"
        ], 
        "seg1": "", 
        "seg2": "", 
        "className": "", 
        "x": 450, 
        "y": 240, 
        "wires": [ ]
    }, 
    {
        "id": "58a15f93.3f2528", 
        "type": "mqtt in", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "topic": "Action1", 
        "qos": "2", 
        "datatype": "auto", 
        "broker": "b4ba4381.73d0a8", 
        "x": 180, 
        "y": 220, 
        "wires": [
            [
                "d8c8d735.0b48a", 
                "fa39b2f.0c3eb5"
            ]
        ]
    }, 
    {
        "id": "f66f499d.734c38", 
        "type": "mqtt in", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "topic": "Action2", 
        "qos": "2", 
        "datatype": "auto", 
        "broker": "b4ba4381.73d0a8", 
        "x": 180, 
        "y": 440, 
        "wires": [
            [
                "1e52052e.58ccbb", 
                "18574447.fd7b1c"
            ]
        ]
    }, 
    {
        "id": "1e52052e.58ccbb", 
        "type": "debug", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "active": true, 
        "tosidebar": true, 
        "console": false, 
        "tostatus": false, 
        "complete": "false", 
        "statusVal": "", 
        "statusType": "auto", 
        "x": 400, 
        "y": 420, 
        "wires": [ ]
    }, 
    {
        "id": "18574447.fd7b1c", 
        "type": "ui_gauge", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "group": "6e9b4b3d.5f0a14", 
        "order": 0, 
        "width": "10", 
        "height": "10", 
        "gtype": "gage", 
        "title": "湿度", 
        "label": "%", 
        "format": "{{value}}", 
        "min": "10", 
        "max": "100", 
        "colors": [
            "#00b500", 
            "#e6e600", 
            "#ca3838"
        ], 
        "seg1": "", 
        "seg2": "", 
        "className": "", 
        "x": 390, 
        "y": 480, 
        "wires": [ ]
    }, 
    {
        "id": "50c44fcd.1a6d5", 
        "type": "ui_switch", 
        "z": "f3db3f27.cba5c", 
        "name": "", 
        "label": "switch", 
        "tooltip": "", 
        "group": "6e9b4b3d.5f0a14", 
        "order": 2, 
        "width": 0, 
        "height": 0, 
        "passthru": true, 
        "decouple": "false", 
        "topic": "topic", 
        "topicType": "msg", 
        "style": "", 
        "onvalue": "true", 
        "onvalueType": "bool", 
        "onicon": "", 
        "oncolor": "", 
        "offvalue": "false", 
        "offvalueType": "bool", 
        "officon": "", 
        "offcolor": "", 
        "animate": false, 
        "className": "", 
        "x": 250, 
        "y": 320, 
        "wires": [
            [
                "d8c8d735.0b48a", 
                "1e52052e.58ccbb"
            ]
        ]
    }, 
    {
        "id": "6e9b4b3d.5f0a14", 
        "type": "ui_group", 
        "name": "Default", 
        "tab": "c6d87ea6.50a2", 
        "order": 1, 
        "disp": true, 
        "width": "20", 
        "collapse": false, 
        "className": ""
    }, 
    {
        "id": "b4ba4381.73d0a8", 
        "type": "mqtt-broker", 
        "name": "Test", 
        "broker": "127.0.0.1", 
        "port": "1883", 
        "clientid": "", 
        "usetls": false, 
        "compatmode": false, 
        "keepalive": "60", 
        "cleansession": true, 
        "birthTopic": "Action1", 
        "birthQos": "2", 
        "birthPayload": "", 
        "closeTopic": "", 
        "closeQos": "0", 
        "closePayload": "", 
        "willTopic": "", 
        "willQos": "0", 
        "willPayload": ""
    }, 
    {
        "id": "c6d87ea6.50a2", 
        "type": "ui_tab", 
        "name": "Tab 1", 
        "icon": "dashboard", 
        "order": 1
    }]

5.调试

编译客户端程序:

gcc mqtt_client.c ‐o mqtt_publish -lpthread ‐lpaho‐mqtt3c -L ./paho .mqtt.c/ ‐I ./paho.mqtt.c/src/

执行客户端程序:

./mqtt_publish 

在这里插入图片描述


总结

以上就是今天要讲的内容,本文仅仅简单的模拟了使用软件模拟实现物联网系统的一部分功能,而真正完成一个物联网系统,除了需要软件知识外,还需要学习相应的硬件知识,需要我们在实践的过程中一点一滴积累。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值