From 10efb461537fd51e9a168a08c1d779d4e03b9441 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Sun, 13 Aug 2023 21:16:41 +0200
Subject: [PATCH 01/10] Add additional registers for PCF85063A

---
 esphome/components/pcf85063/pcf85063.h | 52 +++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/esphome/components/pcf85063/pcf85063.h b/esphome/components/pcf85063/pcf85063.h
index 1a3fd70..cbe9e2a 100644
--- a/esphome/components/pcf85063/pcf85063.h
+++ b/esphome/components/pcf85063/pcf85063.h
@@ -7,6 +7,18 @@
 namespace esphome {
 namespace pcf85063 {
 
+enum PCF85063ATimerInterruptMode_t : bool {
+  TIMER_INTERRUPT_MODE_FLAG = 0,
+  TIMER_INTERRUPT_MODE_PULSE = 1,
+};
+
+enum PCF85063ATimerClockFrequency_t : uint8_t {
+  TIMER_CLOCK_4096HZ = 0,
+  TIMER_CLOCK_64HZ = 1,
+  TIMER_CLOCK_SECOND = 2,
+  TIMER_CLOCK_MINUTE = 3,
+};
+
 class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
  public:
   void setup() override;
@@ -68,7 +80,7 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
 
       // Weekdays register
       uint8_t weekday : 3;
-      uint8_t unused_3 : 5;
+      uint8_t : 5;
 
       // Months register
       uint8_t month : 4;
@@ -78,6 +90,44 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
       // Years register
       uint8_t year : 4;
       uint8_t year_10 : 4;
+
+      // PCF85063A Additional registers
+      // Second alarm
+      uint8_t alarm_second : 4;
+      uint8_t alarm_second_10 : 3;
+      bool alarm_second_enabled : 1;
+
+      // Minute alarm
+      uint8_t alarm_minute : 4;
+      uint8_t alarm_minute_10 : 3;
+      bool alarm_minute_enabled : 1;
+
+      // Hour alarm
+      uint8_t alarm_hour : 4;
+      uint8_t alarm_hour_10 : 2;
+      uint8_t : 1;
+      bool alarm_hour_enabled : 1;
+
+      // Day alarm
+      uint8_t alarm_day : 4;
+      uint8_t alarm_day_10 : 2;
+      uint8_t : 1;
+      bool alarm_day_enabled : 1;
+
+      // Weekday alarm
+      uint8_t alarm_weekday : 3;
+      uint8_t : 4;
+      bool alarm_weekday_enabled : 1;
+
+      // Timer value
+      uint8_t timer_value : 8;
+
+      // Timer mode
+      PCF85063ATimerInterruptMode_t timer_interrupt_mode : 1;
+      bool timer_interrupt_enable : 1;
+      bool timer_enable : 1;
+      PCF85063ATimerClockFrequency_t timer_clock_frequency : 2;
+      uint8_t : 3;
     } reg;
     mutable uint8_t raw[sizeof(reg)];
   } pcf85063_;

From e85874cccfb9c5dbb2ac26c75ee0fccfb3a3b5ea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Tue, 15 Aug 2023 22:11:47 +0200
Subject: [PATCH 02/10] Add functions to read and write the RAM byte

---
 esphome/components/pcf85063/pcf85063.cpp | 10 ++++++++++
 esphome/components/pcf85063/pcf85063.h   |  2 ++
 2 files changed, 12 insertions(+)

diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp
index debc007..941278d 100644
--- a/esphome/components/pcf85063/pcf85063.cpp
+++ b/esphome/components/pcf85063/pcf85063.cpp
@@ -81,6 +81,16 @@ void PCF85063Component::write_time() {
   this->write_rtc_();
 }
 
