mirror of
https://github.com/esphome/esphome.git
synced 2025-09-13 16:52:18 +01:00
🏗 Merge C++ into python codebase (#504)
## Description: Move esphome-core codebase into esphome (and a bunch of other refactors). See https://github.com/esphome/feature-requests/issues/97 Yes this is a shit ton of work and no there's no way to automate it :( But it will be worth it 👍 Progress: - Core support (file copy etc): 80% - Base Abstractions (light, switch): ~50% - Integrations: ~10% - Working? Yes, (but only with ported components). Other refactors: - Moves all codegen related stuff into a single class: `esphome.codegen` (imported as `cg`) - Rework coroutine syntax - Move from `component/platform.py` to `domain/component.py` structure as with HA - Move all defaults out of C++ and into config validation. - Remove `make_...` helpers from Application class. Reason: Merge conflicts with every single new integration. - Pointer Variables are stored globally instead of locally in setup(). Reason: stack size limit. Future work: - Rework const.py - Move all `CONF_...` into a conf class (usage `conf.UPDATE_INTERVAL` vs `CONF_UPDATE_INTERVAL`). Reason: Less convoluted import block - Enable loading from `custom_components` folder. **Related issue (if applicable):** https://github.com/esphome/feature-requests/issues/97 **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
This commit is contained in:
0
esphome/components/time_based/__init__.py
Normal file
0
esphome/components/time_based/__init__.py
Normal file
35
esphome/components/time_based/cover.py
Normal file
35
esphome/components/time_based/cover.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from esphome import automation
|
||||
from esphome.components import cover
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_CLOSE_ACTION, CONF_CLOSE_DURATION, CONF_ID, CONF_NAME, \
|
||||
CONF_OPEN_ACTION, CONF_OPEN_DURATION, CONF_STOP_ACTION
|
||||
|
||||
|
||||
time_based_ns = cg.esphome_ns.namespace('time_based')
|
||||
TimeBasedCover = time_based_ns.class_('TimeBasedCover', cover.Cover, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = cv.nameable(cover.COVER_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(TimeBasedCover),
|
||||
cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True),
|
||||
|
||||
cv.Required(CONF_OPEN_ACTION): automation.validate_automation(single=True),
|
||||
cv.Required(CONF_OPEN_DURATION): cv.positive_time_period_milliseconds,
|
||||
|
||||
cv.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
|
||||
cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds,
|
||||
}).extend(cv.COMPONENT_SCHEMA))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_NAME])
|
||||
yield cg.register_component(var, config)
|
||||
yield cover.register_cover(var, config)
|
||||
|
||||
yield automation.build_automation(var.get_stop_trigger(), [], config[CONF_STOP_ACTION])
|
||||
|
||||
cg.add(var.set_open_duration(config[CONF_OPEN_DURATION]))
|
||||
yield automation.build_automation(var.get_open_trigger(), [], config[CONF_OPEN_ACTION])
|
||||
|
||||
cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION]))
|
||||
yield automation.build_automation(var.get_close_trigger(), [], config[CONF_CLOSE_ACTION])
|
141
esphome/components/time_based/time_based_cover.cpp
Normal file
141
esphome/components/time_based/time_based_cover.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "time_based_cover.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace time_based {
|
||||
|
||||
static const char *TAG = "time_based.cover";
|
||||
|
||||
using namespace esphome::cover;
|
||||
|
||||
void TimeBasedCover::dump_config() {
|
||||
LOG_COVER("", "Time Based Cover", this);
|
||||
ESP_LOGCONFIG(TAG, " Open Duration: %.1fs", this->open_duration_ / 1e3f);
|
||||
ESP_LOGCONFIG(TAG, " Close Duration: %.1fs", this->close_duration_ / 1e3f);
|
||||
}
|
||||
void TimeBasedCover::setup() {
|
||||
auto restore = this->restore_state_();
|
||||
if (restore.has_value()) {
|
||||
restore->apply(this);
|
||||
} else {
|
||||
this->position = 0.5f;
|
||||
}
|
||||
}
|
||||
void TimeBasedCover::loop() {
|
||||
if (this->current_operation == COVER_OPERATION_IDLE)
|
||||
return;
|
||||
|
||||
const uint32_t now = millis();
|
||||
|
||||
// Recompute position every loop cycle
|
||||
this->recompute_position_();
|
||||
|
||||
if (this->current_operation != COVER_OPERATION_IDLE && this->is_at_target_()) {
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->publish_state();
|
||||
}
|
||||
|
||||
// Send current position every second
|
||||
if (this->current_operation != COVER_OPERATION_IDLE && now - this->last_publish_time_ > 1000) {
|
||||
this->publish_state(false);
|
||||
this->last_publish_time_ = now;
|
||||
}
|
||||
}
|
||||
float TimeBasedCover::get_setup_priority() const { return setup_priority::DATA; }
|
||||
CoverTraits TimeBasedCover::get_traits() {
|
||||
auto traits = CoverTraits();
|
||||
traits.set_supports_position(true);
|
||||
traits.set_is_assumed_state(false);
|
||||
return traits;
|
||||
}
|
||||
void TimeBasedCover::control(const CoverCall &call) {
|
||||
if (call.get_stop()) {
|
||||
this->start_direction_(COVER_OPERATION_IDLE);
|
||||
this->publish_state();
|
||||
}
|
||||
if (call.get_position().has_value()) {
|
||||
auto pos = *call.get_position();
|
||||
if (pos == this->position) {
|
||||
// already at target
|
||||
} else {
|
||||
auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
|
||||
this->target_position_ = pos;
|
||||
this->start_direction_(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
void TimeBasedCover::stop_prev_trigger_() {
|
||||
if (this->prev_command_trigger_ != nullptr) {
|
||||
this->prev_command_trigger_->stop();
|
||||
this->prev_command_trigger_ = nullptr;
|
||||
}
|
||||
}
|
||||
bool TimeBasedCover::is_at_target_() const {
|
||||
switch (this->current_operation) {
|
||||
case COVER_OPERATION_OPENING:
|
||||
return this->position >= this->target_position_;
|
||||
case COVER_OPERATION_CLOSING:
|
||||
return this->position <= this->target_position_;
|
||||
case COVER_OPERATION_IDLE:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void TimeBasedCover::start_direction_(CoverOperation dir) {
|
||||
if (dir == this->current_operation)
|
||||
return;
|
||||
|
||||
this->recompute_position_();
|
||||
Trigger<> *trig;
|
||||
switch (dir) {
|
||||
case COVER_OPERATION_IDLE:
|
||||
trig = this->stop_trigger_;
|
||||
break;
|
||||
case COVER_OPERATION_OPENING:
|
||||
trig = this->open_trigger_;
|
||||
break;
|
||||
case COVER_OPERATION_CLOSING:
|
||||
trig = this->close_trigger_;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
this->current_operation = dir;
|
||||
|
||||
this->stop_prev_trigger_();
|
||||
trig->trigger();
|
||||
this->prev_command_trigger_ = trig;
|
||||
|
||||
const uint32_t now = millis();
|
||||
this->start_dir_time_ = now;
|
||||
this->last_recompute_time_ = now;
|
||||
}
|
||||
void TimeBasedCover::recompute_position_() {
|
||||
if (this->current_operation == COVER_OPERATION_IDLE)
|
||||
return;
|
||||
|
||||
float dir;
|
||||
float action_dur;
|
||||
switch (this->current_operation) {
|
||||
case COVER_OPERATION_OPENING:
|
||||
dir = 1.0f;
|
||||
action_dur = this->open_duration_;
|
||||
break;
|
||||
case COVER_OPERATION_CLOSING:
|
||||
dir = -1.0f;
|
||||
action_dur = this->close_duration_;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t now = millis();
|
||||
this->position += dir * (now - this->last_recompute_time_) / action_dur;
|
||||
this->position = clamp(this->position, 0.0f, 1.0f);
|
||||
|
||||
this->last_recompute_time_ = now;
|
||||
}
|
||||
|
||||
} // namespace time_based
|
||||
} // namespace esphome
|
48
esphome/components/time_based/time_based_cover.h
Normal file
48
esphome/components/time_based/time_based_cover.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/cover/cover.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace time_based {
|
||||
|
||||
class TimeBasedCover : public cover::Cover, public Component {
|
||||
public:
|
||||
TimeBasedCover(const std::string &name) : cover::Cover(name) {}
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
Trigger<> *get_open_trigger() const { return this->open_trigger_; }
|
||||
Trigger<> *get_close_trigger() const { return this->close_trigger_; }
|
||||
Trigger<> *get_stop_trigger() const { return this->stop_trigger_; }
|
||||
void set_open_duration(uint32_t open_duration) { this->open_duration_ = open_duration; }
|
||||
void set_close_duration(uint32_t close_duration) { this->close_duration_ = close_duration; }
|
||||
cover::CoverTraits get_traits() override;
|
||||
|
||||
protected:
|
||||
void control(const cover::CoverCall &call) override;
|
||||
void stop_prev_trigger_();
|
||||
bool is_at_target_() const;
|
||||
|
||||
void start_direction_(cover::CoverOperation dir);
|
||||
|
||||
void recompute_position_();
|
||||
|
||||
Trigger<> *open_trigger_{new Trigger<>()};
|
||||
uint32_t open_duration_;
|
||||
Trigger<> *close_trigger_{new Trigger<>()};
|
||||
uint32_t close_duration_;
|
||||
Trigger<> *stop_trigger_{new Trigger<>()};
|
||||
|
||||
Trigger<> *prev_command_trigger_{nullptr};
|
||||
uint32_t last_recompute_time_{0};
|
||||
uint32_t start_dir_time_{0};
|
||||
uint32_t last_publish_time_{0};
|
||||
float target_position_{0};
|
||||
};
|
||||
|
||||
} // namespace time_based
|
||||
} // namespace esphome
|
Reference in New Issue
Block a user