mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	PCF85063 RTC chip (#3873)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -167,6 +167,7 @@ esphome/components/number/* @esphome/core | |||||||
| esphome/components/ota/* @esphome/core | esphome/components/ota/* @esphome/core | ||||||
| esphome/components/output/* @esphome/core | esphome/components/output/* @esphome/core | ||||||
| esphome/components/pca9554/* @hwstar | esphome/components/pca9554/* @hwstar | ||||||
|  | esphome/components/pcf85063/* @brogon | ||||||
| esphome/components/pid/* @OttoWinter | esphome/components/pid/* @OttoWinter | ||||||
| esphome/components/pipsolar/* @andreashergert1984 | esphome/components/pipsolar/* @andreashergert1984 | ||||||
| esphome/components/pm1006/* @habbie | esphome/components/pm1006/* @habbie | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								esphome/components/pcf85063/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/pcf85063/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										105
									
								
								esphome/components/pcf85063/pcf85063.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								esphome/components/pcf85063/pcf85063.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | |||||||
|  | #include "pcf85063.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | // Datasheet: | ||||||
|  | // - https://datasheets.maximintegrated.com/en/ds/DS1307.pdf | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace pcf85063 { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "pcf85063"; | ||||||
|  |  | ||||||
|  | void PCF85063Component::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up PCF85063..."); | ||||||
|  |   if (!this->read_rtc_()) { | ||||||
|  |     this->mark_failed(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PCF85063Component::update() { this->read_time(); } | ||||||
|  |  | ||||||
|  | void PCF85063Component::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "PCF85063:"); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Communication with PCF85063 failed!"); | ||||||
|  |   } | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Timezone: '%s'", this->timezone_.c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float PCF85063Component::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  | void PCF85063Component::read_time() { | ||||||
|  |   if (!this->read_rtc_()) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (pcf85063_.reg.osc_stop) { | ||||||
|  |     ESP_LOGW(TAG, "RTC halted, not syncing to system clock."); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   time::ESPTime rtc_time{.second = uint8_t(pcf85063_.reg.second + 10 * pcf85063_.reg.second_10), | ||||||
|  |                          .minute = uint8_t(pcf85063_.reg.minute + 10u * pcf85063_.reg.minute_10), | ||||||
|  |                          .hour = uint8_t(pcf85063_.reg.hour + 10u * pcf85063_.reg.hour_10), | ||||||
|  |                          .day_of_week = uint8_t(pcf85063_.reg.weekday), | ||||||
|  |                          .day_of_month = uint8_t(pcf85063_.reg.day + 10u * pcf85063_.reg.day_10), | ||||||
|  |                          .day_of_year = 1,  // ignored by recalc_timestamp_utc(false) | ||||||
|  |                          .month = uint8_t(pcf85063_.reg.month + 10u * pcf85063_.reg.month_10), | ||||||
|  |                          .year = uint16_t(pcf85063_.reg.year + 10u * pcf85063_.reg.year_10 + 2000)}; | ||||||
|  |   rtc_time.recalc_timestamp_utc(false); | ||||||
|  |   if (!rtc_time.is_valid()) { | ||||||
|  |     ESP_LOGE(TAG, "Invalid RTC time, not syncing to system clock."); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   time::RealTimeClock::synchronize_epoch_(rtc_time.timestamp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void PCF85063Component::write_time() { | ||||||
|  |   auto now = time::RealTimeClock::utcnow(); | ||||||
|  |   if (!now.is_valid()) { | ||||||
|  |     ESP_LOGE(TAG, "Invalid system time, not syncing to RTC."); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   pcf85063_.reg.year = (now.year - 2000) % 10; | ||||||
|  |   pcf85063_.reg.year_10 = (now.year - 2000) / 10 % 10; | ||||||
|  |   pcf85063_.reg.month = now.month % 10; | ||||||
|  |   pcf85063_.reg.month_10 = now.month / 10; | ||||||
|  |   pcf85063_.reg.day = now.day_of_month % 10; | ||||||
|  |   pcf85063_.reg.day_10 = now.day_of_month / 10; | ||||||
|  |   pcf85063_.reg.weekday = now.day_of_week; | ||||||
|  |   pcf85063_.reg.hour = now.hour % 10; | ||||||
|  |   pcf85063_.reg.hour_10 = now.hour / 10; | ||||||
|  |   pcf85063_.reg.minute = now.minute % 10; | ||||||
|  |   pcf85063_.reg.minute_10 = now.minute / 10; | ||||||
|  |   pcf85063_.reg.second = now.second % 10; | ||||||
|  |   pcf85063_.reg.second_10 = now.second / 10; | ||||||
|  |   pcf85063_.reg.osc_stop = false; | ||||||
|  |  | ||||||
|  |   this->write_rtc_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool PCF85063Component::read_rtc_() { | ||||||
|  |   if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) { | ||||||
|  |     ESP_LOGE(TAG, "Can't read I2C data."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   ESP_LOGD(TAG, "Read  %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u  OSC:%s CLKOUT:%0u", pcf85063_.reg.hour_10, | ||||||
|  |            pcf85063_.reg.hour, pcf85063_.reg.minute_10, pcf85063_.reg.minute, pcf85063_.reg.second_10, | ||||||
|  |            pcf85063_.reg.second, pcf85063_.reg.year_10, pcf85063_.reg.year, pcf85063_.reg.month_10, pcf85063_.reg.month, | ||||||
|  |            pcf85063_.reg.day_10, pcf85063_.reg.day, ONOFF(!pcf85063_.reg.osc_stop), pcf85063_.reg.clkout_control); | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool PCF85063Component::write_rtc_() { | ||||||
|  |   if (!this->write_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) { | ||||||
|  |     ESP_LOGE(TAG, "Can't write I2C data."); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   ESP_LOGD(TAG, "Write %0u%0u:%0u%0u:%0u%0u 20%0u%0u-%0u%0u-%0u%0u  OSC:%s CLKOUT:%0u", pcf85063_.reg.hour_10, | ||||||
|  |            pcf85063_.reg.hour, pcf85063_.reg.minute_10, pcf85063_.reg.minute, pcf85063_.reg.second_10, | ||||||
|  |            pcf85063_.reg.second, pcf85063_.reg.year_10, pcf85063_.reg.year, pcf85063_.reg.month_10, pcf85063_.reg.month, | ||||||
|  |            pcf85063_.reg.day_10, pcf85063_.reg.day, ONOFF(!pcf85063_.reg.osc_stop), pcf85063_.reg.clkout_control); | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  | }  // namespace pcf85063 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										96
									
								
								esphome/components/pcf85063/pcf85063.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								esphome/components/pcf85063/pcf85063.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  | #include "esphome/components/time/real_time_clock.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace pcf85063 { | ||||||
|  |  | ||||||
|  | class PCF85063Component : public time::RealTimeClock, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void update() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |   void read_time(); | ||||||
|  |   void write_time(); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool read_rtc_(); | ||||||
|  |   bool write_rtc_(); | ||||||
|  |   union PCF85063Reg { | ||||||
|  |     struct { | ||||||
|  |       // Control_1 register | ||||||
|  |       bool cap_12pf : 1; | ||||||
|  |       bool am_pm : 1; | ||||||
|  |       bool correction_int_enable : 1; | ||||||
|  |       bool : 1; | ||||||
|  |       bool soft_reset : 1; | ||||||
|  |       bool stop : 1; | ||||||
|  |       bool : 1; | ||||||
|  |       bool ext_test : 1; | ||||||
|  |  | ||||||
|  |       // Control_2 register | ||||||
|  |       uint8_t clkout_control : 3; | ||||||
|  |       bool timer_flag : 1; | ||||||
|  |       bool halfminute_int : 1; | ||||||
|  |       bool minute_int : 1; | ||||||
|  |       bool alarm_flag : 1; | ||||||
|  |       bool alarm_int : 1; | ||||||
|  |  | ||||||
|  |       // Offset register | ||||||
|  |       uint8_t offset : 7; | ||||||
|  |       bool coarse_mode : 1; | ||||||
|  |  | ||||||
|  |       // nvRAM register | ||||||
|  |       uint8_t nvram : 8; | ||||||
|  |  | ||||||
|  |       // Seconds register | ||||||
|  |       uint8_t second : 4; | ||||||
|  |       uint8_t second_10 : 3; | ||||||
|  |       bool osc_stop : 1; | ||||||
|  |  | ||||||
|  |       // Minutes register | ||||||
|  |       uint8_t minute : 4; | ||||||
|  |       uint8_t minute_10 : 3; | ||||||
|  |       uint8_t : 1; | ||||||
|  |  | ||||||
|  |       // Hours register | ||||||
|  |       uint8_t hour : 4; | ||||||
|  |       uint8_t hour_10 : 2; | ||||||
|  |       uint8_t : 2; | ||||||
|  |  | ||||||
|  |       // Days register | ||||||
|  |       uint8_t day : 4; | ||||||
|  |       uint8_t day_10 : 2; | ||||||
|  |       uint8_t : 2; | ||||||
|  |  | ||||||
|  |       // Weekdays register | ||||||
|  |       uint8_t weekday : 3; | ||||||
|  |       uint8_t unused_3 : 5; | ||||||
|  |  | ||||||
|  |       // Months register | ||||||
|  |       uint8_t month : 4; | ||||||
|  |       uint8_t month_10 : 1; | ||||||
|  |       uint8_t : 3; | ||||||
|  |  | ||||||
|  |       // Years register | ||||||
|  |       uint8_t year : 4; | ||||||
|  |       uint8_t year_10 : 4; | ||||||
|  |     } reg; | ||||||
|  |     mutable uint8_t raw[sizeof(reg)]; | ||||||
|  |   } pcf85063_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class WriteAction : public Action<Ts...>, public Parented<PCF85063Component> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->write_time(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class ReadAction : public Action<Ts...>, public Parented<PCF85063Component> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->read_time(); } | ||||||
|  | }; | ||||||
|  | }  // namespace pcf85063 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										60
									
								
								esphome/components/pcf85063/time.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								esphome/components/pcf85063/time.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | 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 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@brogon"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | pcf85063_ns = cg.esphome_ns.namespace("pcf85063") | ||||||
|  | PCF85063Component = pcf85063_ns.class_( | ||||||
|  |     "PCF85063Component", time.RealTimeClock, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  | WriteAction = pcf85063_ns.class_("WriteAction", automation.Action) | ||||||
|  | ReadAction = pcf85063_ns.class_("ReadAction", automation.Action) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = time.TIME_SCHEMA.extend( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(PCF85063Component), | ||||||
|  |     } | ||||||
|  | ).extend(i2c.i2c_device_schema(0x51)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "pcf85063.write_time", | ||||||
|  |     WriteAction, | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.use_id(PCF85063Component), | ||||||
|  |         } | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  | async def pcf85063_write_time_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.read_time", | ||||||
|  |     ReadAction, | ||||||
|  |     automation.maybe_simple_id( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.use_id(PCF85063Component), | ||||||
|  |         } | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  | async def pcf85063_read_time_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]) | ||||||
|  |  | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |     await time.register_time(var, config) | ||||||
| @@ -517,6 +517,9 @@ display: | |||||||
|     lambda: |- |     lambda: |- | ||||||
|       it.print("81818181"); |       it.print("81818181"); | ||||||
|  |  | ||||||
|  | time: | ||||||
|  |   - platform: pcf85063 | ||||||
|  |  | ||||||
| text_sensor: | text_sensor: | ||||||
|   - platform: ezo_pmp |   - platform: ezo_pmp | ||||||
|     dosing_mode: |     dosing_mode: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user