ESP8266 与云智能 App 开发

一、引言

在物联网(IoT)技术蓬勃发展的今天,智能设备已经渗透到我们生活的方方面面。ESP8266 作为一款低成本、高性能的 Wi-Fi 微控制器,凭借其丰富的功能和灵活的开发方式,成为了物联网开发的热门选择。结合云平台和智能 App,我们可以构建出各种智能家居、环境监测、工业控制等应用系统。

本文将详细介绍 ESP8266 和云智能 App 的开发全流程,从硬件选型、开发环境搭建、ESP8266 编程、云平台配置到 App 开发,全方位展示一个完整的物联网应用开发过程。通过丰富的代码示例和详细的说明,帮助读者理解和掌握这一开发技术。

二、硬件准备与选型

2.1 ESP8266 开发板选型

ESP8266 有多种开发板可供选择,常见的有:

  1. NodeMCU:集成度高,带有 USB 转串口芯片,方便编程和调试,适合初学者。
  2. ESP-01:体积小巧,仅支持基本的 Wi-Fi 功能,适合对体积要求较高的应用。
  3. Wemos D1 Mini:尺寸适中,提供了丰富的 GPIO 接口,是一款性价比较高的开发板。

本文以 NodeMCU 开发板为例进行介绍,其主要参数如下:

  • 处理器:ESP8266EX
  • 主频:80MHz/160MHz
  • 内存:64KB IRAM,96KB DRAM
  • Flash:4MB
  • Wi-Fi:802.11 b/g/n
  • GPIO:17 个(部分有特殊功能)
  • 供电:3.3V,支持 USB 供电和外部电源供电

2.2 外围设备连接

在实际应用中,ESP8266 通常需要连接各种传感器和执行器。例如:

  1. DHT11/DHT22 温湿度传感器:用于采集环境温度和湿度数据
  2. LED 灯:用于指示设备状态或作为控制输出
  3. 继电器模块:用于控制大功率设备
  4. 光敏电阻:用于检测光照强度
  5. MQ-2 气体传感器:用于检测烟雾、可燃气体等

下面是一个简单的硬件连接示例,展示如何连接 DHT11 传感器和 LED 灯:

ESP8266 (NodeMCU)      DHT11 传感器
D2 (GPIO4)            -> 数据引脚
3.3V                 -> VCC
GND                  -> GND

ESP8266 (NodeMCU)      LED 灯
D1 (GPIO5)            -> 阳极(通过220Ω电阻)
GND                  -> 阴极

三、开发环境搭建

3.1 Arduino IDE 配置

ESP8266 可以使用 Arduino IDE 进行开发,以下是详细的配置步骤:

  1. 安装 Arduino IDE:从 Arduino 官网 下载并安装最新版本的 Arduino IDE。

  2. 添加 ESP8266 开发板支持

    • 打开 Arduino IDE,点击 "文件" > "首选项"
    • 在 "附加开发板管理器网址" 字段中添加:http://arduino.esp8266.com/stable/package_esp8266com_index.json
    • 点击 "确定" 保存设置
  3. 安装 ESP8266 开发板包

    • 点击 "工具" > "开发板" > "开发板管理器"
    • 在搜索框中输入 "ESP8266"
    • 选择最新版本并点击 "安装"
  4. 选择开发板和端口

    • 点击 "工具" > "开发板",选择 "NodeMCU 1.0 (ESP-12E Module)"
    • 点击 "工具" > "端口",选择 ESP8266 连接的串口

3.2 必要库的安装

在开发过程中,我们需要使用一些库来简化开发工作。可以通过 Arduino IDE 的库管理器来安装这些库:

  1. ESP8266WiFi 库:用于连接 Wi-Fi 网络
  2. PubSubClient 库:用于 MQTT 通信
  3. DHT sensor library:用于读取 DHT11/DHT22 传感器数据
  4. ArduinoJson 库:用于处理 JSON 数据

安装方法:点击 "工具" > "管理库",在搜索框中输入库名称,然后选择最新版本安装。

四、ESP8266 基础编程

4.1 Wi-Fi 连接

