主要功能

在终端对环境温湿度进行采集,通过WIFI接入网络

能够显示实时参数变化(表格和曲线),具备一定的历史数据回溯功能

后期可加入一些联动控制或报警功能

项目目的

没有什么特别的实用性,就是随便玩一玩,建立基础的物联网概念

开展思路

采集端每两秒采集一次数据并传输,数据传输可采用post或websocket,后续考虑直接采用websocket

服务器端实时接受采集的数据并进行显示,每十分钟对数据进行一次存储,作为历史数据(后面这个还没搞。。。)

服务器搭建选择

网络连接可以采用虚拟服务器进行内网映射

本来想用之前的那个红米1s作为本地服务器的,刷了N次机,官方的非官方的刷机包都试过了,稳定版root不了,用开发版每次root之后wifi连接都出现了问题,不知道是什么原因,已经基本放弃了,以后再说吧,还是先老老实实用电脑试试吧

写在前面:
在玩ESP8266的时候,想在ESP8266和DHT11的基础上搞个wifi数据采集模块,实现传感器数据的采集和实时显示。
一开始的时候想通过http轮询get或post方式进行传感器数据的传输,想了一下过程有点繁琐,就在网上找了一下发现websocket是一种比较好的方式。

HTTP请求头部比较长,浪费带宽,而websocket就比较好了,既可以双向传输,也比较节省带宽,目前直播网站中普遍采用websocket方式传输弹幕信息,一些聊天类应用也有所采用。websocket协议的标识符是ws,像https一样如果加密的话是wxs。

在此后的过程中踩了很多坑,包括了各个方面

研究通讯模式时先后发现了两个websocket应用,即socket.io和Nodejs Websocket,他们都是基于Node.js的

Socket.IO

官网:https://socket.io/docs/
Socket.IO是一个库,它支持浏览器和服务器之间的实时、双向和基于事件的通信。它包括:
Node.js服务器:Source | API
浏览器的Javascript客户端库(也可以从Node.js运行):Source | API
具备以下特性:
1.可靠性
2.自动重连
3.断开检测
4.二进制传输
5.多路复用
Socket.IO不是WebSocket实现。尽管Socket.IO确实在可能的情况下使用WebSocket作为传输,但它在每个数据包中添加了一些元数据:需要消息确认时的数据包类型、命名空间和数据包id。这就是为什么WebSocket客户端无法成功连接到Socket.IO服务器,而Socket.IO客户端也无法连接到WebSocket服务器。

上面是Socket.IO的官方简介,尤其是最后一段,一开始的时候我没有注意到,在对示例进行调试的过程中发现,每个连接的端口是不固定的,而且发送数据的格式也如上面所述,都是封装好的,需要浏览器的支持。

这也就造成了我后面没法用这个和8266进行通讯了。

Nodejs Websocket

websocket服务器和客户端的nodejs模块
可以提供一些基础的websocket功能,进而实现传感器数据的传输
所以这里我们就采用这个了

服务器端:
开启websocket服务,接收来自客户端和8266的信息

var http = require("http")
var ws = require("nodejs-websocket")
var fs = require("fs")var moment = require('moment')
moment.locale('zh-cn')http.createServer(function (req, res) {fs.createReadStream("index.html").pipe(res)
}).listen(8080)var server = ws.createServer(function (connection) {connection.nickname = nullconnection.on("text", function (str) {if (connection.nickname === null) {connection.nickname = strbroadcast(str+" entered")} elsebroadcast("["+connection.nickname+"] "+str)})connection.on("close", function () {broadcast(connection.nickname+" left")})connection.on('error',(e)=>{console.log('====>an error occured: '+e.stack)})
})
server.listen(8081)function broadcast(str) {server.connections.forEach(function (connection) {connection.sendText(str+"    time-"+moment().format('YYYY-MM-DD HH:mm:ss'))})
}

