Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
2e6eed2ee8 | |||
152a88ee58 | |||
ec8acc051c | |||
dca13dd292 | |||
95cf42732e | |||
d98d1cabd5 | |||
7c3016349b | |||
aa371c22a4 | |||
e85874cccf | |||
10efb46153 |
13 changed files with 615 additions and 156 deletions
78
.devcontainer/devcontainer.json
Normal file
78
.devcontainer/devcontainer.json
Normal file
|
@ -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"
|
||||||
|
}
|
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -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]
|
17
.vscode/c_cpp_properties.json
vendored
Normal file
17
.vscode/c_cpp_properties.json
vendored
Normal file
|
@ -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
|
||||||
|
}
|
41
.vscode/launch.json
vendored
Normal file
41
.vscode/launch.json
vendored
Normal file
|
@ -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"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"search.exclude": {
|
||||||
|
"**/node_modules": true,
|
||||||
|
"**/bower_components": true,
|
||||||
|
"**/*.code-search": true,
|
||||||
|
".esphome": true,
|
||||||
|
},
|
||||||
|
}
|
|
@ -81,6 +81,97 @@ void PCF85063Component::write_time() {
|
||||||
this->write_rtc_();
|
this->write_rtc_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCF85063Component::write_nvram(uint8_t data) {
|
||||||
|
pcf85063_.reg.nvram = data;
|
||||||
|
this->write_bytes(0x03, &pcf85063_.raw[0x03], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t PCF85063Component::read_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::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;
|
||||||
|
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_();
|
||||||
|
}
|
||||||
|
|
||||||
|
#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::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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCF85063Component::set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t mode) {
|
||||||
|
pcf85063_.reg.timer_interrupt_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PCF85063Component::write_timer_() {
|
||||||
|
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);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool PCF85063Component::read_rtc_() {
|
bool PCF85063Component::read_rtc_() {
|
||||||
if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
|
if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
|
||||||
ESP_LOGE(TAG, "Can't read I2C data.");
|
ESP_LOGE(TAG, "Can't read I2C data.");
|
187
components/pcf85063/pcf85063.h
Normal file
187
components/pcf85063/pcf85063.h
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
#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 {
|
||||||
|
|
||||||
|
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;
|
||||||
|
void update() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void read_time();
|
||||||
|
void write_time();
|
||||||
|
void write_nvram(uint8_t);
|
||||||
|
uint8_t read_nvram();
|
||||||
|
|
||||||
|
//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 stop_timer();
|
||||||
|
bool write_clockout_frequency(uint8_t freq);
|
||||||
|
void set_timer_interrupt_enable_(bool state);
|
||||||
|
void set_timer_interrupt_mode_(PCF85063ATimerInterruptMode_t mode);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool write_timer_();
|
||||||
|
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 : 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;
|
||||||
|
|
||||||
|
// 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_;
|
||||||
|
};
|
||||||
|
|
||||||
|
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_->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...));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
159
components/pcf85063/time.py
Normal file
159
components/pcf85063/time.py
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
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, CONF_VALUE
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
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(
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|
||||||
|
#####
|
||||||
|
|
||||||
|
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.set_timer_seconds(template_))
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await i2c.register_i2c_device(var, config)
|
||||||
|
await time.register_time(var, config)
|
|
@ -1,96 +0,0 @@
|
||||||
#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
|
|
|
@ -1,60 +0,0 @@
|
||||||
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)
|
|
27
openshell-components.code-workspace
Normal file
27
openshell-components.code-workspace
Normal file
|
@ -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",
|
||||||
|
}
|
||||||
|
}
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
-e ../esphome
|
Loading…
Reference in a new issue