mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
Merge branch 'dev' of https://github.com/esphome/esphome into dev
This commit is contained in:
commit
cf6205f9b8
22 changed files with 160 additions and 44 deletions
1
.github/workflows/ci-docker.yml
vendored
1
.github/workflows/ci-docker.yml
vendored
|
@ -18,6 +18,7 @@ jobs:
|
|||
name: Build docker containers
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [amd64, armv7, aarch64]
|
||||
build_type: ["hassio", "docker"]
|
||||
|
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -44,6 +44,7 @@ jobs:
|
|||
container: esphome/esphome-lint:latest
|
||||
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
split: [1, 2, 3, 4]
|
||||
steps:
|
||||
|
@ -107,6 +108,7 @@ jobs:
|
|||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test:
|
||||
- test1
|
||||
|
|
2
.github/workflows/release-dev.yml
vendored
2
.github/workflows/release-dev.yml
vendored
|
@ -41,6 +41,7 @@ jobs:
|
|||
container: esphome/esphome-lint:latest
|
||||
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
split: [1, 2, 3, 4]
|
||||
steps:
|
||||
|
@ -104,6 +105,7 @@ jobs:
|
|||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test:
|
||||
- test1
|
||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -40,6 +40,7 @@ jobs:
|
|||
container: esphome/esphome-lint:latest
|
||||
# Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
split: [1, 2, 3, 4]
|
||||
steps:
|
||||
|
@ -103,6 +104,7 @@ jobs:
|
|||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test:
|
||||
- test1
|
||||
|
|
|
@ -12,8 +12,10 @@ void DaikinClimate::transmit_state() {
|
|||
0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00};
|
||||
|
||||
remote_state[21] = this->operation_mode_();
|
||||
remote_state[24] = this->fan_speed_();
|
||||
remote_state[22] = this->temperature_();
|
||||
uint16_t fan_speed = this->fan_speed_();
|
||||
remote_state[24] = fan_speed >> 8;
|
||||
remote_state[25] = fan_speed & 0xff;
|
||||
|
||||
// Calculate checksum
|
||||
for (int i = 16; i < 34; i++) {
|
||||
|
@ -90,25 +92,38 @@ uint8_t DaikinClimate::operation_mode_() {
|
|||
return operating_mode;
|
||||
}
|
||||
|
||||
uint8_t DaikinClimate::fan_speed_() {
|
||||
uint8_t fan_speed;
|
||||
uint16_t DaikinClimate::fan_speed_() {
|
||||
uint16_t fan_speed;
|
||||
switch (this->fan_mode) {
|
||||
case climate::CLIMATE_FAN_LOW:
|
||||
fan_speed = DAIKIN_FAN_1;
|
||||
fan_speed = DAIKIN_FAN_1 << 8;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_MEDIUM:
|
||||
fan_speed = DAIKIN_FAN_3;
|
||||
fan_speed = DAIKIN_FAN_3 << 8;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
fan_speed = DAIKIN_FAN_5;
|
||||
fan_speed = DAIKIN_FAN_5 << 8;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_AUTO:
|
||||
default:
|
||||
fan_speed = DAIKIN_FAN_AUTO;
|
||||
fan_speed = DAIKIN_FAN_AUTO << 8;
|
||||
}
|
||||
|
||||
// If swing is enabled switch first 4 bits to 1111
|
||||
return this->swing_mode == climate::CLIMATE_SWING_VERTICAL ? fan_speed | 0xF : fan_speed;
|
||||
switch (this->swing_mode) {
|
||||
case climate::CLIMATE_SWING_VERTICAL:
|
||||
fan_speed |= 0x0F00;
|
||||
break;
|
||||
case climate::CLIMATE_SWING_HORIZONTAL:
|
||||
fan_speed |= 0x000F;
|
||||
break;
|
||||
case climate::CLIMATE_SWING_BOTH:
|
||||
fan_speed |= 0x0F0F;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return fan_speed;
|
||||
}
|
||||
|
||||
uint8_t DaikinClimate::temperature_() {
|
||||
|
@ -159,13 +174,19 @@ bool DaikinClimate::parse_state_frame_(const uint8_t frame[]) {
|
|||
this->target_temperature = temperature >> 1;
|
||||
}
|
||||
uint8_t fan_mode = frame[8];
|
||||
if (fan_mode & 0xF)
|
||||
uint8_t swing_mode = frame[9];
|
||||
if (fan_mode & 0xF && swing_mode & 0xF)
|
||||
this->swing_mode = climate::CLIMATE_SWING_BOTH;
|
||||
else if (fan_mode & 0xF)
|
||||
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
|
||||
else if (swing_mode & 0xF)
|
||||
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
|
||||
else
|
||||
this->swing_mode = climate::CLIMATE_SWING_OFF;
|
||||
switch (fan_mode & 0xF0) {
|
||||
case DAIKIN_FAN_1:
|
||||
case DAIKIN_FAN_2:
|
||||
case DAIKIN_FAN_SILENT:
|
||||
this->fan_mode = climate::CLIMATE_FAN_LOW;
|
||||
break;
|
||||
case DAIKIN_FAN_3:
|
||||
|
|
|
@ -21,6 +21,7 @@ const uint8_t DAIKIN_MODE_ON = 0x01;
|
|||
|
||||
// Fan Speed
|
||||
const uint8_t DAIKIN_FAN_AUTO = 0xA0;
|
||||
const uint8_t DAIKIN_FAN_SILENT = 0xB0;
|
||||
const uint8_t DAIKIN_FAN_1 = 0x30;
|
||||
const uint8_t DAIKIN_FAN_2 = 0x40;
|
||||
const uint8_t DAIKIN_FAN_3 = 0x50;
|
||||
|
@ -46,13 +47,14 @@ class DaikinClimate : public climate_ir::ClimateIR {
|
|||
DAIKIN_TEMP_MIN, DAIKIN_TEMP_MAX, 1.0f, true, true,
|
||||
std::vector<climate::ClimateFanMode>{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW,
|
||||
climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH},
|
||||
std::vector<climate::ClimateSwingMode>{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {}
|
||||
std::vector<climate::ClimateSwingMode>{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL,
|
||||
climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {}
|
||||
|
||||
protected:
|
||||
// Transmit via IR the state of this climate controller.
|
||||
void transmit_state() override;
|
||||
uint8_t operation_mode_();
|
||||
uint8_t fan_speed_();
|
||||
uint16_t fan_speed_();
|
||||
uint8_t temperature_();
|
||||
// Handle received IR Buffer
|
||||
bool on_receive(remote_base::RemoteReceiveData data) override;
|
||||
|
|
|
@ -299,7 +299,7 @@ void DisplayBuffer::printf(int x, int y, Font *font, TextAlign align, const char
|
|||
void DisplayBuffer::printf(int x, int y, Font *font, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, COLOR_ON, TextAlign::CENTER_LEFT, format, arg);
|
||||
this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void DisplayBuffer::set_writer(display_writer_t &&writer) { this->writer_ = writer; }
|
||||
|
|
|
@ -36,7 +36,10 @@ const uint8_t FUJITSU_GENERAL_FAN_HIGH_BYTE10 = 0x01;
|
|||
const uint8_t FUJITSU_GENERAL_FAN_MEDIUM_BYTE10 = 0x02;
|
||||
const uint8_t FUJITSU_GENERAL_FAN_LOW_BYTE10 = 0x03;
|
||||
const uint8_t FUJITSU_GENERAL_FAN_SILENT_BYTE10 = 0x04;
|
||||
const uint8_t FUJITSU_GENERAL_SWING_MASK_BYTE10 = 0b00010000;
|
||||
const uint8_t FUJITSU_GENERAL_SWING_NONE_BYTE10 = 0x00;
|
||||
const uint8_t FUJITSU_GENERAL_SWING_VERTICAL_BYTE10 = 0x01;
|
||||
const uint8_t FUJITSU_GENERAL_SWING_HORIZONTAL_BYTE10 = 0x02;
|
||||
const uint8_t FUJITSU_GENERAL_SWING_BOTH_BYTE10 = 0x03;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE10 = 0x00;
|
||||
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE11 = 0x00;
|
||||
|
@ -74,7 +77,12 @@ const uint16_t FUJITSU_GENERAL_TRL_SPACE = 8000;
|
|||
|
||||
const uint32_t FUJITSU_GENERAL_CARRIER_FREQUENCY = 38000;
|
||||
|
||||
FujitsuGeneralClimate::FujitsuGeneralClimate() : ClimateIR(FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1) {}
|
||||
FujitsuGeneralClimate::FujitsuGeneralClimate()
|
||||
: ClimateIR(
|
||||
FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1.0f, true, true,
|
||||
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH},
|
||||
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL, climate::CLIMATE_SWING_HORIZONTAL,
|
||||
climate::CLIMATE_SWING_BOTH}) {}
|
||||
|
||||
void FujitsuGeneralClimate::transmit_state() {
|
||||
if (this->mode == climate::CLIMATE_MODE_OFF) {
|
||||
|
@ -101,8 +109,8 @@ void FujitsuGeneralClimate::transmit_state() {
|
|||
remote_state[15] = FUJITSU_GENERAL_BASE_BYTE15;
|
||||
|
||||
// Set temperature
|
||||
uint8_t safecelsius = std::max((uint8_t) this->target_temperature, FUJITSU_GENERAL_TEMP_MIN);
|
||||
safecelsius = std::min(safecelsius, FUJITSU_GENERAL_TEMP_MAX);
|
||||
auto safecelsius =
|
||||
(uint8_t) roundf(clamp(this->target_temperature, FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX));
|
||||
remote_state[8] = (byte) safecelsius - 16;
|
||||
remote_state[8] = remote_state[8] << 4;
|
||||
|
||||
|
@ -119,18 +127,52 @@ void FujitsuGeneralClimate::transmit_state() {
|
|||
case climate::CLIMATE_MODE_HEAT:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_HEAT_BYTE9;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_DRY:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_DRY_BYTE9;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_FAN_ONLY:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_FAN_BYTE9;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_AUTO:
|
||||
default:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_AUTO_BYTE9;
|
||||
break;
|
||||
// TODO: CLIMATE_MODE_FAN_ONLY, CLIMATE_MODE_DRY, CLIMATE_MODE_10C are missing in esphome
|
||||
// TODO: CLIMATE_MODE_10C are missing in esphome
|
||||
}
|
||||
|
||||
// TODO: missing support for fan speed
|
||||
// Set fan
|
||||
switch (this->fan_mode) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
remote_state[10] = FUJITSU_GENERAL_FAN_HIGH_BYTE10;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_MEDIUM:
|
||||
remote_state[10] = FUJITSU_GENERAL_FAN_MEDIUM_BYTE10;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_LOW:
|
||||
remote_state[10] = FUJITSU_GENERAL_FAN_LOW_BYTE10;
|
||||
break;
|
||||
case climate::CLIMATE_FAN_AUTO:
|
||||
default:
|
||||
remote_state[10] = FUJITSU_GENERAL_FAN_AUTO_BYTE10;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: missing support for swing
|
||||
// remote_state[10] = (byte) remote_state[10] | FUJITSU_GENERAL_SWING_MASK_BYTE10;
|
||||
// Set swing
|
||||
switch (this->swing_mode) {
|
||||
case climate::CLIMATE_SWING_VERTICAL:
|
||||
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_VERTICAL_BYTE10 << 4);
|
||||
break;
|
||||
case climate::CLIMATE_SWING_HORIZONTAL:
|
||||
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_HORIZONTAL_BYTE10 << 4);
|
||||
break;
|
||||
case climate::CLIMATE_SWING_BOTH:
|
||||
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_BOTH_BYTE10 << 4);
|
||||
break;
|
||||
case climate::CLIMATE_SWING_OFF:
|
||||
default:
|
||||
remote_state[10] = (byte) remote_state[10] | (FUJITSU_GENERAL_SWING_NONE_BYTE10 << 4);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: missing support for outdoor unit low noise
|
||||
// remote_state[14] = (byte) remote_state[14] | FUJITSU_GENERAL_OUTDOOR_UNIT_LOW_NOISE_BYTE14;
|
||||
|
|
|
@ -17,7 +17,7 @@ class AQICalculator : public AbstractAQICalculator {
|
|||
|
||||
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 51}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
|
||||
|
||||
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 45}, {36, 55}, {56, 150}, {151, 250}, {251, 500}};
|
||||
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 12}, {13, 35}, {36, 55}, {56, 150}, {151, 250}, {251, 500}};
|
||||
|
||||
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254},
|
||||
{255, 354}, {355, 424}, {425, 604}};
|
||||
|
|
|
@ -102,17 +102,18 @@ class LightTurnOnTrigger : public Trigger<> {
|
|||
public:
|
||||
LightTurnOnTrigger(LightState *a_light) {
|
||||
a_light->add_new_remote_values_callback([this, a_light]() {
|
||||
auto is_on = a_light->current_values.is_on();
|
||||
// using the remote value because of transitions we need to trigger as early as possible
|
||||
auto is_on = a_light->remote_values.is_on();
|
||||
// only trigger when going from off to on
|
||||
auto should_trigger = is_on && !last_on_;
|
||||
auto should_trigger = is_on && !this->last_on_;
|
||||
// Set new state immediately so that trigger() doesn't devolve
|
||||
// into infinite loop
|
||||
last_on_ = is_on;
|
||||
this->last_on_ = is_on;
|
||||
if (should_trigger) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
last_on_ = a_light->current_values.is_on();
|
||||
this->last_on_ = a_light->current_values.is_on();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -122,22 +123,14 @@ class LightTurnOnTrigger : public Trigger<> {
|
|||
class LightTurnOffTrigger : public Trigger<> {
|
||||
public:
|
||||
LightTurnOffTrigger(LightState *a_light) {
|
||||
a_light->add_new_remote_values_callback([this, a_light]() {
|
||||
a_light->add_new_target_state_reached_callback([this, a_light]() {
|
||||
auto is_on = a_light->current_values.is_on();
|
||||
// only trigger when going from on to off
|
||||
auto should_trigger = !is_on && last_on_;
|
||||
// Set new state immediately so that trigger() doesn't devolve
|
||||
// into infinite loop
|
||||
last_on_ = is_on;
|
||||
if (should_trigger) {
|
||||
if (!is_on) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
last_on_ = a_light->current_values.is_on();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool last_on_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class AddressableSet : public Action<Ts...> {
|
||||
|
|
|
@ -145,6 +145,7 @@ void LightState::loop() {
|
|||
if (this->transformer_ != nullptr) {
|
||||
if (this->transformer_->is_finished()) {
|
||||
this->remote_values = this->current_values = this->transformer_->get_end_values();
|
||||
this->target_state_reached_callback_.call();
|
||||
if (this->transformer_->publish_at_end())
|
||||
this->publish_state();
|
||||
this->transformer_ = nullptr;
|
||||
|
@ -336,6 +337,9 @@ void LightCall::perform() {
|
|||
this->parent_->set_immediately_(v, this->publish_);
|
||||
}
|
||||
|
||||
if (!this->has_transition_()) {
|
||||
this->parent_->target_state_reached_callback_.call();
|
||||
}
|
||||
if (this->publish_) {
|
||||
this->parent_->publish_state();
|
||||
}
|
||||
|
@ -752,6 +756,10 @@ void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bo
|
|||
void LightState::add_new_remote_values_callback(std::function<void()> &&send_callback) {
|
||||
this->remote_values_callback_.add(std::move(send_callback));
|
||||
}
|
||||
void LightState::add_new_target_state_reached_callback(std::function<void()> &&send_callback) {
|
||||
this->target_state_reached_callback_.add(std::move(send_callback));
|
||||
}
|
||||
|
||||
LightEffect *LightState::get_active_effect_() {
|
||||
if (this->active_effect_index_ == 0)
|
||||
return nullptr;
|
||||
|
|
|
@ -242,6 +242,13 @@ class LightState : public Nameable, public Component {
|
|||
*/
|
||||
void add_new_remote_values_callback(std::function<void()> &&send_callback);
|
||||
|
||||
/**
|
||||
* The callback is called once the state of current_values and remote_values are equal
|
||||
*
|
||||
* @param send_callback
|
||||
*/
|
||||
void add_new_target_state_reached_callback(std::function<void()> &&send_callback);
|
||||
|
||||
/// Return whether the light has any effects that meet the trait requirements.
|
||||
bool supports_effects();
|
||||
|
||||
|
@ -318,6 +325,12 @@ class LightState : public Nameable, public Component {
|
|||
* starting with the beginning of the transition.
|
||||
*/
|
||||
CallbackManager<void()> remote_values_callback_{};
|
||||
|
||||
/** Callback to call when the state of current_values and remote_values are equal
|
||||
* This should be called once the state of current_values changed and equals the state of remote_values
|
||||
*/
|
||||
CallbackManager<void()> target_state_reached_callback_{};
|
||||
|
||||
LightOutput *output_; ///< Store the output to allow effects to have more access.
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
|
|
|
@ -11,6 +11,7 @@ CONF_SCROLL_DWELL = 'scroll_dwell'
|
|||
CONF_SCROLL_DELAY = 'scroll_delay'
|
||||
CONF_SCROLL_ENABLE = 'scroll_enable'
|
||||
CONF_SCROLL_MODE = 'scroll_mode'
|
||||
CONF_REVERSE_ENABLE = 'reverse_enable'
|
||||
|
||||
SCROLL_MODES = {
|
||||
'CONTINUOUS': 0,
|
||||
|
@ -39,6 +40,7 @@ CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
|
|||
cv.Optional(CONF_SCROLL_SPEED, default='250ms'): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_SCROLL_DELAY, default='1000ms'): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_SCROLL_DWELL, default='1000ms'): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean,
|
||||
}).extend(cv.polling_component_schema('500ms')).extend(spi.spi_device_schema(cs_pin_required=True))
|
||||
|
||||
|
||||
|
@ -56,6 +58,7 @@ def to_code(config):
|
|||
cg.add(var.set_scroll_delay(config[CONF_SCROLL_DELAY]))
|
||||
cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
|
||||
cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
|
||||
cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(MAX7219ComponentRef, 'it')],
|
||||
|
|
|
@ -108,8 +108,12 @@ void MAX7219Component::display() {
|
|||
// Send the data to the chip
|
||||
for (uint8_t i = 0; i < this->num_chips_; i++) {
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
if (this->reverse_) {
|
||||
pixels[j] = this->max_displaybuffer_[(this->num_chips_ - i - 1) * 8 + j];
|
||||
} else {
|
||||
pixels[j] = this->max_displaybuffer_[i * 8 + j];
|
||||
}
|
||||
}
|
||||
this->send64pixels(i, pixels);
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +233,7 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) {
|
|||
b = pixels[col];
|
||||
} else if (this->orientation_ == 2) {
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
b |= ((pixels[i] >> (7 - col)) << (7 - i));
|
||||
b |= ((pixels[i] >> (7 - col)) & 1) << i;
|
||||
}
|
||||
} else {
|
||||
b = pixels[7 - col];
|
||||
|
|
|
@ -52,6 +52,7 @@ class MAX7219Component : public PollingComponent,
|
|||
void set_scroll_delay(uint16_t delay) { this->scroll_delay_ = delay; };
|
||||
void set_scroll(bool on_off) { this->scroll_ = on_off; };
|
||||
void set_scroll_mode(uint8_t mode) { this->scroll_mode_ = mode; };
|
||||
void set_reverse(bool on_off) { this->reverse_ = on_off; };
|
||||
|
||||
void send_char(byte chip, byte data);
|
||||
void send64pixels(byte chip, const byte pixels[8]);
|
||||
|
@ -87,6 +88,7 @@ class MAX7219Component : public PollingComponent,
|
|||
uint8_t intensity_; /// Intensity of the display from 0 to 15 (most)
|
||||
uint8_t num_chips_;
|
||||
bool scroll_;
|
||||
bool reverse_;
|
||||
bool update_{false};
|
||||
uint16_t scroll_speed_;
|
||||
uint16_t scroll_delay_;
|
||||
|
|
|
@ -29,10 +29,9 @@ void FloatOutput::set_level(float state) {
|
|||
this->power_.unrequest();
|
||||
}
|
||||
#endif
|
||||
|
||||
float adjusted_value = (state * (this->max_power_ - this->min_power_)) + this->min_power_;
|
||||
if (this->is_inverted())
|
||||
adjusted_value = 1.0f - adjusted_value;
|
||||
state = 1.0f - state;
|
||||
float adjusted_value = (state * (this->max_power_ - this->min_power_)) + this->min_power_;
|
||||
this->write_state(adjusted_value);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,11 @@ import tzlocal
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.const import CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \
|
||||
from esphome.const import CONF_ID, CONF_CRON, CONF_DAYS_OF_MONTH, CONF_DAYS_OF_WEEK, CONF_HOURS, \
|
||||
CONF_MINUTES, CONF_MONTHS, CONF_ON_TIME, CONF_SECONDS, CONF_TIMEZONE, CONF_TRIGGER_ID, \
|
||||
CONF_AT, CONF_SECOND, CONF_HOUR, CONF_MINUTE
|
||||
from esphome.core import coroutine, coroutine_with_priority
|
||||
from esphome.automation import Condition
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -24,6 +25,7 @@ time_ns = cg.esphome_ns.namespace('time')
|
|||
RealTimeClock = time_ns.class_('RealTimeClock', cg.Component)
|
||||
CronTrigger = time_ns.class_('CronTrigger', automation.Trigger.template(), cg.Component)
|
||||
ESPTime = time_ns.struct('ESPTime')
|
||||
TimeHasTimeCondition = time_ns.class_('TimeHasTimeCondition', Condition)
|
||||
|
||||
|
||||
def _tz_timedelta(td):
|
||||
|
@ -328,3 +330,11 @@ def register_time(time_var, config):
|
|||
def to_code(config):
|
||||
cg.add_define('USE_TIME')
|
||||
cg.add_global(time_ns.using)
|
||||
|
||||
|
||||
@automation.register_condition('time.has_time', TimeHasTimeCondition, cv.Schema({
|
||||
cv.GenerateID(): cv.use_id(RealTimeClock),
|
||||
}))
|
||||
def time_has_time_to_code(config, condition_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(condition_id, template_arg, paren)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <bitset>
|
||||
|
@ -133,5 +134,14 @@ class RealTimeClock : public Component {
|
|||
std::string timezone_{};
|
||||
};
|
||||
|
||||
template<typename... Ts> class TimeHasTimeCondition : public Condition<Ts...> {
|
||||
public:
|
||||
TimeHasTimeCondition(RealTimeClock *parent) : parent_(parent) {}
|
||||
bool check(Ts... x) override { return this->parent_->now().is_valid(); }
|
||||
|
||||
protected:
|
||||
RealTimeClock *parent_;
|
||||
};
|
||||
|
||||
} // namespace time
|
||||
} // namespace esphome
|
||||
|
|
|
@ -31,6 +31,7 @@ void write_row(AsyncResponseStream *stream, Nameable *obj, const std::string &kl
|
|||
stream->print("</td><td></td><td>");
|
||||
stream->print(action.c_str());
|
||||
stream->print("</td>");
|
||||
stream->print("</tr>");
|
||||
}
|
||||
|
||||
UrlMatch match_url(const std::string &url, bool only_domain = false) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
voluptuous==0.11.7
|
||||
PyYAML==5.3.1
|
||||
paho-mqtt==1.5.0
|
||||
paho-mqtt==1.5.1
|
||||
colorlog==4.2.1
|
||||
tornado==6.0.4
|
||||
protobuf==3.13.0
|
||||
|
|
|
@ -6,7 +6,7 @@ pexpect==4.8.0
|
|||
|
||||
# Unit tests
|
||||
pytest==6.0.2
|
||||
pytest-cov==2.10.0
|
||||
pytest-cov==2.10.1
|
||||
pytest-mock==3.3.1
|
||||
asyncmock==0.4.2
|
||||
hypothesis==5.21.0
|
||||
|
|
|
@ -8,6 +8,7 @@ esphome:
|
|||
- wait_until:
|
||||
- api.connected
|
||||
- wifi.connected
|
||||
- time.has_time
|
||||
includes:
|
||||
- custom.h
|
||||
|
||||
|
|
Loading…
Reference in a new issue