From f68d126fb8b76af4858b60e2e418e738b17c1e64 Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Mon, 28 Oct 2024 13:56:16 -0400
Subject: [PATCH 01/18] ratgdo32
---
base.yaml | 4 +-
base_drycontact.yaml | 6 +-
base_secplusv1.yaml | 3 +
components/ratgdo/__init__.py | 2 +-
components/ratgdo/binary_sensor/__init__.py | 3 +
.../binary_sensor/ratgdo_binary_sensor.cpp | 22 +++
.../binary_sensor/ratgdo_binary_sensor.h | 5 +-
components/ratgdo/number/__init__.py | 2 +
components/ratgdo/number/ratgdo_number.cpp | 24 +++
components/ratgdo/number/ratgdo_number.h | 2 +
components/ratgdo/output/__init__.py | 36 +++++
components/ratgdo/output/ratgdo_output.cpp | 53 +++++++
components/ratgdo/output/ratgdo_output.h | 32 ++++
components/ratgdo/ratgdo.cpp | 141 ++++++++++++++++-
components/ratgdo/ratgdo.h | 21 +++
components/ratgdo/ratgdo_state.h | 16 ++
components/ratgdo/sensor/__init__.py | 14 ++
components/ratgdo/sensor/ratgdo_sensor.cpp | 54 +++++++
components/ratgdo/sensor/ratgdo_sensor.h | 14 +-
components/ratgdo/switch/__init__.py | 9 +-
components/ratgdo/switch/ratgdo_switch.cpp | 8 +
components/ratgdo/switch/ratgdo_switch.h | 5 +-
static/v25iboard.yaml | 2 +
static/v25iboard_drycontact.yaml | 1 +
static/v32board.yaml | 65 ++++++++
static/v32board_drycontact.yaml | 64 ++++++++
static/v32board_secplusv1.yaml | 65 ++++++++
static/v32disco.yaml | 149 ++++++++++++++++++
static/v32disco_drycontact.yaml | 141 +++++++++++++++++
static/v32disco_secplusv1.yaml | 142 +++++++++++++++++
v32board.yaml | 1 +
v32board_drycontact.yaml | 1 +
v32board_secplusv1.yaml | 1 +
v32disco.yaml | 1 +
v32disco_drycontact.yaml | 1 +
v32disco_secplusv1.yaml | 1 +
36 files changed, 1099 insertions(+), 12 deletions(-)
create mode 100644 components/ratgdo/output/__init__.py
create mode 100644 components/ratgdo/output/ratgdo_output.cpp
create mode 100644 components/ratgdo/output/ratgdo_output.h
create mode 100644 static/v32board.yaml
create mode 100644 static/v32board_drycontact.yaml
create mode 100644 static/v32board_secplusv1.yaml
create mode 100644 static/v32disco.yaml
create mode 100644 static/v32disco_drycontact.yaml
create mode 100644 static/v32disco_secplusv1.yaml
create mode 120000 v32board.yaml
create mode 120000 v32board_drycontact.yaml
create mode 120000 v32board_secplusv1.yaml
create mode 120000 v32disco.yaml
create mode 120000 v32disco_drycontact.yaml
create mode 120000 v32disco_secplusv1.yaml
diff --git a/base.yaml b/base.yaml
index 7511fe3..79c4d64 100644
--- a/base.yaml
+++ b/base.yaml
@@ -1,10 +1,12 @@
---
-
external_components:
- source:
type: git
url: https://github.com/ratgdo/esphome-ratgdo
refresh: 1s
+ # - source:
+ # type: local
+ # path: components
safe_mode:
diff --git a/base_drycontact.yaml b/base_drycontact.yaml
index 84b172b..d683a54 100644
--- a/base_drycontact.yaml
+++ b/base_drycontact.yaml
@@ -2,11 +2,12 @@
external_components:
- source:
- # type: local
- # path: components
type: git
url: https://github.com/ratgdo/esphome-ratgdo
refresh: 1s
+ # - source:
+ # type: local
+ # path: components
safe_mode:
@@ -20,6 +21,7 @@ text_sensor:
ratgdo:
id: ${id_prefix}
output_gdo_pin: ${uart_tx_pin}
+ input_gdo_pin: ${uart_rx_pin}
input_obst_pin: ${input_obst_pin}
dry_contact_open_sensor: ${id_prefix}_dry_contact_open
dry_contact_close_sensor: ${id_prefix}_dry_contact_close
diff --git a/base_secplusv1.yaml b/base_secplusv1.yaml
index 4248cac..a1331f2 100644
--- a/base_secplusv1.yaml
+++ b/base_secplusv1.yaml
@@ -5,6 +5,9 @@ external_components:
type: git
url: https://github.com/ratgdo/esphome-ratgdo
refresh: 1s
+ # - source:
+ # type: local
+ # path: components
safe_mode:
diff --git a/components/ratgdo/__init__.py b/components/ratgdo/__init__.py
index 5153cad..a6493c7 100644
--- a/components/ratgdo/__init__.py
+++ b/components/ratgdo/__init__.py
@@ -144,4 +144,4 @@ async def to_code(config):
cg.add(var.set_discrete_open_pin(pin))
if CONF_DISCRETE_CLOSE_PIN in config and config[CONF_DISCRETE_CLOSE_PIN]:
pin = await cg.gpio_pin_expression(config[CONF_DISCRETE_CLOSE_PIN])
- cg.add(var.set_discrete_close_pin(pin))
+ cg.add(var.set_discrete_close_pin(pin))
\ No newline at end of file
diff --git a/components/ratgdo/binary_sensor/__init__.py b/components/ratgdo/binary_sensor/__init__.py
index 91a215c..7025eb8 100644
--- a/components/ratgdo/binary_sensor/__init__.py
+++ b/components/ratgdo/binary_sensor/__init__.py
@@ -18,6 +18,9 @@ TYPES = {
"obstruction": SensorType.RATGDO_SENSOR_OBSTRUCTION,
"motor": SensorType.RATGDO_SENSOR_MOTOR,
"button": SensorType.RATGDO_SENSOR_BUTTON,
+ "vehicle_detected": SensorType.RATGDO_SENSOR_VEHICLE_DETECTED,
+ "vehicle_arriving": SensorType.RATGDO_SENSOR_VEHICLE_ARRIVING,
+ "vehicle_leaving": SensorType.RATGDO_SENSOR_VEHICLE_LEAVING,
}
diff --git a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp
index 456058c..ffd2985 100644
--- a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp
+++ b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp
@@ -28,6 +28,22 @@ namespace ratgdo {
this->parent_->subscribe_button_state([=](ButtonState state) {
this->publish_state(state == ButtonState::PRESSED);
});
+ } else if(this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_DETECTED) {
+ this->publish_initial_state(false);
+ this->parent_->subscribe_vehicle_detected_state([=](VehicleDetectedState state) {
+ this->publish_state(state == VehicleDetectedState::YES);
+ this->parent_->presence_change(state == VehicleDetectedState::YES);
+ });
+ } else if(this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_ARRIVING) {
+ this->publish_initial_state(false);
+ this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
+ this->publish_state(state == VehicleArrivingState::YES);
+ });
+ } else if(this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_LEAVING) {
+ this->publish_initial_state(false);
+ this->parent_->subscribe_vehicle_leaving_state([=](VehicleLeavingState state) {
+ this->publish_state(state == VehicleLeavingState::YES);
+ });
}
}
@@ -42,6 +58,12 @@ namespace ratgdo {
ESP_LOGCONFIG(TAG, " Type: Motor");
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_BUTTON) {
ESP_LOGCONFIG(TAG, " Type: Button");
+ } else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_DETECTED) {
+ ESP_LOGCONFIG(TAG, " Type: VehicleDetected");
+ } else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_ARRIVING) {
+ ESP_LOGCONFIG(TAG, " Type: VehicleArriving");
+ } else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_LEAVING) {
+ ESP_LOGCONFIG(TAG, " Type: VehicleLeaving");
}
}
diff --git a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.h b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.h
index 9e3315a..1d738c3 100644
--- a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.h
+++ b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.h
@@ -12,7 +12,10 @@ namespace ratgdo {
RATGDO_SENSOR_MOTION,
RATGDO_SENSOR_OBSTRUCTION,
RATGDO_SENSOR_MOTOR,
- RATGDO_SENSOR_BUTTON
+ RATGDO_SENSOR_BUTTON,
+ RATGDO_SENSOR_VEHICLE_DETECTED,
+ RATGDO_SENSOR_VEHICLE_ARRIVING,
+ RATGDO_SENSOR_VEHICLE_LEAVING,
};
class RATGDOBinarySensor : public binary_sensor::BinarySensor, public RATGDOClient, public Component {
diff --git a/components/ratgdo/number/__init__.py b/components/ratgdo/number/__init__.py
index 59bd7d2..2ffc1dc 100644
--- a/components/ratgdo/number/__init__.py
+++ b/components/ratgdo/number/__init__.py
@@ -16,6 +16,8 @@ TYPES = {
"rolling_code_counter": NumberType.RATGDO_ROLLING_CODE_COUNTER,
"opening_duration": NumberType.RATGDO_OPENING_DURATION,
"closing_duration": NumberType.RATGDO_CLOSING_DURATION,
+ "closing_delay": NumberType.RATGDO_CLOSING_DELAY,
+ "target_distance_measurement": NumberType.RATGDO_TARGET_DISTANCE_MEASUREMENT,
}
diff --git a/components/ratgdo/number/ratgdo_number.cpp b/components/ratgdo/number/ratgdo_number.cpp
index 68df7b5..e3fd1a1 100644
--- a/components/ratgdo/number/ratgdo_number.cpp
+++ b/components/ratgdo/number/ratgdo_number.cpp
@@ -30,6 +30,10 @@ namespace ratgdo {
ESP_LOGCONFIG(TAG, " Type: Opening Duration");
} else if (this->number_type_ == RATGDO_CLOSING_DURATION) {
ESP_LOGCONFIG(TAG, " Type: Closing Duration");
+ } else if (this->number_type_ == RATGDO_CLOSING_DELAY) {
+ ESP_LOGCONFIG(TAG, " Type: Closing Delay");
+ } else if (this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT) {
+ ESP_LOGCONFIG(TAG, " Type: Target Distance Measurement");
}
}
@@ -66,6 +70,14 @@ namespace ratgdo {
this->parent_->subscribe_closing_duration([=](float value) {
this->update_state(value);
});
+ } else if (this->number_type_ == RATGDO_CLOSING_DELAY) {
+ this->parent_->subscribe_closing_delay([=](uint32_t value) {
+ this->update_state(value);
+ });
+ } else if (this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT){
+ // this->parent_->subscribe_target_distance_measurement([=](float value) {
+ // this->update_state(value);
+ // });
}
}
@@ -76,12 +88,20 @@ namespace ratgdo {
this->traits.set_step(0.1);
this->traits.set_min_value(0.0);
this->traits.set_max_value(180.0);
+ } else if (this->number_type_ == RATGDO_CLOSING_DELAY) {
+ this->traits.set_step(1);
+ this->traits.set_min_value(0.0);
+ this->traits.set_max_value(180.0);
} else if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {
this->traits.set_max_value(0xfffffff);
} else if (this->number_type_ == RATGDO_CLIENT_ID) {
this->traits.set_step(0x1000);
this->traits.set_min_value(0x539);
this->traits.set_max_value(0x7ff539);
+ } else if(this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT) {
+ this->traits.set_step(1);
+ this->traits.set_min_value(5);
+ this->traits.set_max_value(3500);
}
}
@@ -102,9 +122,13 @@ namespace ratgdo {
this->parent_->set_opening_duration(value);
} else if (this->number_type_ == RATGDO_CLOSING_DURATION) {
this->parent_->set_closing_duration(value);
+ } else if (this->number_type_ == RATGDO_CLOSING_DELAY) {
+ this->parent_->set_closing_delay(value);
} else if (this->number_type_ == RATGDO_CLIENT_ID) {
value = normalize_client_id(value);
this->parent_->call_protocol(SetClientID { static_cast(value) });
+ } else if (this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT) {
+ this->parent_->set_target_distance_measurement(value);
}
this->update_state(value);
}
diff --git a/components/ratgdo/number/ratgdo_number.h b/components/ratgdo/number/ratgdo_number.h
index e5f78f6..cd85130 100644
--- a/components/ratgdo/number/ratgdo_number.h
+++ b/components/ratgdo/number/ratgdo_number.h
@@ -13,6 +13,8 @@ namespace ratgdo {
RATGDO_ROLLING_CODE_COUNTER,
RATGDO_OPENING_DURATION,
RATGDO_CLOSING_DURATION,
+ RATGDO_CLOSING_DELAY,
+ RATGDO_TARGET_DISTANCE_MEASUREMENT,
};
class RATGDONumber : public number::Number, public RATGDOClient, public Component {
diff --git a/components/ratgdo/output/__init__.py b/components/ratgdo/output/__init__.py
new file mode 100644
index 0000000..957ac21
--- /dev/null
+++ b/components/ratgdo/output/__init__.py
@@ -0,0 +1,36 @@
+import esphome.codegen as cg
+import esphome.config_validation as cv
+from esphome.components import rtttl
+from esphome.const import CONF_ID
+CONF_RTTTL = "rtttl"
+CONF_SONG = "song"
+
+
+from .. import RATGDO_CLIENT_SCHMEA, ratgdo_ns, register_ratgdo_child
+
+DEPENDENCIES = ["esp32","ratgdo","rtttl"]
+
+RATGDOOutput = ratgdo_ns.class_("RATGDOOutput", cg.Component)
+OutputType = ratgdo_ns.enum("OutputType")
+
+CONF_TYPE = "type"
+TYPES = {
+ "beeper": OutputType.RATGDO_BEEPER
+}
+
+CONFIG_SCHEMA = cv.Schema(
+ {
+ cv.Required(CONF_ID): cv.declare_id(RATGDOOutput),
+ cv.Required(CONF_TYPE): cv.enum(TYPES, lower=True),
+ cv.Required(CONF_RTTTL): cv.use_id(rtttl),
+ cv.Required(CONF_SONG): cv.string
+ }
+).extend(RATGDO_CLIENT_SCHMEA)
+
+async def to_code(config):
+ var = cg.new_Pvariable(config[CONF_ID])
+ await cg.register_component(var, config)
+ rtttl = await cg.get_variable(config[CONF_RTTTL])
+ cg.add(var.set_rtttl(rtttl))
+ cg.add(var.set_song(config[CONF_SONG]))
+ await register_ratgdo_child(var, config)
diff --git a/components/ratgdo/output/ratgdo_output.cpp b/components/ratgdo/output/ratgdo_output.cpp
new file mode 100644
index 0000000..c67a8e1
--- /dev/null
+++ b/components/ratgdo/output/ratgdo_output.cpp
@@ -0,0 +1,53 @@
+#include "ratgdo_output.h"
+#include "../ratgdo_state.h"
+#include "esphome/core/log.h"
+
+namespace esphome {
+namespace ratgdo {
+
+static const char *TAG = "ratgdo.output";
+
+void RATGDOOutput::setup(){
+ ESP_LOGD(TAG,"Output was setup");
+
+ if(this->output_type_ == OutputType::RATGDO_BEEPER){
+ this->beeper_->add_on_finished_playback_callback([=] { this->finished_playback(); });
+
+ this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
+ if(state == VehicleArrivingState::YES){
+ this->play();
+ }
+ });
+
+ this->parent_->subscribe_door_action_delayed([=](DoorActionDelayed state) {
+ if(state == DoorActionDelayed::YES){
+ this->play();
+ this->repeat_ = true;
+ } else if(state == DoorActionDelayed::NO) {
+ this->repeat_ = false;
+ }
+ });
+
+ }
+}
+
+void RATGDOOutput::play(){
+ this->beeper_->play(this->rtttlSong_);
+}
+
+void RATGDOOutput::finished_playback(){
+ if(this->repeat_) this->play();
+}
+
+void RATGDOOutput::dump_config() {
+ if (this->output_type_ == OutputType::RATGDO_BEEPER) {
+ ESP_LOGCONFIG(TAG, " Type: Beeper");
+ }
+}
+
+void RATGDOOutput::set_output_type(OutputType output_type_) {
+ this->output_type_ = output_type_;
+}
+
+} //namespace ratgdo
+} //namespace esphome
\ No newline at end of file
diff --git a/components/ratgdo/output/ratgdo_output.h b/components/ratgdo/output/ratgdo_output.h
new file mode 100644
index 0000000..873bb73
--- /dev/null
+++ b/components/ratgdo/output/ratgdo_output.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "../ratgdo.h"
+#include "esphome/core/component.h"
+#include "esphome/components/rtttl/rtttl.h"
+
+namespace esphome {
+namespace ratgdo {
+
+ enum OutputType {
+ RATGDO_BEEPER
+ };
+
+ class RATGDOOutput : public RATGDOClient, public Component {
+ public:
+ void setup() override;
+ void play();
+ void finished_playback();
+ void dump_config() override;
+ void set_output_type(OutputType output_type);
+ void set_song(std::string rtttlSong){ this->rtttlSong_ = rtttlSong; }
+ void set_rtttl(rtttl::Rtttl *output){ this->beeper_ = output; }
+
+ protected:
+ OutputType output_type_;
+ rtttl::Rtttl* beeper_;
+ std::string rtttlSong_;
+ bool repeat_;
+ };
+
+} //namespace ratgdo
+} //namespace esphome
\ No newline at end of file
diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp
index 90cb713..9063bf4 100644
--- a/components/ratgdo/ratgdo.cpp
+++ b/components/ratgdo/ratgdo.cpp
@@ -30,6 +30,9 @@ namespace ratgdo {
static const char* const TAG = "ratgdo";
static const int SYNC_DELAY = 1000;
+ static const int CLEAR_PRESENCE = 60000; // how long to keep arriving/leaving active
+ static const int PRESENCE_DETECT_WINDOW = 300000; // how long to calculate presence after door state change
+
void RATGDOComponent::setup()
{
this->output_gdo_pin_->setup();
@@ -39,7 +42,11 @@ namespace ratgdo {
this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
this->input_obst_pin_->setup();
+#ifdef USE_ESP32
+ this->input_obst_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
+#else
this->input_obst_pin_->pin_mode(gpio::FLAG_INPUT);
+#endif
this->input_obst_pin_->attach_interrupt(RATGDOStore::isr_obstruction, &this->isr_store_, gpio::INTERRUPT_FALLING_EDGE);
this->protocol_->setup(this, &App.scheduler, this->input_gdo_pin_, this->output_gdo_pin_);
@@ -51,6 +58,24 @@ namespace ratgdo {
ESP_LOGD(TAG, "| -| | | | | | | | | | |");
ESP_LOGD(TAG, "|__|__|__|__| |_| |_____|____/|_____|");
ESP_LOGD(TAG, "https://paulwieland.github.io/ratgdo/");
+
+ this->subscribe_door_state([=](DoorState state, float position) {
+ static DoorState lastState = DoorState::UNKNOWN;
+
+ if(lastState != DoorState::UNKNOWN && state != DoorState::CLOSED && !this->presence_detect_window_active_){
+ this->presence_detect_window_active_ = true;
+ set_timeout("presence_detect_window", PRESENCE_DETECT_WINDOW, [=] {
+ this->presence_detect_window_active_ = false;
+ });
+ }
+
+ if(state == DoorState::CLOSED){
+ this->presence_detect_window_active_ = false;
+ cancel_timeout("presence_detect_window");
+ }
+
+ lastState = state;
+ });
}
// initializing protocol, this gets called before setup() because
@@ -335,6 +360,64 @@ namespace ratgdo {
this->closing_duration = duration;
}
+ void RATGDOComponent::set_target_distance_measurement(int16_t distance){
+ this->target_distance_measurement = distance;
+ }
+
+ void RATGDOComponent::set_distance_measurement(int16_t distance)
+ {
+ this->last_distance_measurement = distance;
+
+ // current value = [0], last value = [1]
+ this->distance_measurement.insert(this->distance_measurement.begin(), distance);
+ this->distance_measurement.pop_back();
+ this->calculate_presence();
+ }
+
+ void RATGDOComponent::calculate_presence()
+ {
+ bool all_in_range = true;
+ bool all_out_of_range = true;
+ // int16_t min = *this->target_distance_measurement - PRESENCE_DETECT_TOLERANCE;
+ // int16_t max = *this->target_distance_measurement + PRESENCE_DETECT_TOLERANCE;
+
+ for (int16_t value : this->distance_measurement) {
+ // if (value < min || value > max || value == -1) {
+ if (value >= *this->target_distance_measurement || value == -1) {
+ all_in_range = false;
+ }
+
+ if (value < *this->target_distance_measurement && value != -1) {
+ all_out_of_range = false;
+ }
+ }
+
+ if(all_in_range) this->vehicle_detected_state = VehicleDetectedState::YES;
+ if(all_out_of_range) this->vehicle_detected_state = VehicleDetectedState::NO;
+
+ // auto k = this->distance_measurement;
+ // ESP_LOGD(TAG,"measure: %i,%i,%i,%i,%i,%i,%i,%i,%i,%i; target: %i; all_in: %s; all_out: %s;", k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7],k[8],k[9], *this->target_distance_measurement, all_in_range ? "y" : "n", all_out_of_range ? "y" : "n");
+ }
+
+ void RATGDOComponent::presence_change(bool sensor_value)
+ {
+ if(this->presence_detect_window_active_){
+ if(sensor_value){
+ this->vehicle_arriving_state = VehicleArrivingState::YES;
+ this->vehicle_leaving_state = VehicleLeavingState::NO;
+ set_timeout(CLEAR_PRESENCE, [=] {
+ this->vehicle_arriving_state = VehicleArrivingState::NO;
+ });
+ }else{
+ this->vehicle_arriving_state = VehicleArrivingState::NO;
+ this->vehicle_leaving_state = VehicleLeavingState::YES;
+ set_timeout(CLEAR_PRESENCE, [=] {
+ this->vehicle_leaving_state = VehicleLeavingState::NO;
+ });
+ }
+ }
+ }
+
Result RATGDOComponent::call_protocol(Args args)
{
return this->protocol_->call(args);
@@ -359,7 +442,7 @@ namespace ratgdo {
if (current_millis - last_millis > CHECK_PERIOD) {
// ESP_LOGD(TAG, "%ld: Obstruction count: %d, expected: %d, since asleep: %ld",
- // current_millis, this->isr_store_.obstruction_low_count, PULSES_EXPECTED,
+ // current_millis, this->isr_store_.obstruction_low_count, PULSES_LOWER_LIMIT,
// current_millis - last_asleep
// );
@@ -369,7 +452,11 @@ namespace ratgdo {
this->obstruction_sensor_detected_ = true;
} else if (this->isr_store_.obstruction_low_count == 0) {
// if there have been no pulses the line is steady high or low
+#ifdef USE_ESP32
+ if (this->input_obst_pin_->digital_read()) {
+#else
if (!this->input_obst_pin_->digital_read()) {
+#endif
// asleep
last_asleep = current_millis;
} else {
@@ -494,7 +581,15 @@ namespace ratgdo {
void RATGDOComponent::door_action(DoorAction action)
{
- this->protocol_->door_action(action);
+ if(*this->closing_delay > 0 && action == DoorAction::CLOSE){
+ this->door_action_delayed = DoorActionDelayed::YES;
+ set_timeout("door_action", *this->closing_delay * 1000, [=] {
+ this->door_action_delayed = DoorActionDelayed::NO;
+ this->protocol_->door_action(DoorAction::CLOSE);
+ });
+ }else{
+ this->protocol_->door_action(action);
+ }
}
void RATGDOComponent::door_move_to_position(float position)
@@ -614,6 +709,10 @@ namespace ratgdo {
{
this->closing_duration.subscribe([=](float state) { defer("closing_duration", [=] { f(state); }); });
}
+ void RATGDOComponent::subscribe_closing_delay(std::function&& f)
+ {
+ this->closing_delay.subscribe([=](uint32_t state) { defer("closing_delay", [=] { f(state); }); });
+ }
void RATGDOComponent::subscribe_openings(std::function&& f)
{
this->openings.subscribe([=](uint16_t state) { defer("openings", [=] { f(state); }); });
@@ -640,11 +739,14 @@ namespace ratgdo {
}
void RATGDOComponent::subscribe_door_state(std::function&& f)
{
+ static int num = 0;
+ auto name = "door_state" + std::to_string(num++);
+
this->door_state.subscribe([=](DoorState state) {
- defer("door_state", [=] { f(state, *this->door_position); });
+ defer(name, [=] { f(state, *this->door_position); });
});
this->door_position.subscribe([=](float position) {
- defer("door_state", [=] { f(*this->door_state, position); });
+ defer(name, [=] { f(*this->door_state, position); });
});
}
void RATGDOComponent::subscribe_light_state(std::function&& f)
@@ -679,6 +781,37 @@ namespace ratgdo {
{
this->learn_state.subscribe([=](LearnState state) { defer("learn_state", [=] { f(state); }); });
}
+ void RATGDOComponent::subscribe_door_action_delayed(std::function&& f)
+ {
+ static int num = 0;
+ auto name = "door_action_delayed" + std::to_string(num++);
+
+ this->door_action_delayed.subscribe([=](DoorActionDelayed state) { defer(name, [=] { f(state); }); });
+ }
+ void RATGDOComponent::subscribe_distance_measurement(std::function&& f)
+ {
+ static int num = 0;
+ auto name = "last_distance_measurement" + std::to_string(num++);
+ this->last_distance_measurement.subscribe([=](int16_t state) { defer(name, [=] { f(state); }); });
+ }
+ void RATGDOComponent::subscribe_vehicle_detected_state(std::function&& f)
+ {
+ static int num = 0;
+ auto name = "vehicle_detected_state" + std::to_string(num++);
+ this->vehicle_detected_state.subscribe([=](VehicleDetectedState state) { defer(name, [=] { f(state); }); });
+ }
+ void RATGDOComponent::subscribe_vehicle_arriving_state(std::function&& f)
+ {
+ static int num = 0;
+ auto name = "vehicle_arriving_state" + std::to_string(num++);
+ this->vehicle_arriving_state.subscribe([=](VehicleArrivingState state) { defer(name, [=] { f(state); }); });
+ }
+ void RATGDOComponent::subscribe_vehicle_leaving_state(std::function&& f)
+ {
+ static int num = 0;
+ auto name = "vehicle_leaving_state" + std::to_string(num++);
+ this->vehicle_leaving_state.subscribe([=](VehicleLeavingState state) { defer(name, [=] { f(state); }); });
+ }
// dry contact methods
void RATGDOComponent::set_dry_contact_open_sensor(esphome::binary_sensor::BinarySensor* dry_contact_open_sensor)
diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h
index 228d5bc..a6524ac 100644
--- a/components/ratgdo/ratgdo.h
+++ b/components/ratgdo/ratgdo.h
@@ -62,6 +62,11 @@ namespace ratgdo {
observable opening_duration { 0 };
float start_closing { -1 };
observable closing_duration { 0 };
+ observable closing_delay { 0 };
+
+ observable target_distance_measurement { -1 };
+ std::vector distance_measurement{std::vector(10,-1)}; // the length of this vector determines how many in-range readings are required for presence detection to change states
+ observable last_distance_measurement { 0 };
observable openings { 0 }; // number of times the door has been opened
observable paired_total { PAIRED_DEVICES_UNKNOWN };
@@ -72,6 +77,7 @@ namespace ratgdo {
observable door_state { DoorState::UNKNOWN };
observable door_position { DOOR_POSITION_UNKNOWN };
+ observable door_action_delayed { DoorActionDelayed::NO };
unsigned long door_start_moving { 0 };
float door_start_position { DOOR_POSITION_UNKNOWN };
@@ -84,6 +90,9 @@ namespace ratgdo {
observable button_state { ButtonState::UNKNOWN };
observable motion_state { MotionState::UNKNOWN };
observable learn_state { LearnState::UNKNOWN };
+ observable vehicle_detected_state { VehicleDetectedState::NO };
+ observable vehicle_arriving_state { VehicleArrivingState::NO };
+ observable vehicle_leaving_state { VehicleLeavingState::NO };
OnceCallbacks on_door_state_;
@@ -127,9 +136,14 @@ namespace ratgdo {
void set_door_position(float door_position) { this->door_position = door_position; }
void set_opening_duration(float duration);
void set_closing_duration(float duration);
+ void set_closing_delay(uint32_t delay) { this->closing_delay = delay; }
void schedule_door_position_sync(float update_period = 500);
void door_position_update();
void cancel_position_sync_callbacks();
+ void set_target_distance_measurement(int16_t distance);
+ void set_distance_measurement(int16_t distance);
+ void calculate_presence();
+ void presence_change(bool sensor_value);
// light
void light_toggle();
@@ -158,6 +172,7 @@ namespace ratgdo {
void subscribe_rolling_code_counter(std::function&& f);
void subscribe_opening_duration(std::function&& f);
void subscribe_closing_duration(std::function&& f);
+ void subscribe_closing_delay(std::function&& f);
void subscribe_openings(std::function&& f);
void subscribe_paired_devices_total(std::function&& f);
void subscribe_paired_remotes(std::function&& f);
@@ -173,11 +188,17 @@ namespace ratgdo {
void subscribe_motion_state(std::function&& f);
void subscribe_sync_failed(std::function&& f);
void subscribe_learn_state(std::function&& f);
+ void subscribe_door_action_delayed(std::function&& f);
+ void subscribe_distance_measurement(std::function&& f);
+ void subscribe_vehicle_detected_state(std::function&& f);
+ void subscribe_vehicle_arriving_state(std::function&& f);
+ void subscribe_vehicle_leaving_state(std::function&& f);
protected:
RATGDOStore isr_store_ {};
protocol::Protocol* protocol_;
bool obstruction_sensor_detected_ { false };
+ bool presence_detect_window_active_ { false };
InternalGPIOPin* output_gdo_pin_;
InternalGPIOPin* input_gdo_pin_;
diff --git a/components/ratgdo/ratgdo_state.h b/components/ratgdo/ratgdo_state.h
index f71440a..f541e6e 100644
--- a/components/ratgdo/ratgdo_state.h
+++ b/components/ratgdo/ratgdo_state.h
@@ -25,6 +25,10 @@ namespace ratgdo {
(STOPPED, 3),
(OPENING, 4),
(CLOSING, 5))
+
+ ENUM(DoorActionDelayed, uint8_t,
+ (NO, 0),
+ (YES, 1))
/// Enum for all states a the light can be in.
ENUM(LightState, uint8_t,
@@ -104,6 +108,18 @@ namespace ratgdo {
(STOP, 3),
(UNKNOWN, 4))
+ ENUM(VehicleDetectedState, uint8_t,
+ (NO, 0),
+ (YES, 1))
+
+ ENUM(VehicleArrivingState, uint8_t,
+ (NO, 0),
+ (YES, 1))
+
+ ENUM(VehicleLeavingState, uint8_t,
+ (NO, 0),
+ (YES, 1))
+
struct Openings {
uint16_t count;
uint8_t flag;
diff --git a/components/ratgdo/sensor/__init__.py b/components/ratgdo/sensor/__init__.py
index 5a593c7..70b44dd 100644
--- a/components/ratgdo/sensor/__init__.py
+++ b/components/ratgdo/sensor/__init__.py
@@ -2,6 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import CONF_ID
+CONF_DISTANCE = "distance"
from .. import RATGDO_CLIENT_SCHMEA, ratgdo_ns, register_ratgdo_child
@@ -18,6 +19,7 @@ TYPES = {
"paired_devices_keypads": RATGDOSensorType.RATGDO_PAIRED_KEYPADS,
"paired_devices_wall_controls": RATGDOSensorType.RATGDO_PAIRED_WALL_CONTROLS,
"paired_devices_accessories": RATGDOSensorType.RATGDO_PAIRED_ACCESSORIES,
+ "distance": RATGDOSensorType.RATGDO_DISTANCE
}
@@ -38,3 +40,15 @@ async def to_code(config):
await cg.register_component(var, config)
cg.add(var.set_ratgdo_sensor_type(config[CONF_TYPE]))
await register_ratgdo_child(var, config)
+
+ if config['type'] == 'distance':
+ cg.add_library(
+ name="Wire",
+ version=None
+ )
+ cg.add_library(
+ name="vl53l4cx",
+ repository="https://github.com/stm32duino/VL53L4CX",
+ version=None,
+ )
+ cg.add_define("USE_DISTANCE")
diff --git a/components/ratgdo/sensor/ratgdo_sensor.cpp b/components/ratgdo/sensor/ratgdo_sensor.cpp
index e28290a..c79cfe6 100644
--- a/components/ratgdo/sensor/ratgdo_sensor.cpp
+++ b/components/ratgdo/sensor/ratgdo_sensor.cpp
@@ -33,6 +33,22 @@ namespace ratgdo {
this->parent_->subscribe_paired_accessories([=](uint16_t value) {
this->publish_state(value);
});
+ } else if (this->ratgdo_sensor_type_ == RATGDOSensorType::RATGDO_DISTANCE) {
+#ifdef USE_DISTANCE
+ this->distance_sensor_.setI2cDevice(&I2C);
+ this->distance_sensor_.setXShutPin(32);
+ // I2C.begin(17,16);
+ I2C.begin(19,18);
+ this->distance_sensor_.begin();
+ this->distance_sensor_.VL53L4CX_Off();
+ this->distance_sensor_.InitSensor(0x59);
+ this->distance_sensor_.VL53L4CX_SetDistanceMode(VL53L4CX_DISTANCEMODE_LONG);
+ this->distance_sensor_.VL53L4CX_StartMeasurement();
+
+ this->parent_->subscribe_distance_measurement([=](int16_t value) {
+ this->publish_state(value);
+ });
+#endif
}
}
@@ -51,8 +67,46 @@ namespace ratgdo {
ESP_LOGCONFIG(TAG, " Type: Paired Wall Controls");
} else if (this->ratgdo_sensor_type_ == RATGDOSensorType::RATGDO_PAIRED_ACCESSORIES) {
ESP_LOGCONFIG(TAG, " Type: Paired Accessories");
+ } else if (this->ratgdo_sensor_type_ == RATGDOSensorType::RATGDO_DISTANCE) {
+ ESP_LOGCONFIG(TAG, " Type: Distance");
}
}
+ void RATGDOSensor::loop()
+ {
+#ifdef USE_DISTANCE
+ if (this->ratgdo_sensor_type_ == RATGDOSensorType::RATGDO_DISTANCE) {
+ VL53L4CX_MultiRangingData_t distanceData;
+ VL53L4CX_MultiRangingData_t *pDistanceData = &distanceData;
+ uint8_t dataReady = 0;
+ int objCount = 0;
+ int16_t maxDistance = 0;
+ int status;
+
+ if (this->distance_sensor_.VL53L4CX_GetMeasurementDataReady(&dataReady) == 0 && dataReady) {
+ status = this->distance_sensor_.VL53L4CX_GetMultiRangingData(pDistanceData);
+ objCount = pDistanceData->NumberOfObjectsFound;
+
+ maxDistance = objCount == 0 ? -1 : pDistanceData->RangeData[objCount - 1].RangeMilliMeter;
+ /* if(maxDistance < 0) maxDistance = -1;
+ * if the sensor is pointed at glass, there are many error readings which will fill the
+ * vector with out of range data. The sensor should be sensitive enough to detect the floor
+ * in most situations, unless its mounted really far away.
+ * If this doesn't work, then the vector size will have to increase substantially
+ */
+ if(maxDistance > 0){
+ this->parent_->set_distance_measurement(maxDistance);
+ }
+
+ // ESP_LOGD(TAG,"# obj found %d; distance %d",objCount, maxDistance);
+
+ if (status == 0) {
+ status = this->distance_sensor_.VL53L4CX_ClearInterruptAndStartMeasurement();
+ }
+ }
+ }
+#endif
+ }
+
} // namespace ratgdo
} // namespace esphome
diff --git a/components/ratgdo/sensor/ratgdo_sensor.h b/components/ratgdo/sensor/ratgdo_sensor.h
index 3a3517c..cf405d4 100644
--- a/components/ratgdo/sensor/ratgdo_sensor.h
+++ b/components/ratgdo/sensor/ratgdo_sensor.h
@@ -5,6 +5,12 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
+#ifdef USE_DISTANCE
+ #include "Wire.h"
+ #include "vl53l4cx_class.h"
+ #define I2C Wire
+#endif
+
namespace esphome {
namespace ratgdo {
@@ -14,17 +20,23 @@ namespace ratgdo {
RATGDO_PAIRED_REMOTES,
RATGDO_PAIRED_KEYPADS,
RATGDO_PAIRED_WALL_CONTROLS,
- RATGDO_PAIRED_ACCESSORIES
+ RATGDO_PAIRED_ACCESSORIES,
+ RATGDO_DISTANCE
};
class RATGDOSensor : public sensor::Sensor, public RATGDOClient, public Component {
public:
void dump_config() override;
void setup() override;
+ void loop() override;
void set_ratgdo_sensor_type(RATGDOSensorType ratgdo_sensor_type_) { this->ratgdo_sensor_type_ = ratgdo_sensor_type_; }
protected:
RATGDOSensorType ratgdo_sensor_type_;
+
+#ifdef USE_DISTANCE
+ VL53L4CX distance_sensor_;
+#endif
};
} // namespace ratgdo
diff --git a/components/ratgdo/switch/__init__.py b/components/ratgdo/switch/__init__.py
index 9028cca..786d9c8 100644
--- a/components/ratgdo/switch/__init__.py
+++ b/components/ratgdo/switch/__init__.py
@@ -1,7 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import switch
-from esphome.const import CONF_ID
+from esphome import pins
+from esphome.const import CONF_ID, CONF_PIN
from .. import RATGDO_CLIENT_SCHMEA, ratgdo_ns, register_ratgdo_child
@@ -13,6 +14,7 @@ SwitchType = ratgdo_ns.enum("SwitchType")
CONF_TYPE = "type"
TYPES = {
"learn": SwitchType.RATGDO_LEARN,
+ "led": SwitchType.RATGDO_LED
}
@@ -21,6 +23,7 @@ CONFIG_SCHEMA = (
.extend(
{
cv.Required(CONF_TYPE): cv.enum(TYPES, lower=True),
+ cv.Optional(CONF_PIN): pins.gpio_output_pin_schema,
}
)
.extend(RATGDO_CLIENT_SCHMEA)
@@ -33,3 +36,7 @@ async def to_code(config):
await cg.register_component(var, config)
cg.add(var.set_switch_type(config[CONF_TYPE]))
await register_ratgdo_child(var, config)
+ if CONF_PIN in config:
+ pin = await cg.gpio_pin_expression(config[CONF_PIN])
+ cg.add(var.set_pin(pin))
+
diff --git a/components/ratgdo/switch/ratgdo_switch.cpp b/components/ratgdo/switch/ratgdo_switch.cpp
index b0f911c..18a589a 100644
--- a/components/ratgdo/switch/ratgdo_switch.cpp
+++ b/components/ratgdo/switch/ratgdo_switch.cpp
@@ -21,6 +21,11 @@ namespace ratgdo {
this->parent_->subscribe_learn_state([=](LearnState state) {
this->publish_state(state == LearnState::ACTIVE);
});
+ }else if(this->switch_type_ == SwitchType::RATGDO_LED) {
+ this->pin_->setup();
+ this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
+ this->write_state(state == VehicleArrivingState::YES);
+ });
}
}
@@ -32,6 +37,9 @@ namespace ratgdo {
} else {
this->parent_->inactivate_learn();
}
+ } else if(this->switch_type_ == SwitchType::RATGDO_LED){
+ this->pin_->digital_write(state);
+ this->publish_state(state);
}
}
diff --git a/components/ratgdo/switch/ratgdo_switch.h b/components/ratgdo/switch/ratgdo_switch.h
index 3640bec..8b195df 100644
--- a/components/ratgdo/switch/ratgdo_switch.h
+++ b/components/ratgdo/switch/ratgdo_switch.h
@@ -9,7 +9,8 @@ namespace esphome {
namespace ratgdo {
enum SwitchType {
- RATGDO_LEARN
+ RATGDO_LEARN,
+ RATGDO_LED
};
class RATGDOSwitch : public switch_::Switch, public RATGDOClient, public Component {
@@ -19,9 +20,11 @@ namespace ratgdo {
void set_switch_type(SwitchType switch_type_) { this->switch_type_ = switch_type_; }
void write_state(bool state) override;
+ void set_pin(GPIOPin *pin) { pin_ = pin; }
protected:
SwitchType switch_type_;
+ GPIOPin *pin_;
};
} // namespace ratgdo
diff --git a/static/v25iboard.yaml b/static/v25iboard.yaml
index 98bb6b8..52d2079 100644
--- a/static/v25iboard.yaml
+++ b/static/v25iboard.yaml
@@ -33,6 +33,8 @@ packages:
url: https://github.com/ratgdo/esphome-ratgdo
files: [base.yaml]
refresh: 1s
+ # remote_package: !include
+ # file: base.yaml
# Sync time with Home Assistant.
time:
diff --git a/static/v25iboard_drycontact.yaml b/static/v25iboard_drycontact.yaml
index 2d50afc..3f14f46 100644
--- a/static/v25iboard_drycontact.yaml
+++ b/static/v25iboard_drycontact.yaml
@@ -34,6 +34,7 @@ packages:
refresh: 1s
# remote_package: !include
# file: base_drycontact.yaml
+
# Sync time with Home Assistant.
time:
- platform: homeassistant
diff --git a/static/v32board.yaml b/static/v32board.yaml
new file mode 100644
index 0000000..2f9a0a3
--- /dev/null
+++ b/static/v32board.yaml
@@ -0,0 +1,65 @@
+---
+substitutions:
+ id_prefix: ratgdov32
+ friendly_name: "ratgdov32"
+ uart_tx_pin: GPIO17
+ uart_rx_pin: GPIO21
+ input_obst_pin: GPIO4
+ status_door_pin: GPIO26
+ status_obstruction_pin: GPIO25
+ dry_contact_open_pin: GPIO13
+ dry_contact_close_pin: GPIO14
+ dry_contact_light_pin: GPIO27
+
+web_server:
+
+esphome:
+ name: ${id_prefix}
+ friendly_name: ${friendly_name}
+ name_add_mac_suffix: true
+ project:
+ name: ratgdo.esphome
+ version: "32.0"
+
+esp32:
+ board: esp32dev
+
+dashboard_import:
+ package_import_url: github://ratgdo/esphome-ratgdo/v32board.yaml@main
+
+packages:
+ remote_package:
+ url: https://github.com/ratgdo/esphome-ratgdo
+ files: [base.yaml]
+ refresh: 1s
+ # remote_package: !include
+ # file: base.yaml
+
+switch:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_led
+ type: led
+ pin: GPIO4
+ name: "LED"
+ entity_category: config
+
+sensor:
+ - platform: wifi_signal
+ name: "WiFi Signal"
+ update_interval: 120s
+
+# Sync time with Home Assistant.
+time:
+ - platform: homeassistant
+ id: homeassistant_time
+
+api:
+ id: api_server
+
+improv_serial:
+
+wifi:
+ ap:
+
+logger:
\ No newline at end of file
diff --git a/static/v32board_drycontact.yaml b/static/v32board_drycontact.yaml
new file mode 100644
index 0000000..7f89fe7
--- /dev/null
+++ b/static/v32board_drycontact.yaml
@@ -0,0 +1,64 @@
+---
+substitutions:
+ id_prefix: ratgdo32disco
+ friendly_name: "ratgdo32disco"
+ uart_tx_pin: GPIO17
+ uart_rx_pin: GPIO21
+ input_obst_pin: GPIO4
+ dry_contact_open_pin: GPIO13
+ dry_contact_close_pin: GPIO14
+ discrete_open_pin: GPIO26
+ discrete_close_pin: GPIO25
+
+web_server:
+
+esphome:
+ name: ${id_prefix}
+ friendly_name: ${friendly_name}
+ name_add_mac_suffix: true
+ project:
+ name: ratgdo.esphome
+ version: "32.0"
+
+esp32:
+ board: esp32dev
+
+dashboard_import:
+ package_import_url: github://ratgdo/esphome-ratgdo/v32board_drycontact.yaml@main
+
+packages:
+ remote_package:
+ url: https://github.com/ratgdo/esphome-ratgdo
+ files: [base_drycontact.yaml]
+ refresh: 1s
+ # remote_package: !include
+ # file: base_drycontact.yaml
+
+switch:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_led
+ type: led
+ pin: GPIO4
+ name: "LED"
+ entity_category: config
+
+sensor:
+ - platform: wifi_signal
+ name: "WiFi Signal"
+ update_interval: 120s
+
+# Sync time with Home Assistant.
+time:
+ - platform: homeassistant
+ id: homeassistant_time
+
+api:
+ id: api_server
+
+improv_serial:
+
+wifi:
+ ap:
+
+logger:
\ No newline at end of file
diff --git a/static/v32board_secplusv1.yaml b/static/v32board_secplusv1.yaml
new file mode 100644
index 0000000..2a0f75a
--- /dev/null
+++ b/static/v32board_secplusv1.yaml
@@ -0,0 +1,65 @@
+---
+substitutions:
+ id_prefix: ratgdov32
+ friendly_name: "ratgdov32"
+ uart_tx_pin: GPIO17
+ uart_rx_pin: GPIO21
+ input_obst_pin: GPIO4
+ status_door_pin: GPIO26
+ status_obstruction_pin: GPIO25
+ dry_contact_open_pin: GPIO13
+ dry_contact_close_pin: GPIO14
+ dry_contact_light_pin: GPIO27
+
+web_server:
+
+esphome:
+ name: ${id_prefix}
+ friendly_name: ${friendly_name}
+ name_add_mac_suffix: true
+ project:
+ name: ratgdo.esphome
+ version: "32.0"
+
+esp32:
+ board: esp32dev
+
+dashboard_import:
+ package_import_url: github://ratgdo/esphome-ratgdo/v32board_secplusv1.yaml@main
+
+packages:
+ remote_package:
+ url: https://github.com/ratgdo/esphome-ratgdo
+ files: [base_secplusv1.yaml]
+ refresh: 1s
+ # remote_package: !include
+ # file: base_secplusv1.yaml
+
+switch:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_led
+ type: led
+ pin: GPIO4
+ name: "LED"
+ entity_category: config
+
+sensor:
+ - platform: wifi_signal
+ name: "WiFi Signal"
+ update_interval: 120s
+
+# Sync time with Home Assistant.
+time:
+ - platform: homeassistant
+ id: homeassistant_time
+
+api:
+ id: api_server
+
+improv_serial:
+
+wifi:
+ ap:
+
+logger:
\ No newline at end of file
diff --git a/static/v32disco.yaml b/static/v32disco.yaml
new file mode 100644
index 0000000..bfb14ac
--- /dev/null
+++ b/static/v32disco.yaml
@@ -0,0 +1,149 @@
+---
+substitutions:
+ id_prefix: ratgdo32disco
+ friendly_name: "ratgdo32disco"
+ uart_tx_pin: GPIO17
+ uart_rx_pin: GPIO21
+ input_obst_pin: GPIO4
+ status_door_pin: GPIO26
+ status_obstruction_pin: GPIO25
+ dry_contact_open_pin: GPIO13
+ dry_contact_close_pin: GPIO14
+ dry_contact_light_pin: GPIO27
+
+web_server:
+
+esphome:
+ name: ${id_prefix}
+ friendly_name: ${friendly_name}
+ name_add_mac_suffix: true
+ project:
+ name: ratgdo.esphome
+ version: "32disco"
+
+esp32:
+ board: esp32dev
+
+dashboard_import:
+ package_import_url: github://ratgdo/esphome-ratgdo/v32disco.yaml@main
+
+packages:
+ remote_package:
+ url: https://github.com/ratgdo/esphome-ratgdo
+ files: [base.yaml]
+ refresh: 1s
+ # remote_package: !include
+ # file: base.yaml
+
+# Sync time with Home Assistant.
+time:
+ - platform: homeassistant
+ id: homeassistant_time
+
+api:
+ id: api_server
+
+improv_serial:
+
+binary_sensor:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_detected
+ type: vehicle_detected
+ name: "Vehicle detected"
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_arriving
+ type: vehicle_arriving
+ name: "Vehicle arriving"
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_leaving
+ type: vehicle_leaving
+ name: "Vehicle leaving"
+
+number:
+ - platform: ratgdo
+ id: ${id_prefix}_target_distance_measurement
+ type: target_distance_measurement
+ entity_category: config
+ ratgdo_id: ${id_prefix}
+ name: "Vehicle distance target"
+ mode: box
+ unit_of_measurement: "mm"
+ - platform: ratgdo
+ id: ${id_prefix}_closing_delay
+ type: closing_delay
+ entity_category: config
+ ratgdo_id: ${id_prefix}
+ name: "Closing Delay"
+ unit_of_measurement: "s"
+
+output:
+ - platform: ledc
+ pin: GPIO33
+ id: ${id_prefix}_ledc
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_beeper
+ type: beeper
+ rtttl: ${id_prefix}_rtttl
+ song: "alert:d=8,o=5,b=120:a,p,a,p,a,p,4b,p"
+
+rtttl:
+ - id: ${id_prefix}_rtttl
+ output: ${id_prefix}_ledc
+
+switch:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_led
+ type: led
+ pin: GPIO2
+ name: "LED"
+ entity_category: config
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_laser
+ type: led
+ pin: GPIO23
+ name: "LASER"
+ entity_category: config
+
+sensor:
+ - platform: wifi_signal
+ name: "WiFi Signal"
+ update_interval: 120s
+ - platform: ratgdo
+ id: ${id_prefix}_vehicle_distance_actual
+ type: distance
+ name: "Vehicle distance actual"
+ ratgdo_id: ${id_prefix}
+ unit_of_measurement: "mm"
+ filters:
+ - throttle: 1s
+ - filter_out: -1
+ - median:
+ window_size: 20
+ send_every: 5
+ send_first_at: 5
+ - platform: adc
+ pin: GPIO34
+ name: "Voltage"
+ attenuation: auto
+ update_interval: 60s
+ filters:
+ - calibrate_linear:
+ - 1.16 -> 5
+ - 2.783 -> 12
+ # uncomment to convert voltage scale to a % for lead acid batteries
+ # - 2.43 -> 0 # 10.5v = 0%
+ # - 2.98 -> 100 # 12.85 = 100%
+ # - clamp:
+ # min_value: 0
+ # max_value: 100
+ # unit_of_measurement: "%"
+
+logger:
+
+ota:
\ No newline at end of file
diff --git a/static/v32disco_drycontact.yaml b/static/v32disco_drycontact.yaml
new file mode 100644
index 0000000..99fc1d2
--- /dev/null
+++ b/static/v32disco_drycontact.yaml
@@ -0,0 +1,141 @@
+---
+substitutions:
+ id_prefix: ratgdo32disco
+ friendly_name: "ratgdo32disco"
+ uart_tx_pin: GPIO17
+ uart_rx_pin: GPIO21
+ input_obst_pin: GPIO4
+ dry_contact_open_pin: GPIO13
+ dry_contact_close_pin: GPIO14
+ discrete_open_pin: GPIO26
+ discrete_close_pin: GPIO25
+
+web_server:
+
+esphome:
+ name: ${id_prefix}
+ friendly_name: ${friendly_name}
+ name_add_mac_suffix: true
+ project:
+ name: ratgdo.esphome
+ version: "32disco"
+
+esp32:
+ board: esp32dev
+
+dashboard_import:
+ package_import_url: github://ratgdo/esphome-ratgdo/v32disco_drycontact.yaml@main
+
+packages:
+ remote_package:
+ url: https://github.com/ratgdo/esphome-ratgdo
+ files: [base_drycontact.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
+
+improv_serial:
+
+binary_sensor:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_detected
+ type: vehicle_detected
+ name: "Vehicle detected"
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_arriving
+ type: vehicle_arriving
+ name: "Vehicle arriving"
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_leaving
+ type: vehicle_leaving
+ name: "Vehicle leaving"
+
+number:
+ - platform: ratgdo
+ id: ${id_prefix}_target_distance_measurement
+ type: target_distance_measurement
+ entity_category: config
+ ratgdo_id: ${id_prefix}
+ name: "Vehicle distance target"
+ mode: box
+ unit_of_measurement: "mm"
+ - platform: ratgdo
+ id: ${id_prefix}_closing_delay
+ type: closing_delay
+ entity_category: config
+ ratgdo_id: ${id_prefix}
+ name: "Closing Delay"
+ unit_of_measurement: "s"
+
+output:
+ - platform: ledc
+ pin: GPIO33
+ id: ${id_prefix}_ledc
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_beeper
+ type: beeper
+ rtttl: ${id_prefix}_rtttl
+ song: "alert:d=8,o=5,b=120:a,p,a,p,a,p,4b,p"
+
+rtttl:
+ - id: ${id_prefix}_rtttl
+ output: ${id_prefix}_ledc
+
+switch:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_led
+ type: led
+ pin: GPIO2
+ name: "LED"
+ entity_category: config
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_laser
+ type: led
+ pin: GPIO23
+ name: "LASER"
+ entity_category: config
+
+sensor:
+ - platform: wifi_signal
+ name: "WiFi Signal"
+ update_interval: 120s
+ - platform: ratgdo
+ id: ${id_prefix}_vehicle_distance_actual
+ type: distance
+ name: "Vehicle distance actual"
+ ratgdo_id: ${id_prefix}
+ unit_of_measurement: "mm"
+ filters:
+ - throttle: 10s
+ - filter_out: -1
+ - median:
+ window_size: 20
+ send_every: 5
+ send_first_at: 5
+ - platform: adc
+ pin: GPIO34
+ name: "Voltage"
+ attenuation: auto
+ update_interval: 60s
+ filters:
+ - calibrate_linear:
+ - 1.16 -> 5
+ - 2.783 -> 12
+
+logger:
+
+ota:
\ No newline at end of file
diff --git a/static/v32disco_secplusv1.yaml b/static/v32disco_secplusv1.yaml
new file mode 100644
index 0000000..1bbd06a
--- /dev/null
+++ b/static/v32disco_secplusv1.yaml
@@ -0,0 +1,142 @@
+---
+substitutions:
+ id_prefix: ratgdo32disco
+ friendly_name: "ratgdo32disco"
+ uart_tx_pin: GPIO17
+ uart_rx_pin: GPIO21
+ input_obst_pin: GPIO4
+ status_door_pin: GPIO26
+ status_obstruction_pin: GPIO25
+ dry_contact_open_pin: GPIO13
+ dry_contact_close_pin: GPIO14
+ dry_contact_light_pin: GPIO27
+
+web_server:
+
+esphome:
+ name: ${id_prefix}
+ friendly_name: ${friendly_name}
+ name_add_mac_suffix: true
+ project:
+ name: ratgdo.esphome
+ version: "32disco"
+
+esp32:
+ board: esp32dev
+
+dashboard_import:
+ package_import_url: github://ratgdo/esphome-ratgdo/v32disco_secplusv1.yaml@main
+
+packages:
+ remote_package:
+ url: https://github.com/ratgdo/esphome-ratgdo
+ files: [base_secplusv1.yaml]
+ refresh: 1s
+ # remote_package: !include
+ # file: base_secplusv1.yaml
+
+# Sync time with Home Assistant.
+time:
+ - platform: homeassistant
+ id: homeassistant_time
+
+api:
+ id: api_server
+
+improv_serial:
+
+binary_sensor:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_detected
+ type: vehicle_detected
+ name: "Vehicle detected"
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_arriving
+ type: vehicle_arriving
+ name: "Vehicle arriving"
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_vehicle_leaving
+ type: vehicle_leaving
+ name: "Vehicle leaving"
+
+number:
+ - platform: ratgdo
+ id: ${id_prefix}_target_distance_measurement
+ type: target_distance_measurement
+ entity_category: config
+ ratgdo_id: ${id_prefix}
+ name: "Vehicle distance target"
+ mode: box
+ unit_of_measurement: "mm"
+ - platform: ratgdo
+ id: ${id_prefix}_closing_delay
+ type: closing_delay
+ entity_category: config
+ ratgdo_id: ${id_prefix}
+ name: "Closing Delay"
+ unit_of_measurement: "s"
+
+output:
+ - platform: ledc
+ pin: GPIO33
+ id: ${id_prefix}_ledc
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_beeper
+ type: beeper
+ rtttl: ${id_prefix}_rtttl
+ song: "alert:d=8,o=5,b=120:a,p,a,p,a,p,4b,p"
+
+rtttl:
+ - id: ${id_prefix}_rtttl
+ output: ${id_prefix}_ledc
+
+switch:
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_led
+ type: led
+ pin: GPIO2
+ name: "LED"
+ entity_category: config
+ - platform: ratgdo
+ ratgdo_id: ${id_prefix}
+ id: ${id_prefix}_laser
+ type: led
+ pin: GPIO23
+ name: "LASER"
+ entity_category: config
+
+sensor:
+ - platform: wifi_signal
+ name: "WiFi Signal"
+ update_interval: 120s
+ - platform: ratgdo
+ id: ${id_prefix}_vehicle_distance_actual
+ type: distance
+ name: "Vehicle distance actual"
+ ratgdo_id: ${id_prefix}
+ unit_of_measurement: "mm"
+ filters:
+ - throttle: 10s
+ - filter_out: -1
+ - median:
+ window_size: 20
+ send_every: 5
+ send_first_at: 5
+ - platform: adc
+ pin: GPIO34
+ name: "Voltage"
+ attenuation: auto
+ update_interval: 60s
+ filters:
+ - calibrate_linear:
+ - 1.16 -> 5
+ - 2.783 -> 12
+
+logger:
+
+ota:
\ No newline at end of file
diff --git a/v32board.yaml b/v32board.yaml
new file mode 120000
index 0000000..4f67680
--- /dev/null
+++ b/v32board.yaml
@@ -0,0 +1 @@
+static/v32board.yaml
\ No newline at end of file
diff --git a/v32board_drycontact.yaml b/v32board_drycontact.yaml
new file mode 120000
index 0000000..892ccfa
--- /dev/null
+++ b/v32board_drycontact.yaml
@@ -0,0 +1 @@
+static/v32board_drycontact.yaml
\ No newline at end of file
diff --git a/v32board_secplusv1.yaml b/v32board_secplusv1.yaml
new file mode 120000
index 0000000..71c7430
--- /dev/null
+++ b/v32board_secplusv1.yaml
@@ -0,0 +1 @@
+static/v32board_secplusv1.yaml
\ No newline at end of file
diff --git a/v32disco.yaml b/v32disco.yaml
new file mode 120000
index 0000000..8a4d4be
--- /dev/null
+++ b/v32disco.yaml
@@ -0,0 +1 @@
+static/v32disco.yaml
\ No newline at end of file
diff --git a/v32disco_drycontact.yaml b/v32disco_drycontact.yaml
new file mode 120000
index 0000000..278419c
--- /dev/null
+++ b/v32disco_drycontact.yaml
@@ -0,0 +1 @@
+static/v32disco_drycontact.yaml
\ No newline at end of file
diff --git a/v32disco_secplusv1.yaml b/v32disco_secplusv1.yaml
new file mode 120000
index 0000000..8d32965
--- /dev/null
+++ b/v32disco_secplusv1.yaml
@@ -0,0 +1 @@
+static/v32disco_secplusv1.yaml
\ No newline at end of file
From 516eb29d967abfb84397e11454f828c05aa45eee Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Thu, 7 Nov 2024 09:43:47 -0500
Subject: [PATCH 02/18] correct yaml
---
static/v32disco.yaml | 13 ++++++++-----
static/v32disco_drycontact.yaml | 13 ++++++++-----
static/v32disco_secplusv1.yaml | 13 ++++++++-----
3 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/static/v32disco.yaml b/static/v32disco.yaml
index bfb14ac..b850723 100644
--- a/static/v32disco.yaml
+++ b/static/v32disco.yaml
@@ -45,6 +45,13 @@ api:
improv_serial:
+wifi:
+ ap:
+
+logger:
+
+ota:
+
binary_sensor:
- platform: ratgdo
ratgdo_id: ${id_prefix}
@@ -142,8 +149,4 @@ sensor:
# - clamp:
# min_value: 0
# max_value: 100
- # unit_of_measurement: "%"
-
-logger:
-
-ota:
\ No newline at end of file
+ # unit_of_measurement: "%"
\ No newline at end of file
diff --git a/static/v32disco_drycontact.yaml b/static/v32disco_drycontact.yaml
index 99fc1d2..ab24738 100644
--- a/static/v32disco_drycontact.yaml
+++ b/static/v32disco_drycontact.yaml
@@ -44,6 +44,13 @@ api:
improv_serial:
+wifi:
+ ap:
+
+logger:
+
+ota:
+
binary_sensor:
- platform: ratgdo
ratgdo_id: ${id_prefix}
@@ -134,8 +141,4 @@ sensor:
filters:
- calibrate_linear:
- 1.16 -> 5
- - 2.783 -> 12
-
-logger:
-
-ota:
\ No newline at end of file
+ - 2.783 -> 12
\ No newline at end of file
diff --git a/static/v32disco_secplusv1.yaml b/static/v32disco_secplusv1.yaml
index 1bbd06a..58ce207 100644
--- a/static/v32disco_secplusv1.yaml
+++ b/static/v32disco_secplusv1.yaml
@@ -45,6 +45,13 @@ api:
improv_serial:
+wifi:
+ ap:
+
+logger:
+
+ota:
+
binary_sensor:
- platform: ratgdo
ratgdo_id: ${id_prefix}
@@ -135,8 +142,4 @@ sensor:
filters:
- calibrate_linear:
- 1.16 -> 5
- - 2.783 -> 12
-
-logger:
-
-ota:
\ No newline at end of file
+ - 2.783 -> 12
\ No newline at end of file
From 8068dbed46f06846f442f162fce1c847e7fea6fe Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Thu, 7 Nov 2024 11:36:35 -0500
Subject: [PATCH 03/18] ignore bugs
---
components/ratgdo/ratgdo.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp
index 9063bf4..154371f 100644
--- a/components/ratgdo/ratgdo.cpp
+++ b/components/ratgdo/ratgdo.cpp
@@ -32,6 +32,7 @@ namespace ratgdo {
static const int CLEAR_PRESENCE = 60000; // how long to keep arriving/leaving active
static const int PRESENCE_DETECT_WINDOW = 300000; // how long to calculate presence after door state change
+ static const int MIN_DISTANCE = 20; // ignore bugs crawling on the distance sensor
void RATGDOComponent::setup()
{
@@ -366,6 +367,8 @@ namespace ratgdo {
void RATGDOComponent::set_distance_measurement(int16_t distance)
{
+ if(distance > 0 && distance < MIN_DISTANCE) return;
+
this->last_distance_measurement = distance;
// current value = [0], last value = [1]
From 1e15dae5a786561031f107bc2ded16b4ff82e86b Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Sun, 10 Nov 2024 10:25:43 -0500
Subject: [PATCH 04/18] Add disco to build/webtools
---
.github/workflows/build.yml | 18 ++++++++++++++++++
static/index.html | 20 ++++++++++++--------
2 files changed, 30 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2996155..4ea2fa0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -55,6 +55,24 @@ jobs:
- file: v25iboard_drycontact.yaml
name: V2.5i Board Dry Contact
manifest_filename: v25iboard_drycontact-manifest.json
+ - file: v32board.yaml
+ name: V32 Board Security+ 2.0
+ manifest_filename: v32board-manifest.json
+ - file: v32board_secplusv1.yaml
+ name: V32 Board Security+ 1.0
+ manifest_filename: v32board_secplusv1-manifest.json
+ - file: v32board_drycontact.yaml
+ name: V32 Board Board Dry Contact
+ manifest_filename: v32board_drycontact-manifest.json
+ - file: v32disco.yaml
+ name: V32 Disco Board Security+ 2.0
+ manifest_filename: v32disco-manifest.json
+ - file: v32disco_secplusv1.yaml
+ name: V32 Disco Board Security+ 1.0
+ manifest_filename: v32disco_secplusv1-manifest.json
+ - file: v32disco_drycontact.yaml
+ name: V32 Disco Board Dry Contact
+ manifest_filename: v32disco_drycontact-manifest.json
fail-fast: false
steps:
- name: Checkout source code
diff --git a/static/index.html b/static/index.html
index 77e016c..17168d1 100644
--- a/static/index.html
+++ b/static/index.html
@@ -177,7 +177,7 @@
/>
ESPHome ratgdo
- In order to install the firmware, first pick your door opener control protocol, then pick your ratgdo control board version.
+ In order to install the firmware, first pick your door opener control protocol, then pick your ratgdo control board version.
No programming or other software required.
@@ -209,6 +209,12 @@
Choose your ratgdo control board:
@@ -255,12 +261,10 @@
Drivers
If you can't connect to your ratgdo board make sure you have the right driver installed for the type of board you have.
- Watch the driver and firmware installation [video on YouTube].
-
-
+ Watch the v2.5i driver and firmware installation [video on YouTube].
Advanced Users
From fd43050842ecf063f3700243478c009d43fccacc Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Sun, 10 Nov 2024 11:41:55 -0500
Subject: [PATCH 05/18] closing delay max
reduce to increase slider resolution
---
components/ratgdo/number/ratgdo_number.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/components/ratgdo/number/ratgdo_number.cpp b/components/ratgdo/number/ratgdo_number.cpp
index e3fd1a1..da99b5d 100644
--- a/components/ratgdo/number/ratgdo_number.cpp
+++ b/components/ratgdo/number/ratgdo_number.cpp
@@ -91,7 +91,7 @@ namespace ratgdo {
} else if (this->number_type_ == RATGDO_CLOSING_DELAY) {
this->traits.set_step(1);
this->traits.set_min_value(0.0);
- this->traits.set_max_value(180.0);
+ this->traits.set_max_value(60.0);
} else if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {
this->traits.set_max_value(0xfffffff);
} else if (this->number_type_ == RATGDO_CLIENT_ID) {
From eee6f5e4d504b08b9522d30740e8207210058ddd Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Sun, 10 Nov 2024 18:05:29 +0000
Subject: [PATCH 06/18] [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---
components/ratgdo/__init__.py | 2 +-
.../binary_sensor/ratgdo_binary_sensor.cpp | 6 +-
components/ratgdo/number/ratgdo_number.cpp | 4 +-
components/ratgdo/output/ratgdo_output.cpp | 79 ++++++++++---------
components/ratgdo/output/ratgdo_output.h | 42 +++++-----
components/ratgdo/ratgdo.cpp | 28 ++++---
components/ratgdo/ratgdo.h | 2 +-
components/ratgdo/ratgdo_state.h | 2 +-
components/ratgdo/sensor/__init__.py | 2 +-
components/ratgdo/sensor/ratgdo_sensor.cpp | 12 +--
components/ratgdo/sensor/ratgdo_sensor.h | 6 +-
components/ratgdo/switch/__init__.py | 1 -
components/ratgdo/switch/ratgdo_switch.cpp | 4 +-
components/ratgdo/switch/ratgdo_switch.h | 4 +-
static/v32board.yaml | 2 +-
static/v32board_drycontact.yaml | 2 +-
static/v32board_secplusv1.yaml | 2 +-
static/v32disco.yaml | 2 +-
static/v32disco_drycontact.yaml | 2 +-
static/v32disco_secplusv1.yaml | 2 +-
20 files changed, 107 insertions(+), 99 deletions(-)
diff --git a/components/ratgdo/__init__.py b/components/ratgdo/__init__.py
index a6493c7..5153cad 100644
--- a/components/ratgdo/__init__.py
+++ b/components/ratgdo/__init__.py
@@ -144,4 +144,4 @@ async def to_code(config):
cg.add(var.set_discrete_open_pin(pin))
if CONF_DISCRETE_CLOSE_PIN in config and config[CONF_DISCRETE_CLOSE_PIN]:
pin = await cg.gpio_pin_expression(config[CONF_DISCRETE_CLOSE_PIN])
- cg.add(var.set_discrete_close_pin(pin))
\ No newline at end of file
+ cg.add(var.set_discrete_close_pin(pin))
diff --git a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp
index ffd2985..2c50669 100644
--- a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp
+++ b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp
@@ -28,18 +28,18 @@ namespace ratgdo {
this->parent_->subscribe_button_state([=](ButtonState state) {
this->publish_state(state == ButtonState::PRESSED);
});
- } else if(this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_DETECTED) {
+ } else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_DETECTED) {
this->publish_initial_state(false);
this->parent_->subscribe_vehicle_detected_state([=](VehicleDetectedState state) {
this->publish_state(state == VehicleDetectedState::YES);
this->parent_->presence_change(state == VehicleDetectedState::YES);
});
- } else if(this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_ARRIVING) {
+ } else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_ARRIVING) {
this->publish_initial_state(false);
this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
this->publish_state(state == VehicleArrivingState::YES);
});
- } else if(this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_LEAVING) {
+ } else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_VEHICLE_LEAVING) {
this->publish_initial_state(false);
this->parent_->subscribe_vehicle_leaving_state([=](VehicleLeavingState state) {
this->publish_state(state == VehicleLeavingState::YES);
diff --git a/components/ratgdo/number/ratgdo_number.cpp b/components/ratgdo/number/ratgdo_number.cpp
index da99b5d..40ab378 100644
--- a/components/ratgdo/number/ratgdo_number.cpp
+++ b/components/ratgdo/number/ratgdo_number.cpp
@@ -74,7 +74,7 @@ namespace ratgdo {
this->parent_->subscribe_closing_delay([=](uint32_t value) {
this->update_state(value);
});
- } else if (this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT){
+ } else if (this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT) {
// this->parent_->subscribe_target_distance_measurement([=](float value) {
// this->update_state(value);
// });
@@ -98,7 +98,7 @@ namespace ratgdo {
this->traits.set_step(0x1000);
this->traits.set_min_value(0x539);
this->traits.set_max_value(0x7ff539);
- } else if(this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT) {
+ } else if (this->number_type_ == RATGDO_TARGET_DISTANCE_MEASUREMENT) {
this->traits.set_step(1);
this->traits.set_min_value(5);
this->traits.set_max_value(3500);
diff --git a/components/ratgdo/output/ratgdo_output.cpp b/components/ratgdo/output/ratgdo_output.cpp
index c67a8e1..ba389ba 100644
--- a/components/ratgdo/output/ratgdo_output.cpp
+++ b/components/ratgdo/output/ratgdo_output.cpp
@@ -5,49 +5,54 @@
namespace esphome {
namespace ratgdo {
-static const char *TAG = "ratgdo.output";
+ static const char* TAG = "ratgdo.output";
-void RATGDOOutput::setup(){
- ESP_LOGD(TAG,"Output was setup");
+ void RATGDOOutput::setup()
+ {
+ ESP_LOGD(TAG, "Output was setup");
- if(this->output_type_ == OutputType::RATGDO_BEEPER){
- this->beeper_->add_on_finished_playback_callback([=] { this->finished_playback(); });
+ if (this->output_type_ == OutputType::RATGDO_BEEPER) {
+ this->beeper_->add_on_finished_playback_callback([=] { this->finished_playback(); });
- this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
- if(state == VehicleArrivingState::YES){
- this->play();
- }
- });
-
- this->parent_->subscribe_door_action_delayed([=](DoorActionDelayed state) {
- if(state == DoorActionDelayed::YES){
- this->play();
- this->repeat_ = true;
- } else if(state == DoorActionDelayed::NO) {
- this->repeat_ = false;
- }
- });
+ this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
+ if (state == VehicleArrivingState::YES) {
+ this->play();
+ }
+ });
+ this->parent_->subscribe_door_action_delayed([=](DoorActionDelayed state) {
+ if (state == DoorActionDelayed::YES) {
+ this->play();
+ this->repeat_ = true;
+ } else if (state == DoorActionDelayed::NO) {
+ this->repeat_ = false;
+ }
+ });
+ }
}
-}
-void RATGDOOutput::play(){
- this->beeper_->play(this->rtttlSong_);
-}
-
-void RATGDOOutput::finished_playback(){
- if(this->repeat_) this->play();
-}
-
-void RATGDOOutput::dump_config() {
- if (this->output_type_ == OutputType::RATGDO_BEEPER) {
- ESP_LOGCONFIG(TAG, " Type: Beeper");
+ void RATGDOOutput::play()
+ {
+ this->beeper_->play(this->rtttlSong_);
}
-}
-void RATGDOOutput::set_output_type(OutputType output_type_) {
- this->output_type_ = output_type_;
-}
+ void RATGDOOutput::finished_playback()
+ {
+ if (this->repeat_)
+ this->play();
+ }
-} //namespace ratgdo
-} //namespace esphome
\ No newline at end of file
+ void RATGDOOutput::dump_config()
+ {
+ if (this->output_type_ == OutputType::RATGDO_BEEPER) {
+ ESP_LOGCONFIG(TAG, " Type: Beeper");
+ }
+ }
+
+ void RATGDOOutput::set_output_type(OutputType output_type_)
+ {
+ this->output_type_ = output_type_;
+ }
+
+} // namespace ratgdo
+} // namespace esphome
diff --git a/components/ratgdo/output/ratgdo_output.h b/components/ratgdo/output/ratgdo_output.h
index 873bb73..f15a5d6 100644
--- a/components/ratgdo/output/ratgdo_output.h
+++ b/components/ratgdo/output/ratgdo_output.h
@@ -1,32 +1,32 @@
#pragma once
#include "../ratgdo.h"
-#include "esphome/core/component.h"
#include "esphome/components/rtttl/rtttl.h"
+#include "esphome/core/component.h"
namespace esphome {
namespace ratgdo {
- enum OutputType {
- RATGDO_BEEPER
- };
+ enum OutputType {
+ RATGDO_BEEPER
+ };
- class RATGDOOutput : public RATGDOClient, public Component {
- public:
- void setup() override;
- void play();
- void finished_playback();
- void dump_config() override;
- void set_output_type(OutputType output_type);
- void set_song(std::string rtttlSong){ this->rtttlSong_ = rtttlSong; }
- void set_rtttl(rtttl::Rtttl *output){ this->beeper_ = output; }
+ class RATGDOOutput : public RATGDOClient, public Component {
+ public:
+ void setup() override;
+ void play();
+ void finished_playback();
+ void dump_config() override;
+ void set_output_type(OutputType output_type);
+ void set_song(std::string rtttlSong) { this->rtttlSong_ = rtttlSong; }
+ void set_rtttl(rtttl::Rtttl* output) { this->beeper_ = output; }
- protected:
- OutputType output_type_;
- rtttl::Rtttl* beeper_;
- std::string rtttlSong_;
- bool repeat_;
- };
+ protected:
+ OutputType output_type_;
+ rtttl::Rtttl* beeper_;
+ std::string rtttlSong_;
+ bool repeat_;
+ };
-} //namespace ratgdo
-} //namespace esphome
\ No newline at end of file
+} // namespace ratgdo
+} // namespace esphome
diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp
index 154371f..309ff85 100644
--- a/components/ratgdo/ratgdo.cpp
+++ b/components/ratgdo/ratgdo.cpp
@@ -63,14 +63,14 @@ namespace ratgdo {
this->subscribe_door_state([=](DoorState state, float position) {
static DoorState lastState = DoorState::UNKNOWN;
- if(lastState != DoorState::UNKNOWN && state != DoorState::CLOSED && !this->presence_detect_window_active_){
+ if (lastState != DoorState::UNKNOWN && state != DoorState::CLOSED && !this->presence_detect_window_active_) {
this->presence_detect_window_active_ = true;
set_timeout("presence_detect_window", PRESENCE_DETECT_WINDOW, [=] {
this->presence_detect_window_active_ = false;
});
}
- if(state == DoorState::CLOSED){
+ if (state == DoorState::CLOSED) {
this->presence_detect_window_active_ = false;
cancel_timeout("presence_detect_window");
}
@@ -361,13 +361,15 @@ namespace ratgdo {
this->closing_duration = duration;
}
- void RATGDOComponent::set_target_distance_measurement(int16_t distance){
+ void RATGDOComponent::set_target_distance_measurement(int16_t distance)
+ {
this->target_distance_measurement = distance;
}
void RATGDOComponent::set_distance_measurement(int16_t distance)
{
- if(distance > 0 && distance < MIN_DISTANCE) return;
+ if (distance > 0 && distance < MIN_DISTANCE)
+ return;
this->last_distance_measurement = distance;
@@ -394,9 +396,11 @@ namespace ratgdo {
all_out_of_range = false;
}
}
-
- if(all_in_range) this->vehicle_detected_state = VehicleDetectedState::YES;
- if(all_out_of_range) this->vehicle_detected_state = VehicleDetectedState::NO;
+
+ if (all_in_range)
+ this->vehicle_detected_state = VehicleDetectedState::YES;
+ if (all_out_of_range)
+ this->vehicle_detected_state = VehicleDetectedState::NO;
// auto k = this->distance_measurement;
// ESP_LOGD(TAG,"measure: %i,%i,%i,%i,%i,%i,%i,%i,%i,%i; target: %i; all_in: %s; all_out: %s;", k[0],k[1],k[2],k[3],k[4],k[5],k[6],k[7],k[8],k[9], *this->target_distance_measurement, all_in_range ? "y" : "n", all_out_of_range ? "y" : "n");
@@ -404,14 +408,14 @@ namespace ratgdo {
void RATGDOComponent::presence_change(bool sensor_value)
{
- if(this->presence_detect_window_active_){
- if(sensor_value){
+ if (this->presence_detect_window_active_) {
+ if (sensor_value) {
this->vehicle_arriving_state = VehicleArrivingState::YES;
this->vehicle_leaving_state = VehicleLeavingState::NO;
set_timeout(CLEAR_PRESENCE, [=] {
this->vehicle_arriving_state = VehicleArrivingState::NO;
});
- }else{
+ } else {
this->vehicle_arriving_state = VehicleArrivingState::NO;
this->vehicle_leaving_state = VehicleLeavingState::YES;
set_timeout(CLEAR_PRESENCE, [=] {
@@ -584,13 +588,13 @@ namespace ratgdo {
void RATGDOComponent::door_action(DoorAction action)
{
- if(*this->closing_delay > 0 && action == DoorAction::CLOSE){
+ if (*this->closing_delay > 0 && action == DoorAction::CLOSE) {
this->door_action_delayed = DoorActionDelayed::YES;
set_timeout("door_action", *this->closing_delay * 1000, [=] {
this->door_action_delayed = DoorActionDelayed::NO;
this->protocol_->door_action(DoorAction::CLOSE);
});
- }else{
+ } else {
this->protocol_->door_action(action);
}
}
diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h
index a6524ac..35a9b46 100644
--- a/components/ratgdo/ratgdo.h
+++ b/components/ratgdo/ratgdo.h
@@ -65,7 +65,7 @@ namespace ratgdo {
observable closing_delay { 0 };
observable target_distance_measurement { -1 };
- std::vector distance_measurement{std::vector(10,-1)}; // the length of this vector determines how many in-range readings are required for presence detection to change states
+ std::vector distance_measurement { std::vector(10, -1) }; // the length of this vector determines how many in-range readings are required for presence detection to change states
observable last_distance_measurement { 0 };
observable openings { 0 }; // number of times the door has been opened
diff --git a/components/ratgdo/ratgdo_state.h b/components/ratgdo/ratgdo_state.h
index f541e6e..679cc8b 100644
--- a/components/ratgdo/ratgdo_state.h
+++ b/components/ratgdo/ratgdo_state.h
@@ -25,7 +25,7 @@ namespace ratgdo {
(STOPPED, 3),
(OPENING, 4),
(CLOSING, 5))
-
+
ENUM(DoorActionDelayed, uint8_t,
(NO, 0),
(YES, 1))
diff --git a/components/ratgdo/sensor/__init__.py b/components/ratgdo/sensor/__init__.py
index 70b44dd..d87d320 100644
--- a/components/ratgdo/sensor/__init__.py
+++ b/components/ratgdo/sensor/__init__.py
@@ -40,7 +40,7 @@ async def to_code(config):
await cg.register_component(var, config)
cg.add(var.set_ratgdo_sensor_type(config[CONF_TYPE]))
await register_ratgdo_child(var, config)
-
+
if config['type'] == 'distance':
cg.add_library(
name="Wire",
diff --git a/components/ratgdo/sensor/ratgdo_sensor.cpp b/components/ratgdo/sensor/ratgdo_sensor.cpp
index c79cfe6..e90017f 100644
--- a/components/ratgdo/sensor/ratgdo_sensor.cpp
+++ b/components/ratgdo/sensor/ratgdo_sensor.cpp
@@ -38,7 +38,7 @@ namespace ratgdo {
this->distance_sensor_.setI2cDevice(&I2C);
this->distance_sensor_.setXShutPin(32);
// I2C.begin(17,16);
- I2C.begin(19,18);
+ I2C.begin(19, 18);
this->distance_sensor_.begin();
this->distance_sensor_.VL53L4CX_Off();
this->distance_sensor_.InitSensor(0x59);
@@ -77,7 +77,7 @@ namespace ratgdo {
#ifdef USE_DISTANCE
if (this->ratgdo_sensor_type_ == RATGDOSensorType::RATGDO_DISTANCE) {
VL53L4CX_MultiRangingData_t distanceData;
- VL53L4CX_MultiRangingData_t *pDistanceData = &distanceData;
+ VL53L4CX_MultiRangingData_t* pDistanceData = &distanceData;
uint8_t dataReady = 0;
int objCount = 0;
int16_t maxDistance = 0;
@@ -86,15 +86,15 @@ namespace ratgdo {
if (this->distance_sensor_.VL53L4CX_GetMeasurementDataReady(&dataReady) == 0 && dataReady) {
status = this->distance_sensor_.VL53L4CX_GetMultiRangingData(pDistanceData);
objCount = pDistanceData->NumberOfObjectsFound;
-
+
maxDistance = objCount == 0 ? -1 : pDistanceData->RangeData[objCount - 1].RangeMilliMeter;
- /* if(maxDistance < 0) maxDistance = -1;
- * if the sensor is pointed at glass, there are many error readings which will fill the
+ /* if(maxDistance < 0) maxDistance = -1;
+ * if the sensor is pointed at glass, there are many error readings which will fill the
* vector with out of range data. The sensor should be sensitive enough to detect the floor
* in most situations, unless its mounted really far away.
* If this doesn't work, then the vector size will have to increase substantially
*/
- if(maxDistance > 0){
+ if (maxDistance > 0) {
this->parent_->set_distance_measurement(maxDistance);
}
diff --git a/components/ratgdo/sensor/ratgdo_sensor.h b/components/ratgdo/sensor/ratgdo_sensor.h
index cf405d4..d7cfdaf 100644
--- a/components/ratgdo/sensor/ratgdo_sensor.h
+++ b/components/ratgdo/sensor/ratgdo_sensor.h
@@ -6,9 +6,9 @@
#include "esphome/core/component.h"
#ifdef USE_DISTANCE
- #include "Wire.h"
- #include "vl53l4cx_class.h"
- #define I2C Wire
+#include "Wire.h"
+#include "vl53l4cx_class.h"
+#define I2C Wire
#endif
namespace esphome {
diff --git a/components/ratgdo/switch/__init__.py b/components/ratgdo/switch/__init__.py
index 786d9c8..c13265b 100644
--- a/components/ratgdo/switch/__init__.py
+++ b/components/ratgdo/switch/__init__.py
@@ -39,4 +39,3 @@ async def to_code(config):
if CONF_PIN in config:
pin = await cg.gpio_pin_expression(config[CONF_PIN])
cg.add(var.set_pin(pin))
-
diff --git a/components/ratgdo/switch/ratgdo_switch.cpp b/components/ratgdo/switch/ratgdo_switch.cpp
index 18a589a..11b85dd 100644
--- a/components/ratgdo/switch/ratgdo_switch.cpp
+++ b/components/ratgdo/switch/ratgdo_switch.cpp
@@ -21,7 +21,7 @@ namespace ratgdo {
this->parent_->subscribe_learn_state([=](LearnState state) {
this->publish_state(state == LearnState::ACTIVE);
});
- }else if(this->switch_type_ == SwitchType::RATGDO_LED) {
+ } else if (this->switch_type_ == SwitchType::RATGDO_LED) {
this->pin_->setup();
this->parent_->subscribe_vehicle_arriving_state([=](VehicleArrivingState state) {
this->write_state(state == VehicleArrivingState::YES);
@@ -37,7 +37,7 @@ namespace ratgdo {
} else {
this->parent_->inactivate_learn();
}
- } else if(this->switch_type_ == SwitchType::RATGDO_LED){
+ } else if (this->switch_type_ == SwitchType::RATGDO_LED) {
this->pin_->digital_write(state);
this->publish_state(state);
}
diff --git a/components/ratgdo/switch/ratgdo_switch.h b/components/ratgdo/switch/ratgdo_switch.h
index 8b195df..f4631c4 100644
--- a/components/ratgdo/switch/ratgdo_switch.h
+++ b/components/ratgdo/switch/ratgdo_switch.h
@@ -20,11 +20,11 @@ namespace ratgdo {
void set_switch_type(SwitchType switch_type_) { this->switch_type_ = switch_type_; }
void write_state(bool state) override;
- void set_pin(GPIOPin *pin) { pin_ = pin; }
+ void set_pin(GPIOPin* pin) { pin_ = pin; }
protected:
SwitchType switch_type_;
- GPIOPin *pin_;
+ GPIOPin* pin_;
};
} // namespace ratgdo
diff --git a/static/v32board.yaml b/static/v32board.yaml
index 2f9a0a3..743973f 100644
--- a/static/v32board.yaml
+++ b/static/v32board.yaml
@@ -62,4 +62,4 @@ improv_serial:
wifi:
ap:
-logger:
\ No newline at end of file
+logger:
diff --git a/static/v32board_drycontact.yaml b/static/v32board_drycontact.yaml
index 7f89fe7..e9df584 100644
--- a/static/v32board_drycontact.yaml
+++ b/static/v32board_drycontact.yaml
@@ -61,4 +61,4 @@ improv_serial:
wifi:
ap:
-logger:
\ No newline at end of file
+logger:
diff --git a/static/v32board_secplusv1.yaml b/static/v32board_secplusv1.yaml
index 2a0f75a..e433ae1 100644
--- a/static/v32board_secplusv1.yaml
+++ b/static/v32board_secplusv1.yaml
@@ -62,4 +62,4 @@ improv_serial:
wifi:
ap:
-logger:
\ No newline at end of file
+logger:
diff --git a/static/v32disco.yaml b/static/v32disco.yaml
index b850723..01b3307 100644
--- a/static/v32disco.yaml
+++ b/static/v32disco.yaml
@@ -149,4 +149,4 @@ sensor:
# - clamp:
# min_value: 0
# max_value: 100
- # unit_of_measurement: "%"
\ No newline at end of file
+ # unit_of_measurement: "%"
diff --git a/static/v32disco_drycontact.yaml b/static/v32disco_drycontact.yaml
index ab24738..a87f691 100644
--- a/static/v32disco_drycontact.yaml
+++ b/static/v32disco_drycontact.yaml
@@ -141,4 +141,4 @@ sensor:
filters:
- calibrate_linear:
- 1.16 -> 5
- - 2.783 -> 12
\ No newline at end of file
+ - 2.783 -> 12
diff --git a/static/v32disco_secplusv1.yaml b/static/v32disco_secplusv1.yaml
index 58ce207..bb80b95 100644
--- a/static/v32disco_secplusv1.yaml
+++ b/static/v32disco_secplusv1.yaml
@@ -142,4 +142,4 @@ sensor:
filters:
- calibrate_linear:
- 1.16 -> 5
- - 2.783 -> 12
\ No newline at end of file
+ - 2.783 -> 12
From be6ec93b3e9b1186db7e66de13c192186b2929f5 Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Sun, 10 Nov 2024 13:21:39 -0500
Subject: [PATCH 07/18] add branch
to be removed after merge
---
static/v32board.yaml | 1 +
static/v32board_drycontact.yaml | 1 +
static/v32board_secplusv1.yaml | 1 +
static/v32disco.yaml | 1 +
static/v32disco_drycontact.yaml | 1 +
static/v32disco_secplusv1.yaml | 1 +
6 files changed, 6 insertions(+)
diff --git a/static/v32board.yaml b/static/v32board.yaml
index 2f9a0a3..a0455d7 100644
--- a/static/v32board.yaml
+++ b/static/v32board.yaml
@@ -30,6 +30,7 @@ dashboard_import:
packages:
remote_package:
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
files: [base.yaml]
refresh: 1s
# remote_package: !include
diff --git a/static/v32board_drycontact.yaml b/static/v32board_drycontact.yaml
index 7f89fe7..daa3db1 100644
--- a/static/v32board_drycontact.yaml
+++ b/static/v32board_drycontact.yaml
@@ -29,6 +29,7 @@ dashboard_import:
packages:
remote_package:
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
files: [base_drycontact.yaml]
refresh: 1s
# remote_package: !include
diff --git a/static/v32board_secplusv1.yaml b/static/v32board_secplusv1.yaml
index 2a0f75a..e14b493 100644
--- a/static/v32board_secplusv1.yaml
+++ b/static/v32board_secplusv1.yaml
@@ -30,6 +30,7 @@ dashboard_import:
packages:
remote_package:
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
files: [base_secplusv1.yaml]
refresh: 1s
# remote_package: !include
diff --git a/static/v32disco.yaml b/static/v32disco.yaml
index b850723..138e093 100644
--- a/static/v32disco.yaml
+++ b/static/v32disco.yaml
@@ -30,6 +30,7 @@ dashboard_import:
packages:
remote_package:
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
files: [base.yaml]
refresh: 1s
# remote_package: !include
diff --git a/static/v32disco_drycontact.yaml b/static/v32disco_drycontact.yaml
index ab24738..b5b32ed 100644
--- a/static/v32disco_drycontact.yaml
+++ b/static/v32disco_drycontact.yaml
@@ -29,6 +29,7 @@ dashboard_import:
packages:
remote_package:
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
files: [base_drycontact.yaml]
refresh: 1s
# remote_package: !include
diff --git a/static/v32disco_secplusv1.yaml b/static/v32disco_secplusv1.yaml
index 58ce207..af533a3 100644
--- a/static/v32disco_secplusv1.yaml
+++ b/static/v32disco_secplusv1.yaml
@@ -30,6 +30,7 @@ dashboard_import:
packages:
remote_package:
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
files: [base_secplusv1.yaml]
refresh: 1s
# remote_package: !include
From ae8d1a3c2a4bb69a5ae56c72e5d04443bf44b98c Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Sun, 10 Nov 2024 13:47:47 -0500
Subject: [PATCH 08/18] add branch
roll back after merge
---
base.yaml | 1 +
base_drycontact.yaml | 1 +
base_secplusv1.yaml | 1 +
3 files changed, 3 insertions(+)
diff --git a/base.yaml b/base.yaml
index 79c4d64..895610d 100644
--- a/base.yaml
+++ b/base.yaml
@@ -3,6 +3,7 @@ external_components:
- source:
type: git
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
refresh: 1s
# - source:
# type: local
diff --git a/base_drycontact.yaml b/base_drycontact.yaml
index d683a54..8265070 100644
--- a/base_drycontact.yaml
+++ b/base_drycontact.yaml
@@ -4,6 +4,7 @@ external_components:
- source:
type: git
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
refresh: 1s
# - source:
# type: local
diff --git a/base_secplusv1.yaml b/base_secplusv1.yaml
index a1331f2..5266d0f 100644
--- a/base_secplusv1.yaml
+++ b/base_secplusv1.yaml
@@ -4,6 +4,7 @@ external_components:
- source:
type: git
url: https://github.com/ratgdo/esphome-ratgdo
+ ref: ratgdo32
refresh: 1s
# - source:
# type: local
From ee0f0bcabd7f6f0eb9aa018764dae4e77a3fc630 Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Sun, 10 Nov 2024 13:53:47 -0500
Subject: [PATCH 09/18] LED GPIO
---
static/v32board.yaml | 2 +-
static/v32board_drycontact.yaml | 2 +-
static/v32board_secplusv1.yaml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/static/v32board.yaml b/static/v32board.yaml
index c56d33c..b606582 100644
--- a/static/v32board.yaml
+++ b/static/v32board.yaml
@@ -41,7 +41,7 @@ switch:
ratgdo_id: ${id_prefix}
id: ${id_prefix}_led
type: led
- pin: GPIO4
+ pin: GPIO2
name: "LED"
entity_category: config
diff --git a/static/v32board_drycontact.yaml b/static/v32board_drycontact.yaml
index 5a7a365..746e1ed 100644
--- a/static/v32board_drycontact.yaml
+++ b/static/v32board_drycontact.yaml
@@ -40,7 +40,7 @@ switch:
ratgdo_id: ${id_prefix}
id: ${id_prefix}_led
type: led
- pin: GPIO4
+ pin: GPIO2
name: "LED"
entity_category: config
diff --git a/static/v32board_secplusv1.yaml b/static/v32board_secplusv1.yaml
index a47a8e3..87da7a2 100644
--- a/static/v32board_secplusv1.yaml
+++ b/static/v32board_secplusv1.yaml
@@ -41,7 +41,7 @@ switch:
ratgdo_id: ${id_prefix}
id: ${id_prefix}_led
type: led
- pin: GPIO4
+ pin: GPIO2
name: "LED"
entity_category: config
From 1f9b4a4682642ed2208a38628c7d8f4d4d5781eb Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Tue, 12 Nov 2024 12:18:40 -0500
Subject: [PATCH 10/18] temp switch gh pages to ratgdo32 branch
---
.github/workflows/build.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4ea2fa0..f9c30c9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -97,7 +97,7 @@ jobs:
consolidate:
- if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
+ if: github.event_name != 'pull_request' && github.ref == 'refs/heads/ratgdo32'
name: Consolidate firmwares
runs-on: ubuntu-latest
needs: build
@@ -119,7 +119,7 @@ jobs:
path: output
deploy:
- if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
+ if: github.event_name != 'pull_request' && github.ref == 'refs/heads/ratgdo32'
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
needs: consolidate
From 53a2589ba313277399ddbe44f3146e877a407b82 Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Tue, 12 Nov 2024 12:35:05 -0500
Subject: [PATCH 11/18] ratgdo32 branch
---
.github/workflows/build.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f9c30c9..19c19d1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -4,7 +4,7 @@ on:
workflow_dispatch:
push:
branches:
- - main
+ - ratgdo32
pull_request:
schedule:
- cron: '0 4 * * 1'
@@ -78,7 +78,7 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v3.3.0
- name: Build firmware
- uses: ratgdo/esphome-build-action@main
+ uses: ratgdo/esphome-build-action@ratgdo32
id: esphome-build
with:
yaml_file: ${{ matrix.firmware.file }}
From f0cf81b5dde71ad9bff7e0fdf42770b3b1dcf53a Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Tue, 12 Nov 2024 12:52:59 -0500
Subject: [PATCH 12/18] Update build.yml
---
.github/workflows/build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 19c19d1..fffa5a9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -78,7 +78,7 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v3.3.0
- name: Build firmware
- uses: ratgdo/esphome-build-action@ratgdo32
+ uses: ratgdo/esphome-build-action@main
id: esphome-build
with:
yaml_file: ${{ matrix.firmware.file }}
From e919ff53dac5cd8773a30c3392ab00365af03885 Mon Sep 17 00:00:00 2001
From: Paul Wieland
Date: Tue, 12 Nov 2024 13:06:36 -0500
Subject: [PATCH 13/18] Create ratgdo32_disco.jpg
---
static/ratgdo32_disco.jpg | Bin 0 -> 82739 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 static/ratgdo32_disco.jpg
diff --git a/static/ratgdo32_disco.jpg b/static/ratgdo32_disco.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2ff768345692b51ac18d582a7598e7d1487bad76
GIT binary patch
literal 82739
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