• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

ESP8266、Golang、Vue3搭建个人气象站收集和简易数据看板平台

武飞扬头像
下雪还是下雨
帮助1

前言

这是一个简单,但是横跨嵌入式开发、后端Web开发、前端开发的项目。在开始之前,你可能需要了解Golang语言基础Gin框架MySQL基础HTTP请求ArduinoVue3

需要注意的是,项目并没有完全实现所有接口,读者可以根据自己的需求修改调整

设计与架构

学新通本文使用ESP8266 DHT11作为温湿度的收集设备,使用Golang的Gin框架作为Web后端,使用Vue3作为前端数据展示。

环境要求

系统环境的配置较多,详情查看下面的表格,本文不会讲解关于环境配置的相关问题。此处以笔者的配置为例,笔者使用的是windows11系统

环境 版本
node.js(nvm) 16.15.1
golang 1.18.3
mysql(docker) 8.0.29-1debian10
redis(docker) 7.0.2
arduino *

接口定义

title: 个人气象平台 v1.0.0
language_tabs:

  • shell: Shell
  • http: HTTP
  • javascript: JavaScript
  • ruby: Ruby
  • python: Python
  • php: PHP
  • java: Java
  • go: Go
    toc_footers: []
    includes: []
    search: true
    code_clipboard: true
    highlight_theme: darkula
    headingLevel: 2
    generator: “@tarslib/widdershins v4.0.15”

后端服务状态

GET ping测试

GET /server/ping

不限频率的接口,测试服务端是否存活,可用于服务看板

返回示例

成功

{
  "code": 0,
  "data": "pong",
  "msg": "ok"
}
返回结果
状态码 状态码含义 说明 数据模型
200 OK 成功 Inline
返回数据结构

状态码 200

名称 类型 必选 约束 中文名 说明
» code integer true none   none
» data string true none   none
» msg string true none   none

POST 服务端状态

POST /server/statue

监测服务端的基本状态,包括数据库延迟等,需要鉴权以及限制请求频率,防止过多请求,服务端被攻击。

请求参数
名称 位置 类型 必选 说明
MAC header string MAC地址
SN header string 设备编码

返回示例

成功

{
  "code": 0,
  "msg": "ok",
  "data": {
    "to_mysql": 13.9,
    "to_redis": 21.8,
    "to_hyper": 30.8
  }
}
返回结果
状态码 状态码含义 说明 数据模型
200 OK 成功 Inline
返回数据结构

状态码 200

名称 类型 必选 约束 中文名 说明
» code integer true none   none
» msg string true none   none
» data object true none   none
»» to_mysql number true none   MySQL读写延迟
»» to_redis number true none   Redis读写延迟
»» to_hyper number false none   心知天气API延迟

数据上报

POST 数据收集平台数据上报

POST /record/upload

Body 请求参数

{
  "temperature": 0,
  "humidity": 0
}
请求参数
名称 位置 类型 必选 说明
SN header string 设备注册ID
body body object none
» temperature body integer none
» humidity body number none

返回示例

成功

{
  "code": 0,
  "data": null,
  "msg": "ok"
}
返回结果
状态码 状态码含义 说明 数据模型
200 OK 成功 Inline
返回数据结构

状态码 200

名称 类型 必选 约束 中文名 说明
» code integer true none   none
» data null true none   none
» msg string true none   none

数据提供

GET 现在的温湿度

GET /data/new

返回示例

成功

{
  "code": 0,
  "data": {
    "temperature": 0,
    "humidity": 0,
    "time": ""
  },
  "msg": "ok"
}
返回结果
状态码 状态码含义 说明 数据模型
200 OK 成功 Inline
返回数据结构

状态码 200

名称 类型 必选 约束 中文名 说明
» code integer true none   none
» data object true none   none
»» temperature integer true none   none
»» humidity integer true none   none
»» time string true none   none
» msg string true none   none

POST 历史数据

POST /data/history

Body 请求参数

{
  "start_time": 0,
  "end_time": 0
}
请求参数
名称 位置 类型 必选 说明
body body object none
» start_time body integer none
» end_time body integer none

返回示例

成功

{
  "code": 0,
  "data": [
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    },
    {
      "temperature": 1,
      "humidity": 90,
      "time": "2022-07-05T21:38:46 08:00"
    }
  ],
  "msg": "ok"
}
学新通
返回结果
状态码 状态码含义 说明 数据模型
200 OK 成功 Inline
返回数据结构

