物联网之微信小程序控制LED集合、开关灯、闪烁灯、呼吸灯、流水灯、WiFi、http

news2024/9/17 8:54:55

MENU

  • ESP32(服务端)
    • C++
    • 解析
  • 微信小程序(移动端)
    • Html
    • JavaScript


ESP32(服务端)

C++

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>

const char* ssid = "jifu";
const char* pass = "2022xinchan!@#";
const int ledPin = 5;
bool isTwinkle = false;
bool isFlowing = false;
int pin_list[5] = { 13, 23, 14, 27, 4 };
int size = sizeof(pin_list) / sizeof(pin_list[0]);
bool isBreathing = false;

WebServer server(8068);

// 通用响应函数
void sendResponse(int code, const char* status, const char* message, const String& response) {
  StaticJsonDocument<200> doc;
  doc["code"] = code;
  doc["status"] = status;
  doc["message"] = message;
  doc["response"] = response;
  String res;
  serializeJson(doc, res);
  server.send(code, "application/json", res);
}

// LED开关
void ledSwitch() {
  String isSwitch = server.arg("isSwitch");
  if (isSwitch == "true") {
    digitalWrite(ledPin, HIGH);
    sendResponse(200, "success", "LED已打开", isSwitch);
  } else if (isSwitch == "false") {
    digitalWrite(ledPin, LOW);
    sendResponse(200, "success", "LED已关闭", isSwitch);
  } else {
    sendResponse(400, "error", "无效的开关状态", isSwitch);
  }
}

// LED闪烁
void ledTwinkle() {
  String twinkle = server.arg("isTwinkle");
  if (twinkle == "true") {
    isTwinkle = true;
    sendResponse(200, "success", "LED开始闪烁", twinkle);
  } else if (twinkle == "false") {
    isTwinkle = false;
    sendResponse(200, "success", "LED停止闪烁", twinkle);
  } else {
    sendResponse(400, "error", "无效的闪烁状态", twinkle);
  }
}

// LED呼吸
void ledBreathing() {
  String breathing = server.arg("isBreathing");
  if (breathing == "true") {
    isBreathing = true;
    sendResponse(200, "success", "LED开始呼吸", breathing);
  } else if (breathing == "false") {
    isBreathing = false;
    // 因为使用同一个引脚
    // 当启动过呼吸灯后
    // 同一引脚的其他功能无法使用
    // 所以在关闭呼吸灯时初始化一下引脚
    pinMode(ledPin, OUTPUT);
    sendResponse(200, "success", "LED停止呼吸", breathing);
  } else {
    sendResponse(400, "error", "无效的呼吸状态", breathing);
  }
}

// LED流水
void ledFlowing() {
  String flowing = server.arg("isFlowing");
  if (flowing == "true") {
    isFlowing = true;
    sendResponse(200, "success", "LED开始流水", flowing);
  } else if (flowing == "false") {
    isFlowing = false;
    for (int i = 0; i < size; i++) digitalWrite(pin_list[i], LOW);
    sendResponse(200, "success", "LED停止流水", flowing);
  } else {
    isFlowing = false;
    for (int i = 0; i < size; i++) digitalWrite(pin_list[i], LOW);
    sendResponse(400, "error", "无效的流水状态", flowing);
  }
}

// 主函数
void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("Loading in progress...");
  }

  Serial.print("\nWiFiIP: ");
  Serial.println(WiFi.localIP());

  server.on("/api/led/switch", HTTP_GET, ledSwitch);
  server.on("/api/led/twinkle", HTTP_GET, ledTwinkle);
  server.on("/api/led/breathing", HTTP_GET, ledBreathing);
  server.on("/api/led/flowing", HTTP_GET, ledFlowing);

  for (int i = 0; i < size; i++) pinMode(pin_list[i], OUTPUT);
  server.begin();
}

