Gifford47 / HCPBridgeMqtt

Emulates Hörmann UAP1-HCP board using an ESP32 and a RS485 converter, and exposes garage door controls over web page and MQTT.
64 stars 16 forks source link

configuration is lost after a few minutes (2024.07.08) #88

Open webflash-aj opened 1 month ago

webflash-aj commented 1 month ago

Describe the bug when I flash my ESP with the new firmware, nothing works after a few minutes. after rebooting the ESP, my entire configuration is lost (WiFi & MQTT).

the old version 0.0.6.1 does not show this behavior.

any ideas?

To Reproduce

ESP is not connected to the Supramatic

Gifford47 commented 1 month ago

Does it also happen when connected to the motor?

webflash-aj commented 1 month ago

unfortunately yes

tried the esp32.bin and the esp32_BME280_HCSR04.bin

no other sensors are connected

burmistrzak commented 3 weeks ago

@Gifford47 I unfortunately can confirm this behavior. 👀

Our @Tysonpower board, running the latest build from master, also just lost it’s entire configuration… It was working fine for about a month and only went belly up around two hours ago.

I‘ve only included support for the BME280 in my build (i.e. esp32s3_tynet_BME280), because that’s the single sensor we’re using. The previous firmware (that came with the board) was working perfectly for months.

We’ll definitely have to figure this out soon. The current failure mode is really suboptimal, because it enables the unsecured setup AP that potentially allows anyone to control your garage door. Probably not something we want. 😅

Edit: Checking the diff, it’s not immediately obvious what could be causing this problem. Besides the pinned platform version, mainly changes to the web UI are baked into all builds (with or without sensors)…

A possible workaround might be to hardcode the customized configuration? However, if the ESP32 temporarily bricks the motor by resetting/crashing, we probably have other things to worry about first…

webflash-aj commented 3 weeks ago

@burmistrzak My ESP says goodbye after a few minutes with the new firmware. What I have not tried is to compile the repo myself.

If anyone would like me to, I would be happy to test it. Unfortunately I don't have the experience for debugging.

dev-strom commented 3 weeks ago

I can confirm this behavior. I'm using an ESP32 with the BME280 sensor. The first time I run this software it lost the configuration multiple times a day. I tried some stuff and installed an additional wifi repeater to make the wifi connection more reliable, After that the hcp bridge ran a few weeks (or was it month?) without any problems. But last week it lost its configuration again one time. I'm not sure, what the reason is. But it looks to me, it could be an issue with a lost wifi connection.

BradleyFord commented 3 weeks ago

It seems much easier to just switch the ESPHome version of the code, then all of these issues disappear as that is all standard functionality

Tysonpower commented 3 weeks ago

Currently on vacation so i can't test that, but i wonder if this only happens on the BME and DHT22 Sensor enabled versions, sounds like that to me currently. Still annoying and this should not happen, i think i will make a stable fork for my boards if the repo is that unstable. Maybe i switch to esphome as well, didnt try the esphome version yet. @BradleyFord Do you have a link t the esphome version?

Just had a look and there also is a /reset endpoint now, i wonder if this is triggered by some device on the network that causes this issue. Because i can't find any other use of the reset function in the code besides reset button and the /reset endpoint of the webserver. Another problem could be that the boot/reset button is floating and causes a false trigger event, this can't really happen on most PCBs tho because it's pulled to gnd.

BradleyFord commented 3 weeks ago

The ESPHome fork is here, essentially it is build off the good work ok people in this thread. But the core elements have been extracted and is used within ESPHome, hence then you get the ESPHome stability and extras

https://github.com/mapero/esphome-hcpbridge

burmistrzak commented 3 weeks ago

@Tysonpower According to @webflash-aj, they’ve also tried a build without sensors, with similar results. So it’s probably not the sensor. I second the idea of switching to an ESPHome-based firmware. Adding e.g. a BME280 should be easy enough with ESPHome. The one fork by @14yannick seems particularly promising.

