ESP8266 nodemcu + DHT11 制作简易温湿度检测器

该教程只做整合使用。

前提

  1. 首先需要你有 开发板(ESP8266 nodemcu)


和 DHT11 温度检测器 ,三角的,

购买DHT11的时候选那些送杜邦线的

2.win 电脑

3.需要有wifi并且知道密码

4.arduino-ide 下载

https://downloads.arduino.cc/arduino-ide/nightly/arduino-ide_nightly-20221114_Windows_64bit.zip
5.烧录程序必须需要USB数据线 有些USB数据线只能充电不能传数据

教程一 简单的不用下载app的方式查看,通过wifi内网查看

将DHT11连接到NodeMCU是比较简单的,但连接方式有所不同,具体取决于您使用的是3个引脚的传感器还是4个引脚的传感器。
开发板和DHT11连接方式如下:

DHT11上标有(+或VCC)引脚的连接nodemcu的+ 3V引脚。
DHT11上标有(S或OUT)引脚的连接nodemcu的D4V引脚。
DHT11上标有(-或GND)引脚的连接nodemcu的GND引脚。


安装Arduino IDE


,打开ArduinoIDE,点击【项目】,再点击【新建】

我们首先要安装两个库DHT和Adafruit Unified Sensor

打开Arduino点击 项目>加载库>管理库


安装NodeMcu1.0开发板

打开Arduino点击 文件>首选向
在附加开发板管理网址填这个

https://arduino.esp8266.com/stable/package_esp8266com_index.json

然后点击 工具>开发板>开发板管理器 搜索esp8266然后安装

上传代码

首先选择NodeMcu1.0 工具 > 开发板 >NodeMcu1.0(ESP-12E Module)

然后 在选择端口 端口不正确会上传不成功
这个端口你可以看你的电脑 设备管理 里面会出现一个端口的 在里面看开发板端口
代码如下:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "DHT.h"

// Uncomment one of the lines below for whatever DHT sensor type you're using!
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

/*Put your SSID & Password*/
const char* ssid = "end";  // 这里改为你的wifi名称
const char* password = "12345678";  //这里改为你的wifi密码

ESP8266WebServer server(80);

// DHT Sensor
uint8_t DHTPin = D4; 
               
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);                

float Temperature;
float Humidity;
 
void setup() {
  Serial.begin(115200);
  delay(100);
  
  pinMode(DHTPin, INPUT);

  dht.begin();              

  Serial.println("Connecting to ");
  Serial.println(ssid);

  //connect to your local wi-fi network
  WiFi.begin(ssid, password);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected..!");
  Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

  server.on("/", handle_OnConnect);
  server.onNotFound(handle_NotFound);

  server.begin();
  Serial.println("HTTP server started");

}
void loop() {
  
  server.handleClient();
  
}

void handle_OnConnect() {

 Temperature = dht.readTemperature(); // Gets the values of the temperature
  Humidity = dht.readHumidity(); // Gets the values of the humidity 
  server.send(200, "text/html", SendHTML(Temperature,Humidity)); 
}

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

String SendHTML(float Temperaturestat,float Humiditystat){
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr +="<head> <meta name=\"viewport\" content=\"width=device-width,  initial-scale=1.0, user-scalable=no\">\n";
  ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";
  ptr +="<meta charset=\"UTF-8\">\n";
  ptr +="<title>智能温湿计</title>\n";
  ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
  ptr +="body{margin-top: 50px;}\n";
  ptr +="h1 {margin: 50px auto 30px;}\n";
  ptr +=" .wd {margin: 50px auto 30px;width: auto;color: #f39c12}\n";
  ptr +=" .wd1 {margin: 50px auto 30px;width: auto;color: #3498db}\n";
  ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
  ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
  ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
  ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
  ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
  ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
  ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
  ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
  ptr +=".data{padding: 10px;}\n";
  ptr +="</style>\n";
  ptr +="</head>\n";
  ptr +="<body>\n";
  
   ptr +="<div id=\"webpage\">\n";
   
   ptr +="<h1>室内温室检测系统</h1>\n";
   ptr +="<div class=\"data\">\n";
   ptr +="<div class=\"side-by-side temperature-icon\">\n";
   ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
   ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
   ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
   ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
   ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
   ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
   ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
   ptr +="</svg>\n";
   ptr +="</div>\n";
   ptr +="<div class=\"side-by-side temperature-text\">室内温度:</div>\n";
   ptr +="<div class=\"side-by-side temperature\">";
   ptr +=(int)Temperaturestat;
   ptr +="<span class=\"superscript\">°C</span></div>\n";
   ptr +="</div>\n";
   ptr +="<div class=\"data\">\n";
   ptr +="<div class=\"side-by-side humidity-icon\">\n";
   ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
   ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
   ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
   ptr +="</svg>\n";
   ptr +="</div>\n";
   ptr +="<div class=\"side-by-side humidity-text\">室内湿度:</div>\n";
   ptr +="<div class=\"side-by-side humidity\">";
   ptr +=(int)Humiditystat;
   ptr +="<span class=\"superscript\">%</span></div>\n";
   ptr +="</div>\n";
   //定义温度变量,并且赋值,用于逻辑判断。
    int wd = Temperaturestat ;
     
   if (wd>=30){
    ptr +="<div class=\"wd\">今天天气热,注意防暑哦</div>\n";
   }
   if (29>=wd&&wd>20){
    ptr +="<div class=\"wd1\">今天天气不错吆,尽情的玩耍吧</div>\n";
   }
   if (wd<10){
    ptr +="<div class=\"side-by-side humidity-text\">今天天气比较冷,多穿点衣服,小心着凉</div>\n";
   }
   ptr +="</div>\n";
   ptr +="</body>\n";
   ptr +="</html>\n";
   return ptr;
   }