状态码 200

名称 类型 必选 约束 中文名 说明
» code integer true none   none
» data [object] true none   none
»» temperature integer true none   none
»» humidity integer true none   none
»» time integer true none   none
» msg string true none   none

数据模型

基本返回结构




{
  "code": 0,
  "msg": "string",
  "data": "string"
}

属性
名称 类型 必选 约束 中文名 说明
code integer true none   none
msg string true none   none
data string true none   none

数据收集平台制作

设备平台

  • ESP8266(带底板)
  • DHT11温湿度传感器(带底板3脚)
  • 杜邦线若干

物理连接

使用ESP8266的GPIO14接口作为传感器的信号线
如果您的ESP8266带底板,可以参考下图中的引脚对应关系,或查询自己所购买主板的说明文档
学新通
本文使用的DHT11传感器也带底板,引脚数为3,如图
学新通

连接对应表

ESP8266 DHT11
D5(GPIO14) DATA
3V VCC
GND GND

程序编写

首先新建一个空项目

// The setup() function runs once each time the micro-controller starts
void setup() {

}

// Add the main program code into the continuous loop() function
void loop() {

}

添加网络连接,需要使用ESP8266WiFi.h
具体可以查看代码注释,注意需要修改WIFI配置

#include <ESP8266WiFi.h>

// 设置WIFI连接参数,记得更改
#ifndef STASSID
#define STASSID "XXXX"      // WIFI连接SSID
#define STAPSK  "XXXXXXXX" // WIFI连接密码
#endif

void setup() {
	// 设置WIFI连接参数,并开始连接
	WiFi.begin(STASSID, STAPSK);
	
	// 循环检测WIFI连接状态,是否连接成功
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
	}
}

void loop() {
    if ((WiFi.status() == WL_CONNECTED)) {
		// 接下来会在此处添加处理程序
    }
	
}
学新通

你们会注意到在loop函数中,我们依旧会判断WIFI连接是否正常,以防连接断开。

添加获取温度,需要使用SimpleDHT.h
需要注意读取频率,DHT11限制为1Hz,但是我们读取的颗粒精度不需要这么精细,我们会在每一个循环休眠2s

#include <ESP8266WiFi.h>
#include <SimpleDHT.h>
// 设置WIFI连接参数,记得更改
#ifndef STASSID
#define STASSID "XXXX"      // WIFI连接SSID
#define STAPSK  "XXXXXXXX" // WIFI连接密码
#endif

// DHT11对象
int pinDHT11 = 14;
SimpleDHT11 dht11(pinDHT11);

void setup() {
	// 设置WIFI连接参数,并开始连接
	WiFi.begin(STASSID, STAPSK);
	
	// 循环检测WIFI连接状态,是否连接成功
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
	}
}

void loop() {
    if ((WiFi.status() == WL_CONNECTED)) {
		// 从DHT11获取温度
		byte temperature = 0; //温度
		byte humidity = 0;    //湿度
		// 读取数据,并写入
		dht11.read(&temperature, &humidity, NULL);
		
    }
	
	// 休眠2秒
	delay(2000);
	
}
学新通

我们成功的读取了温湿度数据,但是总有可能导致数据读取失败,需要我们判断温度是否读取失败,然后在短时间内重试

#include <ESP8266WiFi.h>
#include <SimpleDHT.h>
// 设置WIFI连接参数,记得更改
#ifndef STASSID
#define STASSID "XXXX"      // WIFI连接SSID
#define STAPSK  "XXXXXXXX" // WIFI连接密码
#endif

// DHT11对象
int pinDHT11 = 14;
SimpleDHT11 dht11(pinDHT11);

void setup() {
	// 设置WIFI连接参数,并开始连接
	WiFi.begin(STASSID, STAPSK);
	
	// 循环检测WIFI连接状态,是否连接成功
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
	}
}

void loop() {
    if ((WiFi.status() == WL_CONNECTED)) {
		// 从DHT11获取温度
		byte temperature = 0; //温度
		byte humidity = 0;    //湿度
		int err = SimpleDHTErrSuccess; //错误码
		// 读取数据,并写入
		if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
			// 如果读取错误,就在短时间内重试
			delay(800);
			return;
		}
		
    }
	
	// 休眠2秒
	delay(2000);
	
}
学新通