客户端:
接收服务器传递的websocket数据,使用echarts进行动态数据的显示,echarts更新由温度信息的接收触发

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>温度在线采集显示</title>
<script src="https://cdn.bootcss.com/echarts/4.2.1-rc1/echarts.min.js"></script>
</head><body>
<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 type="text/javascript">
var connection
window.addEventListener("load", function () {var nickname = prompt("Choose a nickname")if (nickname) {connection = new WebSocket("ws://"+window.location.hostname+":8081")connection.onopen = function () {console.log("Connection opened")connection.send(nickname)document.getElementById("form").onsubmit = function (event) {var msg = document.getElementById("msg")if (msg.value)connection.send(msg.value)msg.value = ""event.preventDefault()}  }connection.onclose = function () {console.log("Connection closed")}connection.onerror = function () {console.error("Connection error")}connection.onmessage = function (event) {var div = document.createElement("div")div.textContent = event.datavar board = document.getElementById("main")var object = board.appendChild(div)tempinfo = event.dataif (tempinfo.includes("DHT Temperature:")){redraw(tempinfo)}}}
})//***************************************************************************************************
// 基于准备好的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("time-")[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:24;Humidity:35 time-2020-03-23 21:44:57";
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: false,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>

ESP8266程序
首先连接wifi,定时采集DHT11的温度信息,将信息以一定的格式发送至websocket服务端,服务端将这些信息发送至客户端,并在客户端进行解析和数据显示

设置自动重连功能,断开后一段时间就再次连接服务端

程序中设置温度采集开启和关闭功能,通过发送“”和“”进行设置

init.lua程序:

if not tmr.create():alarm(1000, tmr.ALARM_SINGLE, function()print("Init start")wifi.setmode(wifi.STATION)station_cfg={}station_cfg.ssid="user"station_cfg.pwd="abc456456"station_cfg.save=falsewifi.sta.config(station_cfg)wifi.sta.connect(function(connected_cb)print(connected_cb.SSID)dofile("wstest.lua")end)
end)thenprint("whoopsie")
end

wstest.lua程序

onclose = false
ws = nil
ws = websocket.createClient()
ws:close()
onclose = truetemp_flag = falsetempsendtmr = tmr.create()
tempsendtmr:register(3000, tmr.ALARM_AUTO, function()
tempinfo = get_tempinfo()
ws:send(tempinfo)
end)
tempsendtmr:stop()ws:on("connection", function(ws)print('got ws connection')ws:send('abc')
end)ws:on("receive", function(_, msg, opcode)print('got ws message:', msg, opcode) -- opcode is 1 for text message, 2 for binary if string.find(msg, "temp send open", 1)  thenprint("temp_true")temp_flag = truetempsendtmr:start()endif string.find(msg, "temp send close", 1)  thenprint("temp_true")temp_flag = truetempsendtmr:stop()end
end)--***********************close event***************************
ws:on("close", function(_, status)onclose = falseprint('ws connection closed', status)
if not tmr.create():alarm(2000, tmr.ALARM_SINGLE, function()print('wstest reconnected....')ws:connect('ws://192.168.0.144:8081')end)
thenprint("whoopsie")
end end)
--*************************************************************--***********************init connection***************************
if not tmr.create():alarm(2000, tmr.ALARM_SINGLE, function()print("if init connection")if onclose thenprint('init connection....')ws:connect('ws://192.168.0.144:8081')end
end)
thenprint("whoopsie")
end
--*************************************************************function get_tempinfo()
pin = 4
status, temp, humi, temp_dec, humi_dec = dht.read(pin)if status == dht.OK then-- Integer firmware using this exampletext_data=string.format("DHT Temperature:%d;Humidity:%d\r\n",temp,                      humi                      )    --print(text_data)elseif status == dht.ERROR_CHECKSUM thenprint( "DHT Checksum error." )elseif status == dht.ERROR_TIMEOUT thenprint( "DHT timed out." )end
return text_data
end

完成之后的效果如图

后续考虑
1.在数据显示上,目前只显示了温度,没有湿度,同时对坐标轴等进一步优化
2.考虑加入数据库对采集到的信息进行存储,后续也可以对历史数据进行展示
3.对于通信方式,可采用更为专业的MQTT协议,这个也是在后续了解的过程中才知道的,所以这里面就先用websocket了
开展上述工作中,学习到了很多新的知识,对回调函数和事件驱动有了更进一部的认识