点击 右箭头上传代码,代码需要编译需要时间,

这是上传成功的:

打开 工具>串口监视器
设置为115200波特率
按一下espp8266上面的的RST就可查看获取的ip地址

教程二 支持远程wifi查看的

下载点灯app
https://www.diandeng.tech/home
下载完app后,可以在app里面配置设备信息


下载完成之后可以添加设备,这里的密匙复制下来,等会代码要用到

安装Blinker库
打开arduinoIDE,点击项目,——加载库——管理库下搜索blinker安装最新版本

开发板和DHT11连接方式如下:

DHT11上标有(+或VCC)引脚的连接nodemcu的+ 3V引脚。
DHT11上标有(S或OUT)引脚的连接nodemcu的D4V引脚。
DHT11上标有(-或GND)引脚的连接nodemcu的GND引脚。



首先选择NodeMcu1.0 工具 > 开发板 >NodeMcu1.0(ESP-12E Module)

然后 在选择端口 端口不正确会上传不成功
这个端口你可以看你的电脑 设备管理 里面会出现一个端口的 在里面看开发板端口

上传代码:

#define BLINKER_WIFI
#define BLINKER_MIOT_SENSOR   //小爱同学定义为传感器设备
#include <Blinker.h>
#include <DHT.h>

#define DHTPIN 0 //定义单总线协议传输的数据引脚 这里也要改具体怎么改看下面说明
#define DHTTYPE    DHT11
DHT dht(DHTPIN, DHTTYPE);

char auth[] = "你的密匙";  //替代为你的密匙
char ssid[] = "wifi名称"; //2.4Gwifi名称,可以是手机热点,不要有中文
char pswd[] = "wifi密码";//WiFi密码

float humi_read = 0, temp_read = 0;
//新建数据类型组件
BlinkerNumber HUMI("humi");
BlinkerNumber TEMP("temp");


//心跳包
 void heartbeat()
  {
    HUMI.print(humi_read);
    TEMP.print(temp_read);

  }

void miotQuery(int32_t queryCode)      //小爱同学语音命令反馈
{
    BLINKER_LOG("MIOT Query codes: ", queryCode);

            int humi_read_int=humi_read;     //去掉湿度浮点
            BlinkerMIOT.humi(humi_read_int);     //小爱接收湿度
            BlinkerMIOT.temp(temp_read);      //小爱接收温度
            BlinkerMIOT.print();

}
void setup() {
    // 初始化串口,并开启调试信息,项目成型后可关闭
    Serial.begin(115200);
    BLINKER_DEBUG.stream(Serial);
    // 初始化有LED的IO
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    // 初始化blinker
    Blinker.begin(auth, ssid, pswd);
    Blinker.attachHeartbeat(heartbeat);//绑定回调函数
    dht.begin();
    BlinkerMIOT.attachQuery(miotQuery);
}

void loop() {
    Blinker.run();
    float h = dht.readHumidity();//读取温湿度数据
    float t = dht.readTemperature();

    if (isnan(h) || isnan(t))
    {
        BLINKER_LOG("Failed to read from DHT sensor!");
    }
    else
    {
        BLINKER_LOG("Humidity: ", h, " %");
        BLINKER_LOG("Temperature: ", t, " *C");//串口打印
        humi_read = h;
        temp_read = t;
    }
    Blinker.delay(2000); //延时2s
} 

这是上传成功的:


将代码中的你的密匙替换为在点灯app上获取到的密匙,wifi名称和密码分别替换成2.4GWiFi,也可以用手机热点代替,方便查看是否成功连接WiFi

添加数据组件


湿度数据,数据键名为代码前定义的humi,显示文本为湿度,单位为%,最大值为100
温度数据,数据键名为代码前定义的temp,显示文本为温度,单位为℃,最大值为100

设置完后保存,设备显示在线状态下,效果如图所示,我们可以看到温湿度有数据了

通用的坑

1.在代码的注释内容下我们可以很容易的找到用esp8266接收数据的引脚是哪一个

但是在这里指的是GPIO0,并不是我们esp8266d nodemcu的D0
代码上的

#define DHTPIN 0 //定义单总线协议传输的数据引脚 这里也要改具体怎么改看下面说明

这里我为大家提供了编号装换图,与是得知,我设置的gpio5是我们开发板上的D1