// 循环函数
void loop() {
  server.handleClient();
  if (isTwinkle) {
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
  }
  if (isBreathing) {
    for (int i = 0; i < 256; i++) {
      analogWrite(ledPin, i);
      delay(10);
    }
    for (int i = 255; i >= 0; i--) {
      analogWrite(ledPin, i);
      delay(10);
    }
  }
  if (isFlowing) {
    for (int i = 0; i < size; i++) {
      digitalWrite(pin_list[i], HIGH);
      digitalWrite(pin_list[(i > 0) ? (i - 1) : (size - 1)], LOW);
      delay(250);
    }
  }
}

解析

前言
程序是一个通过WiFi使用Web接口控制ESP32上LED灯的应用。它使用WiFi连接网络,并通过WebServer库处理HTTP请求,从而根据请求执行各种LED操作(开关灯、闪烁灯、呼吸灯和流水灯)。


包含的库

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>

WiFi.h用于连接ESP32到WiFi网络。
WebServer.h用于创建一个Web服务器来处理HTTP请求。
ArduinoJson.h用于构建和解析JSON数据,方便API的响应格式化。


全局变量

const char* ssid = "jifu";
const char* pass = "2022xinchan!@#";
const int ledPin = 5;
bool isTwinkle = false;
bool isFlowing = false;
int pin_list[5] = { 13, 23, 14, 27, 4 };
int size = sizeof(pin_list) / sizeof(pin_list[0]);
bool isBreathing = false;

WebServer server(8068);

ssid和passWiFi的SSID和密码,用于连接WiFi网络。
ledPin控制LED灯的GPIO引脚,这里设置为5号引脚。
isTwinkleisFlowingisBreathing分别标识LED是否正在执行闪烁、流水、呼吸灯效果。
pin_list存储多个GPIO引脚,用于控制流水灯效果。
server(8068)创建一个Web服务器,监听8086端口。


通用响应函数

void sendResponse(int code, const char* status, const char* message, const String& response) {
  StaticJsonDocument<200> doc;
  doc["code"] = code;
  doc["status"] = status;
  doc["message"] = message;
  doc["response"] = response;
  String res;
  serializeJson(doc, res);
  server.send(code, "application/json", res);
}

sendResponse用于发送HTTP响应,将请求结果打包成JSON格式,包含code、status、message和response字段,返回给客户端。


LED开关控制

void ledSwitch() {
  String isSwitch = server.arg("isSwitch");
  if (isSwitch == "true") {
    digitalWrite(ledPin, HIGH);
    sendResponse(200, "success", "LED已打开", isSwitch);
  } else if (isSwitch == "false") {
    digitalWrite(ledPin, LOW);
    sendResponse(200, "success", "LED已关闭", isSwitch);
  } else {
    sendResponse(400, "error", "无效的开关状态", isSwitch);
  }
}

根据isSwitch参数来控制LED的开关状态,true表示打开,false表示关闭。


LED闪烁控制

void ledTwinkle() {
  String twinkle = server.arg("isTwinkle");
  if (twinkle == "true") {
    isTwinkle = true;
    sendResponse(200, "success", "LED开始闪烁", twinkle);
  } else if (twinkle == "false") {
    isTwinkle = false;
    sendResponse(200, "success", "LED停止闪烁", twinkle);
  } else {
    sendResponse(400, "error", "无效的闪烁状态", twinkle);
  }
}

通过控制isTwinkle变量,来启动或停止LED的闪烁效果。


LED呼吸灯控制

void ledBreathing() {
  String breathing = server.arg("isBreathing");
  if (breathing == "true") {
    isBreathing = true;
    sendResponse(200, "success", "LED开始呼吸", breathing);
  } else if (breathing == "false") {
    isBreathing = false;
    pinMode(ledPin, OUTPUT);
    sendResponse(200, "success", "LED停止呼吸", breathing);
  } else {
    sendResponse(400, "error", "无效的呼吸状态", breathing);
  }
}

根据isBreathing参数控制LED的呼吸效果,呼吸灯效果通过循环改变LED亮度实现。


LED流水灯控制

void ledFlowing() {
  String flowing = server.arg("isFlowing");
  if (flowing == "true") {
    isFlowing = true;
    sendResponse(200, "success", "LED开始流水", flowing);
  } else if (flowing == "false") {
    isFlowing = false;
    for (int i = 0; i < size; i++) digitalWrite(pin_list[i], LOW);
    sendResponse(200, "success", "LED停止流水", flowing);
  } else {
    sendResponse(400, "error", "无效的流水状态", flowing);
  }
}