接下来,我们会向服务器发送请求,并完成所有的嵌入式代码

完整的代码如下:

#include <ESP8266HTTPClient.h>
#include <ESP8266WiFi.h>
#include <SimpleDHT.h>

#define SERVER_IP "weather.station.ptianya.top" // 后端服务的位置


// 设置WIFI连接参数,记得更改
#ifndef STASSID
#define STASSID "XXXX"      // WIFI连接SSID
#define STAPSK  "XXXXXXXX" // WIFI连接密码
#endif

// DHT11对象
int pinDHT11 = 14;
SimpleDHT11 dht11(pinDHT11);

void setup() {
	// 设置WIFI连接参数,并开始连接
	WiFi.begin(STASSID, STAPSK);
	
	// 循环检测WIFI连接状态,是否连接成功
	while (WiFi.status() != WL_CONNECTED) {
		delay(500);
	}
}

void loop() {
    if ((WiFi.status() == WL_CONNECTED)) {
		// 从DHT11获取温度
		byte temperature = 0; //温度
		byte humidity = 0;    //湿度
		int err = SimpleDHTErrSuccess; //错误码
		// 读取数据,并写入
		if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
			// 如果读取错误,就在短时间内重试
			delay(800);
			return;
		}
		
		WiFiClient client;
		HTTPClient http;

		// 设置请求路由
		http.begin(client, "http://" SERVER_IP "/record/upload"); //HTTP
		// 设置请求头
		http.addHeader("Content-Type", "application/json");
		http.addHeader("sn", "9d0dd9f2e3bc");
		// 设置Body
		char body[1024];
		snprintf(body, sizeof(body), "{\"temperature\":%d,\"humidity\":%d}", (int)temperature, (int)humidity);
		// 开始请求
		int httpCode = http.POST(body);

		// httpCode will be negative on error

		http.end();
    }
	
	// 休眠2秒
	delay(2000);
	
}
学新通

后端部分实现

目前,后端项目已经开源在了Github上,具体可以访问源码,具体说明,可以查看项目文档

前端部分实现

前端部分大致只修改了App.vue部分,故直接在此处贴出代码
需要使用arco的组件库
并修改文中的服务地址

<template>
  <div class = main>
    <a-space size="large">
      <a-statistic :value=temperature :precision="1" show-group-separator :value-style="{ color: temperature_color }">
        <template #suffix>&#8451</template>
        <template #title>温度</template>
      </a-statistic>
      <a-statistic title="湿度" :value=humidity :precision="2" :value-style="{ color: humidity_color }">
        <template #suffix>%</template>
      </a-statistic>
    </a-space>
  </div>
  <div id="update_time_div">
    <a-space>
      <a-statistic title="更新时间" :value=time format="YYYY-MM-DD HH:mm:ss" id="update_time" animation>
      </a-statistic>
    </a-space>
  </div>
</template>



<script>
import axios from 'axios'
import dayjs from 'dayjs'
export default {
  mounted() {
    this.getData()
    setInterval(() => {
      this.getData()
    }, 2000)
  },
  data() {
    return {
      temperature: -999,
      humidity: -99.99,
      time: '',
      temperature_color: '#0fbf60',
      humidity_color: '#0fbf60',
    }
  },
  methods: {
    getData() {
      axios.get("http://XXXX").then(res => {
        this.temperature = res.data.data.temperature
        this.humidity = res.data.data.humidity
        this.time = dayjs(res.data.data.time)
        if (this.temperature < 10) {
          this.temperature_color = '#3491FA'
        } else if (this.temperature >= 30) {
          this.temperature_color = '#F53F3F'
        } else {
          this.temperature_color = '#0fbf60'
        }
        if (this.humidity < 58) {
          this.humidity_color = '#F53F3F'
        } else if (this.humidity > 80) {
          this.humidity_color = '#3491FA'
        } else {
          this.humidity_color = '#0fbf60'
        }
      })
    }
  }
}

</script>

<style>
.main {
  margin: 0 auto;
  text-align: center;
}

#update_time .arco-statistic-value {
  font-size: 16px;
}

#update_time_div {
  margin-top: 20px;
}
</style>

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgekiaf
系列文章
更多 icon
同类精品
更多 icon
继续加载