Arduino 米家 巴法云 小爱同学 开关灯 仿真

一、创建巴法云tcp设备

关于设备类型,由创建的主题名称决定:
当主题名字后三位是001时为插座设备
当主题名字后三位是002时为灯泡设备
当主题名字后三位是003时为风扇设备
当主题名字后三位是004时为传感器设备

二、米家输入巴法云账号密码

同步即可导入设备

三、代码

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include "CustomWiFiManager.h"  // 引入自定义WiFiManager库


// 巴法云服务器地址默认即可
#define TCP_SERVER_ADDR "bemfa.com"
// 服务器端口,TCP创客云端口8344
#define TCP_SERVER_PORT "8344"

//********************需要修改的部分*******************//

String UID = " ";  // 用户私钥,可在控制台获取, 修改为自己的UID
String TOPIC = "switch002";  // 主题名字,可在控制台新建

//**************************************************//


// 全局作用域声明 servo 对象
Servo servo;
const int SERVO_PIN = 2;  // 舵机连接到 GPIO2

const int SERVO_DEFAULT_POS = 90;   // 舵机默认位置
const int SERVO_ON_POS = 45;       // 舵机打开位置
const int SERVO_OFF_POS = 135;     // 舵机关闭位置
unsigned long servoStartTime = 0;  // 记录舵机动作开始的时间
const unsigned long SERVO_DELAY = 1000;  // 舵机保持动作的时间 (ms)
bool servoActive = false;          // 舵机是否正在动作



// 最大字节数
#define MAX_PACKETSIZE 512
// 设置心跳值 30s
#define KEEPALIVEATIME 60 * 1000

// TCP 客户端相关初始化,默认即可
WiFiClient TCPclient;
String TcpClient_Buff = "";
unsigned int TcpClient_BuffIndex = 0;
unsigned long TcpClient_preTick = 0;
unsigned long preHeartTick = 0;      // 心跳
unsigned long preTCPStartTick = 0;  // 连接
bool preTCPConnected = false;

// 相关函数初始化
// TCP 初始化连接
void doTCPClientTick();
void startTCPClient();
void sendtoTCPServer(String p);
void handleServo() ;
void turnOnServo() ;
void turnOffServo();


void handleServo() {
  // 非阻塞舵机控制:检查是否需要恢复舵机位置
  if (servoActive && (millis() - servoStartTime >= SERVO_DELAY)) {
    servo.write(SERVO_DEFAULT_POS);  // 恢复舵机默认位置
    Serial.println("Servo returned to default position");
    servoActive = false;            // 结束动作标记
  }
}

void turnOnServo() {
  Serial.println("Turn ON Servo");
  servo.write(SERVO_ON_POS);      // 舵机转到打开位置
  servoStartTime = millis();      // 记录开始时间
  servoActive = true;             // 标记舵机正在动作
}

void turnOffServo() {
  Serial.println("Turn OFF Servo");
  servo.write(SERVO_OFF_POS);     // 舵机转到关闭位置
  servoStartTime = millis();      // 记录开始时间
  servoActive = true;             // 标记舵机正在动作
}



// TCP 发送数据到服务器
void sendtoTCPServer(String p) {
  if (!TCPclient.connected()) {
    Serial.println("Client is not ready");
    return;
  }
  TCPclient.print(p);
  preHeartTick = millis();  // 心跳计时开始,需要每隔60秒发送一次数据
}

// 初始化和服务器建立连接
void startTCPClient() {
  if (TCPclient.connect(TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT))) {
    Serial.println("Connected to server:");
    Serial.printf("%s:%d\r\n", TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT));

    String tcpTemp = "";  // 初始化字符串
    tcpTemp = "cmd=1&uid=" + UID + "&topic=" + TOPIC + "\r\n";  // 构建订阅指令
    sendtoTCPServer(tcpTemp);                                  // 发送订阅指令
    tcpTemp = "";                                              // 清空

    preTCPConnected = true;
    TCPclient.setNoDelay(true);
  } else {
    Serial.print("Failed connected to server:");
    Serial.println(TCP_SERVER_ADDR);
    TCPclient.stop();
    preTCPConnected = false;
  }
  preTCPStartTick = millis();
}

// 检查数据,发送心跳
void doTCPClientTick() {
  if (WiFi.status() != WL_CONNECTED) return;

  if (!TCPclient.connected()) {  // 断开重连
    if (preTCPConnected == true) {
      preTCPConnected = false;
      preTCPStartTick = millis();
      Serial.println("TCP Client disconnected.");
      TCPclient.stop();
    } else if (millis() - preTCPStartTick > 1 * 1000)  // 重新连接
      startTCPClient();
  } else {
    if (TCPclient.available()) {  // 收数据
      char c = TCPclient.read();
      TcpClient_Buff += c;
      TcpClient_BuffIndex++;
      TcpClient_preTick = millis();

      if (TcpClient_BuffIndex >= MAX_PACKETSIZE - 1) {
        TcpClient_BuffIndex = MAX_PACKETSIZE - 2;
        TcpClient_preTick = TcpClient_preTick - 200;
      }
    }
    if (millis() - preHeartTick >= KEEPALIVEATIME) {  // 保持心跳
      preHeartTick = millis();
      sendtoTCPServer("cmd=0&msg=keep\r\n");
    }
  }

  if ((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick >= 200)) {
    // 处理接收到的数据
    TCPclient.flush();
    TcpClient_Buff.trim();  // 去掉首位空格
    String getTopic = "";
    String getMsg = "";
    if (TcpClient_Buff.length() > 15) { //注意TcpClient_Buff只是个字符串,在上面开头做了初始化 String TcpClient_Buff = "";
      //此时会收到推送的指令,指令大概为 cmd=2&uid=xxx&topic=light002&msg=off
      int topicIndex = TcpClient_Buff.indexOf("&topic=") + 7; //c语言字符串查找,查找&topic=位置,并移动7位,不懂的可百度c语言字符串查找
      int msgIndex = TcpClient_Buff.indexOf("&msg=");//c语言字符串查找,查找&msg=位置
      getTopic = TcpClient_Buff.substring(topicIndex, msgIndex); //c语言字符串截取,截取到topic,不懂的可百度c语言字符串截取
      getMsg = TcpClient_Buff.substring(msgIndex + 5); //c语言字符串截取,截取到消息
      Serial.print("\ntopic: ");
      Serial.println(getTopic); //打印截取到的主题值
      Serial.print("msg: ");
      Serial.println(getMsg);   //打印截取到的消息值
    }


    if (getMsg  == "on") {     //如果是消息==舵机打开
      turnOnServo();
    } else if (getMsg == "off") { //如果是消息==舵机关闭
      turnOffServo();
    }

    TcpClient_Buff = "";
    TcpClient_BuffIndex = 0;
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting...");

  // 自定义 WiFiManager 配置
  WiFiManager wifiManager;
  wifiManager.setTimeout(180);  // 设置配网超时 3 分钟
  if (!wifiManager.autoConnect("Smart_Switch_Config")) {  // 使用热点名称 "Smart_Switch_Config"
    Serial.println("Failed to connect and hit timeout");
    ESP.restart();  // 如果未连接,重启
  }

  // 启动 TCP 客户端
  startTCPClient();
}

void loop() {
  doTCPClientTick();
  handleServo();
}

拉取工程

git clone https://gitee.com/back-cat/lazy-person_mini_switch.git

参考博客

esp8266接入米家、小爱同学,附开源app控制-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

chem4111

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

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

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

打赏作者

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

抵扣说明:

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

余额充值