At least in our case, the HCPBridge is on an isolated network, so other devices can’t mess with it. I personally lean towards some sort of memory issue.

Just FYI, the pins used for I2C & Co. are slightly different on a Tynet board, so I had to add some compile flags to set the correct pinout.

webflash-aj commented 3 weeks ago

@burmistrzak I tested with an esp32 and just the rs485-module connected, nothing else. downloaded the esp32.bin binary from github. Also tested esp32_BME280_HCSR04.bin (without connecting a sensor) with the same results.

Tysonpower commented 3 weeks ago

I will investigate into the issue in two weeks when i'm back home, if you find the issue let me know.

burmistrzak commented 3 weeks ago

@webflash-aj Are you using a pre-built board? Also, how's your Wi-Fi coverage? The lost connection hypothesis by @dev-strom sounds plausible.

burmistrzak commented 3 weeks ago

@Tysonpower Do Tynet boards use your fork or this repo? Also which version? v0.0.6.1?

Anyhow, ESPHome might really be a more sustainable solution going forward.

webflash-aj commented 3 weeks ago

@burmistrzak No, "normal" USB-C ESP32-Board (see attached Photo for my setup) powered over USB-C (currently no connected rs485-Module to garage-door). Old Firmware (v0.0.6.1) have no porblems. WiFI should be also fine (Strong Signal). AP is just arround the corner.

IMG_0977

burmistrzak commented 3 weeks ago

@webflash-aj Hmm, I now believe the ESP isn't actually resetting, because ESP.restart(); would certainly brick the motor and that didn't happen (at least in my case). https://github.com/Gifford47/HCPBridgeMqtt/blob/514164d3409782c7c6f95bce8b55b10a8383fc31/HCPBridgeESP32/src/preferencesKeys.h#L205-L209

IMHO, it's more likely that firstStart somehow gets flipped back on... https://github.com/Gifford47/HCPBridgeMqtt/blob/514164d3409782c7c6f95bce8b55b10a8383fc31/HCPBridgeESP32/src/preferencesKeys.h#L137

Not only network preferences are gone, but also any sensor adjustments made previously.

Tysonpower commented 3 weeks ago

@webflash-aj Hmm, I now believe the ESP isn't actually resetting, because ESP.restart(); would certainly brick the motor and that didn't happen (at least in my case).

https://github.com/Gifford47/HCPBridgeMqtt/blob/514164d3409782c7c6f95bce8b55b10a8383fc31/HCPBridgeESP32/src/preferencesKeys.h#L205-L209

IMHO, it's more likely that firstStart somehow gets flipped back on...

https://github.com/Gifford47/HCPBridgeMqtt/blob/514164d3409782c7c6f95bce8b55b10a8383fc31/HCPBridgeESP32/src/preferencesKeys.h#L137

Not only network preferences are gone, but also any sensor adjustments made previously.

Yeah this sounds to be the issue i guess, but why is the big question, i can't find any reference in the code so far how this can get reset by accident. But i'm happy it's not a PCb issue with my board :)

burmistrzak commented 3 weeks ago

@Tysonpower Don’t bother finding that bug. I totally agree with @BradleyFord, ESPHome is the way to go. 🔥 Just flashed @14yannick‘s fork onto my board. Was even able to integrated the BME280. 🤩

Here's my customized hcpbridge.yaml for a Tynet board with a single I2C sensor.

esphome:
  name: hcpbridge
  libraries:
    - emelianov/modbus-esp8266
  platformio_options:
    board_build.f_cpu: 240000000L
    board_build.flash_mode: qio
    monitor_speed: 9600
    monitor_filters: esp32_exception_decoder
    lib_ldf_mode: deep+
    # board_build.f_flash: 40000000L

external_components:
  - source:
      type: local
      path: components
    refresh: 0s

esp32:
  board: adafruit_feather_esp32s3
  framework:
    type: arduino

hcpbridge:
  is_connected:
    name: "HCPBridge Connected"
    id: hcpbridge_id
  rx_pin: 18 # optional, default=18
  tx_pin: 17 # optional, default=17

