Compare commits

..

No commits in common. "master" and "upstream" have entirely different histories.

13 changed files with 156 additions and 615 deletions

View file

@ -1,78 +0,0 @@
// 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
View file

@ -1,6 +0,0 @@
# 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]

View file

@ -1,17 +0,0 @@
{
"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
View file

@ -1,41 +0,0 @@
{
// 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"
},
]
}

View file

@ -1,8 +0,0 @@
{
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true,
".esphome": true,
},
}

View file

@ -1,187 +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 {
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

View file

@ -1,159 +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, 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)

View file

@ -81,97 +81,6 @@ void PCF85063Component::write_time() {
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_() {
if (!this->read_bytes(0, this->pcf85063_.raw, sizeof(this->pcf85063_.raw))) {
ESP_LOGE(TAG, "Can't read I2C data.");

View 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

View 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)

View file

@ -1,27 +0,0 @@
{
"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",
}
}

View file

@ -1 +0,0 @@
-e ../esphome