使用ESP8266构建一个简单的温湿度在线监测装置相关推荐

  1. 如何只使用标签来构建一个简单的电影推荐系统

    作者:Johnson Kuan   编译:ronghuaiyang 导读 使用基于内容的方法来找到最相似的电影. No MIT chalkboard required 介绍 假设你正在推出下一个非常大 ...

  2. 基于PyTorch,如何构建一个简单的神经网络

    本文为 PyTorch 官方教程中:如何构建神经网络.基于 PyTorch 专门构建神经网络的子模块 torch.nn 构建一个简单的神经网络. 完整教程运行 codelab→ https://ope ...

  3. python推荐系统-利用python构建一个简单的推荐系统

    摘要: 快利用python构建一个属于你自己的推荐系统吧,手把手教学,够简单够酷炫. 本文将利用python构建一个简单的推荐系统,在此之前读者需要对pandas和numpy等数据分析包有所了解. 什 ...

  4. github密码格式_如何使用GitHub构建一个简单的网页 (不用框架版本)

    1.申请GitHub账号 进入GitHub官网,点击右上角的Sign up进行注册, 注册很简单,只要填写好用户名,邮箱,密码就行(已注册的用户名,邮箱不能再进行注册) 下面有一个你是人类的验证(照着 ...

  5. 【编译原理】构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 9.)(笔记)语法分析(未完,先搁置了!)

    [编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 9.) 文章目录 spi.py spi_lexer 我记得当我在大学(很久以前) ...

  6. 【编译原理】构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 8.)(笔记)一元运算符正负(+,-)

    [编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 8.) 文章目录 C语言代码(作者没提供完整的python代码,关键的改动提供了 ...

  7. 【编译原理】构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 7.)(笔记)解释器 interpreter 解析器 parser 抽象语法树AST

    [编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 7.) 文章目录 python代码 插--后序遍历 C语言代码(有错误) C语言 ...

  8. 【编译原理】让我们来构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 6.)(python/c/c++版)(笔记)

    [编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 6.) 文章目录 python代码 C语言代码 总结 今天是这一天:) &quo ...

  9. 【编译原理】让我们来构建一个简单的解释器(Let’s Build A Simple Interpreter. Part 5.)(python/c/c++版)(笔记)Lexer词法分析程序

    [编译原理]让我们来构建一个简单的解释器(Let's Build A Simple Interpreter. Part 5.) 文章目录 python代码 C语言代码 总结 你如何处理像理解如何创建解 ...

最新文章

  1. 知乎热问:国家何时整治程序员的高薪现象?
  2. Linux计划任务详解
  3. First Missing Positive
  4. 软件工程之快速原型模型
  5. Flask 第三方组件之 SQLAlchemy
  6. visuall assist x 破解方法
  7. maven处理和java平级的资源文件
  8. VueGoogleMaps在vue中的使用
  9. 【入门篇】Nginx + FastCGI 程序(C/C++) 搭建高性能web service的Demo及部署发布
  10. RHEL 5基础篇—Linux常用命令参考手册
  11. c 语言与试验系统,Turbo C/C++软件学习下载
  12. 一个Log系统,客户端运行起来,排除那些可以输出(编辑器文件)
  13. JavaScript设计模式——观察者模式
  14. leetcode *1818. 绝对差值和(2021.7.14)
  15. web前端-写给大家看的设计书-笔记-颜色运用-色轮使用
  16. oracle linux 退格,oracle database for linux 不能使用退格键
  17. nvme固态硬盘开机慢_解决win10系统下nvme固体硬盘开机慢的方法
  18. 邮件发送平台哪个最好?一站式邮件发送平台推荐!
  19. 微信公众平台接口调试工具json格式不对怎么搞_腾讯云和微信推出更快速的小程序开发平台,微信读书小程序作示范...
  20. 一个月份是第几季度输出

热门文章

  1. C语言用字符串sex储存,C语言必须要记住的经典程序
  2. 嵌入式制造愿景:选择智能相机的好处
  3. 业精于勤,荒于嬉;行成于思,毁于随(博客园)
  4. 业精于勤荒于嬉,行成于思毁于随
  5. [unity] 音频的二进制流转化为audioclip的两种方式
  6. 云客Drupal源码分析之合并数组
  7. Unity使用艺术字体
  8. 对比两张图片的MD5值
  9. 使用redis实现防止重复提交,成功解决方案 春风化作秋雨 2018-09-13 18:09:52 13787 收藏 6 分类专栏: 解决方案 版权 1、业务场景 业务开发中,常常涉及对前端操作
  10. chrome网页F12调试快捷键