控制多个引脚上的LED依次亮灭,模拟流水灯效果。


主函数setup()

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print("Loading in progress...");
  }

  Serial.print("\nWiFiIP: ");
  Serial.println(WiFi.localIP());

  server.on("/api/led/switch", HTTP_GET, ledSwitch);
  server.on("/api/led/twinkle", HTTP_GET, ledTwinkle);
  server.on("/api/led/breathing", HTTP_GET, ledBreathing);
  server.on("/api/led/flowing", HTTP_GET, ledFlowing);

  for (int i = 0; i < size; i++) pinMode(pin_list[i], OUTPUT);
  server.begin();
}

设置WiFi连接、初始化LED引脚和Web服务器,监听不同的API路径并关联对应的处理函数。


主循环loop()

void loop() {
  server.handleClient();
  if (isTwinkle) {
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
  }
  if (isBreathing) {
    for (int i = 0; i < 256; i++) {
      analogWrite(ledPin, i);
      delay(10);
    }
    for (int i = 255; i >= 0; i--) {
      analogWrite(ledPin, i);
      delay(10);
    }
  }
  if (isFlowing) {
    for (int i = 0; i < size; i++) {
      digitalWrite(pin_list[i], HIGH);
      digitalWrite(pin_list[(i > 0) ? (i - 1) : (size - 1)], LOW);
      delay(250);
    }
  }
}

循环执行LED的控制逻辑,处理客户端的请求,并根据当前的状态变量决定是否执行闪烁、呼吸或流水效果。


总结
程序通过简单的HTTP接口,通过Web页面实现控制ESP32的LED开关灯、闪烁灯、呼吸灯和流水灯功能。


微信小程序(移动端)

Html

代码

<view>
  <view class="p_18 bs_bb bs_0_8_8_efefef radius_6 fs_28">
    <view class="fw_b">名称: {{info.title}}</view>
    <view class="color_909399">别名: {{info.aliasListStr}}</view>
  </view>
  <view class="mt_58 d_g gtc_2fr gg_38">
    <view class="w_100_ pt_28 pb_28 bs_bb ta_c bc_efefef radius_8 {{activa===item.id?'color_409eff':''}}" wx:for="{{apiList}}" wx:key="id" data-id="{{item.id}}" catchtap="handleLedAction">
      LED{{item.title}}灯已{{ledSwitch?'开启':'关闭'}}
    </view>
  </view>
</view>

解析
前言
代码段用于微信小程序的WXML模板,构建一个视图,用于显示LED灯的控制面板。包含一些动态数据绑定、条件渲染和事件处理。


外层<view>标签
最外层的<view>标签包含整个视图的结构布局,是微信小程序中用于显示布局的基础容器。它内嵌多个<view>子元素,每个子元素分别对应不同的功能展示。


第一个<view>块显示信息

<view class="p_18 bs_bb bs_0_8_8_efefef radius_6 fs_28">
  <view class="fw_b">名称: {{info.title}}</view>
  <view class="color_909399">别名: {{info.aliasListStr}}</view>
</view>

1、class="p_18 bs_bb bs_0_8_8_efefef radius_6 fs_28"用于<view>多个CSS样式类,控制外边距、边框样式、圆角半径和字体大小。
1.1、p_18表示内边距为18单位。
1.2、bs_bb表示边框样式为双线框。
1.3、radius_6表示圆角半径为6单位。
1.4、fs_28表示字体大小为28单位。
2、{{info.title}}通过数据绑定显示info.title,这是一个动态数据,用于显示某个对象的名称。
3、{{info.aliasListStr}}通过数据绑定显示info.aliasListStr,显示对象的别名。


第二个<view>块控制LED面板

