【ESP32】【微信小程序】MQTT物联网智能家居案例

这里写自定义目录标题

案例成果

1.Ardino写入部分

c 复制代码
#include <WiFi.h>          // ESP32 WiFi库
#include <PubSubClient.h>  // MQTT客户端库
#include <DHT.h>           // DHT传感器库

// WiFi配置
const char *ssid = "601B";       // WiFi名称
const char *password = "12345678"; // WiFi密码

// MQTT服务器配置
const char* mqtt_server = "bemfa.com";    // MQTT服务器地址
const int mqtt_server_port = 9501;        // MQTT服务器端口
#define ID_MQTT "0c876e1774cc3bd27de1d5d1bfc61c90" // 您的客户端ID

// 创建WiFi和MQTT客户端实例
WiFiClient espClient;
PubSubClient client(espClient);

// 定义引脚 - 注意:ESP32使用GPIO编号,而不是NodeMCU的D编号
#define ledpin 2       // LED指示灯连接的引脚,用于远程控制开关 (GPIO2)
#define eqpin 3        // 地震传感器连接的引脚,用于检测震动 (GPIO3)
#define beeppin 18      // 蜂鸣器连接的引脚,用于警报提示 
#define flapin 5       // 火灾传感器连接的引脚,用于检测火情 (GPIO5)
#define dhtpin 15      // DHT11温湿度传感器连接的引脚 (GPIO15)
#define DHTTYPE DHT11  // 定义使用的温湿度传感器类型为DHT11
#define airpin 34      // 空气质量传感器连接的模拟引脚,用于检测空气污染程度 (GPIO34 - ADC6)

// 创建DHT传感器对象
DHT dht(dhtpin, DHTTYPE);

// 定义状态变量
bool val1 = 0;  // 地震传感器状态
bool val2 = 0;  // 火灾传感器状态

// MQTT主题 - 与微信小程序匹配的命名
const char* mqtt_switch_topic = "switch";     // LED开关主题(接收控制命令)
const char* mqtt_temper_topic = "temper";     // 温度主题(发布温度数据)
const char* mqtt_humid_topic = "humid";       // 湿度主题(发布湿度数据)
const char* mqtt_air_topic = "air";           // 空气质量主题(发布空气质量数据)
const char* mqtt_earthquake_topic = "earthquake"; // 地震主题(发布地震状态)
const char* mqtt_flame_topic = "flame";       // 火灾主题(发布火灾状态)
const char* mqtt_beep_topic = "beep";         // 蜂鸣器主题(可选)

// WiFi连接函数
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

// MQTT消息接收回调函数
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("订阅的信息为 [");
  Serial.print(topic);
  Serial.print("] ");
  
  // 将接收到的字节数组转换为字符串
  String message;
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  
  Serial.println(message);
  
  // 控制LED
  if (strcmp(topic, mqtt_switch_topic) == 0) {
    if (message == "on") {
      digitalWrite(ledpin, HIGH);
      Serial.println("打开 LED 灯");
    } else if (message == "off") {
      digitalWrite(ledpin, LOW);
      Serial.println("关闭 LED 灯");
    }
  }
}