cover:
  - platform: hcpbridge
    name: "Garage Door"
    device_class: garage
    id: garagedoor_cover

binary_sensor:
  - platform: template
    name: "Garage Door Light sensor"
    internal: true
    device_class: light
    id: sensor_light
    lambda: !lambda |-
      return (id(garagedoor_cover).get_light_state());
    on_state:
      #needed to correct the state fo the light
      if:
        condition:
          or:
            - and:
                - binary_sensor.is_on: sensor_light
                - light.is_off: light_1
            - and:
                - binary_sensor.is_off: sensor_light
                - light.is_on: light_1
        then:
          - light.toggle: light_1

output:
  - platform: template
    type: binary
    id: output_light
    write_action:
      lambda: !lambda |-
        id(garagedoor_cover).set_light_state(state);

light:
  - platform: binary
    output: output_light
    id: light_1
    name: "Garage Door Light"

button:
  platform: template
  id: button_vent
  name: "Garage Door Vent"
  on_press:
    - lambda: |-
        id(garagedoor_cover).on_go_to_vent();

text_sensor:
  - platform: template
    id: sensor_templ_state
    name: "Garage Door State"
    update_interval: 5s
    filters:
      - lambda: |-
          static std::string last;
          if (x == last)
            return {};
          last = x;
          return x;
    lambda: |-
      std::string stateText;
      switch (id(garagedoor_cover).get_cover_state()) {
          case HoermannState::OPENING:
            stateText = "opening";
            break;
          case HoermannState::MOVE_VENTING:
            stateText = "move venting";
            break;
          case HoermannState::MOVE_HALF:
            stateText = "move half";
            break;
          case HoermannState::CLOSING:
            stateText = "closing";
            break;
          case HoermannState::OPEN:
            stateText = "open";
            break;
          case HoermannState::CLOSED:
            stateText = "closed";
            break;
          case HoermannState::STOPPED:
            stateText = "stopped";
            break;
          case HoermannState::HALFOPEN:
            stateText = "half open";
            break;
          case HoermannState::VENT:
            stateText = "venting";
            break;
          default:
            stateText = "unknown";
            break;
        }
      return {stateText};

switch:
  - platform: template
    id: switch_vent
    name: "Venting"
    lambda: |-
      return (id(garagedoor_cover).get_cover_state() == HoermannState::VENT);
    optimistic: True
    turn_on_action:
      - lambda: |-
          if (id(garagedoor_cover).get_cover_state() != HoermannState::VENT) {
            id(garagedoor_cover).on_go_to_vent();
          }
    turn_off_action:
      #without wait device not booting
      - wait_until:
          condition:
            binary_sensor.is_on: hcpbridge_id
      - if:
          condition:
            lambda: |-
              return (id(garagedoor_cover).position != COVER_CLOSED);
          then:
            - cover.close: garagedoor_cover

mqtt:
  broker: mqtt.svc.home.arpa
  username: !secret mqtt_username
  password: !secret mqtt_password

web_server:
  port: 80
  auth:
    username: !secret web_username
    password: !secret web_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

# Enable logging
logger:
  level: DEBUG

# Example configuration entry
ota:
  - platform: esphome
    password: !secret ota_password

safe_mode:
  disabled: false

i2c:
  sda: 6
  scl: 5
  scan: false
  id: bus_a

sensor:
  - platform: bme280_i2c
    i2c_id: bus_a
    address: 0x76
    temperature:
      name: "Garage Temperature"
    humidity:
      name: "Garage Humidity"
Tysonpower commented 3 weeks ago

This is cool @burmistrzak ! Thanks for the work!

@14yannick looks like you are actively working on the Fork, is it possible to make a all in one sensor firmware with esphome as well? Maybe we should focus on your Fork?

Edit: One big thing i'm missing is seeing and setting the door in percentage, i guess this is also possible with esphome?

burmistrzak commented 3 weeks ago

@Tysonpower Yes, it’s part of the standard cover component for HA. 😊