<view class="mt_58 d_g gtc_2fr gg_38">
  <view class="w_100_ pt_28 pb_28 bs_bb ta_c bc_efefef radius_8 {{activa===item.id?'color_409eff':''}}" wx:for="{{apiList}}" wx:key="id" data-id="{{item.id}}" catchtap="handleLedAction">
    LED{{item.title}}灯已{{ledSwitch?'开启':'关闭'}}
  </view>
</view>

1、外层<view>样式,
1.1、mt_58设置顶部外边距为58单位。
1.2、d_g设置为网格布局(display: grid)。
1.3、gtc_2fr设置网格布局的列定义为2个fr单位。
1.4、gg_38网格单元格之间的间距为38单位。
2、内层<view>,每个内层<view>是一个LED控制按钮。
2.1、w_100_宽度设置为100%。
2.2、pt_28 pb_28上下内边距为28单位。
2.3、bs_bb边框样式为双线框。
2.4、ta_c文本居中。
2.5、bc_efefef背景颜色设置为浅灰色(#efefef)。
2.6、radius_8圆角半径为8单位。
2.7、{{activa===item.id?'color_409eff':''}}是一个条件样式绑定,检查activa是否等于当前项的id,如果是,则应用color_409eff(蓝色)样式;否则,不应用任何颜色样式。
3、wx:for="{{apiList}}" wx:key="id"使用wx:for指令进行循环渲染,apiList是一个列表,表示多个LED控制选项,每个选项的id作为唯一键。
4、data-id="{{item.id}}"为每个<view>元素设置一个自定义数据属性data-id,保存当前LED的id,以便在事件中使用。
5、catchtap="handleLedAction"绑定点击事件catchtap,当用户点击该LED控制时,会调用handleLedAction函数。
6、LED{{item.title}}灯已{{ledSwitch?'开启':'关闭'}}动态显示LED状态,{{item.title}}显示当前LED的名称,{{ledSwitch ? ‘开启’ : ‘关闭’}}根据ledSwitch变量的布尔值来显示“开启”或“关闭”状态。


总结
代码段是微信小程序中的WXML模板,显示一个LED灯控制面板。每个LED通过一个点击区域显示其当前状态(开启或关闭),并且点击该区域时触发相应的事件来切换LED的状态。


JavaScript

前言

代码段是一个微信小程序的页面逻辑,主要功能是通过API接口控制LED灯的不同操作(开关灯、闪烁灯、呼吸灯和流水灯)。


代码

import {
  apiLedSwitch,
  apiLedTwinkle,
  apiBreathing,
  apiLedFlowing
} from '../../api/led.js';

const {
  showToast
} = getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    info: {},
    apiObj: {},
    apiList: [],
    activa: ''
  },

  async handleLedAction(event) {
    const that = this;
    const thatData = that.data;
    const apiObj = thatData.apiObj;
    const id = event.target.dataset.id;
    let activa = thatData.activa;
    let api = undefined;
    let text = undefined;

    if (activa === '') {
      activa = id;
    } else if (id === activa) {
      activa = '';
    } else if (activa !== '' && id !== activa) {
      return showToast('请先关闭其他LED');
    }
    api = apiObj[id];
    text = api.text;

    const {
      message
    } = await api.fn({
      [text]: activa ? true : false
    });

    that.setData({
        activa
      },
      () => showToast(message)
    );
  },

  runInit() {
    let that = this,
      thatData = thatData,
      apiObj = {
        ledSwitch: {
          title: '开关',
          text: 'isSwitch',
          fn: apiLedSwitch
        },
        ledFlicker: {
          title: '闪烁',
          text: 'isTwinkle',
          fn: apiLedTwinkle
        },
        ledBreathing: {
          title: '呼吸',
          text: 'isBreathing',
          fn: apiBreathing
        },
        ledFlowing: {
          title: '流水',
          text: 'isFlowing',
          fn: apiLedFlowing
        }
      },
      apiList = [];

    for (const key in apiObj) {
      if (Object.hasOwnProperty.call(apiObj, key)) {
        let title = apiObj[key].title;

        apiList.push({
          id: key,
          title
        });
      }
    }
    that.setData({
      apiObj,
      apiList
    });
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.runInit();
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
    const row = wx.getStorageSync('electronicComponent');

    row.aliasListStr = row.aliasList.slice(1);
    row.aliasListStr = row.aliasListStr.toString();
    row.aliasListStr = row.aliasListStr.replace(/,/g, "、");
    this.setData({
      info: row
    });
  }
});