// 重连函数
void reconnect() {
  // 循环直到重新连接
  while (!client.connected()) {
    Serial.print("尝试连接MQTT...");
    
    // 尝试连接
    if (client.connect(ID_MQTT)) {
      Serial.println("connected");
      // 连接成功后,订阅LED控制主题
      client.subscribe(mqtt_switch_topic);
      Serial.print("已订阅主题: ");
      Serial.println(mqtt_switch_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

// 初始化
void setup() {
  // 初始化串口
  Serial.begin(115200);
  Serial.println("初始化系统...");
  
  // 初始化DHT传感器
  dht.begin();
  
  // 设置引脚模式
  pinMode(ledpin, OUTPUT);
  digitalWrite(ledpin, LOW);
  
  // 设置传感器引脚
  pinMode(eqpin, INPUT);
  pinMode(flapin, INPUT);
  pinMode(beeppin, OUTPUT);
  pinMode(airpin, INPUT);  // 模拟输入
  
  // 连接WiFi
  setup_wifi();
  
  // 设置MQTT服务器和回调
  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
  
  // 连接MQTT服务器
  reconnect();
  
  Serial.println("系统初始化完成!");
}

void loop() {
  // 检查MQTT连接状态
  if (!client.connected()) {
    reconnect(); // 重新连接
  }
  
  // 处理MQTT消息
  client.loop();
  
  // 读取温湿度
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  
  // 检查温湿度读取是否成功
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
  } else {
    // 输出温湿度
    Serial.print("湿度: ");
    Serial.print(h);
    Serial.print("%, 温度: ");
    Serial.print(t);
    Serial.println("°C");
    
    // 转换为字符串用于发布
    String tempMsg = String(t);
    String humidMsg = String(h);
    
    // 发布温湿度数据到MQTT
    client.publish(mqtt_temper_topic, tempMsg.c_str());
    client.publish(mqtt_humid_topic, humidMsg.c_str());
  }
  
  // 读取空气质量
  int airval = analogRead(airpin);
  Serial.print("空气质量: ");
  Serial.println(airval);
  String airMsg = String(airval);
  client.publish(mqtt_air_topic, airMsg.c_str());
  
  // 读取地震传感器状态
  val1 = digitalRead(eqpin);
  if (val1 == 0) {
    // 发布地震警报
    client.publish(mqtt_earthquake_topic, "off");
    Serial.println("无震感");
    client.publish(mqtt_beep_topic, "off"); // 前端无需显示蜂鸣器的状态
  }
  else {
    // 发布地震警报
    client.publish(mqtt_earthquake_topic, "on");
    Serial.println("有震感");
    client.publish(mqtt_beep_topic, "on"); // 前端无需显示蜂鸣器的状态
  }
  
  // 读取火灾传感器状态
  val2 = digitalRead(flapin);
  Serial.print("火灾传感器状态: ");
  Serial.println(val2);
  if (val2 == 1) {
    // 发布火灾警报
    client.publish(mqtt_flame_topic, "off");
    Serial.println("无火灾");
    digitalWrite(beeppin, HIGH);
  }
  else {
    // 发布火灾警报
    client.publish(mqtt_flame_topic, "on");
    Serial.println("有火灾");
    digitalWrite(beeppin, LOW);
  }
  
  // 延时100毫秒
  delay(100);
}

2.微信小程序JS部分

c 复制代码
// pages/class/class.js
const app = getApp()
import mqtt from '../../utils/mqtt.min'

Page({
  data: {
    // 主题定义
    ledtopic: "switch",          // LED开关主题
    eqtopic: "earthquake",       // 地震传感器主题
    fhtopic: "flame",            // 火灾传感器主题
    wdtopic: "temper",           // 温度传感器主题
    sdtopic: "humid",            // 湿度传感器主题
    kqtopic: "air",              // 空气质量传感器主题
    beeptopic: "beep",           // 新增:蜂鸣器主题

    uid: "0c876e1774cc3bd27de1d5d1bfc61c90",  // 设备唯一ID
    
    // 传感器状态
    qustatus: "无震感",          // 地震状态
    flastatus: "无火灾",         // 火灾状态
    wdval: "未知",               // 温度值
    sdval: "未知",               // 湿度值
    airval: "未知",              // 空气质量值
    beepstatus: "关闭",          // 新增:蜂鸣器状态

    isThemeOn: false,            // 开关状态,默认关闭
    device_status: "离线",       // 设备连接状态
    client: null                 // MQTT客户端
  },

  // MQTT连接方法
  mqttConnect() {
    var that = this;
    var options = {
      keepalive: 60,             // 心跳间隔
      clean: true,               // 清除会话
      protocolVersion: 4,        // MQTT协议版本
      clientId: that.data.uid    // 客户端ID
    };

    // 连接到MQTT服务器
    that.data.client = mqtt.connect('wxs://bemfa.com:9504/wss', options);
    
    // 连接成功回调
    that.data.client.on('connect', function() {
      console.log("连接服务器成功");
      that.setData({
        device_status: "在线"
      });
      
      // 订阅所有传感器主题
      // 订阅地震传感器主题
      that.data.client.subscribe(that.data.eqtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅火灾传感器主题
      that.data.client.subscribe(that.data.fhtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅温度传感器主题
      that.data.client.subscribe(that.data.wdtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅湿度传感器主题
      that.data.client.subscribe(that.data.sdtopic, function(err) {
        if(err) console.log(err);
      });
      
      // 订阅空气质量传感器主题
      that.data.client.subscribe(that.data.kqtopic, function(err) {
        if(err) console.log(err);
      });
      // 新增:订阅蜂鸣器主题
      that.data.client.subscribe(that.data.beeptopic, function(err) {
        if(err) console.log(err);
      });
    });

    // 接收消息回调
    that.data.client.on('message', function(topic, message) {
      var msg = message.toString();
      
      // 处理不同主题的消息
      // 地震传感器消息
      if(topic === that.data.eqtopic) {
        that.setData({
          qustatus: msg === 'on' ? '有地震' : '无地震'
        });
      }
      
      // 火灾传感器消息
      else if(topic === that.data.fhtopic) {
        that.setData({
          flastatus: msg === 'on' ? '有火灾' : '无火灾'
        });
      }
      
      // 温度传感器消息
      else if(topic === that.data.wdtopic) {
        that.setData({
          wdval: msg
        });
      }
      
      // 湿度传感器消息
      else if(topic === that.data.sdtopic) {
        that.setData({
          sdval: msg
        });
      }
      
      // 空气质量传感器消息
      else if(topic === that.data.kqtopic) {
        that.setData({
          airval: msg
        });
      }

      // 新增:蜂鸣器消息
      else if(topic === that.data.beeptopic) {
        that.setData({
          beepstatus: msg === 'on' ? '开启' : '关闭'
        });
      }

    });

    // 重连回调
    that.data.client.on('reconnect', function() {
      console.log("重新连接");
      that.setData({
        device_status: "连接中"
      });
    });

    // 连接错误回调
    that.data.client.on('error', function(error) {
      console.log("连接失败", error);
      that.setData({
        device_status: "离线"
      });
    });
  },

  // 页面加载时连接MQTT服务器
  onLoad() {
    this.mqttConnect()
  },

  // 开关点击事件处理
  onThemeSwitchTap: function() {
    if(this.data.client && this.data.client.connected) {
      // 切换开关状态
      const message = this.data.isThemeOn ? 'off' : 'on';
      
      // 发布消息到LED开关主题
      this.data.client.publish(this.data.ledtopic, message);
      
      // 更新UI状态
      this.setData({
        isThemeOn: !this.data.isThemeOn
      });
    } else {
      console.log("MQTT未连接");
    }
  }
})

3.微信小程序xml部分

c 复制代码
<!--pages/znjj/znjj.wxml-->
<view class="imag4_src"></view>
<image class="imag4" src="/img/znjj.png"></image>
<view class="spacer"></view>

<view class="container1">
  <view class="view1">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/wd.png"></image>
        <text>温度</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定温度数据 -->
        <text class="loading-text">{{wdval}}</text>
      </view>
    </view>
  </view>
  
  <view class="view2">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/sd.png"></image>
        <text>湿度</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定湿度数据 -->
        <text class="loading-text">{{sdval}}</text>
      </view>
    </view>
  </view>
  
  <view class="view3">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/PM2.5.png"></image>
        <text>空气</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定空气质量数据 -->
        <text class="loading-text">{{airval}}</text>
      </view>
    </view>
  </view>
</view>

<view class="spacer"></view>

<view class="container2">
  <view class="view4">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/hy.png"></image>
        <text>防火</text>
      </view>
      <view class="loading-container">
        <!-- 修改:绑定火灾状态 -->
        <text class="loading-text">{{flastatus}}</text>
      </view>
    </view>
  </view>
  
  <view class="view5">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/dz.png"></image>
        <text>地震</text>
      </view>
      <view class="loading-container">
        <text class="loading-text">{{qustatus}}</text>
      </view>
    </view>
  </view>
  
  <view class="view6">
    <view class="img_wd">
      <view class="content-row">
        <image class="img1" src="/img/kt.png"></image>
        <text>空调</text>
      </view>
      <view class="switch-container">
        <button class="theme-switch-button" bindtap="onThemeSwitchTap">
          {{isThemeOn ? 'on' : 'off'}}
        </button>
      </view>
    </view>
  </view>
</view>

<view class="spacer"></view>

<view class="container3">
  <view class="view7">
    <view class="img_wd">
      <view class="content-text">
        <text>设备状态</text>
        <text class="module">{{device_status}}</text>
      </view>
    </view>
  </view>
  
  <view class="view8">
    <view class="img_wd">
      <view class="content-text">
        <text>火灾告警</text>
        <view wx:if="{{flastatus == '有火灾'}}">
          <image class="img5" src="/img/hz_on.png"></image>
        </view>
        <view wx:else>
          <image class="img5" src="/img/hz_off.png"></image>
        </view>
      </view>
    </view>
  </view>
  
  <view class="view9">
    <view class="img_wd">
      <view class="content-text">
        <text>地震告警</text>
        <!-- 修改:使用qustatus而不是eqstatus -->
        <view wx:if="{{qustatus == '有地震'}}">
          <image class="img5" src="/img/dz_on.png"></image>
        </view>
        <view wx:else>
          <image class="img5" src="/img/dz_off.png"></image>
        </view>
      </view>
    </view>
  </view> 
</view>

4. 微信小程序CSS部分

c 复制代码
/* 顶部标题图片容器样式 */
.imag4_src{
    display: block;  /* 设置为块级元素,占据整行 */
    width: 100%;     /* 宽度占满父容器 */
  }
  
  /* 顶部标题图片样式 */
  .imag4{
    width: 350px;    /* 设置固定宽度 */
    height: 200px;   /* 设置固定高度 */
    justify-content: center;  /* 水平居中对齐 */
    border: 1px solid #000;   /* 添加1像素黑色边框 */
    border-radius: 10px;      /* 设置10像素圆角 */
    margin: 20px;             /* 四周添加20像素外边距 */
    box-shadow: 5px 5px 15px rgba(0,0,0,0.3);  /* 添加阴影效果:右下偏移,模糊度,颜色 */
    transition: transform 0.3s ease;  /* 添加变换过渡效果:持续0.3秒,缓动函数ease */
  }
  
  /* 标题图片悬停效果 */
  .imag4:hover{
    transform: scale(1.05);  /* 悬停时放大图片到原尺寸的1.05倍 */
  }
  
  /* 垂直间隔元素 */
  .spacer{
    height: 10px;  /* 创建10像素高度的垂直间隔 */
  }
  
  /* 第一行和第二行容器共同样式 */
  .container1,
  .container2{
    display: flex;           /* 设置为Flex布局容器 */
    flex-direction: row;     /* 子元素水平排列(默认值) */
    justify-content: center; /* 子元素在主轴(水平)上居中对齐 */
  }
  
  /* 第一行和第二行中所有方块的共同样式 */
  .container1 .view1,
  .container1 .view2,
  .container1 .view3,
  .container2 .view4,
  .container2 .view5,
  .container2 .view6{
    width: 90px;             /* 设置宽度为90像素 */
    height: 100px;           /* 设置高度为100像素 */
    margin: 20px;            /* 四周添加20像素外边距 */
    position: relative;      /* 设置相对定位,作为内部元素的定位参考 */
    background-color: transparent;  /* 背景透明(但随后被单独的规则覆盖) */
    display: flex;           /* 设置为Flex布局容器 */
    align-items: lsft;       /* 注意:这里有拼写错误,应为'left',垂直方向左对齐 */
    justify-content: center; /* 水平居中对齐 */
    border: 2px solid rgb(291,214,214);  /* 注意:RGB值错误,291超出范围(0-255) */
    box-shadow: 0 0 10px rgba(37,37,37,0.5);  /* 添加阴影效果,模拟立体边框 */
  }
  
  /* 第一行各模块的背景颜色 */
  .container1 .view1 { background-color: #e3ece2; }  /* 温度模块:淡绿色 */
  .container1 .view2 { background-color: #ccd4cb; }  /* 湿度模块:灰绿色 */
  .container1 .view3 { background-color: #e5f3ee; }  /* 空气模块:浅蓝绿色 */
  
  /* 第二行各模块的背景颜色 */
  .container2 .view4 { background-color: #f7e7e9; }  /* 防火模块:淡粉色 */
  .container2 .view5 { background-color: #d7eef7; }  /* 地震模块:淡蓝色 */
  .container2 .view6 { background-color: #e3e4f1; }  /* 空调模块:淡紫色 */
  
  /* 模块内容容器样式 */
  .img_wd{
    justify-content: flex-start;  /* 内容在水平方向靠左对齐 */
    align-items: flex-start;      /* 内容在垂直方向靠上对齐 */
    width: 100px;                 /* 设置宽度为100像素 */
    height: 100px;                /* 设置高度为100像素 */
    position: relative;           /* 设置相对定位,供内部元素参考 */
  }
  
  /* 图标和文字行样式 */
  .content-row{
    margin-top: 1px;       /* 顶部添加1像素外边距 */
    display: flex;         /* 设置为Flex布局容器 */
    align-items: center;   /* 子元素在垂直方向居中对齐 */
    margin-left: 3px;      /* 左侧添加3像素外边距 */
  }
  
  /* 图标样式 */
  .img1{
    width: 30px;           /* 设置图标宽度为30像素 */
    height: 30px;          /* 设置图标高度为30像素 */
    border: 1px solid rgb(211,209,209);  /* 添加浅灰色边框 */
    border-radius: 10px;                 /* 设置10像素圆角 */
    margin: 3px;                         /* 四周添加3像素外边距 */
    box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3);  /* 添加阴影效果 */
    transition: transform 0.3s ease;               /* 添加变换过渡效果 */
    margin-right: 5px;                           /* 右侧添加5像素外边距,与文字分开 */
  }
  
  /* 数据加载容器样式 */
  .loading-container{
    margin-top: 20px;     /* 顶部添加20像素外边距 */
    display: flex;        /* 设置为Flex布局容器 */
    justify-content: center;  /* 水平居中对齐 */
    align-items: center;      /* 垂直居中对齐 */
  }
  
  /* 加载文本样式 */
  .loading-text{
    justify-content: center;  /* 水平居中对齐(在flex子项中) */
    align-items: center;      /* 垂直居中对齐(在flex子项中) */
    font-size: 16px;          /* 设置字体大小为16像素 */
    color: #333;              /* 设置字体颜色为深灰色 */
    height: 20px;             /* 设置高度为20像素 */
  }
  
  /* 第三行容器样式 */
  .container3{
    display: flex;           /* 设置为Flex布局容器 */
    flex-direction: row;     /* 子元素水平排列 */
    justify-content: center; /* 水平居中对齐 */
    /* 注释提到暂时移除其他样式以进行故障排除 */
  }
  
  /* 第三行各模块共同样式 */
  .container3 .view7,
  .container3 .view8,
  .container3 .view9{
    width: 90px;            /* 设置宽度为90像素 */
    height: 100px;          /* 设置高度为100像素 */
    margin: 20px;           /* 四周添加20像素外边距 */
    position: relative;     /* 设置相对定位 */
    background-color: transparent;  /* 背景透明(但随后被单独的规则覆盖) */
    display: flex;          /* 设置为Flex布局容器 */
    align-items: left;      /* 垂直方向左对齐(注意:这应为vertical-align或align-items:flex-start) */
    justify-content: center; /* 水平居中对齐 */
    border: 2px solid rgb(219, 214, 214);  /* 添加浅灰色边框 */
    box-shadow: 0 0 10px rgba(37, 37, 37, 0.5);  /* 添加阴影效果 */
    border-radius: 60px;    /* 设置60像素圆角,几乎成为圆形 */
  }
  
  /* 第三行各模块的背景颜色 */
  .container3 .view7 { background-color: #f1ecec; }  /* 设备状态模块:淡红灰色 */
  .container3 .view8 { background-color: #f3f8f6; }  /* 火灾告警模块:淡青色 */
  .container3 .view9 { background-color: #ece6f5; }  /* 地震告警模块:淡紫色 */
  
  /* 开关按钮容器样式 */
  .switch-container {
    width: 60px;           /* 设置宽度为60像素 */
    height: 30px;          /* 设置高度为30像素 */
    display: flex;         /* 设置为Flex布局容器 */
    justify-content: center;  /* 水平居中对齐 */
    align-items: center;      /* 垂直居中对齐 */
    margin-top: 20px;         /* 顶部添加20像素外边距 */
    margin-left: auto;        /* 左侧自动外边距,配合右侧自动外边距实现水平居中 */
    margin-right: auto;       /* 右侧自动外边距,配合左侧自动外边距实现水平居中 */
  }
  
  /* 开关按钮样式 */
  .theme-switch-button {
    height: 30px;          /* 设置高度为30像素 */
    line-height: 30px;     /* 设置行高等于高度,使文字垂直居中 */
    background-color: rgb(146, 198, 247);  /* 设置淡蓝色背景 */
    color: rgb(13, 13, 14);               /* 设置几乎黑色的文字颜色 */
    border: none;                         /* 移除默认边框 */
    border-radius: 20px;                  /* 设置20像素圆角,使按钮呈胶囊形 */
    text-align: center;                   /* 文字水平居中 */
    font-size: 13px;                      /* 设置字体大小为13像素 */
    border: 1px solid rgb(241, 234, 234); /* 添加浅灰色边框 */
    box-shadow: 0 0 10px rgba(2, 8, 27, 0.5);  /* 添加阴影效果 */
    padding: 0;                           /* 移除内边距,确保文字居中显示 */
  }
  
  /* 文本内容容器样式 */
  .content-text {
    display: flex;                /* 设置为Flex布局容器 */
    flex-direction: column;       /* 子元素垂直排列 */
    align-items: center;          /* 水平居中对齐 */
    justify-content: flex-start;  /* 垂直方向从顶部开始对齐 */
    margin-top: 15px;             /* 顶部添加15像素外边距 */
    width: 100%;                  /* 宽度占满父容器 */
    box-sizing: border-box;       /* 边框和内边距包含在宽度内 */
  }
  
  /* 模块状态文本样式 */
  .module {
    margin-top: 10px;     /* 顶部添加10像素外边距 */
    color: #f74d4d;       /* 设置文字颜色为鲜红色 */
    font-weight: bold;    /* 设置字体为粗体 */
  }
  
  /* 告警图标样式 */
  .img5{
    margin-top: 5px;      /* 顶部添加5像素外边距 */
    width: 50px;          /* 设置宽度为50像素 */
    height: 40px;         /* 设置高度为40像素 */
  }
相关推荐
TDengine (老段)2 小时前
TDengine 支持的平台汇总
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
TDengine (老段)4 小时前
TDengine 开发指南——无模式写入
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
Uyker7 小时前
从零开始制作小程序简单概述
前端·微信小程序·小程序
CodeCraft Studio13 小时前
【案例分享】如何借助JS UI组件库DHTMLX Suite构建高效物联网IIoT平台
javascript·物联网·ui
打小就很皮...13 小时前
HBuilder 发行Android(apk包)全流程指南
前端·javascript·微信小程序
华奥系科技15 小时前
智慧水务发展迅猛:从物联网架构到AIoT系统的跨越式升级
人工智能·物联网·智慧城市
zzlyx9916 小时前
AI大数据模型如何与thingsboard物联网结合
人工智能·物联网
远创智控研发五部21 小时前
边缘计算网关提升水产养殖尾水处理的远程运维效率
物联网·远程监控·工业自动化·边缘计算网关·无线数传模块
前端缘梦1 天前
微信小程序登录方案实践-从账号体系到用户信息存储
前端·微信小程序
Despacito0o1 天前
MQTT入门实战宝典:从零起步掌握物联网核心通信协议
物联网·struts·servlet