I’ll have to update my configuration to add a dedicated half open switch, but otherwise everything seems to work fine. I was planning to move all my ESP-based devices to ESPHome anyways, so… 💪

14yannick commented 3 weeks ago

Hi, I also moved a couple month to the esphome port. The framework really help in the maintainability and reduce by a big margin the needed code. @burmistrzak can have a look in my example yaml there I have implement the vent function with a template. if you want to do the same for the half open it would look like something like this.

switch:
  - platform: template
    id: switch_half
    name: "Open to Half"
    lambda: |-
      return (id(garagedoor_cover).get_cover_state() == HoermannState::HALFOPEN);
    optimistic: True
    turn_on_action:
      - lambda: |-
          if (id(garagedoor_cover).get_cover_state() != HoermannState::HALFOPEN) {
            id(garagedoor_cover).on_go_to_half();
          }
    turn_off_action:
      #without wait device not booting
      - wait_until:
          condition:
            binary_sensor.is_on: hcpbridge_id
      - if:
          condition:
            lambda :  |-
              return (id(garagedoor_cover).position != COVER_CLOSED);
          then:
            - cover.close: garagedoor_cover

@Tysonpower if you want to get the door position in percent you can do it by adding a sensor like this. It's untested but you can play around with.

sensor:
  - platform: template
    name: cover percent
    id: cover_percent
    icon: 'mdi:percent-box-outline'
    unit_of_measurement: '%'
    update_interval: 5s
    filters:
      - lambda: |-
          static std::string last;
          if (x == last)
            return {};
          last = x;
          return x;
    lambda: |-
      return {id(garagedoor_cover).position};

Actually I'm working to get the logic of the relay state you can configure to get the prewarn signal or other state based on the settings of menu 30 of the motor. This will solve this issue.

burmistrzak commented 3 weeks ago

@14yannick Nice job with the templates! AFAICT, we’re now able to replicate all current features with ESPHome, right?

I had to make very slight changes to our dew point ventilation flow in Node-RED, but only because the MQTT structure is now different. Seems to be working tho…🤞

@Tysonpower Improving the ESPHome port really seems to be a much more sustainable effort. While it’s already working pretty well, there’s still some stuff to do, e.g. removing external Modbus dependencies, switching to callbacks, etc. Time much better spent, IMHO. 😉

@webflash-aj I‘ll suggested you give 14yannick‘s fork of the ESPHome port a try.

webflash-aj commented 3 weeks ago

@14yannick sorry to reuse this thread, but could you help me to get esphome running on HA?

I will get this error, when compiling with your example-config on github:

INFO ESPHome 2024.7.3
INFO Reading configuration /config/esphome/eg-out-garage.yaml...
INFO Updating https://github.com/mapero/esphome-hcpbridge.git@None
INFO Generating C++ source...
INFO Compiling app...
Processing hcpbridge (board: adafruit_feather_esp32s3; framework: arduino; platform: platformio/espressif32@5.4.0)
--------------------------------------------------------------------------------
HARDWARE: ESP32S3 240MHz, 320KB RAM, 4MB Flash
 - toolchain-riscv32-esp @ 8.4.0+2021r2-patch5 
 - toolchain-xtensa-esp32s3 @ 8.4.0+2021r2-patch5
Dependency Graph
|-- AsyncTCP-esphome @ 2.1.3
|-- modbus-esp8266 @ 4.1.0
|-- WiFi @ 2.0.0
|-- FS @ 2.0.0
|-- Update @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 3.2.2
|-- ESPmDNS @ 2.0.0
|-- ArduinoJson @ 6.18.5
|-- noise-c @ 0.1.4
Compiling .pioenvs/hcpbridge/src/main.cpp.o
Archiving .pioenvs/hcpbridge/libd16/libAsyncTCP-esphome.a
Compiling .pioenvs/hcpbridge/lib932/modbus-esp8266/Modbus.cpp.o
Compiling .pioenvs/hcpbridge/lib932/modbus-esp8266/ModbusRTU.cpp.o
/config/esphome/eg-out-garage.yaml: In lambda function:
/config/esphome/eg-out-garage.yaml:61:33: error: 'class esphome::hcpbridge::HCPBridgeCover' has no member named 'get_relay_state'; did you mean 'restore_state_'?
       return (id(garagedoor_cover).get_relay_state());
                                 ^~~~~~~~~~~~~~~
                                 restore_state_
