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