ESP8266 的首要任务是连接到 Wi-Fi 网络。以下是一个简单的 Wi-Fi 连接示例:

#include <ESP8266WiFi.h>

// Wi-Fi 配置
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";

void setup() {
  Serial.begin(115200);
  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.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // 主循环可以留空,因为我们只需要连接一次
}

4.2 传感器数据采集

接下来,让我们看看如何读取 DHT11 温湿度传感器的数据:

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

// Wi-Fi 配置
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";

// DHT 传感器配置
#define DHTPIN 2      // DHT 传感器连接的引脚
#define DHTTYPE DHT11 // DHT 传感器类型

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
  Serial.println("DHT11 Sensor Test");
  
  // 初始化 DHT 传感器
  dht.begin();
  
  // 连接 Wi-Fi
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // 读取温度和湿度
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();
  
  // 检查是否读取成功
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
  
  // 打印数据
  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(temperature);
  Serial.println(" *C");
  
  // 延时2秒
  delay(2000);
}

4.3 简单 Web 服务器

ESP8266 可以作为一个简单的 Web 服务器,处理 HTTP 请求。以下是一个控制 LED 灯的 Web 服务器示例:

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

// Wi-Fi 配置
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";

// LED 配置
const int ledPin = 5; // D1 引脚

// 创建 Web 服务器对象,监听 80 端口
ESP8266WebServer server(80);

void setup() {
  Serial.begin(115200);
  
  // 配置 LED 引脚为输出模式
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  // 连接 Wi-Fi
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  // 设置 Web 服务器路由
  server.on("/", handleRoot);
  server.on("/on", handleLEDOn);
  server.on("/off", handleLEDOff);
  server.onNotFound(handleNotFound);
  
  // 启动 Web 服务器
  server.begin();
  Serial.println("Web server started!");
}

void loop() {
  // 处理客户端请求
  server.handleClient();
}

// 处理根路径请求
void handleRoot() {
  String html = "<html><body>";
  html += "<h1>ESP8266 LED Control</h1>";
  html += "<p>LED Status: ";
  html += (digitalRead(ledPin) == HIGH) ? "ON" : "OFF";
  html += "</p>";
  html += "<a href=\"/on\"><button>Turn ON</button></a>";
  html += "<a href=\"/off\"><button>Turn OFF</button></a>";
  html += "</body></html>";
  
  server.send(200, "text/html", html);
}

// 处理 LED 打开请求
void handleLEDOn() {
  digitalWrite(ledPin, HIGH);
  server.send(200, "text/plain", "LED is now ON");
}

// 处理 LED 关闭请求
void handleLEDOff() {
  digitalWrite(ledPin, LOW);
  server.send(200, "text/plain", "LED is now OFF");
}

// 处理未找到的页面
void handleNotFound() {
  server.send(404, "text/plain", "Page not found");
}

五、云平台选择与配置

5.1 云平台选择

在物联网应用中,云平台扮演着数据存储、处理和分发的核心角色。常见的物联网云平台有:

  1. 阿里云物联网平台:提供完整的设备接入、数据存储和分析能力
  2. 腾讯云物联网平台:提供稳定可靠的设备连接和管理服务
  3. 华为云物联网平台:提供一站式物联网解决方案
  4. MQTT Broker:如 EMQ X、Mosquitto 等开源 MQTT 服务器
  5. 自建服务器:使用 Node.js、Python 等搭建自定义服务器

本文以 EMQ X MQTT Broker 为例进行介绍,因为它是开源的、轻量级的,适合学习和开发。

5.2 EMQ X MQTT Broker 安装与配置

  1. 安装 EMQ X

    • 对于 Linux 系统,可以使用 apt-get 或 yum 安装
    • 对于 Windows 系统,可以下载安装包进行安装
    • 也可以使用 Docker 容器快速部署
  2. 配置 EMQ X

    • 默认情况下,EMQ X 监听 1883 端口(MQTT 协议)和 8083 端口(WebSocket 协议)
    • 可以通过修改配置文件 /etc/emqx/emqx.conf 进行自定义配置
  3. 启动 EMQ X

    • 在 Linux 系统上,可以使用命令 systemctl start emqx 启动
    • 在 Windows 系统上,可以通过服务管理器启动

