『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 3538|回复: 14

[硬件DIY] 明基SP840投影机通过ESPHOME接入HA

[复制链接]

5

主题

190

帖子

926

积分

高级会员

Rank: 4

积分
926
金钱
731
HASS币
20
发表于 2022-10-9 00:43:59 | 显示全部楼层 |阅读模式
家里客厅有台BENQ SP840投影机,原来一直是用的博联的RM pro学习遥控码来控制,总感觉不是很完美,有时候控制会出现问题,看到投影机有RS232接口,在某多弄了一个232转TTL板子,加上D1_min和家里到处都能找到的手机充电器供电,通过ESPHOME接入,经过无数次测试,终于可以控制。就是串口接收判断不会弄,到处学习了一阵,大概需要定制一个二进制传感器,可惜还是不会弄,开关没有反馈,不过控制足够了,成本15块以内,本来想用合宙的9.9元包邮的ESP32C3,成本还要低,wifi信号也要好得多,性能还要好,首批买两块用完了,新买的还在路上,暂时用剩下的d1_min,,不知什么原因,后期买的d1_minWIF信号都很差了,好在客厅WIFI信号非常好,可用的代码如下(其中sp840 status那个SWITCH是查询投影电源状态的,不会写自定义插件,没啥用,只能看到返回\x00w#\r\r\n \x00*POW=OFF#\r\n):
esphome:
  name: $devicename
  platform: ESP8266
  board: d1_mini
  #断电记忆,恢复上次的状态
  esp8266_restore_from_flash: yes



#------- 自定义的配置 -------

substitutions:
  devicename: benqsp840
  #如果SSID是隐藏的,设置为true
  wififastconnect: 'false'
  #WiFi离线多久后重启设备,秒s/分钟min/小时h,不需要此功能设置为0s,建议设置0s,防止异常重启,或者设置的大一些
  wifireboottimeout: 0s
  #与API服务端失去连接多久后重启设备,秒s/分钟min/小时h,不需要此功能设置为0s,建议设置0s,防止异常重启,或者设置的大一些
  apireboottimeout: 0s
  
#------- WIFI配置 -------
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  domain: .local
  reboot_timeout: $wifireboottimeout
  power_save_mode: none
  fast_connect: $wififastconnect
  
  #use_address: 192.168.0.55
  
#------- WIFI AP配置 -------
  ap:
    ssid: $devicename
    password: "1234567890"
#对应的管理IP地址为192.168.4.1
captive_portal:

#---------api配置---------
api:
  reboot_timeout: $apireboottimeout
  password: !secret api_password
#----------------------------------------------------

#------- OTA 升级配置 -------
ota:
  safe_mode: true
  password: !secret ota_password
#  port: 3286

#------- WEB后台 -------
web_server:
  port: 80
#  css_url: https://esphome.io/_static/webserver-v1.min.css
#  js_url: https://esphome.io/_static/webserver-v1.min.js
#----------------------------------------------------


#----------------------------------------------------
logger:
  #不同的log等级看到的信息详细程度不一样,信息量从少到多依次为
  # NONE、ERROR、WARN、INFO、DEBUG、VERBOSE、VERY_VERBOSE
  level: DEBUG
  #设置为0关闭通过UART的log输出
  baud_rate: 0
  #通过TTL看log信息,取消注释下面这行,读取接口为RX1,具体见模组接口说明图
#  hardware_uart: UART1
time:
  - platform: sntp
    timezone: Asia/Chongqing
    servers: ntp1.aliyun.com
    id: sntp_time
   
   



uart:
  rx_pin: D1
  tx_pin: D2
  baud_rate: 9600
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);

switch:
  - platform: template
    name: "SP840 Power"
    id: sp840power
    turn_on_action:
      - switch.template.publish:
            id: sp840power
            state: ON
      - uart.write: "\r*pow=on#\r"
    turn_off_action:
      - switch.template.publish:
            id: sp840power
            state: OFF
      - uart.write: "\r*pow=off#\r"
  - platform: template
    name: "SP840 status"
    id: sp840status
    turn_on_action:
      - uart.write: "\r*pow=?#\r"

评分

参与人数 1金钱 +9 收起 理由
jpcugv + 9 感谢楼主分享!

查看全部评分

回复

使用道具 举报

22

主题

656

帖子

4574

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4574
金钱
3903
HASS币
40
发表于 2022-10-9 11:17:38 | 显示全部楼层
楼主看我的帖子,rs232-esp(mqtt)接入明基投影
https://bbs.hassbian.com/thread-17319-1-1.html
回复

使用道具 举报

22

主题

656

帖子

4574

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4574
金钱
3903
HASS币
40
发表于 2022-10-9 11:28:31 | 显示全部楼层
esphome中,可以用binary sensor来建立对power status的判断,然后再配置个switch,状态用这个binary sensor。
回复

使用道具 举报

5

主题

190

帖子

926

积分

高级会员

Rank: 4

积分
926
金钱
731
HASS币
20
 楼主| 发表于 2022-10-10 07:44:08 来自手机 | 显示全部楼层
whxciotw 发表于 2022-10-9 11:28
esphome中,可以用binary sensor来建立对power status的判断,然后再配置个switch,状态用这个binary senso ...

就是不会弄那个串口插件,需要弄个插件,先发一个/r*POW=?#/r,检查返回再来设置二进制传感器状态!
回复

使用道具 举报

22

主题

656

帖子

4574

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4574
金钱
3903
HASS币
40
发表于 2022-10-10 18:04:14 | 显示全部楼层
BG8HQE 发表于 2022-10-10 07:44
就是不会弄那个串口插件,需要弄个插件,先发一个/r*POW=?#/r,检查返回再来设置二进制传感器状态! ...

官网这里写的比较清楚,做uart自定义插件Custom UART Text Sensor — ESPHome

具体就是在esphome的配置文件夹中新建uart_read_line_sensor.h,再在明基的yaml配置文件中引用、并新增text sensor。


以下是我的配置文件,你试试看。
uart_read_line_sensor.h
#include "esphome.h"

class UartReadLineSensor : public Component, public UARTDevice, public TextSensor {
 public:
  UartReadLineSensor(UARTComponent *parent) : UARTDevice(parent) {}

  void setup() override {
    // nothing to do here
  }

  int readline(int readch, char *buffer, int len)
  {
    static int pos = 0;
    int rpos;

    if (readch > 0) {
      switch (readch) {
        case '\n': // Ignore new-lines
          break;
        case '\r': // Return on CR
          rpos = pos;
          pos = 0;  // Reset position index ready for next time
          return rpos;
        default:
          if (pos < len-1) {
            buffer[pos++] = readch;
            buffer[pos] = 0;
          }
      }
    }
    // No end of line has been found, so return -1.
    return -1;
  }

  void loop() override {
    const int max_line_length = 80;
    static char buffer[max_line_length];
    while (available()) {
      if(readline(read(), buffer, max_line_length) > 0) {
        publish_state(buffer);
      }
    }
  }
};
benq.yaml:

esphome:
  name: benq
  includes:
    - uart_read_line_sensor.h
    
esp8266:
  board: d1_mini

# Enable logging
logger:
  level: VERBOSE #makes uart stream available in esphome logstream
  baud_rate: 0 #disable logging over uart
  
# Enable Home Assistant API
api:

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: true  
  use_address: 192.168.19.56
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Benq"
    password: !secret ap_password

captive_portal:

uart:
  id: uart_bus
  tx_pin: GPIO13
  rx_pin: GPIO15
  baud_rate: 115200
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);
      
text_sensor:
- platform: custom
  lambda: |-
    auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));
    App.register_component(my_custom_sensor);
    return {my_custom_sensor};
  text_sensors:
    id: "uart_readline"

switch:
  - platform: template
    name: "Switch"
    lambda: |-
      if (id(uart_readline).state == "*POW=ON#") {
        return true;
      } else if(id(uart_readline).state == "*POW=OFF#") {
        return false;
      } else {
        return {};
      }
    turn_on_action:
      - uart.write: "\r*pow=on#\r"
    turn_off_action:
      - uart.write: "\r*pow=off#\r"

interval:
  - interval: 10s
    then:
      - uart.write: "\r*pow=?#\r"
      


需要注意的是:
1,我的是明基w1080
2,波特率用的115200,之前试了9600都不成功
3,esphome的log中,能够看到uart反复轮训投影的状态,也是能看到正确状态的uart返回值;但是switch的状态(或者叫做text sensor的状态),变换的很慢,可能要过5min、乃至10min,才能正确显示投影的状态。我反复尝试,不知道是怎么回事。你看能否解决
回复

使用道具 举报

5

主题

190

帖子

926

积分

高级会员

Rank: 4

积分
926
金钱
731
HASS币
20
 楼主| 发表于 2022-10-10 22:39:28 | 显示全部楼层
whxciotw 发表于 2022-10-10 18:04
官网这里写的比较清楚,做uart自定义插件Custom UART Text Sensor — ESPHome

具体就是在esphome的配置 ...

  明基W1080和SP840协议是一样的,波特率默认是115200,可以在投影仪菜单中修改,修改为好多就用好多即可,其实不用轮询,每次发送了命令正确执行后都会回显,命令正确在某些模型下无法执行,比如关机状态发送关机命令\r*pow=off#\r或者开机状态下发送开机命令\r*pow=on#\r,会返回Block item,所以不去取状态几乎不影响使用,如果要取状态检测,需要过滤出*pow=on和pow=off,因为返回状态还包含了其他一下字符,比如返回CC!*POW=OFF#\r\n,\x85C!*POW=OFF#\r\n,\xEEn\xAE\xB88\xE1*POW=ON#\r\n,判断相等几乎很难得到正确结果,我目前是不取返回状态,强制模板开关状态在使用。
    合宙9.9包邮的ESP32C3到货了,改成这个,WIFI信号好多了,最近买的D1_mini不知道为撒,简单应用WIFI信号极差,比以前我的存货差多了,而且刷WLED全部不成功,无法启动,以前存货一点没问题,现在不准备用D1_mini了,全面转向ESP32C3,价格便宜,WIFI信号也好,链接速度也感觉快了很多。
   贴上ESP32C3代码:
esphome:
  name: $devicename
  platformio_options:
    board_build.flash_mode: dio
    board_build.mcu: esp32c3
#  includes:
#    - uart_read_line_sensor.h
  
  
esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino
    version: '2.0.2'
    platform_version: '4.2.0'
   

#    type: esp-idf
#    version: latest
#    platform_version: https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream





#------- 一些自定义的配置,一般情况下只需要改这下面的内容 -------

substitutions:
  devicename: benqsp840
  #如果SSID是隐藏的,设置为true
  wififastconnect: 'false'
  #WiFi离线多久后重启设备,秒s/分钟min/小时h,不需要此功能设置为0s,建议设置0s,防止异常重启,或者设置的大一些
  wifireboottimeout: 0s
  #与API服务端失去连接多久后重启设备,秒s/分钟min/小时h,不需要此功能设置为0s,建议设置0s,防止异常重启,或者设置的大一些
  apireboottimeout: 0s
  
#------- WIFI配置 -------
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
#----------需要设置静态地址的改下面的配置------------
#  manual_ip:
#    static_ip: 192.168.178.230
#    gateway: 192.168.178.1
#    subnet: 255.255.255.0
#    dns1: 1.1.1.1
#    dns2: 1.2.2.1
#--------------------------------------------------
  domain: .local
  reboot_timeout: $wifireboottimeout
  power_save_mode: none
  fast_connect: $wififastconnect
  #需要修改名字的时候,启用,OTA后禁用
  #use_address: 192.168.0.55
  
#------- WIFI AP配置 -------
  ap:
    ssid: $devicename
    password: "1234567890"
#对应的管理IP地址为192.168.4.1
captive_portal:

#---------不使用api与设备连接的话删除api配置---------
api:
  reboot_timeout: $apireboottimeout
  password: !secret api_password
#----------------------------------------------------
#mqtt:
#  broker: !secret mqtt_broker
#  client_id: pzemac3
#  username: !secret mqtt_username
#  password: !secret mqtt_password
#------- OTA 空中升级配置 -------
ota:
  safe_mode: true
  password: !secret ota_password
#  port: 3286

#------- WEB后台,不建议使用 -------
web_server:
  port: 80
#  css_url: https://esphome.io/_static/webserver-v1.min.css
#  js_url: https://esphome.io/_static/webserver-v1.min.js
#----------------------------------------------------

#------- 深度休眠配置,一般情况下不建议使用,休眠后将无法远程控制设置 -------
#deep_sleep:
  #唤醒时间
#  run_duration: 50s
  #休眠时间
#  sleep_duration: 10min
#----------------------------------------------------
logger:
  #不同的log等级看到的信息详细程度不一样,信息量从少到多依次为
  # NONE、ERROR、WARN、INFO、DEBUG、VERBOSE、VERY_VERBOSE
  level: DEBUG
  #设置为0关闭通过UART的log输出
  baud_rate: 0


time:
  - platform: sntp
    timezone: Asia/Chongqing
    servers: ntp1.aliyun.com
    id: sntp_time
   
   



uart:
  rx_pin: GPIO01
  tx_pin: GPIO00
  baud_rate: 9600
  id: uart_bus
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);



switch:
  - platform: template
    name: "Sp840 Power"
    id: sp840power
   
    turn_on_action:
      - switch.template.publish:
          id: sp840power
          state: ON
      - uart.write: "\r*pow=on#\r"
    turn_off_action:
      - switch.template.publish:
          id: sp840power
          state: OFF
      - uart.write: "\r*pow=off#\r"
回复

使用道具 举报

22

主题

656

帖子

4574

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4574
金钱
3903
HASS币
40
发表于 2022-10-11 23:38:00 | 显示全部楼层
BG8HQE 发表于 2022-10-10 22:39
明基W1080和SP840协议是一样的,波特率默认是115200,可以在投影仪菜单中修改,修改为好多就用好多即可 ...

lamba这一段,就可以判断投影状态
switch:
  - platform: template
    name: "Switch"
    lambda: |-
      if (id(uart_readline).state == "*POW=ON#") {
        return true;
      } else if(id(uart_readline).state == "*POW=OFF#") {
        return false;
      } else {
        return {};
      }


回复

使用道具 举报

5

主题

190

帖子

926

积分

高级会员

Rank: 4

积分
926
金钱
731
HASS币
20
 楼主| 发表于 2022-10-12 23:39:29 | 显示全部楼层
本帖最后由 BG8HQE 于 2022-10-12 23:40 编辑
whxciotw 发表于 2022-10-11 23:38
lamba这一段,就可以判断投影状态

实际返回类似返回类似CC!*POW=OFF#\r\n,\x85C!*POW=OFF#\r\n,\xEEn\xAE\xB88\xE1*POW=ON#\r\n这样==是不行吧,我把text_sensor 加上name:在HA前端可以看到,状态都是未知,证明==*POW=ON#和==*POW=OFF#是取不到状态的,是包含有*POW=ON#和*POW=OFF#,状态取包含应该可以实现实时返回正确状态。
回复

使用道具 举报

22

主题

656

帖子

4574

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4574
金钱
3903
HASS币
40
发表于 2022-10-13 09:56:12 来自手机 | 显示全部楼层
text sensor中,*POW=ON#和OFF的状态,是能够取到的。但是取得正确状态的速度很慢。
回复

使用道具 举报

22

主题

656

帖子

4574

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4574
金钱
3903
HASS币
40
发表于 2022-10-13 09:57:22 来自手机 | 显示全部楼层
esphome的log中,能够看到uart反复轮训投影的状态,也是能看到正确状态的uart返回值;但是switch的状态(或者叫做text sensor的状态),变换的很慢,可能要过5min、乃至10min,才能正确显示投影的状态。我反复尝试,不知道是怎么回事。我用另一个mqtt的固件,是可以正常获取。你看能否解决
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-11-24 04:39 , Processed in 0.181114 second(s), 32 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表