温度实时监测——服务端部分/Node.js/Express/MQTT服务器 篇二

篇一主要是ESP8266相关的内容,这里主要涉及MQTT服务器和温度数据显示页面。

Express是一个基于Node.js平台的web开发框架,主要是提供route服务,有很多中间件可用,在到达路由之前进行一些请求处理,本项目其实没有利用多少他的优势,只是一个简单的示范。

使用Express生成器即可快速创建一个应用的骨架,通过下面的命令

express --view=ejs myapp

由此创建了一个名称为 myapp 的 Express 应用。此应用将在当前目录下的 myapp 目录中创建,并且设置为使用ejs模板引擎(view engine),通过下面的命令安装所有依赖包,将所有package.json中所有依赖安装在node_modules文件夹中。

npm install

通过下面的命令启动

 DEBUG=myapp:* npm start

本项目中,首先修改app.js

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

//*********mqtt server******************************
var mqtt_srever = require('./routes/mqtt_server');
//*********mqtt server******************************

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

在这里新增的内容主要是Mqtt服务器,即mqtt_server.js,如下所述

输入http://localhost:3000/后,首先通过路由为/routes/index,其中的内容为

var express = require('express');
var router = express.Router();


/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: '温度动态采集显示' });
});

module.exports = router;

进一步对index进行渲染,index.ejs内容如后面的内容所示。

关于MQTT服务器端,当时在这里也卡壳了很久,主要是开头的那个服务器建立格式不对,到目前还是不知道什么原因。。。

mqtt_server.js

 var mosca = require("mosca");

var MqttServer = new mosca.Server({
  http: {
    port: 8083,
    bundle: true,
    static: './'
  }
});

MqttServer.on('ready', function(){
    console.log('mqtt is running...');
    //MqttServer.authenticate = authenticate;
});
 
MqttServer.on('clientConnected', function(client){
    console.log('client connected', client.id);
}); 
 
MqttServer.on('clientDisconnected', function (client) {
    console.log('Client Disconnected     := ', client.id);
});
 
 
MqttServer.on('subscribed', function (topic, client) {
    console.log("Subscribed :=", topic, client.id);
});
 
MqttServer.on('unsubscribed', function (topic, client) {
    console.log('unsubscribed := ', topic, client.id);
});
 
 
 
MqttServer.on('published', function(packet, client) {
    
    if (typeof (client) == "undefined")
	return;
 
    else
	console.log('client ', client.id, ' publish :', 'topic ='+packet.topic+ ',message = '+ packet.payload.toString());
 
}); 
 
 
MqttServer.on("error", function (err) {
    console.log(err);
});

module.exports = MqttServer;

这里是被index.js渲染的内容,即网页呈现的内容,这里面主要完成mqtt数据的接收和显示,同时通过按钮控制ESP8266是否采集并发送温度数据

index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
 <!- 注释的内容*************************************************************************************** ->   
    <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js"></script>
    <script src="https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"></script>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/moment.js/2.20.1/moment.min.js"></script>
 <!- 注释的内容*************************************************************************************** ->  
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
    <button onclick="opentemp()">open tmp transfer!</button>
    <button onclick="closetemp()">close tmp transfer!</button>
 <!- 注释的内容*************************************************************************************** ->  
<form id="form">
Message: <input size="50" id="msg"> <input type="submit" value="Submit">
</form>
<div id="chart" style="width: 600px;height:400px;"></div>

<div id="main" style="width: 600px;height:400px;overflow:auto;"></div>


<!- 注释的内容*************************************************************************************** ->  

<script>



var url = location.hostname;
var port = 8083;
client = new Paho.MQTT.Client(url, Number(port), "websockets-client");//建立客户端实例
client.connect({onSuccess:onConnect});//连接服务器并注册连接成功处理事件
function onConnect() {
       console.log("onConnected");
       topic = '/tempinfo'; //订阅的主题
       client.subscribe(topic);//订阅主题
       console.log("subscribed topic:"+topic);
       //发送消息
       }
client.onConnectionLost = onConnectionLost;//注册连接断开处理事件
client.onMessageArrived = onMessageArrived;//注册消息接收处理事件

function onConnectionLost(responseObject) {
         if (responseObject.errorCode !== 0) {
         // console.log("onConnectionLost:"+responseObject.errorMessage);
                console.log("连接已断开");
                 }
         }


function onMessageArrived(message) {
         console.log("收到消息:"+message.payloadString);
         console.log("主题:"+message.destinationName);
         tempinfo = message.payloadString + ".... ...."+moment().format('YYYY-MM-DD HH:mm:ss')


         var div = document.createElement("div")
	 div.textContent = tempinfo
	 var board = document.getElementById("main")
	 var object = board.insertBefore(div,board.childNodes[0])
	 if (tempinfo.includes("DHT Temperature:")){
            redraw(tempinfo)}
         }



function mqttsend(msg){
			if(msg.length > 0){
                                topic2 = '/topic'; //订阅的主题
				message = new Paho.MQTT.Message(msg);
				message.destinationName = topic2;
				client.send(message);
				console.log("消息发送成功"+message);
			}
			else {
				alert("发送的消息不能为空");
			}
		}