+void PCF85063Component::write_nvram(uint8_t data) {
+  this->pcf85063_.reg.nvram = data;
+  this->write_bytes(0x03, &this->pcf85063_.raw[0x03], 1);
+}
+
+uint8_t PCF85063Component::read_nvram() {
+  this->read_bytes(0x03, &this->pcf85063_.raw[0x03], 1);
+  return this->pcf85063_.reg.nvram;
+}
+
 bool PCF85063Component::read_rtc_() {
   if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
     ESP_LOGE(TAG, "Can't read I2C data.");
diff --git a/esphome/components/pcf85063/pcf85063.h b/esphome/components/pcf85063/pcf85063.h
index cbe9e2a..3d3589c 100644
--- a/esphome/components/pcf85063/pcf85063.h
+++ b/esphome/components/pcf85063/pcf85063.h
@@ -27,6 +27,8 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
   float get_setup_priority() const override;
   void read_time();
   void write_time();
+  void write_nvram(uint8_t);
+  uint8_t read_nvram();
 
  protected:
   bool read_rtc_();

From aa371c22a4a64d22e5ee75b47f8ab3d893a40439 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Thu, 17 Aug 2023 00:21:56 +0200
Subject: [PATCH 03/10] Add pcf85063.start_timer action

---
 esphome/components/pcf85063/pcf85063.cpp | 36 +++++++++++++++++++++++
 esphome/components/pcf85063/pcf85063.h   | 14 +++++++++
 esphome/components/pcf85063/time.py      | 37 +++++++++++++++++++++++-
 3 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp
index 941278d..da7d82d 100644
--- a/esphome/components/pcf85063/pcf85063.cpp
+++ b/esphome/components/pcf85063/pcf85063.cpp
@@ -91,6 +91,42 @@ uint8_t PCF85063Component::read_nvram() {
   return this->pcf85063_.reg.nvram;
 }
 
+/*
+  TIMER_CLOCK_MINUTE      60    15300     1m     4h15m
+  TIMER_CLOCK_SECOND       1      255     1s     4m15s
+*/
+bool PCF85063Component::set_timer_interval(uint16_t interval_seconds) {
+  if (interval_seconds < 256) {
+    pcf85063_.reg.timer_clock_frequency = TIMER_CLOCK_SECOND;
+    pcf85063_.reg.timer_value = interval_seconds;
+    pcf85063_.reg.timer_enable = true;
+    return this->write_timer_();
+  } else if (interval_seconds > 15300) {
+    ESP_LOGE(TAG, "Specified interval is longer than max allowed, clamping to 4h15m.");
+    interval_seconds = 15300;
+  }
+  div_t dm = div(interval_seconds, 60);
+  if (dm.rem) {
+    ESP_LOGI(TAG, "Interval out of seconds range, rounding down to closest whole minute.");
+  }
+  
+  pcf85063_.reg.timer_clock_frequency = TIMER_CLOCK_MINUTE;
+  pcf85063_.reg.timer_value = dm.quot;
+  pcf85063_.reg.timer_enable = true;
+  return this->write_timer_();
+}
+
+bool PCF85063Component::write_timer_() {
+  if (!this->write_bytes(0x10, &this->pcf85063_.raw[0x03], 2)) {
+    ESP_LOGE(TAG, "Can't write I2C data.");
+    return false;
+  }
+  ESP_LOGD(TAG, "Write timer %s %0u CLOCK=%0u IR=%s %0u",
+           ONOFF(pcf85063_.reg.timer_enable), pcf85063_.reg.timer_value, pcf85063_.reg.timer_clock_frequency,
+           ONOFF(pcf85063_.reg.timer_interrupt_enable), pcf85063_.reg.timer_interrupt_mode);
+  return true;
+}
+
 bool PCF85063Component::read_rtc_() {
   if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
     ESP_LOGE(TAG, "Can't read I2C data.");
diff --git a/esphome/components/pcf85063/pcf85063.h b/esphome/components/pcf85063/pcf85063.h
index 3d3589c..48e830d 100644
--- a/esphome/components/pcf85063/pcf85063.h
+++ b/esphome/components/pcf85063/pcf85063.h
@@ -30,7 +30,11 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
   void write_nvram(uint8_t);
   uint8_t read_nvram();
 
+  bool set_timer_interval(uint16_t interval);
+
+
  protected:
+  bool write_timer_();
   bool read_rtc_();
   bool write_rtc_();
   union PCF85063Reg {
@@ -135,6 +139,16 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
   } pcf85063_;
 };
 
+template<typename... Ts> class StartTimerAction : public Action<Ts...>, public Parented<PCF85063Component> {
+ public:
+  TEMPLATABLE_VALUE(uint16_t, timer_seconds);
+  void play(Ts... x) override {
+    this->parent_->pcf85063_.reg.timer_interrupt_enable = true;
+    this->parent_->pcf85063_.reg.timer_interrupt_mode = TIMER_INTERRUPT_MODE_FLAG;
+    this->parent_->set_timer_interval(this->timer_seconds_.value(x...));
+  }
+};
+
 template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<PCF85063Component> {
  public:
   void play(Ts... x) override { this->parent_->write_time(); }
diff --git a/esphome/components/pcf85063/time.py b/esphome/components/pcf85063/time.py
index 67ec230..43a9a06 100644
--- a/esphome/components/pcf85063/time.py
+++ b/esphome/components/pcf85063/time.py
@@ -2,7 +2,7 @@ import esphome.config_validation as cv
 import esphome.codegen as cg
 from esphome import automation
 from esphome.components import i2c, time
-from esphome.const import CONF_ID
+from esphome.const import CONF_ID, CONF_INTERVAL
 
 
 CODEOWNERS = ["@brogon"]
@@ -13,6 +13,7 @@ PCF85063Component = pcf85063_ns.class_(
 )
 WriteAction = pcf85063_ns.class_("WriteAction", automation.Action)
 ReadAction = pcf85063_ns.class_("ReadAction", automation.Action)
+StartTimerAction = pcf85063_ns.class_("StartTimerAction", automation.Action)
 
 
 CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
@@ -52,6 +53,40 @@ async def pcf85063_read_time_to_code(config, action_id, template_arg, args):
     return var
 
 
+def validate_timer_seconds(value):
+    value: cv.TimePeriodSeconds = cv.positive_time_period_seconds(value)
+    min_interval = cv.TimePeriod(seconds=1)
+    max_interval = cv.TimePeriod(minutes=255)
+
+    if value < min_interval:
+        raise cv.Invalid(
+            f"This timer interval is not possible, please choose a larger interval (at least {min_interval})"
+        )
+    if value > max_interval:
+        raise cv.Invalid(
+            f"This timer interval is not possible, please choose a lower interval (at most {max_interval})"
+        )
+    return value
+
+@automation.register_action(
+    "pcf85063.start_timer",
+    StartTimerAction,
+    cv.Schema(
+        {
+            cv.GenerateID(): cv.use_id(PCF85063Component),
+            cv.Required(CONF_INTERVAL): cv.templatable(validate_timer_seconds),
+        }
+    ),
+)
+async def pcf85063_start_timer_to_code(config, action_id, template_arg, args):
+    var = cg.new_Pvariable(action_id, template_arg)
+
+    template_ = await cg.templatable(config[CONF_INTERVAL], args, cv.TimePeriodSeconds)
+    cg.add(var.start_timer(template_))
+
+    await cg.register_parented(var, config[CONF_ID])
+    return var
+
 async def to_code(config):
     var = cg.new_Pvariable(config[CONF_ID])
 

From 7c3016349bd6b1b2dded1f85761ebfd161b62646 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Thu, 17 Aug 2023 19:10:44 +0000
Subject: [PATCH 04/10] Fix pcf85063.start_timer action

---
 esphome/components/pcf85063/pcf85063.cpp | 18 +++++++++++++-----
 esphome/components/pcf85063/pcf85063.h   | 11 +++++++----
 esphome/components/pcf85063/time.py      |  4 ++--
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp
index da7d82d..c0825d9 100644
--- a/esphome/components/pcf85063/pcf85063.cpp
+++ b/esphome/components/pcf85063/pcf85063.cpp
@@ -82,20 +82,20 @@ void PCF85063Component::write_time() {
 }
 
 void PCF85063Component::write_nvram(uint8_t data) {
-  this->pcf85063_.reg.nvram = data;
-  this->write_bytes(0x03, &this->pcf85063_.raw[0x03], 1);
+  pcf85063_.reg.nvram = data;
+  this->write_bytes(0x03, &pcf85063_.raw[0x03], 1);
 }
 
 uint8_t PCF85063Component::read_nvram() {
-  this->read_bytes(0x03, &this->pcf85063_.raw[0x03], 1);
-  return this->pcf85063_.reg.nvram;
+  this->read_bytes(0x03, &pcf85063_.raw[0x03], 1);
+  return pcf85063_.reg.nvram;
 }
 
 /*
   TIMER_CLOCK_MINUTE      60    15300     1m     4h15m
   TIMER_CLOCK_SECOND       1      255     1s     4m15s
 */
-bool PCF85063Component::set_timer_interval(uint16_t interval_seconds) {
+bool PCF85063Component::write_timer_interval(uint16_t interval_seconds) {
   if (interval_seconds < 256) {
     pcf85063_.reg.timer_clock_frequency = TIMER_CLOCK_SECOND;
     pcf85063_.reg.timer_value = interval_seconds;
@@ -116,6 +116,14 @@ bool PCF85063Component::set_timer_interval(uint16_t interval_seconds) {
   return this->write_timer_();
 }
 
+void PCF85063Component::set_timer_interrupt_enable_(bool state) {
+  pcf85063_.reg.timer_interrupt_enable = state;
+}
+
+void PCF85063Component::set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t mode) {
+  pcf85063_.reg.timer_interrupt_mode = mode;
+}
+
 bool PCF85063Component::write_timer_() {
   if (!this->write_bytes(0x10, &this->pcf85063_.raw[0x03], 2)) {
     ESP_LOGE(TAG, "Can't write I2C data.");
diff --git a/esphome/components/pcf85063/pcf85063.h b/esphome/components/pcf85063/pcf85063.h
index 48e830d..036d783 100644
--- a/esphome/components/pcf85063/pcf85063.h
+++ b/esphome/components/pcf85063/pcf85063.h
@@ -30,7 +30,10 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
   void write_nvram(uint8_t);
   uint8_t read_nvram();
 
-  bool set_timer_interval(uint16_t interval);
+  //bool set_timer_interval_us(uint64_t interval_us);
+  bool write_timer_interval(uint16_t interval);
+  void set_timer_interrupt_enable_(bool state);
+  void set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t mode);
 
 
  protected:
@@ -143,9 +146,9 @@ template<typename... Ts> class StartTimerAction : public Action<Ts...>, public P
  public:
   TEMPLATABLE_VALUE(uint16_t, timer_seconds);
   void play(Ts... x) override {
-    this->parent_->pcf85063_.reg.timer_interrupt_enable = true;
-    this->parent_->pcf85063_.reg.timer_interrupt_mode = TIMER_INTERRUPT_MODE_FLAG;
-    this->parent_->set_timer_interval(this->timer_seconds_.value(x...));
+    this->parent_->set_timer_interrupt_enable_(true);
+    this->parent_->set_timer_interrupt_mode_(TIMER_INTERRUPT_MODE_FLAG);
+    this->parent_->write_timer_interval(this->timer_seconds_.value(x...));
   }
 };
 
diff --git a/esphome/components/pcf85063/time.py b/esphome/components/pcf85063/time.py
index 43a9a06..4386cd5 100644
--- a/esphome/components/pcf85063/time.py
+++ b/esphome/components/pcf85063/time.py
@@ -81,8 +81,8 @@ def validate_timer_seconds(value):
 async def pcf85063_start_timer_to_code(config, action_id, template_arg, args):
     var = cg.new_Pvariable(action_id, template_arg)
 
-    template_ = await cg.templatable(config[CONF_INTERVAL], args, cv.TimePeriodSeconds)
-    cg.add(var.start_timer(template_))
+    #template_ = await cg.templatable(config[CONF_INTERVAL], args, cv.TimePeriodSeconds)
+    #cg.add(var.timer_seconds_(template_))
 
     await cg.register_parented(var, config[CONF_ID])
     return var

From d98d1cabd5b27dbc24e9dff72311434aa96a5685 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Thu, 17 Aug 2023 22:04:40 +0000
Subject: [PATCH 05/10] Fix setting pcf85063.start_timer action variable

---
 esphome/components/pcf85063/time.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/esphome/components/pcf85063/time.py b/esphome/components/pcf85063/time.py
index 4386cd5..75cd96a 100644
--- a/esphome/components/pcf85063/time.py
+++ b/esphome/components/pcf85063/time.py
@@ -81,8 +81,8 @@ def validate_timer_seconds(value):
 async def pcf85063_start_timer_to_code(config, action_id, template_arg, args):
     var = cg.new_Pvariable(action_id, template_arg)
 
-    #template_ = await cg.templatable(config[CONF_INTERVAL], args, cv.TimePeriodSeconds)
-    #cg.add(var.timer_seconds_(template_))
+    template_ = await cg.templatable(config[CONF_INTERVAL], args, cv.TimePeriodSeconds)
+    cg.add(var.set_timer_seconds(template_))
 
     await cg.register_parented(var, config[CONF_ID])
     return var

From 95cf42732efedff753d3eb86e5379ce9bef54fc6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Sun, 20 Aug 2023 02:17:31 +0000
Subject: [PATCH 06/10] Correct write_timer_ source data address

---
 esphome/components/pcf85063/pcf85063.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp
index c0825d9..b402f6e 100644
--- a/esphome/components/pcf85063/pcf85063.cpp
+++ b/esphome/components/pcf85063/pcf85063.cpp
@@ -125,7 +125,7 @@ void PCF85063Component::set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t
 }
 
 bool PCF85063Component::write_timer_() {
-  if (!this->write_bytes(0x10, &this->pcf85063_.raw[0x03], 2)) {
+  if (!this->write_bytes(0x10, &this->pcf85063_.raw[0x10], 2)) {
     ESP_LOGE(TAG, "Can't write I2C data.");
     return false;
   }

From dca13dd292856ece18438006ea182637316de4a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Sun, 20 Aug 2023 03:14:01 +0000
Subject: [PATCH 07/10] Implement pcf85063 clear_timer_flag, clear_alarm_flag
 and clockout_frequency

---
 esphome/components/pcf85063/pcf85063.cpp | 38 +++++++++++--
 esphome/components/pcf85063/pcf85063.h   | 21 ++++++++
 esphome/components/pcf85063/time.py      | 68 +++++++++++++++++++++++-
 3 files changed, 121 insertions(+), 6 deletions(-)

diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp
index b402f6e..7abb243 100644
--- a/esphome/components/pcf85063/pcf85063.cpp
+++ b/esphome/components/pcf85063/pcf85063.cpp
@@ -116,6 +116,39 @@ bool PCF85063Component::write_timer_interval(uint16_t interval_seconds) {
   return this->write_timer_();
 }
 
+#define PCF85063_READ_REG(reg, len) \
+  if (!this->read_bytes(reg, &this->pcf85063_.raw[reg], len)) { \
+    ESP_LOGE(TAG, "Can't read I2C data."); \
+    return false; \
+  }
+
+#define PCF85063_WRITE_REG(reg, len) \
+  if (!this->write_bytes(reg, &this->pcf85063_.raw[reg], len)) { \
+    ESP_LOGE(TAG, "Can't write I2C data."); \
+    return false; \
+  }
+
+bool PCF85063Component::clear_timer_flag() {
+  PCF85063_READ_REG(0x01, 1);
+  this->pcf85063_.reg.timer_flag = 0;
+  PCF85063_WRITE_REG(0x01, 1);
+  return true;
+}
+
+bool PCF85063Component::clear_alarm_flag() {
+  PCF85063_READ_REG(0x01, 1);
+  this->pcf85063_.reg.alarm_flag = 0;
+  PCF85063_WRITE_REG(0x01, 1);
+  return true;
+}
+
+bool PCF85063Component::write_clockout_frequency(uint8_t freq) {
+  PCF85063_READ_REG(0x01, 1);
+  this->pcf85063_.reg.clkout_control = freq & 0b111;
+  PCF85063_WRITE_REG(0x01, 1);
+  return true;
+}
+
 void PCF85063Component::set_timer_interrupt_enable_(bool state) {
   pcf85063_.reg.timer_interrupt_enable = state;
 }
@@ -125,10 +158,7 @@ void PCF85063Component::set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t
 }
 
 bool PCF85063Component::write_timer_() {
-  if (!this->write_bytes(0x10, &this->pcf85063_.raw[0x10], 2)) {
-    ESP_LOGE(TAG, "Can't write I2C data.");
-    return false;
-  }
+  PCF85063_WRITE_REG(0x10, 2);
   ESP_LOGD(TAG, "Write timer %s %0u CLOCK=%0u IR=%s %0u",
            ONOFF(pcf85063_.reg.timer_enable), pcf85063_.reg.timer_value, pcf85063_.reg.timer_clock_frequency,
            ONOFF(pcf85063_.reg.timer_interrupt_enable), pcf85063_.reg.timer_interrupt_mode);
diff --git a/esphome/components/pcf85063/pcf85063.h b/esphome/components/pcf85063/pcf85063.h
index 036d783..3643764 100644
--- a/esphome/components/pcf85063/pcf85063.h
+++ b/esphome/components/pcf85063/pcf85063.h
@@ -32,6 +32,9 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
 
   //bool set_timer_interval_us(uint64_t interval_us);
   bool write_timer_interval(uint16_t interval);
+  bool clear_timer_flag();
+  bool clear_alarm_flag();
+  bool write_clockout_frequency(uint8_t freq);
   void set_timer_interrupt_enable_(bool state);
   void set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t mode);
 
@@ -152,6 +155,24 @@ template<typename... Ts> class StartTimerAction : public Action<Ts...>, public P
   }
 };
 
+template<typename... Ts> class SetClockoutFrequencyAction : public Action<Ts...>, public Parented<PCF85063Component> {
+ public:
+  TEMPLATABLE_VALUE(uint8_t, freq);
+  void play(Ts... x) override {
+    this->parent_->write_clockout_frequency(this->freq_.value(x...));
+  }
+};
+
+template<typename... Ts> class ClearTimerFlagAction : public Action<Ts...>, public Parented<PCF85063Component> {
+ public:
+  void play(Ts... x) override { this->parent_->clear_timer_flag(); }
+};
+
+template<typename... Ts> class ClearAlarmFlagAction : public Action<Ts...>, public Parented<PCF85063Component> {
+ public:
+  void play(Ts... x) override { this->parent_->clear_alarm_flag(); }
+};
+
 template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<PCF85063Component> {
  public:
   void play(Ts... x) override { this->parent_->write_time(); }
diff --git a/esphome/components/pcf85063/time.py b/esphome/components/pcf85063/time.py
index 75cd96a..14c7637 100644
--- a/esphome/components/pcf85063/time.py
+++ b/esphome/components/pcf85063/time.py
@@ -2,7 +2,7 @@ import esphome.config_validation as cv
 import esphome.codegen as cg
 from esphome import automation
 from esphome.components import i2c, time
-from esphome.const import CONF_ID, CONF_INTERVAL
+from esphome.const import CONF_ID, CONF_INTERVAL, CONF_VALUE
 
 
 CODEOWNERS = ["@brogon"]
@@ -14,7 +14,9 @@ PCF85063Component = pcf85063_ns.class_(
 WriteAction = pcf85063_ns.class_("WriteAction", automation.Action)
 ReadAction = pcf85063_ns.class_("ReadAction", automation.Action)
 StartTimerAction = pcf85063_ns.class_("StartTimerAction", automation.Action)
-
+ClearTimerFlagAction = pcf85063_ns.class_("ClearTimerFlagAction", automation.Action)
+ClearAlarmFlagAction = pcf85063_ns.class_("ClearAlarmFlagAction", automation.Action)
+SetClockoutFrequencyAction = pcf85063_ns.class_("SetClockoutFrequencyAction", automation.Action)
 
 CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
     {
@@ -22,6 +24,7 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
     }
 ).extend(i2c.i2c_device_schema(0x51))
 
+#####
 
 @automation.register_action(
     "pcf85063.write_time",
@@ -37,6 +40,7 @@ async def pcf85063_write_time_to_code(config, action_id, template_arg, args):
     await cg.register_parented(var, config[CONF_ID])
     return var
 
+#####
 
 @automation.register_action(
     "pcf85063.read_time",
@@ -52,6 +56,7 @@ async def pcf85063_read_time_to_code(config, action_id, template_arg, args):
     await cg.register_parented(var, config[CONF_ID])
     return var
 
+#####
 
 def validate_timer_seconds(value):
     value: cv.TimePeriodSeconds = cv.positive_time_period_seconds(value)
@@ -87,6 +92,65 @@ async def pcf85063_start_timer_to_code(config, action_id, template_arg, args):
     await cg.register_parented(var, config[CONF_ID])
     return var
 
+#####
+
+def validate_clockout_frequency(value):
+    value = cv.int_range(0b000, 0b111)(value)
+    return value
+
+@automation.register_action(
+    "pcf85063.clockout_frequency",
+    SetClockoutFrequencyAction,
+    cv.Schema(
+        {
+            cv.GenerateID(): cv.use_id(PCF85063Component),
+            cv.Required(CONF_VALUE): cv.templatable(validate_clockout_frequency),
+        }
+    ),
+)
+async def pcf85063_clockout_frequency_to_code(config, action_id, template_arg, args):
+    var = cg.new_Pvariable(action_id, template_arg)
+
+    template_ = await cg.templatable(config[CONF_VALUE], args, type(int))
+    cg.add(var.set_freq(template_))
+
+    await cg.register_parented(var, config[CONF_ID])
+    return var
+
+#####
+
+@automation.register_action(
+    "pcf85063.clear_timer_flag",
+    ClearTimerFlagAction,
+    cv.Schema(
+        {
+            cv.GenerateID(): cv.use_id(PCF85063Component),
+        }
+    ),
+)
+async def pcf85063_clear_timer_flag_to_code(config, action_id, template_arg, args):
+    var = cg.new_Pvariable(action_id, template_arg)
+    await cg.register_parented(var, config[CONF_ID])
+    return var
+
+#####
+
+@automation.register_action(
+    "pcf85063.clear_alarm_flag",
+    ClearAlarmFlagAction,
+    cv.Schema(
+        {
+            cv.GenerateID(): cv.use_id(PCF85063Component),
+        }
+    ),
+)
+async def pcf85063_clear_alarm_flag_to_code(config, action_id, template_arg, args):
+    var = cg.new_Pvariable(action_id, template_arg)
+    await cg.register_parented(var, config[CONF_ID])
+    return var
+
+#####
+
 async def to_code(config):
     var = cg.new_Pvariable(config[CONF_ID])
 

From ec8acc051c0ad96a55d271c91a55e1e95e00215b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Tue, 12 Sep 2023 22:48:20 +0000
Subject: [PATCH 08/10] pcf85063: Add stop_timer method

---
 esphome/components/pcf85063/pcf85063.cpp | 7 +++++++
 esphome/components/pcf85063/pcf85063.h   | 1 +
 2 files changed, 8 insertions(+)

diff --git a/esphome/components/pcf85063/pcf85063.cpp b/esphome/components/pcf85063/pcf85063.cpp
index 7abb243..102f329 100644
--- a/esphome/components/pcf85063/pcf85063.cpp
+++ b/esphome/components/pcf85063/pcf85063.cpp
@@ -135,6 +135,13 @@ bool PCF85063Component::clear_timer_flag() {
   return true;
 }
 
+bool PCF85063Component::stop_timer() {
+  PCF85063_READ_REG(0x11, 1);
+  this->pcf85063_.reg.timer_enable = false;
+  PCF85063_WRITE_REG(0x11, 1);
+  return true;
+}
+
 bool PCF85063Component::clear_alarm_flag() {
   PCF85063_READ_REG(0x01, 1);
   this->pcf85063_.reg.alarm_flag = 0;
diff --git a/esphome/components/pcf85063/pcf85063.h b/esphome/components/pcf85063/pcf85063.h
index 3643764..c5e3272 100644
--- a/esphome/components/pcf85063/pcf85063.h
+++ b/esphome/components/pcf85063/pcf85063.h
@@ -34,6 +34,7 @@ class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice {
   bool write_timer_interval(uint16_t interval);
   bool clear_timer_flag();
   bool clear_alarm_flag();
+  bool stop_timer();
   bool write_clockout_frequency(uint8_t freq);
   void set_timer_interrupt_enable_(bool state);
   void set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t mode);

From 152a88ee5867f13868d4321b61a9a056eafe53f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Tue, 12 Sep 2023 22:57:36 +0000
Subject: [PATCH 09/10] Add devcontainer including picoprobe openocd

---
 .devcontainer/devcontainer.json     | 78 +++++++++++++++++++++++++++++
 .gitignore                          |  6 +++
 .vscode/c_cpp_properties.json       | 17 +++++++
 .vscode/launch.json                 | 41 +++++++++++++++
 .vscode/settings.json               |  8 +++
 openshell-components.code-workspace | 27 ++++++++++
 requirements.txt                    |  1 +
 7 files changed, 178 insertions(+)
 create mode 100644 .devcontainer/devcontainer.json
 create mode 100644 .gitignore
 create mode 100644 .vscode/c_cpp_properties.json
 create mode 100644 .vscode/launch.json
 create mode 100644 .vscode/settings.json
 create mode 100644 openshell-components.code-workspace
 create mode 100644 requirements.txt

diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..17c7c71
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,78 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/python
+{
+	"name": "Python 3",
+	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
+	"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bookworm",
+
+	// Features to add to the dev container. More info: https://containers.dev/features.
+	// "features": {},
+	"features": {
+		"ghcr.io/devcontainers-contrib/features/apt-get-packages:1": {
+			"packages": "usbutils,libusb-1.0,texinfo,libftdi1,libtinfo5,gdb-arm-none-eabi,gcc-arm-none-eabi,cmake"
+		}
+	},
+
+	// Use 'forwardPorts' to make a list of ports inside the container available locally.
+	// "forwardPorts": [],
+	
+	"runArgs": [
+		"-v", "/dev/bus/usb:/dev/bus/usb", 
+		"-v", "/usr/lib/udev/hwdb.bin:/usr/lib/udev/hwdb.bin:ro", 
+		"-v", "/lib/udev/hwdb.bin:/lib/udev/hwdb.bin:ro", 
+		"-v", "/usr/share/hwdata/usb.ids:/usr/share/hwdata/usb.ids:ro", 
+		"-v", "/run/udev:/run/udev", 
+		"-v", "/sys:/sys:ro",
+		"--privileged",
+		"--device-cgroup-rule", "c 188:* rmw",
+		"--device-cgroup-rule", "c 166:* rmw"
+	],
+
+	"mounts": [
+		{
+			"source": "${localWorkspaceFolder}/../esphome",
+			"target": "${containerWorkspaceFolder}/../esphome",
+			"type": "bind"
+		},
+		{
+			"source": "${localEnv:HOME}/.platformio",
+			"target": "/home/vscode/.platformio",
+			"type": "bind"
+		},
+		{
+			"source": "${localWorkspaceFolder}/../rp2040",
+			"target": "${containerWorkspaceFolder}/../rp2040",
+			"type": "bind"
+		},
+		{
+			"source": "/opt/openocd-rp2040",
+			"target": "/opt/openocd-rp2040",
+			"type": "bind"
+		}
+	],
+
+	// Use 'postCreateCommand' to run commands after the container is created.
+	"postCreateCommand": "pip3 install -r requirements.txt",
+
+	// Configure tool-specific properties.
+	"customizations": {
+		"vscode": {
+			"extensions": [
+				"ms-vscode.cpptools-extension-pack",
+				"jbenden.c-cpp-flylint",
+				"ESPHome.esphome-vscode",
+				"ms-python.vscode-pylance",
+				"marus25.cortex-debug",
+				"ms-vscode.cpptools",
+				"ms-vscode.cmake-tools",
+				"mikestead.dotenv",
+				"ZixuanWang.linkerscript",
+				"alefragnani.Bookmarks",
+				"ciprianelies.arm-assembly-syntax"
+			]
+		}
+	},
+
+	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+	// "remoteUser": "root"
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b639a65
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Gitignore settings for ESPHome
+# This is an example and may include too much for your use-case.
+# You can modify this file to suit your needs.
+/.esphome/
+/secrets.yaml
+*.py[ocd]
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..5239be6
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,17 @@
+{
+    "configurations": [
+        {
+            "name": "Linux",
+            "includePath": [
+                "${workspaceFolder}/**",
+                "${workspaceFolder}/../esphome/"
+            ],
+            "defines": ["USE_RP2040"],
+            "compilerPath": "/usr/bin/gcc",
+            "cStandard": "c11",
+            "cppStandard": "gnu++14",
+            "intelliSenseMode": "linux-gcc-x64"
+        }
+    ],
+    "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..7a62736
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,41 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Pico Debug (Cortex-Debug)",
+            "cwd": "${workspaceRoot}",
+            "executable": "${workspaceRoot}/.esphome/build/enviro-weather/.pioenvs/enviro-weather/firmware.elf",
+            "request": "launch",
+            "type": "cortex-debug",
+            "servertype": "openocd",
+            "device": "RP2040",
+            "runToEntryPoint": "main",
+            "configFiles": [
+                "interface/cmsis-dap.cfg",
+                "target/rp2040.cfg"
+            ],
+            "openOCDLaunchCommands": [
+                "adapter speed 5000"
+            ],
+            "searchDir": ["/opt/openocd-rp2040/share/openocd/scripts"],
+            "svdFile": "/workspaces/rp2040/pico-sdk/src/rp2040/hardware_regs/rp2040.svd",
+            "gdbPath": "gdb-multiarch"
+        },
+        {
+            "name": "Pico Debug (Cortex-Debug with external OpenOCD)",
+            "cwd": "${workspaceRoot}",
+            "executable": "${workspaceRoot}/.esphome/build/enviro-weather/.pioenvs/enviro-weather/firmware.elf",
+            "request": "launch",
+            "type": "cortex-debug",
+            "servertype": "external",
+            "gdbTarget": "localhost:3333",
+            "device": "RP2040",
+            "runToEntryPoint": "main",
+            "svdFile": "/workspaces/rp2040/pico-sdk/src/rp2040/hardware_regs/rp2040.svd",
+            "showDevDebugOutput": "raw"
+        },
+    ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..a3b08b1
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,8 @@
+{
+    "search.exclude": {
+        "**/node_modules": true,
+        "**/bower_components": true,
+        "**/*.code-search": true,
+        ".esphome": true,
+    },
+}
\ No newline at end of file
diff --git a/openshell-components.code-workspace b/openshell-components.code-workspace
new file mode 100644
index 0000000..808e0f9
--- /dev/null
+++ b/openshell-components.code-workspace
@@ -0,0 +1,27 @@
+{
+	"folders": [
+		{
+			"path": "."
+		},
+		{
+			"path": "../rp2040"
+		},
+		{
+			"path": "../esphome"
+		}
+	],
+	"settings": {
+		"c-cpp-flylint.flexelint.enable": false,
+		"c-cpp-flylint.lizard.enable": false,
+		"c-cpp-flylint.flawfinder.enable": false,
+		"files.associations": {
+			"*.tmpl": "jinja",
+			"*.txt": "plaintext",
+			"memory": "cpp",
+			"istream": "cpp",
+			"ostream": "cpp"
+		},
+		"cortex-debug.openocdPath": "/opt/openocd-rp2040/bin/openocd",
+		//"cortex-debug.gdbPath": "/workspaces/rp2040/system/arm-none-eabi/bin/arm-none-eabi-gdb",
+	}
+}
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..c8d0acb
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+-e ../esphome
\ No newline at end of file

From 2e6eed2ee8569a592ce151b98c4dcbc3edfecfe1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= <oddstr13@openshell.no>
Date: Sun, 17 Sep 2023 21:41:11 +0000
Subject: [PATCH 10/10] Avoid shadowing for linters

---
 {esphome/components => components}/pcf85063/__init__.py  | 0
 {esphome/components => components}/pcf85063/pcf85063.cpp | 0
 {esphome/components => components}/pcf85063/pcf85063.h   | 0
 {esphome/components => components}/pcf85063/time.py      | 0
 4 files changed, 0 insertions(+), 0 deletions(-)
 rename {esphome/components => components}/pcf85063/__init__.py (100%)
 rename {esphome/components => components}/pcf85063/pcf85063.cpp (100%)
 rename {esphome/components => components}/pcf85063/pcf85063.h (100%)
 rename {esphome/components => components}/pcf85063/time.py (100%)

diff --git a/esphome/components/pcf85063/__init__.py b/components/pcf85063/__init__.py
similarity index 100%
rename from esphome/components/pcf85063/__init__.py
rename to components/pcf85063/__init__.py
diff --git a/esphome/components/pcf85063/pcf85063.cpp b/components/pcf85063/pcf85063.cpp
similarity index 100%
rename from esphome/components/pcf85063/pcf85063.cpp
rename to components/pcf85063/pcf85063.cpp
diff --git a/esphome/components/pcf85063/pcf85063.h b/components/pcf85063/pcf85063.h
similarity index 100%
rename from esphome/components/pcf85063/pcf85063.h
rename to components/pcf85063/pcf85063.h
diff --git a/esphome/components/pcf85063/time.py b/components/pcf85063/time.py
similarity index 100%
rename from esphome/components/pcf85063/time.py
rename to components/pcf85063/time.py