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