esp32发送蓝牙广播实现电视的开关机


现在很多电视的遥控器配备的都是蓝牙遥控器,所以无法使用红外信号来控制电视的开机。
前面的文章用树莓派配合hdmi-cec实现了电视的开机,但是电视有线外接了一个树莓派,多少有点难看,那么是否有更好的办法无线实现电视的开机操作呢?
之前在瀚思彼岸论坛有看到坛友利用此方法实现了极米的开机,按照此方法成功将家里的夏普电视成功接入到Homeassistant实现控制电视的开关机,并且之前抓包过夏普电视的app可以通过发送tcp包控制电视关机。
我家里的电视是夏普LCD-70MY6150A电视,如果有和我用的同型号的同学可以直接抄作业。

准备工作

  1. 准备一台ios设备, 下载安装 bluetooth smart scanner app
  2. 把电视或者投影仪关机
  3. 不停的按遥控器上的开机按键,这时在bluetooth smart scanner 上可以找到遥控器发射的ble advertisement信号
  4. 在上面的信号中, 找到manufactorer data
  5. 可以通过EFR connect这个安卓app发送蓝牙广播来验证能否使用上面的manufactorer data唤起电视或者投影
  6. 如果电视或者投影能成功开机,那么就说明成功了。

file

接下来就是如何让ESP32实现这个模拟发送这个蓝牙广播让Homeassistant来控制实现电视的开机

附上Arduino的代码

#include <ESP32BleAdvertise.h>
#include <WiFi.h>
#include <PubSubClient.h>

// WiFi 设置
const char* ssid = "wifi";
const char* password = "12345678";

// MQTT 设置
const char* mqtt_server = "192.168.199.100";
const char* mqtt_user = "mqtt";
const char* mqtt_password = "password";
const char* mqtt_topic = "homeassistant/switch/tv_switch/state";
const char* mqtt_command_topic = "homeassistant/switch/tv_switch/set";

// TCP 设置
const char* target_ip = "192.168.199.50";
const int target_port = 9688;  // 目标端口号
const char* turn_off_msg = "SPRC#DIRK#19#1#2#1|22#";//发送TCP包来关闭电视

WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
SimpleBLE bleadv;
bool currentState = false; // 开关当前状态

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

void callback(char* topic, byte* payload, unsigned int length) {
  String message;
  for (unsigned int i = 0; i < length; i++) {
    message += (char)payload[i];
  }

  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  Serial.println(message);

  if (String(topic) == mqtt_command_topic) {
    if (message == "ON") {
      //发送蓝牙开机指令
      currentState = true;
      turnon();
    // bleadv.begin();                                                                                                                   //初始化蓝牙名
    // uint8_t data[] = { 0x46, 0x00, 0x2E, 0x5F, 0xDF, 0xED, 0x84, 0x20, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0x53, 0x48, 0x41, 0x52, 0x50 };  //蓝牙广播内容
    // bleadv.advertise(data, 18);
    // delay(5000);
    // bleadv.end();
    } else if (message == "OFF") {
      send_tcp_message(turn_off_msg);
      currentState = false;
    }
  }
}

void send_tcp_message(const char* message) {
  WiFiClient client;
  if (!client.connect(target_ip, target_port)) {
    Serial.println("Connection to target IP failed");
    return;
  }
  client.print(message);
  client.stop();
}

bool check_tcp_status() {
  WiFiClient client;
  if (!client.connect(target_ip, target_port)) {
    return false;
  }
  client.stop();
  return true;
}

void reconnect() {
  while (!mqttClient.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (mqttClient.connect("ESP32Client", mqtt_user, mqtt_password)) {
      Serial.println("connected");
      mqttClient.subscribe(mqtt_command_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(mqttClient.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void turnon(){
  if(currentState){
      bleadv.begin();                                                                                                                   //初始化蓝牙名
      uint8_t data[] = { 0x46, 0x00, 0x2E, 0x5F, 0xDF, 0xED, 0x84, 0x20, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0x53, 0x48, 0x41, 0x52, 0x50 };  //蓝牙广播内容
      bleadv.advertise(data, 18);
    }else{
      bleadv.end();
    }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  setup_wifi();
  mqttClient.setServer(mqtt_server, 1883);
  mqttClient.setCallback(callback);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (!mqttClient.connected()) {
    reconnect();
  }
  mqttClient.loop();
  static unsigned long last_check = 0;
  if (millis() - last_check > 5000) {  // 每5秒检查一次
    last_check = millis();
    bool status = check_tcp_status();
    mqttClient.publish(mqtt_topic, status ? "ON" : "OFF");
    if(status&&currentState){//如果电视现在是开机状态,并且广播还在发送中,取消发送
      currentState=false;
    }
    turnon();

  }
}

上面用到的蓝牙库的地址:https://github.com/peterk54/ESP32BLESimpleAdvertiser

在写入esp32s的时候遇到容量不足的问题

Sketch uses 1648605 bytes (125%) of program storage space. Maximum is 1310720 bytes.
Global variables use 57980 bytes (17%) of dynamic memory, leaving 269700 bytes for local variables. Maximum is 327680 bytes.
Sketch too big; see https://support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing it.
text section exceeds available space in board

Compilation error: text section exceeds available space in board

解决办法:Arduino IDE: Tools -> Partition Scheme:change "Default" to "Huge APP(3MB No OTA)"

把上面的代码编译写入ESP32后,最后在Homeassistant里的configuration.yaml配置这个mqtt开关

mqtt:
  - switch:
    name: "tv power"
    state_topic: "homeassistant/switch/tv_switch/state"
    command_topic: "homeassistant/switch/tv_switch/set"
    qos: 0
    retain: true

大功告成!

本文地址:https://www.blear.cn/article/esp32-bluetooth-tv-power

转载时请以链接形式注明出处

评论
受监管部门要求,个人网站不允许评论功能,评论已关闭,抱歉!