5.3 ESP8266 连接 MQTT 服务器

下面是一个 ESP8266 连接 MQTT 服务器并发布 / 订阅消息的示例:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Wi-Fi 配置
const char* ssid = "Your_WiFi_SSID";
const char* password = "Your_WiFi_Password";

// MQTT 配置
const char* mqttServer = "your_mqtt_server_ip";
const int mqttPort = 1883;
const char* mqttUser = "your_mqtt_username";
const char* mqttPassword = "your_mqtt_password";

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

// 主题定义
const char* publishTopic = "esp8266/data";
const char* subscribeTopic = "esp8266/command";

// LED 配置
const int ledPin = 5;

void setup() {
  Serial.begin(115200);
  
  // 配置 LED 引脚
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  // 连接 Wi-Fi
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  
  // 配置 MQTT 服务器和回调函数
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
  
  // 连接 MQTT 服务器
  reconnect();
}

void loop() {
  // 检查 MQTT 连接状态
  if (!client.connected()) {
    reconnect();
  }
  
  // 处理 MQTT 消息
  client.loop();
  
  // 发布数据到 MQTT 服务器
  static unsigned long lastPublishTime = 0;
  if (millis() - lastPublishTime > 5000) { // 每5秒发布一次
    lastPublishTime = millis();
    
    // 构建 JSON 格式的数据
    String payload = "{\"temperature\":25.5,\"humidity\":60.2,\"led_status\":";
    payload += (digitalRead(ledPin) == HIGH) ? "true" : "false";
    payload += "}";
    
    // 发布消息
    client.publish(publishTopic, payload.c_str());
    Serial.println("Published: " + payload);
  }
}

// 处理接收到的 MQTT 消息
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  
  // 将消息转换为字符串
  String message = "";
  for (unsigned int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  Serial.println(message);
  
  // 处理 LED 控制命令
  if (String(topic) == subscribeTopic) {
    if (message == "led_on") {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED turned ON");
    } else if (message == "led_off") {
      digitalWrite(ledPin, LOW);
      Serial.println("LED turned OFF");
    }
  }
}

// 重新连接 MQTT 服务器
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    
    // 创建客户端 ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    
    // 尝试连接
    if (client.connect(clientId.c_str(), mqttUser, mqttPassword)) {
      Serial.println("connected");
      
      // 订阅命令主题
      client.subscribe(subscribeTopic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      
      // 等待 5 秒后重试
      delay(5000);
    }
  }
}

六、云智能 App 开发

6.1 开发平台选择

开发云智能 App 有多种平台和框架可供选择:

  1. 原生开发

    • Android:使用 Java 或 Kotlin 开发
    • iOS:使用 Swift 或 Objective-C 开发
  2. 跨平台开发

    • Flutter:使用 Dart 语言,由 Google 开发
    • React Native:使用 JavaScript,由 Facebook 开发
    • Ionic:使用 HTML、CSS 和 JavaScript

本文以 Flutter 为例进行介绍,因为它可以同时开发 Android 和 iOS 应用,并且具有出色的性能和丰富的 UI 组件。

6.2 Flutter 环境搭建

  1. 安装 Flutter SDK

    • 从 Flutter 官网 下载最新的 Flutter SDK
    • 解压并配置环境变量
  2. 安装 Android Studio

  3. 安装 Visual Studio Code 或 IntelliJ IDEA

    • 安装 Flutter 和 Dart 插件
  4. 验证环境配置

    • 在终端中运行 flutter doctor 命令检查环境配置

6.3 Flutter 应用开发

下面是一个使用 Flutter 开发的简单 IoT App 示例,包含连接 MQTT 服务器、显示传感器数据和控制 LED 的功能:

import 'package:flutter/material.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
import 'dart:convert';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ESP8266 IoT App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // MQTT 配置
  final String _mqttServer = 'your_mqtt_server_ip';
  final int _mqttPort = 1883;
  final String _mqttClientId = 'flutter_client_${DateTime.now().millisecondsSinceEpoch}';
  final String _mqttUsername = 'your_mqtt_username';
  final String _mqttPassword = 'your_mqtt_password';
  
  // 主题配置
  final String _subscribeTopic = 'esp8266/data';
  final String _publishTopic = 'esp8266/command';
  
  // MQTT 客户端
  MqttServerClient? _client;
  
  // 传感器数据
  double _temperature = 0.0;
  double _humidity = 0.0;
  bool _ledStatus = false;
  
  // 连接状态
  bool _isConnected = false;
  
  @override
  void initState() {
    super.initState();
    _connectToMQTT();
  }
  
  @override
  void dispose() {
    _disconnectFromMQTT();
    super.dispose();
  }
  
  // 连接到 MQTT 服务器
  void _connectToMQTT() async {
    _client = MqttServerClient(_mqttServer, _mqttClientId);
    _client!.port = _mqttPort;
    _client!.keepAlivePeriod = 60;
    _client!.onDisconnected = _onDisconnected;
    
    // 设置安全连接
    if (_mqttUsername.isNotEmpty && _mqttPassword.isNotEmpty) {
      _client!.securityContext = null;
      _client!.username = _mqttUsername;
      _client!.password = _mqttPassword;
    }
    
    // 设置回调函数
    _client!.updates!.listen((List<MqttReceivedMessage<MqttMessage>>? c) {
      final MqttPublishMessage recMess = c![0].payload as MqttPublishMessage;
      final String message = MqttPublishPayload.bytesToStringAsString(recMess.payload.message);
      
      // 处理接收到的消息
      _handleMessage(message);
    });
    
    try {
      await _client!.connect();
    } catch (e) {
      print('MQTT 连接错误: $e');
      _isConnected = false;
      setState(() {});
      return;
    }
    
    if (_client!.connectionStatus!.state == MqttConnectionState.connected) {
      _isConnected = true;
      _subscribeToTopic(_subscribeTopic);
      setState(() {});
    } else {
      print('MQTT 连接失败, 状态码: ${_client!.connectionStatus!.returnCode}');
      _isConnected = false;
      setState(() {});
    }
  }
  
  // 断开 MQTT 连接
  void _disconnectFromMQTT() {
    if (_client != null && _client!.connectionStatus!.state == MqttConnectionState.connected) {
      _client!.disconnect();
      _isConnected = false;
      setState(() {});
    }
  }
  
  // 订阅主题
  void _subscribeToTopic(String topic) {
    if (_client != null && _client!.connectionStatus!.state == MqttConnectionState.connected) {
      _client!.subscribe(topic, MqttQos.atMostOnce);
    }
  }
  
  // 发布消息
  void _publishMessage(String topic, String message) {
    if (_client != null && _client!.connectionStatus!.state == MqttConnectionState.connected) {
      final MqttClientPayloadBuilder builder = MqttClientPayloadBuilder();
      builder.addString(message);
      _client!.publishMessage(topic, MqttQos.atMostOnce, builder.payload!);
    }
  }
  
  // 处理接收到的消息
  void _handleMessage(String message) {
    try {
      final data = json.decode(message);
      
      setState(() {
        _temperature = data['temperature'] ?? 0.0;
        _humidity = data['humidity'] ?? 0.0;
        _ledStatus = data['led_status'] ?? false;
      });
    } catch (e) {
      print('消息解析错误: $e');
    }
  }
  
  // LED 控制
  void _toggleLED(bool value) {
    final message = value ? 'led_on' : 'led_off';
    _publishMessage(_publishTopic, message);
  }
  
  // 断开连接回调
  void _onDisconnected() {
    print('MQTT 连接已断开');
    _isConnected = false;
    setState(() {});
    
    // 尝试重新连接
    Future.delayed(const Duration(seconds: 5), () {
      _connectToMQTT();
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ESP8266 IoT App'),
        actions: [
          Icon(
            _isConnected ? Icons.check_circle : Icons.error_circle,
            color: _isConnected ? Colors.green : Colors.red,
          ),
          SizedBox(width: 16),
        ],
      ),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              // 温度显示
              Card(
                elevation: 4,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        '温度:',
                        style: TextStyle(fontSize: 18),
                      ),
                      Text(
                        '$_temperature °C',
                        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                ),
              ),
              
              SizedBox(height: 16),
              
              // 湿度显示
              Card(
                elevation: 4,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        '湿度:',
                        style: TextStyle(fontSize: 18),
                      ),
                      Text(
                        '$_humidity %',
                        style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                      ),
                    ],
                  ),
                ),
              ),
              
              SizedBox(height: 32),
              
              // LED 控制
              Card(
                elevation: 4,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        'LED 控制:',
                        style: TextStyle(fontSize: 18),
                      ),
                      Switch(
                        value: _ledStatus,
                        onChanged: _toggleLED,
                        activeColor: Colors.green,
                      ),
                    ],
                  ),
                ),
              ),
              
              SizedBox(height: 32),
              
              // 连接状态
              Text(
                _isConnected ? '已连接到 MQTT 服务器' : '未连接到 MQTT 服务器',
                style: TextStyle(
                  color: _isConnected ? Colors.green : Colors.red,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

七、系统整合与测试

7.1 整体系统架构

完成各个部分的开发后,整个系统的架构如下:

+------------------+      +------------------+      +------------------+
|                  |      |                  |      |                  |
|   ESP8266 设备    |<---->|   MQTT 服务器     |<---->|    智能 App       |
|  (传感器与执行器) |      |   (云平台)        |      |  (Android/iOS)    |
|                  |      |                  |      |                  |
+------------------+      +------------------+      +------------------+

7.2 系统测试

  1. 硬件测试

    • 确保 ESP8266 开发板能够正常工作
    • 测试传感器数据采集的准确性
    • 验证执行器控制的可靠性
  2. 网络通信测试

    • 测试 ESP8266 与 MQTT 服务器之间的通信
    • 验证数据是否能够正确发布和订阅
    • 测试网络断开后的自动重连功能
  3. App 功能测试

    • 测试 App 与 MQTT 服务器的连接
    • 验证传感器数据是否能够正确显示
    • 测试控制指令是否能够正确发送和执行

7.3 常见问题与解决方案

  1. ESP8266 连接 Wi-Fi 失败

    • 检查 Wi-Fi 名称和密码是否正确
    • 确保 Wi-Fi 信号强度足够
    • 尝试重启 ESP8266 和路由器
  2. MQTT 连接失败

    • 检查 MQTT 服务器地址和端口是否正确
    • 验证用户名和密码是否正确
    • 确保 MQTT 服务器允许外部连接
  3. 数据传输不稳定

    • 检查网络环境是否稳定
    • 调整 MQTT 消息发布频率
    • 添加消息重发机制

八、项目扩展与优化

8.1 功能扩展

  1. 添加更多传感器:如光照传感器、气压传感器等
  2. 实现定时控制:设置定时开关功能
  3. 添加数据存储:将传感器数据存储到数据库
  4. 实现数据分析:对历史数据进行分析和可视化
  5. 添加语音控制:集成语音识别功能

8.2 性能优化

  1. 代码优化:减少内存占用,提高执行效率
  2. 网络优化:优化 MQTT 消息格式,减少数据传输量
  3. 电源管理:对于电池供电的设备,实现低功耗模式
  4. 安全性增强:添加数据加密和身份验证机制

8.3 部署与发布

  1. 云平台部署:将 MQTT 服务器部署到云服务器
  2. App 发布:将开发的 App 发布到应用商店
  3. 设备量产:对于需要量产的项目,进行硬件设计和生产

九、总结

本文详细介绍了 ESP8266 和云智能 App 的开发全流程,从硬件选型、开发环境搭建、ESP8266 编程、云平台配置到 App 开发,全方位展示了一个完整的物联网应用开发过程。通过丰富的代码示例和详细的说明,帮助读者理解和掌握这一开发技术。

通过这种方式,我们可以开发出各种智能家居、环境监测、工业控制等应用系统。随着物联网技术的不断发展,ESP8266 和云智能 App 的组合将为更多创新应用提供可能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亿只小灿灿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值