导入依赖模块

import {
  apiLedSwitch,
  apiLedTwinkle,
  apiBreathing,
  apiLedFlowing
} from '../../api/led.js';

const {
  showToast
} = getApp();

apiLedSwitchapiLedTwinkleapiBreathingapiLedFlowing从led.js文件中导入控制LED操作的API函数。
showToast通过getApp()获取全局的showToast方法,用于展示提示信息。


页面data数据

data: {
  info: {},
  apiObj: {},
  apiList: [],
  activa: ''
}

info存储当前电子组件的信息。
apiObj存储每个LED操作的API函数、文本标识以及对应的标题信息。
apiList生成的LED操作列表,用于显示在页面上。
activa标识当前激活的LED操作的ID,用于控制每次只能激活一个LED功能。


handleLedAction方法

async handleLedAction(event) {
  const that = this;
  const thatData = that.data;
  const apiObj = thatData.apiObj;
  const id = event.target.dataset.id;
  let activa = thatData.activa;
  let api = undefined;
  let text = undefined;

  if (activa === '') {
    activa = id;
  } else if (id === activa) {
    activa = '';
  } else if (activa !== '' && id !== activa) {
    return showToast('请先关闭其他LED');
  }
  api = apiObj[id];
  text = api.text;

  const { message } = await api.fn({ [text]: activa ? true : false });

  that.setData({
      activa
    },
    () => showToast(message)
  );
}

event通过事件对象event获取当前点击的LED按钮的id。
activa当前激活的LED操作。如果没有激活,则将activa设置为点击的id;如果已经激活,再次点击同一个id,则取消激活;如果点击其他LED,则提示先关闭当前的LED。
apiObj从apiObj中获取当前id对应的API函数和参数text,text用于动态生成请求的参数字段名。
api.fn调用对应的API函数,传入动态生成的参数,如{ isSwitch: true }{ isSwitch: false },控制LED状态。
messageAPI响应后,显示API返回的提示信息。
setData更新activa状态,并在回调中使用showToast显示操作结果的提示。


runInit方法

runInit() {
  let that = this,
    thatData = thatData,
    apiObj = {
      ledSwitch: {
        title: '开关',
        text: 'isSwitch',
        fn: apiLedSwitch
      },
      ledFlicker: {
        title: '闪烁',
        text: 'isTwinkle',
        fn: apiLedTwinkle
      },
      ledBreathing: {
        title: '呼吸',
        text: 'isBreathing',
        fn: apiBreathing
      },
      ledFlowing: {
        title: '流水',
        text: 'isFlowing',
        fn: apiLedFlowing
      }
    },
    apiList = [];

  for (const key in apiObj) {
    if (Object.hasOwnProperty.call(apiObj, key)) {
      let title = apiObj[key].title;
      apiList.push({
        id: key,
        title
      });
    }
  }
  that.setData({
    apiObj,
    apiList
  });
}

apiObj是一个配置对象,包含每种LED操作的标题(如"开关"、"闪烁"等)、对应的API参数字段(如isSwitch、isTwinkle等)和API函数(如apiLedSwitch、apiLedTwinkle等)。
apiList通过遍历apiObj生成LED操作列表,每个操作项包含id和title,用于显示在界面上。
setData将生成的apiObj和apiList更新到页面的数据中。


onLoad生命周期函数

onLoad(options) {
  this.runInit();
}

页面加载时,调用runInit方法初始化API操作列表。


onShow生命周期函数

onShow() {
  const row = wx.getStorageSync('electronicComponent');
  
  row.aliasListStr = row.aliasList.slice(1);
  row.aliasListStr = row.aliasListStr.toString();
  row.aliasListStr = row.aliasListStr.replace(/,/g, "、");
  this.setData({
    info: row
  });
}

