diff --git a/esphome/components/binary_sensor/__init__.py b/esphome/components/binary_sensor/__init__.py
index 9f92207b19..c391e12895 100644
--- a/esphome/components/binary_sensor/__init__.py
+++ b/esphome/components/binary_sensor/__init__.py
@@ -41,6 +41,7 @@ BinarySensorCondition = binary_sensor_ns.class_('BinarySensorCondition', Conditi
 
 # Filters
 Filter = binary_sensor_ns.class_('Filter')
+DelayedOnOffFilter = binary_sensor_ns.class_('DelayedOnOffFilter', Filter, cg.Component)
 DelayedOnFilter = binary_sensor_ns.class_('DelayedOnFilter', Filter, cg.Component)
 DelayedOffFilter = binary_sensor_ns.class_('DelayedOffFilter', Filter, cg.Component)
 InvertFilter = binary_sensor_ns.class_('InvertFilter', Filter)
@@ -55,6 +56,14 @@ def invert_filter_to_code(config, filter_id):
     yield cg.new_Pvariable(filter_id)
 
 
+@FILTER_REGISTRY.register('delayed_on_off', DelayedOnOffFilter,
+                          cv.positive_time_period_milliseconds)
+def delayed_on_off_filter_to_code(config, filter_id):
+    var = cg.new_Pvariable(filter_id, config)
+    yield cg.register_component(var, {})
+    yield var
+
+
 @FILTER_REGISTRY.register('delayed_on', DelayedOnFilter,
                           cv.positive_time_period_milliseconds)
 def delayed_on_filter_to_code(config, filter_id):
diff --git a/esphome/components/binary_sensor/filter.cpp b/esphome/components/binary_sensor/filter.cpp
index b7ac2c4a79..f4612d62e9 100644
--- a/esphome/components/binary_sensor/filter.cpp
+++ b/esphome/components/binary_sensor/filter.cpp
@@ -23,6 +23,19 @@ void Filter::input(bool value, bool is_initial) {
     this->output(*b, is_initial);
   }
 }
+
+DelayedOnOffFilter::DelayedOnOffFilter(uint32_t delay) : delay_(delay) {}
+optional<bool> DelayedOnOffFilter::new_value(bool value, bool is_initial) {
+  if (value) {
+    this->set_timeout("ON_OFF", this->delay_, [this, is_initial]() { this->output(true, is_initial); });
+  } else {
+    this->set_timeout("ON_OFF", this->delay_, [this, is_initial]() { this->output(false, is_initial); });
+  }
+  return {};
+}
+
+float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
+
 DelayedOnFilter::DelayedOnFilter(uint32_t delay) : delay_(delay) {}
 optional<bool> DelayedOnFilter::new_value(bool value, bool is_initial) {
   if (value) {
@@ -46,6 +59,7 @@ optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) {
     return true;
   }
 }
+
 float DelayedOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
 
 optional<bool> InvertFilter::new_value(bool value, bool is_initial) { return !value; }
diff --git a/esphome/components/binary_sensor/filter.h b/esphome/components/binary_sensor/filter.h
index d1e9a0d23a..0b54251cda 100644
--- a/esphome/components/binary_sensor/filter.h
+++ b/esphome/components/binary_sensor/filter.h
@@ -25,6 +25,18 @@ class Filter {
   Deduplicator<bool> dedup_;
 };
 
+class DelayedOnOffFilter : public Filter, public Component {
+ public:
+  explicit DelayedOnOffFilter(uint32_t delay);
+
+  optional<bool> new_value(bool value, bool is_initial) override;
+
+  float get_setup_priority() const override;
+
+ protected:
+  uint32_t delay_;
+};
+
 class DelayedOnFilter : public Filter, public Component {
  public:
   explicit DelayedOnFilter(uint32_t delay);