/config/esphome/eg-out-garage.yaml: In lambda function:
/config/esphome/eg-out-garage.yaml:71:25: error: 'class esphome::hcpbridge::HCPBridgeCover' has no member named 'set_light_state'; did you mean 'publish_state'?
         id(garagedoor_cover).set_light_state(state);
                         ^~~~~~~~~~~~~~~
                         publish_state
/config/esphome/eg-out-garage.yaml: In lambda function:
/config/esphome/eg-out-garage.yaml:101:33: error: 'class esphome::hcpbridge::HCPBridgeCover' has no member named 'get_cover_state'; did you mean 'get_component_state'?
       switch (id(garagedoor_cover).get_cover_state()) {
                                 ^~~~~~~~~~~~~~~
                                 get_component_state
/config/esphome/eg-out-garage.yaml: In lambda function:
/config/esphome/eg-out-garage.yaml:141:33: error: 'class esphome::hcpbridge::HCPBridgeCover' has no member named 'get_cover_state'; did you mean 'get_component_state'?
       return (id(garagedoor_cover).get_cover_state() == HoermannState::VENT);
                                 ^~~~~~~~~~~~~~~
                                 get_component_state
/config/esphome/eg-out-garage.yaml: In lambda function:
/config/esphome/eg-out-garage.yaml:145:29: error: 'class esphome::hcpbridge::HCPBridgeCover' has no member named 'get_cover_state'; did you mean 'get_component_state'?
           if (id(garagedoor_cover).get_cover_state() != HoermannState::VENT) {
                             ^~~~~~~~~~~~~~~
                             get_component_state
/config/esphome/eg-out-garage.yaml: In lambda function:
/config/esphome/eg-out-garage.yaml:43:33: error: 'class esphome::hcpbridge::HCPBridgeCover' has no member named 'get_light_state'; did you mean 'publish_state'?
       return (id(garagedoor_cover).get_light_state());
                                 ^~~~~~~~~~~~~~~
                                 publish_state
*** [.pioenvs/hcpbridge/src/main.cpp.o] Error 1
========================= [FAILED] Took 49.02 seconds =========================
14yannick commented 3 weeks ago

@webflash-aj in the yaml replace

external_components:
    source: github://mapero/esphome-hcpbridge
    refresh: 0s # Ensure you always get the latest version

With

external_components:
    source: github://14yannick/esphome-hcpbridge
    refresh: 0s # Ensure you always get the latest version
webflash-aj commented 3 weeks ago

source: github://14yannick/esphome-hcpbridge

Thanks for your fast Feedback.. just found the "Problem" one second before your post.. :-) Didn't realize the wrong repo in the yaml.

The ESP won't boot :(

22:02:40]rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0
[22:02:40]invalid header: 0x000000f0

got it.. had to change the board to "esp32dev".. :-) i will give a try tomorrow connected to the door.

webflash-aj commented 3 weeks ago

@14yannick : maybe you will also change the board to "esp32dev". It will make it easier for beginners/dummies like me.. in the example.xml

webflash-aj commented 3 weeks ago

@14yannick : maybe you want also to change the RX-PIN to 16 (or just left somewhere a hint) i use de default wireing rx_pin: 16 # optional, default=18 tx_pin: 17 # optional, default=17

@burmistrzak & @14yannick : thanks for the esphome-fork.. i will give it a try.. it's working and it looks good so far.

14yannick commented 3 weeks ago

A lot of people use an esp s3 board specially the one from tynet. For them the board from and pin in the yaml are correct. I think I will comments the stuff and add some more explanation.