1、从本地存储中读取电子组件的信息(electronicComponent),并处理其aliasList字段。
1.1、slice(1)移除第一个别名(可能是主名称)。
1.2、toString()将别名列表转换为字符串。
1.3、replace(/,/g, "、")将逗号替换为顿号。
2、将处理后的信息设置到info数据字段,用于页面展示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GB2312编码(加2020H、8080H原理)

区位码、内码、国标码 转换及原理 背景答题思考相关资料 背景 问题: 某汉字的国标码为5650H&#xff0c;那么它的机内码为&#xff08; B &#xff09;。A E6E0H B D6D0H C C6C0H D 8080H答题 思考 为什么要加上2020H和8080H&#xff1f;区位码、内码、国标码怎么转换非常简单…

【硬件知识】关于RAM的“那些事”

文章目录 一、DRAM&#xff08;动态随机存取存储器&#xff09;二、SRAM&#xff08;静态随机存取存储器&#xff09;三、DRAM和SRAM的差异与区别 一、DRAM&#xff08;动态随机存取存储器&#xff09; 工作原理&#xff1a;DRAM使用电容来存储数据。每一位数据通过一个电容和…

【深度学习讲解笔记】第1章-机器学习基础

1.机器学习是什么 机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09;&#xff0c;顾名思义就是让机器学会做一件事情&#xff0c;比如语音识别&#xff0c;机器听一段声音&#xff0c;产生这段声音对应的文字。或是识别图片中有几个人&#xff0c;几辆车。这些…

2024年语音识别转文字工具的崛起

无论是繁忙的会议记录、远程教学的即时笔记&#xff0c;还是日常生活的语音备忘&#xff0c;只需轻轻一说&#xff0c;便能瞬间转化为清晰可编辑的文字&#xff0c;这种便捷与高效无疑为现代生活增添了无限可能。本文将带你深入探索语音识别转文字工具的奥秘。 1.365在线转文字…

【Python篇】matplotlib超详细教程-由入门到精通(上篇)

文章目录 第一部分&#xff1a;基础概念与简单绘图1.1 matplotlib 简介1.2 创建第一个折线图1.3 图表的基本组成元素 第二部分&#xff1a;图表样式与修饰2.1 修改图表样式2.2 添加图例2.3 调整坐标轴与刻度 第三部分&#xff1a;绘制不同类型的图表3.1 散点图 (Scatter Plot)3…

使用 Homebrew 在 macOS 上安装 Conda

Homebrew 是一个流行的 macOS 包管理器&#xff0c;可以帮助你安装和管理各种软件包。 以下是使用 Homebrew 安装 Conda 的步骤&#xff1a; 1. 安装 Homebrew 如果你还没有安装 Homebrew&#xff0c;可以通过以下命令安装&#xff1a; /bin/bash -c "$(curl -fsSL htt…

《机器学习》—— XGBoost(xgb.XGBClassifier) 分类器

文章目录 一、XGBoost 分类器的介绍二、XGBoost&#xff08;xgb.XGBClassifier&#xff09; 分类器与随机森林分类器&#xff08;RandomForestClassifier&#xff09;的区别三、XGBoost&#xff08;xgb.XGBClassifier&#xff09; 分类器代码使用示例 一、XGBoost 分类器的介绍…

微信小程序 自定义组件

1. 微信小程序 自定义组件 微信小程序支持组件化开发&#xff0c;这有助于我们复用代码&#xff0c;提高开发效率。下面我将给出一个简单的微信小程序组件化示例&#xff0c;包括一个自定义组件的创建和使用。 1.1. 创建自定义组件 首先&#xff0c;在项目的 components 目录…

建筑二次供水的基本概念

什么是二次供水&#xff1f; 二次供水是城市供水的主要组成部分&#xff0c;是指集中式供水在入户之前经再度储存、加压和消毒后&#xff0c;通过管道输送给用户的供水方式。 为什么要使用二次供水&#xff1f; 由于市政供水的服务水压通常只能达到较低的楼层&#xff0c;而…

部分库函数及其模拟