//***************************************************************************************************

document.getElementById("form").onsubmit = function (event) {
				var msg = document.getElementById("msg")
				if (msg.value)
					mqttsend(msg.value)
				msg.value = ""
				event.preventDefault()
                                }


function opentemp()
{
mqttsend("temp send open");
console.log("open");
}

function closetemp()
{
mqttsend("temp send close")
console.log("close");
}

//***************************************************************************************************
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('chart'));

function checkTime(i)
{
if (i<10) 
  {i="0" + i}
  return i
}


function getnewData(tempinfo) {
    now = tempinfo.split(".... ....")[1];
    value = tempinfo.split("DHT Temperature:")[1].split(";Humidity")[0];
    
    return {
        name: now,
        value: [
            now,
            Math.round(value)
        ]
    };
}

var data = [];
var tempinfo_init = "[abc] DHT Temperature:22.000000;Humidity:28.000000 .... ....2020-03-27 23:03:50";
for (var i = 0; i < 90; i++) {
  //  data.push(getnewData(tempinfo_init));
}

option = {
    title: {
        text: '实时温度显示'
    },
    grid: {
        left: '3%',
        right: '4%',
        bottom: '3%',
        containLabel: true
    },
    tooltip: {
        trigger: 'axis',
        axisPointer: { // 坐标轴指示器,坐标轴触发有效
            type: 'line' // 默认为直线,可选为:'line' | 'shadow'
        },
        formatter: function(params) {
            //console.log(params)
            return params[0].name + '<br/>' +
                params[0].seriesName + ' : ' + params[0].value[1] + ' <span>&#8451<SUP> </SUP></span>'
        }
    },
    xAxis: {
        type: 'time',
        splitNumber: 8,
        splitLine: {
            show: false
        }
    },
    yAxis: {
        type: 'value',
        boundaryGap: [0, '100%'],
        splitLine: {
            show: false
        }
    },
    series: [{
        name: '实时温度',
        type: 'line',
        smooth: true,
        showSymbol: true,
        symbolSize: 10,
        hoverAnimation: false,
        data: data
    }]
};

function redraw(i)
{
if (data.length<100)
{
s = getnewData(i)
data.push(s);
}
else
{
data.shift();
s = getnewData(i)
data.push(s);
}
myChart.setOption(option);
}


//***************************************************************************************************

</script>

 <!- 注释的内容*************************************************************************************** ->  

<!- 注释的内容*************************************************************************************** ->  



  </body>
</html>

首先创建数据库和数据表:

create database ***;
create table esptemp(temp float,datatime TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);

在app.js中加入mysql数据库代码,将ESP8266采集得到的温度信息存储,并在前端页面中进行历史数据显示,写入代码如下:

if (packet.topic == "/tempinfo")        
        {
        tempinfo = packet.payload.toString();

        if ((tempinfo.search("Temperature:"))&&(tempinfo.search(";Humidity"))){          
        temp_char = tempinfo.split(";Humidity")[0];
        temp_char = temp_char.split("Temperature:")[1];             
        if (temp_char!=null)
         {
        addSql = 'INSERT INTO esptemp (temp) VALUES (?)';
        addSqlParams = parseFloat(temp_char);
        connection.query(addSql,addSqlParams,function (err, result) {
          if(err){
           console.log('[INSERT ERROR] - ',err.message);
           return;
            }         
           console.log('-----------INSERT-------------');
           //console.log('INSERT ID:',result.insertId);        
           console.log('INSERT ID:',result);        
           //console.log('-----\n\n');  
                });
             }      

服务器端查询代码如下:

var mysql  = require('mysql');  
var express = require('express');
var router = express.Router();   
/* POST home page. */
router.post('/', function(req, res, next) {
  console.log(req.body.time_begin);
  console.log(req.body.time_end);
  date_temp(req.body.time_begin,req.body.time_end,function(temp_result){
      //console.log(temp_result);
      res.send(temp_result);
   });  
});


function date_temp(time_begin,time_end,callback)   //callback function
{
var connection = mysql.createConnection({     
  host     : 'host',       
  user     : '***',              
  password : '***',       
  port: '***',     
  database: '***' 
  });  
connection.connect();

var  temp_text;
var  sql = 'select datatime, temp from esptemp where datatime >? and datatime<?';
var  addSqlParams = [time_begin, time_end];

connection.query(sql,addSqlParams,function (err, result) {
        if(err){
          console.log('[SELECT ERROR] - ',err.message);
          return;
        }
       var dataString = JSON.stringify(result);
       var temp_json = JSON.parse(dataString);
       //temp_text = JSON.stringify(temp_json);
       console.log('-----------SELECT-------------');
       console.log(temp_json);
       console.log('\n\n'); 
       callback(temp_json); 
       });   
connection.end();
}

module.exports = router;

需要注意的是,在数据库查询中需要用到回调函数的返回值,需要特别处理。

项目路径和启动

cd /var/www/html/node_websocket/expresstest/exp_mqtt/myapp
DEBUG=myapp:* npm start
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值