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


ESP32(服务端)

C++

cpp 复制代码
#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操作(开关灯、闪烁灯、呼吸灯和流水灯)。


包含的库

cpp 复制代码
#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>

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


全局变量

cpp 复制代码
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端口。


通用响应函数

cpp 复制代码
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开关控制

cpp 复制代码
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闪烁控制

cpp 复制代码
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呼吸灯控制

cpp 复制代码
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流水灯控制

cpp 复制代码
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()

cpp 复制代码
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()

cpp 复制代码
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

代码

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>块显示信息

html 复制代码
<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面板

html 复制代码
<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灯的不同操作(开关灯、闪烁灯、呼吸灯和流水灯)。


代码

javascript 复制代码
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
    });
  }
});

导入依赖模块

javascript 复制代码
import {
  apiLedSwitch,
  apiLedTwinkle,
  apiBreathing,
  apiLedFlowing
} from '../../api/led.js';

const {
  showToast
} = getApp();

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


页面data数据

javascript 复制代码
data: {
  info: {},
  apiObj: {},
  apiList: [],
  activa: ''
}

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


handleLedAction方法

javascript 复制代码
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方法

javascript 复制代码
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生命周期函数

javascript 复制代码
onLoad(options) {
  this.runInit();
}

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


onShow生命周期函数

javascript 复制代码
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数据字段,用于页面展示。

相关推荐
前端拾光者16 分钟前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
HerayChen39 分钟前
微信小程序混合 h5 wx.miniProgram是 undefined
微信小程序·小程序·h5
木子02041 小时前
前端VUE项目启动方式
前端·javascript·vue.js
endingCode1 小时前
45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
javascript·macos·typescript
Myli_ing2 小时前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
I_Am_Me_3 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
℘团子এ3 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z3 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
前端百草阁3 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜3 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript