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

标题: 明基投影仪RS232接入(之ESPHome版) [打印本页]

作者: whxciotw    时间: 2024-8-25 23:25
标题: 明基投影仪RS232接入(之ESPHome版)
本帖最后由 whxciotw 于 2024-8-26 00:08 编辑

之前分享过投影仪接入的rs232-esp的mqtt方案,这是以前的帖子,这次再分享一个ESPHome的固件方案,灵活性更强。
主要参考来源:GitHub链接

ESPHome配置文件
  1. substitutions:
  2.   device_name: benq
  3.   ip_address: 192.168.19.54
  4.       
  5. esphome:
  6.   name: ${device_name}
  7.   includes:
  8.     - uart_read_line_sensor.h

  9. esp8266:
  10.   board: nodemcuv2

  11. # Enable logging
  12. logger:

  13. # Enable UART. Please select the pins you're using on your board.
  14. uart:
  15.   id: projector
  16.   tx_pin: D4  #GPIO2
  17.   rx_pin: RX  #GPIO3
  18.   baud_rate: 115200

  19. # Enable Home Assistant API
  20. api:

  21. ota:
  22.   platform: esphome

  23. wifi:
  24.   ssid: !secret wifi_ssid
  25.   password: !secret wifi_password
  26.   fast_connect: true  
  27.   use_address: ${ip_address}
  28.   # Enable fallback hotspot (captive portal) in case wifi connection fails
  29.   ap:
  30.     ssid: ${device_name}
  31.     password: !secret ap_password

  32. captive_portal:

  33. # This is our hub - it manages our connection to the projector.
  34. text_sensor:
  35.   - platform: custom
  36.     lambda: |-
  37.       auto my_custom_sensor = new UartReadLineSensor(id(projector));
  38.       App.register_component(my_custom_sensor);
  39.       return {my_custom_sensor};
  40.     text_sensors:
  41.       id: "uart_readline"
  42.       on_value:
  43.         then:
  44.           - lambda: |-
  45.              // Clean up the end of the string   
  46.              std::string str = x;
  47.              str = str.erase(str.size()-1, 1);

  48.              // Parse commands and values
  49.              std::string command = str.substr(1, str.find("=")-1);
  50.              std::string param = str.substr(str.find("=")+1, str.size());
  51.             
  52.              if ((param == "?") || (param == "+") || (param == "-")){
  53.                return;
  54.              }

  55.              if (command == "VOL") {
  56.                id(projector_volume).publish_state(atoi(param.c_str()));
  57.              } else if (command == "LTIM") {
  58.                id(projector_ltim).publish_state(atoi(param.c_str()));
  59.              } else if (command == "POW") {
  60.                id(projector_power).publish_state(param == "ON");
  61.              } else if (command == "SOUR") {
  62.                id(projector_source).publish_state(param.c_str());
  63.              }

  64. select:
  65.   - platform: template
  66.     name: ${device_name} Source
  67.     id: projector_source
  68.     # Change this to the inputs your projector has
  69.     options:
  70.       - HDMI1
  71.       - HDMI2
  72.       - USBREADER
  73.     set_action:
  74.       then:
  75.         - lambda: |-
  76.             if ((x) != id(projector_source).state) {
  77.               std::string c = "\r*SOUR=" + x + "#\r";
  78.               id(projector).write_array((const uint8_t*)c.c_str(), c.size());
  79.               id(projector_source).publish_state(x);
  80.             }
  81.    
  82.    
  83. number:
  84.   - platform: template
  85.     id: projector_volume
  86.     step: 1
  87.     min_value: 0
  88.     max_value: 50
  89.     name: ${device_name} Volume
  90.       
  91.     set_action:
  92.       then:
  93.         - lambda: |-
  94.             int target = round(x);
  95.             int current = id(projector_volume).state;
  96.             int delta = target - current;

  97.             for (int i=0; i<abs(delta);i++) {
  98.               std::string c = "";
  99.               if (delta < 0) {
  100.                   
  101.                   c = "\r*vol=-#\r";
  102.               }
  103.               else if (delta > 0){
  104.                   c = "\r*vol=+#\r";
  105.               }
  106.               else {
  107.                 // nothing
  108.               }
  109.               
  110.               if (c != "") {
  111.                 id(projector).write_array((const uint8_t*)c.c_str(), c.size());
  112.               }
  113.             }
  114.             
  115.             id(projector_volume).publish_state(target);

  116.    
  117.       
  118. sensor:

  119.   - platform: template
  120.     name: ${device_name} Lamp Hours
  121.     id: projector_ltim


  122. switch:
  123.   - platform: template
  124.     name: ${device_name} Power
  125.     id: projector_power

  126.     turn_on_action:
  127.       - uart.write: "\r*pow=on#\r"
  128.     turn_off_action:
  129.       - uart.write: "\r*pow=off#\r"
  130.   
  131. interval:
  132.   - interval: 10s # not pretty, but works
  133.     then:
  134.       - uart.write: "\r*pow=?#\r"
  135.       - delay: 1s
  136.       - if:
  137.           condition:
  138.             lambda: 'return id(projector_power).state;'
  139.           then:
  140.             - uart.write: "\r*sour=?#\r"
  141.             - delay: 1s
  142.             - uart.write: "\r*vol=?#\r"
  143.             - delay: 1s
  144.             - uart.write: "\r*ltim=?#\r"

  145.           else:
  146.             - logger.log: "Projector is OFF"


  147.       
复制代码


uart_read_line_sensor.h文件
  1. #include "esphome.h"

  2. class UartReadLineSensor : public Component, public UARTDevice, public TextSensor {
  3. public:
  4.   UartReadLineSensor(UARTComponent *parent) : UARTDevice(parent) {}

  5.   void setup() override {
  6.     // nothing to do here
  7.   }

  8.   int readline(int readch, char *buffer, int len)
  9.   {
  10.     static int pos = 0;
  11.     int rpos;

  12.     if (readch > 0) {
  13.       switch (readch) {
  14.         case '\n': // Ignore new-lines
  15.           break;
  16.         case '\r': // Return on CR
  17.           rpos = pos;
  18.           pos = 0;  // Reset position index ready for next time
  19.           return rpos;
  20.         default:
  21.           if (pos < len-1) {
  22.             buffer[pos++] = readch;
  23.             buffer[pos] = 0;
  24.           }
  25.       }
  26.     }
  27.     // No end of line has been found, so return -1.
  28.     return -1;
  29.   }

  30.   void loop() override {
  31.     const int max_line_length = 80;
  32.     static char buffer[max_line_length];
  33.     while (available()) {
  34.       if(readline(read(), buffer, max_line_length) > 0) {
  35.         publish_state(buffer);
  36.       }
  37.     }
  38.   }
  39. };
复制代码



作者: lxgxdx    时间: 2024-8-26 10:52
感谢分享
作者: lxgxdx    时间: 2024-8-26 11:00
其他牌子的投影仪不知道能不能用啊
作者: whxciotw    时间: 2024-8-26 13:00
lxgxdx 发表于 2024-8-26 11:00
其他牌子的投影仪不知道能不能用啊

看 rs232 协议是否一致
作者: lxgxdx    时间: 2024-8-26 20:57
whxciotw 发表于 2024-8-26 13:00
看 rs232 协议是否一致

怎么看协议是不是一样啊
作者: whxciotw    时间: 2024-8-26 22:26
lxgxdx 发表于 2024-8-26 20:57
怎么看协议是不是一样啊

试着去问问AI
作者: fulinsky    时间: 2024-10-22 17:10
本帖最后由 fulinsky 于 2024-10-24 08:17 编辑

斑竹好,本人手上有HITACHI N3410W投影机,用的D1-mini,只想实现ha控制开关机,照葫芦画瓢您的方案,现在是能开机,但是开机后开关就变成关闭状态,也没有办法关机!请求大大伸手相助。投影机的232控制代码见下图:[attach]64485[/attach]

下面是我的yaml代码:
  1. esphome:
  2.   name: mediaroom-bridge
  3.   includes:
  4.     - uart_read_line_sensor.h

  5. logger:
  6.   level: DEBUG #makes uart stream available in esphome logstream
  7.   baud_rate: 0 #disable logging over uart

  8. uart:
  9.   id: uart_bus
  10.   tx_pin: D4
  11.   rx_pin: RX
  12.   baud_rate: 19200

  13. text_sensor:
  14. - platform: custom
  15.   lambda: |-
  16.     auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));
  17.     App.register_component(my_custom_sensor);
  18.     return {my_custom_sensor};
  19.   text_sensors:
  20.     id: "uart_readline"
  21.     on_value:
  22.       then:
  23.         - lambda: |-
  24.            // Clean up the end of the string   
  25.            std::string str = x;
  26.            str = str.erase(str.size()-1, 1);

  27.            // Parse commands and values
  28.            std::string command = str.substr(1, str.find("=")-1);
  29.            std::string param = str.substr(str.find("=")+1, str.size());
  30.             
  31.            if ((param == "?") || (param == "+") || (param == "-")){
  32.              return;
  33.            }

  34.            if (command == "POW") {
  35.              id(projector_power).publish_state(param == "ON");
  36.            }

  37. switch:
  38.   - platform: template
  39.     name: "HITACHI Projector"
  40.     id: projector_power
  41.     turn_on_action:
  42.       - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0xBA, 0xD2, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00]
  43.     turn_off_action:
  44.       - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0x2A, 0xD3, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00]

  45. interval:
  46.   - interval: 10s
  47.     then:
  48.       - uart.write:  [0xBE, 0xEF, 0x03, 0x06, 0x00, 0x19, 0xD3, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00]
  49.    
  50. esp8266:
  51.   board: d1_mini
  52.   
  53. web_server:
  54.   port: 80

  55. # Enable Home Assistant API
  56. api:
  57.   encryption:
  58.     key: "XXXXXXXXXXXXXXXX"

  59. ota:
  60.   - platform: esphome
  61.     password: "XXXXXXXXXXXXXXX"

  62. wifi:
  63.   ssid: "XXXX"
  64.   password: "XXXXXXXX"
  65.   fast_connect: True
  66.   manual_ip:
  67.     static_ip: 192.168.1.XXX
  68.     gateway: 192.168.1.1
  69.     subnet: 255.255.255.0

  70.   # Enable fallback hotspot (captive portal) in case wifi connection fails
  71.   ap:
  72.     ssid: "Mediaroom-Bridge"
  73.     password: "XXXXXXXX"

  74. captive_portal:
复制代码


作者: whxciotw    时间: 2024-10-23 23:47
本帖最后由 whxciotw 于 2024-10-23 23:50 编辑
fulinsky 发表于 2024-10-22 17:10
斑竹大大好,本人手上有HITACHI N3410W投影机,用的D1-mini,只想实现ha控制开关机,照葫芦画瓢您的方案, ...
你试试这个,markdown发不出来,你将就看下

esphome:
  name: mediaroom-bridge
  includes:
    - uart_read_line_sensor.h

logger:
  level: DEBUG #makes uart stream available in esphome logstream
  baud_rate: 0 #disable logging over uart

uart:
  id: uart_bus
  tx_pin: D4
  rx_pin: RX
  baud_rate: 19200


switch:
  - platform: template
    name: "HITACHI Projector"
    id: projector_power
    assumed_state: true
    turn_on_action:
      - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0xBA, 0xD2, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00]
    turn_off_action:
      - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0x2A, 0xD3, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00]

esp8266:
  board: d1_mini

web_server:
  port: 80

# Enable Home Assistant API
api:
  encryption:
    key: "XXXXXXXXXXXXXXXX"

ota:
  - platform: esphome
    password: "XXXXXXXXXXXXXXX"

wifi:
  ssid: "XXXX"
  password: "XXXXXXXX"
  fast_connect: True
  manual_ip:
    static_ip: 192.168.1.XXX
    gateway: 192.168.1.1
    subnet: 255.255.255.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Mediaroom-Bridge"
    password: "XXXXXXXX"

captive_portal:


作者: fulinsky    时间: 2024-10-24 08:10
本帖最后由 fulinsky 于 2024-10-24 08:28 编辑
whxciotw 发表于 2024-10-23 23:47
你试试这个,markdown发不出来,你将就看下

esphome:

修改后,下载project失败,加上text_sensor:就可以了,感谢!

  1. <div style="color: rgb(232, 232, 233); background-color: rgb(30, 30, 30); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, &quot;Liberation Mono&quot;, &quot;Courier New&quot;, monospace, Menlo, Monaco, &quot;Courier New&quot;, monospace; font-size: 12px; line-height: 18px; white-space: pre;"><div>text_sensor:</div><div>- platform: custom</div><div>  lambda: |-</div><div><span style="color: rgb(206, 145, 120);">    auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));</span></div><div><span style="color: rgb(206, 145, 120);">    App.register_component(my_custom_sensor);</span></div><div><span style="color: rgb(206, 145, 120);">    return {my_custom_sensor};</span></div><div>  text_sensors:</div><div>    id: <span style="color: rgb(206, 145, 120);">"uart_readline"</span></div></div>
复制代码


作者: whxciotw    时间: 2024-10-24 11:59
本帖最后由 whxciotw 于 2024-10-24 12:00 编辑
fulinsky 发表于 2024-10-24 08:10
修改后,下载project失败,加上text_sensor:就可以了,感谢!
应该不用加text_sensor呀,我在esphome中验证是通过的,你再看看。
  1. esphome:
  2.   name: mediaroom-bridge
  3.   includes:
  4.     - uart_read_line_sensor.h

  5. logger:
  6.   level: DEBUG #makes uart stream available in esphome logstream
  7.   baud_rate: 0 #disable logging over uart

  8. uart:
  9.   id: uart_bus
  10.   tx_pin: D4
  11.   rx_pin: RX
  12.   baud_rate: 19200

  13. switch:
  14.   - platform: template
  15.     name: "HITACHI Projector"
  16.     id: projector_power
  17.     assumed_state: True
  18.     turn_on_action:
  19.       - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0xBA, 0xD2, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00]
  20.     turn_off_action:
  21.       - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0x2A, 0xD3, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00]

  22. esp8266:
  23.   board: d1_mini
  24.   
  25. web_server:
  26.   port: 80

  27. # Enable Home Assistant API
  28. api:


  29. ota:
  30.   - platform: esphome


  31. wifi:
  32.   ssid: "XXXX"
  33.   password: "XXXXXXXX"
  34.   fast_connect: True
  35.   manual_ip:
  36.     static_ip: 192.168.1.1
  37.     gateway: 192.168.1.1
  38.     subnet: 255.255.255.0

  39.   # Enable fallback hotspot (captive portal) in case wifi connection fails
  40.   ap:
  41.     ssid: "Mediaroom-Bridge"
  42.     password: "XXXXXXXX"

  43. captive_portal:
复制代码

作者: fulinsky    时间: 2024-10-24 12:10
whxciotw 发表于 2024-10-24 11:59
应该不用加text_sensor呀,我在esphome中验证是通过的,你再看看。

您在esphome中点击logs测试的吗?如果不加text_sensor,logs提示错误和uart_read_line_sensor.h文件相关,是不是因为在uart_read_line_sensor.h文件中有public TextSensor,所以必须加上text_sensor才能通过?我的esphome是最新版的。
作者: whxciotw    时间: 2024-10-24 12:22
fulinsky 发表于 2024-10-24 12:10
您在esphome中点击logs测试的吗?如果不加text_sensor,logs提示错误和uart_read_line_sensor.h文件相关 ...