2.
需要在工具上面选择开发板和端口信息

springboot设置bean为默认主要bean

当springboot有多个不能名称但是相同bean的时候,可以使用 @Primary 注解设置其中一个为主要默认bean

有些类它没有用别名去注入bean,会导致注入的时候找到多个相同bean,报错

package com.jinw.config;

import com.jinw.utils.Threads;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 多线程配置
 *
 * @author admin
 */
@Configuration
@EnableAsync
public class ThreadConfig {
    /**
     * 短信类线程
     */
    public static final String SMS = "smsTaskExecutor";
    /**
     * 默认通用线程池
     */
    public static final String DEFAULT = "defaulTaskExecutor";
    /**
     * 周期性任务线程
     */
    public static final String SCHEDULED = "scheduledExecutorService";

    /**
     * MAIL任务线程
     */
    public static final String MAIL = "mailTaskExecutor";

    // 核心线程池大小
    private int corePoolSize = 50;


    @Bean(DEFAULT)
    @Primary
    public TaskExecutor defaultExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(3);
        // 设置最大线程数
        executor.setMaxPoolSize(3);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix(DEFAULT + "-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }

    @Bean(SMS)
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(3);
        // 设置最大线程数
        executor.setMaxPoolSize(3);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix(SMS + "-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(SCHEDULED)
    protected ScheduledExecutorService scheduledExecutorService() {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }

    /**
     * MAIL定时任务
     */
    @Bean(MAIL)
    public TaskExecutor mailTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(3);
        // 设置最大线程数
        executor.setMaxPoolSize(3);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix(MAIL + "-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

解决springboot yml文件明文显示密码的问题

1.pom添加 加密依赖

        <!-- 加密依赖 -->
        <dependency>
            <groupId>com.github.ulisesbocchio</groupId>
            <artifactId>jasypt-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>

2.编写工具类

package com.jeesite.modules.utils;

import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 配置文件加解密工具类
 * https://blog.csdn.net/qq_41617261/article/details/121448939
 */
@Component
public class JasyptUtil {
    private static String password;

    @Value("${jasypt.encryptor.password}")
    public static void setPassword(String password) {
        JasyptUtil.password = password;
    }

    private static final String PBEWITHMD5ANDDES = "PBEWithMD5AndDES";

    private static final String PBEWITHHMACSHA512ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";

    public static void main(String[] args) {
        JasyptUtil.password = "+oE67TSCE/j7==";
        // 加密
        String username = encyptPwd("123");
        String password = encyptPwd("678");
        System.out.println(username);
        System.out.println(password);
    }

    /**
     * 加密方法
     *
     * @param value 需要加密的值
     */
    public static String encyptPwd(String value) {
        // 1. 创建加解密工具实例
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        // 2. 加解密配置
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(password);
        config.setAlgorithm(PBEWITHMD5ANDDES);
        // 3. 为减少配置文件的书写,以下都是 Jasyp 3.x 版本,配置文件默认配置
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        String result = encryptor.encrypt(value);
        return result;
    }

    /**
     * 解密方法
     *
     * @param value 需要解密的值
     */
    public static String decryptPwd(String value) {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(password);
        config.setAlgorithm(PBEWITHMD5ANDDES);
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setProviderName("SunJCE");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);
        String result = encryptor.decrypt(value);
        return result;
    }
}

3.yml文件添加必要内容

#数据库密码加密
jasypt:
  encryptor:
    #加密盐
    password: +oE67TSCE/j7+
    algorithm: PBEWithMD5AndDES
    iv-generator-classname: org.jasypt.iv.NoIvGenerator

因为3.x的版本里面的加密方式默认是别的所以yml文件需要指定一下

4.

jdbc:
  # Mysql 数据库配置
  type: mysql
  driver: com.mysql.jdbc.Driver
  username: ENC(Y1dsy3NNUuDHERMyfT8jJRMNeBdg3l8U)
  password: ENC(SDQcQ+7C6/6H1eO4AoTwLmrmOWc4uOhfI0MG/llr1KA=)

先用工具类把明文加密然后在填进去
密文用ENC(密文字符串) 这种类型填入

linux设置jar自动启动

1、首先在jar包目录创建一个sh文件,并写上
在文件里面写上jdk环境变量
start.sh

#!/bin/bash
export JAVA_HOME=/usr/local/java/jdk1.8.0_291
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
nohup java -jar 具体路径/ROOT.jar >  /dev/null 2>&1 &

2、然后在服务器的/etc/rc.d文件夹里的
rc.local
添加上面的sh脚本

sh 具体路径/start.sh

3、重启linux
reboot
测试项目

4、如果想要输出日志可以这样写

nohup java -jar 具体路径/ROOT.jar > 具体路径/log.log 2>&1 &

记一次 前同事借钱不还问题

事实起由:

2021年4月20日,被告因资金周转向原告借款14798元,多次催促还钱,均为还。
被告身份证、手机号 姓名我都有。

以提交到被告户籍地,预计8月4号开庭审理。