From e79c0823e3cfbb1c089bceecde5ad902f72b03eb Mon Sep 17 00:00:00 2001 From: Paul Wieland Date: Fri, 22 Mar 2024 13:08:51 -0400 Subject: [PATCH] Setting up dry contact protocol --- base_drycontact.yaml | 212 ++++++++++++++++++++++++++++++ components/ratgdo/dry_contact.cpp | 41 ++++++ components/ratgdo/dry_contact.h | 8 ++ v25iboard_drycontact.yaml | 54 ++++++++ 4 files changed, 315 insertions(+) create mode 100644 base_drycontact.yaml create mode 100644 v25iboard_drycontact.yaml diff --git a/base_drycontact.yaml b/base_drycontact.yaml new file mode 100644 index 0000000..f3e4375 --- /dev/null +++ b/base_drycontact.yaml @@ -0,0 +1,212 @@ +--- + +external_components: + - source: + type: local + path: components + # type: git + # url: https://github.com/ratgdo/esphome-ratgdo + # refresh: 1s + +preferences: + flash_write_interval: 1min + +ratgdo: + id: ${id_prefix} + input_gdo_pin: ${uart_rx_pin} + output_gdo_pin: ${uart_tx_pin} + input_obst_pin: ${input_obst_pin} + protocol: drycontact + on_sync_failed: + then: + - homeassistant.service: + service: persistent_notification.create + data: + title: "${friendly_name} sync failed" + message: "Failed to communicate with garage opener on startup." + notification_id: "esphome_ratgdo_${id_prefix}_sync_failed" + +lock: + - platform: ratgdo + id: ${id_prefix}_lock_remotes + ratgdo_id: ${id_prefix} + name: "Lock remotes" + +switch: + - platform: gpio + id: "${id_prefix}_status_door" + internal: true + pin: + number: ${status_door_pin} # D0 output door status, HIGH for open, LOW for closed + mode: + output: true + name: "Status door" + entity_category: diagnostic + - platform: gpio + id: "${id_prefix}_status_obstruction" + internal: true + pin: + number: ${status_obstruction_pin} # D8 output for obstruction status, HIGH for obstructed, LOW for clear + mode: + output: true + name: "Status obstruction" + entity_category: diagnostic + +binary_sensor: + - platform: ratgdo + type: motion + id: ${id_prefix}_motion + ratgdo_id: ${id_prefix} + name: "Motion" + device_class: motion + - platform: ratgdo + type: obstruction + id: ${id_prefix}_obstruction + ratgdo_id: ${id_prefix} + name: "Obstruction" + device_class: problem + on_press: + - switch.turn_on: ${id_prefix}_status_obstruction + on_release: + - switch.turn_off: ${id_prefix}_status_obstruction + - platform: ratgdo + type: button + id: ${id_prefix}_button + ratgdo_id: ${id_prefix} + name: "Button" + entity_category: diagnostic + - platform: gpio + id: "${id_prefix}_dry_contact_open" + pin: + number: ${dry_contact_open_pin} # D5 dry contact for opening door + inverted: true + mode: + input: true + pullup: true + name: "Dry contact open" + entity_category: diagnostic + filters: + - delayed_on_off: 500ms + # on_state: + # then: + # lambda: |- + # id($id_prefix)->call_protocol(set_open_limit { static_cast(true) }); + + - platform: gpio + id: "${id_prefix}_dry_contact_close" + pin: + number: ${dry_contact_close_pin} # D6 dry contact for closing door + inverted: true + mode: + input: true + pullup: true + name: "Dry contact close" + entity_category: diagnostic + filters: + - delayed_on_off: 500ms + # on_press: + # - if: + # condition: + # binary_sensor.is_off: ${id_prefix}_dry_contact_open + # then: + # - cover.close: ${id_prefix}_garage_door + - platform: gpio + id: "${id_prefix}_dry_contact_light" + pin: + number: ${dry_contact_light_pin} # D3 dry contact for triggering light (no discrete light commands, so toggle only) + inverted: true + mode: + input: true + pullup: true + name: "Dry contact light" + entity_category: diagnostic + filters: + - delayed_on_off: 500ms + on_press: + - light.toggle: ${id_prefix}_light + +number: + - platform: ratgdo + id: ${id_prefix}_rolling_code_counter + type: rolling_code_counter + entity_category: config + ratgdo_id: ${id_prefix} + name: "Rolling code counter" + mode: box + unit_of_measurement: "codes" + + - platform: ratgdo + id: ${id_prefix}_opening_duration + type: opening_duration + entity_category: config + ratgdo_id: ${id_prefix} + name: "Opening duration" + unit_of_measurement: "s" + + - platform: ratgdo + id: ${id_prefix}_closing_duration + type: closing_duration + entity_category: config + ratgdo_id: ${id_prefix} + name: "Closing duration" + unit_of_measurement: "s" + + - platform: ratgdo + id: ${id_prefix}_client_id + type: client_id + entity_category: config + ratgdo_id: ${id_prefix} + name: "Client ID" + mode: box + +cover: + - platform: ratgdo + id: ${id_prefix}_garage_door + device_class: garage + name: "Door" + ratgdo_id: ${id_prefix} + on_closed: + - switch.turn_off: ${id_prefix}_status_door + on_open: + - switch.turn_on: ${id_prefix}_status_door + +light: + - platform: ratgdo + id: ${id_prefix}_light + name: "Light" + ratgdo_id: ${id_prefix} + +button: + - platform: restart + id: ${id_prefix}_restart + name: "Restart" + - platform: safe_mode + id: ${id_prefix}_safe_mode + name: "Safe mode boot" + entity_category: diagnostic + + - platform: template + id: ${id_prefix}_query_status + entity_category: diagnostic + name: "Query status" + on_press: + then: + lambda: !lambda |- + id($id_prefix).query_status(); + + - platform: template + id: ${id_prefix}_sync + name: "Sync" + entity_category: diagnostic + on_press: + then: + lambda: !lambda |- + id($id_prefix).sync(); + + - platform: template + id: ${id_prefix}_toggle_door + name: "Toggle door!" + on_press: + then: + lambda: !lambda |- + id($id_prefix).door_toggle(); \ No newline at end of file diff --git a/components/ratgdo/dry_contact.cpp b/components/ratgdo/dry_contact.cpp index 5dc5a9d..776e063 100644 --- a/components/ratgdo/dry_contact.cpp +++ b/components/ratgdo/dry_contact.cpp @@ -18,6 +18,11 @@ namespace ratgdo { this->scheduler_ = scheduler; this->tx_pin_ = tx_pin; this->rx_pin_ = rx_pin; + + this->open_limit_reached_ = 0; + this->last_open_limit_ = 0; + this->close_limit_reached_ = 0; + this->last_close_limit_ = 0; } void DryContact::loop() @@ -33,6 +38,42 @@ namespace ratgdo { { } + void DryContact::set_open_limit(bool val) + { + ESP_LOGD(TAG, "Set open_limit_reached to %d", val); + this->last_open_limit_ = this->open_limit_reached_; + this->open_limit_reached_ = val; + this->send_door_state(); + } + + void DryContact::set_close_limit(bool val) + { + ESP_LOGD(TAG, "Set close_limit_reached to %d", val); + this->last_close_limit_ = this->close_limit_reached_; + this->close_limit_reached_ = val; + this->send_door_state(); + } + + void DryContact::send_door_state(){ + DoorState door_state; + + if(this->open_limit_reached_){ + door_state = DoorState::OPEN; + }else if(this->close_limit_reached_){ + door_state = DoorState::CLOSED; + }else if(!this->close_limit_reached_ && !this->open_limit_reached_){ + if(this->last_close_limit_){ + door_state = DoorState::OPENING; + } + + if(this->last_open_limit_){ + door_state = DoorState::CLOSING; + } + } + + this->ratgdo_->received(door_state); + } + void DryContact::light_action(LightAction action) { ESP_LOG1(TAG, "Ignoring light action: %s", LightAction_to_string(action)); diff --git a/components/ratgdo/dry_contact.h b/components/ratgdo/dry_contact.h index 99dd024..3f9643c 100644 --- a/components/ratgdo/dry_contact.h +++ b/components/ratgdo/dry_contact.h @@ -29,6 +29,9 @@ namespace ratgdo { void light_action(LightAction action); void lock_action(LockAction action); void door_action(DoorAction action); + void set_open_limit(bool val); + void set_close_limit(bool val); + void send_door_state(); Result call(Args args); @@ -42,6 +45,11 @@ namespace ratgdo { RATGDOComponent* ratgdo_; Scheduler* scheduler_; + + bool open_limit_reached_; + bool last_open_limit_; + bool close_limit_reached_; + bool last_close_limit_; }; } // namespace secplus1 diff --git a/v25iboard_drycontact.yaml b/v25iboard_drycontact.yaml new file mode 100644 index 0000000..b08e08c --- /dev/null +++ b/v25iboard_drycontact.yaml @@ -0,0 +1,54 @@ +--- +substitutions: + id_prefix: ratgdov25i + friendly_name: "ratgdov2.5i" + uart_tx_pin: D1 + uart_rx_pin: D2 + input_obst_pin: D7 + status_door_pin: D0 + status_obstruction_pin: D8 + dry_contact_open_pin: D5 + dry_contact_close_pin: D6 + dry_contact_light_pin: D3 + +web_server: + +esphome: + name: ${id_prefix} + friendly_name: ${friendly_name} + name_add_mac_suffix: true + project: + name: ratgdo.esphome + version: "2.5i" + +esp8266: + board: d1_mini + restore_from_flash: true + +dashboard_import: + package_import_url: github://ratgdo/esphome-ratgdo/v25iboard_secplusv1.yaml@main + +packages: + # remote_package: + # url: https://github.com/ratgdo/esphome-ratgdo + # files: [base_secplusv1.yaml] + # refresh: 1s + remote_package: !include + file: base_drycontact.yaml +# Sync time with Home Assistant. +time: + - platform: homeassistant + id: homeassistant_time + +api: + id: api_server + +ota: + +improv_serial: + +wifi: + ap: + +logger: + level: DEBUG \ No newline at end of file