我是在esphome中validate验证通过,也是最新版。不加text sensor,你那里能validate通过吗?
另外,如果想加上电源的状态反馈,可以改一改代码。大体如下,详细的你可以配合AI改一改。
  1. esphome:
  2.   name: mediaroom-bridge
  3.   includes:
  4.     - uart_read_line_sensor.h

  5. logger:
  6.   level: DEBUG #makes uart stream available in esphome logstream
  7.   baud_rate: 0 #disable logging over uart

  8. uart:
  9.   id: uart_bus
  10.   tx_pin: D4
  11.   rx_pin: RX
  12.   baud_rate: 19200

  13. text_sensor:
  14. - platform: custom
  15.   lambda: |-
  16.     auto uart_sensor = new UartReadLineSensor();
  17.     App.register_component(uart_sensor);
  18.     return {uart_sensor};
  19.   text_sensors:
  20.     - id: uart_readline
  21.       on_value:
  22.         then:
  23.           - lambda: |-
  24.               std::string value = x;
  25.               // 检查字符串是否以0xBE, 0xEF等开始,并根据最后一个字节确定状态
  26.               if (value.size() >= 26 && value.substr(0, 22) == "0xBE, 0xEF, 0x03, 0x06, 0x00, 0x19, 0xD3, 0x02, 0x00, 0x00, 0x60") {
  27.                 uint8_t last_byte = strtol(value.substr(24, 2).c_str(), nullptr, 16);
  28.                 if (last_byte == 0x01) {
  29.                   id(projector_power).publish_state(true);
  30.                 } else if (last_byte == 0x00 || last_byte == 0x02) {
  31.                   id(projector_power).publish_state(false);
  32.                 }
  33.               }

  34. switch:
  35.   - platform: template
  36.     name: "HITACHI Projector"
  37.     id: projector_power
  38.     # assumed_state: True
  39.     turn_on_action:
  40.       - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0xBA, 0xD2, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00]
  41.     turn_off_action:
  42.       - uart.write: [0xBE, 0xEF, 0x03, 0x06, 0x00, 0x2A, 0xD3, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00]

  43. interval:
  44.   - interval: 10s
  45.     then:
  46.       - uart.write:  [0xBE, 0xEF, 0x03, 0x06, 0x00, 0x19, 0xD3, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00]

  47. esp8266:
  48.   board: d1_mini
  49.   
  50. web_server:
  51.   port: 80

  52. # Enable Home Assistant API
  53. api:


  54. ota:
  55.   - platform: esphome


  56. wifi:
  57.   ssid: "XXXX"
  58.   password: "XXXXXXXX"
  59.   fast_connect: True
  60.   manual_ip:
  61.     static_ip: 192.168.1.1
  62.     gateway: 192.168.1.1
  63.     subnet: 255.255.255.0

  64.   # Enable fallback hotspot (captive portal) in case wifi connection fails
  65.   ap:
  66.     ssid: "Mediaroom-Bridge"
  67.     password: "XXXXXXXX"

  68. captive_portal:
复制代码



作者: fulinsky    时间: 2024-10-24 16:55
whxciotw 发表于 2024-10-24 12:22
我是在esphome中validate验证通过,也是最新版。不加text sensor,你那里能validate通过吗?
另外,如果想 ...

谢谢斑竹,只怪自己太菜,折腾一下午,用chatgpt也没搞出个所以然,还是打开后开关就回到关闭状态,无法正确反馈电源状态。暂时就用个homekit的开关吧!
作者: tanbobo    时间: 2024-10-28 09:14
咨询一下 我的是benq的MW516
按照你的 固件 超了作业 编译也好了 搭建好线路 但是 无法控制 投影机 麻烦指导一下!
作者: whxciotw    时间: 2024-10-28 10:48
tanbobo 发表于 2024-10-28 09:14
咨询一下 我的是benq的MW516
按照你的 固件 超了作业 编译也好了 搭建好线路 但是 无法控制 投影机 麻烦指 ...

日志?
作者: coldkevin    时间: 2025-1-2 23:38
fulinsky 发表于 2024-10-24 16:55
谢谢斑竹,只怪自己太菜,折腾一下午,用chatgpt也没搞出个所以然,还是打开后开关就回到关闭状态,无法 ...

我在modbus controller用了一个笨办法,reture时候,x>0,ture,否则false
作者: coldkevin    时间: 2025-1-3 09:41
https://esphome.io/custom/uart
今年1.0版本要被弃用




欢迎光临 『瀚思彼岸』» 智能家居技术论坛 (https://bbs.hassbian.com/) Powered by Discuz! X3.5