前言&#xff1a;当我们学习c/c库函数的时候&#xff0c;我们可以用网站 cplusplus.com - The C Resources Network 来进行查阅&#xff0c;学习。 目录 库函数&#xff1a; 1.字符串函数 1.1求字符串长度 strlen 1.2长度不受限制的字符串函数 1.2.1strcpy 1.2.2strca…

“阡陌云旅”黄河九省文化旅游平台

“阡陌云旅”黄河九省文化旅游平台 GitHub地址&#xff1a;https://github.com/guoJiaQi-123/Yellow-River-Cloud-Journey 项目背景 “阡陌云旅”黄河九省文化旅游平台 “阡陌云旅” 黄河九省文化旅游平台是一个专注于黄河流域九省文化旅游资源整合与推广的项目。 黄河是中…

Spring Framework系统框架

序号表示的是学习顺序 IoC&#xff08;控制反转&#xff09;/DI&#xff08;依赖注入&#xff09;: ioc&#xff1a;思想上是控制反转&#xff0c;spring提供了一个容器&#xff0c;称为IOC容器&#xff0c;用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理…

HomeAssistant添加HACS绑定米家与苹果HomeKit设备并实现远程管理

文章目录 前言1. 下载HACS源码2. 添加HACS商店3. 绑定米家设备 前言 之前介绍过如何实现在群晖NAS使用Docker部署HomeAssistant&#xff0c;通过内网穿透在户外控制家庭智能设备。本文将介绍如何在HA平台安装HACS插件商店&#xff0c;将米家&#xff0c;果家设备接入 Home Ass…

推荐清晖一套不错的讲解沟通的线上讲座

推荐清晖一套不错的讲解沟通的线上讲座&#xff0c;比较实际贴地&#xff0c;听完了推荐给大家&#xff1a; 《项目管理中的沟通策略&#xff0c;听出弦外之音&#xff0c;变身沟通达人》 地址&#xff1a;项目管理中的沟通策略&#xff0c;听出弦外之音&#xff0c;变身沟通达…

数据结构(1):ArrayList和顺序表

数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的数据元素的集合。 下面我们就开一个新坑&#xff0c;数据结构。数据结构&#xff0c;简单来说就是存放数据的方式&#xff0c;这些方式多种多样&#xff0c;我们来一点一…

Statcounter Global Stats 提供全球统计数据信息

Statcounter Global Stats 提供全球统计数据信息 1. Statcounter Global Stats2. Mobile & Tablet Android Version Market Share WorldwideReferences Statcounter Global Stats https://gs.statcounter.com/ Statcounter Global Stats are brought to you by Statcounte…

C++ 定时器

这是第一次独立设计一个模块&#xff0c;从接口定义&#xff0c;模块组合到多线程并发可能遇到的各种问题&#xff0c;虽然定时挺简单的&#xff0c;但是想设计精度高&#xff0c;并且能应对高并发似乎也不是很容易&#xff0c;当然&#xff0c;最后没有测试定时器的代码&#…

架构模式:MVC

引言 MVC&#xff0c;即 Model&#xff08;模型&#xff09;-View&#xff08;视图&#xff09;-Controller&#xff08;控制器&#xff09;&#xff0c;是广泛应用于交互式系统中的典型架构模式&#xff0c;尤其在 GUI 和 Web 应用中。 MVC 的概念源自 GOF&#xff08;Gang …

JS解密工具之**如何续期 Charles 的 SSL 证书**

本文由 jsjiami加密/一键JS解密 独家赞助 有问题请私聊加密官方客服 Charles 是一款常用的 HTTP 代理工具&#xff0c;用于调试网络请求。然而&#xff0c;Charles 的 SSL 证书会定期过期&#xff0c;如果 SSL 证书失效&#xff0c;你将无法对 HTTPS 请求进行抓包。本文将详细…

SQL语句中in条件超过1000怎么办?

博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 引言 当遇到SQL语句中IN条件超过1000个的情况时&#xff0c;可以采取以下几种策略来有效处理这一问题&#xff1a; 使用临时表&#xff1a;将IN列表中的值存储在临时表中&#xff0c;并将该临时表与查询表进行J…