1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-09 03:21:52 +00:00

Compare commits

..

90 Commits

Author SHA1 Message Date
Otto Winter
3aaa92fdff Bump version to v1.14.0 2019-11-01 18:27:24 +01:00
Otto Winter
5efd076c08 Merge branch 'beta' 2019-11-01 18:26:19 +01:00
Otto Winter
5f535e9756 Bump version to v1.14.0b5 2019-10-31 23:46:18 +01:00
Otto Winter
70faeb2fa8 Fix some binary_sensor not having an initial state (#819)
Fixes https://github.com/home-assistant/home-assistant/issues/28384
2019-10-31 23:46:10 +01:00
Otto Winter
469c0db981 Fix fan oscillating (#818)
Fixes https://github.com/esphome/issues/issues/783
2019-10-31 23:46:09 +01:00
Otto Winter
440e428aa4 Scheduler fixes (#813)
* Scheduler fixes

Fixes https://github.com/esphome/issues/issues/789, fixes https://github.com/esphome/issues/issues/788

Also changes to use unique_ptr - this should be much safer than the raw pointers form before (though the scoping rules might cause some issues, but looking closely I didn't find anything)

* Disable debugging

* Format
2019-10-31 23:46:09 +01:00
Otto Winter
dde70c95a4 Allow TimePeriod for time_period_str_unit (#815) 2019-10-31 23:46:09 +01:00
Otto Winter
09d1846261 Print update interval for pulse counter (#816) 2019-10-31 23:46:09 +01:00
Otto Winter
34d26a517d Uppercase ESPHome (#814) 2019-10-31 23:46:09 +01:00
Nikolay Vasilchuk
d24b88271c [Hotfix] Dashboard authentication on Py3 (#812)
* Fix

* Review fix

* Reverted first fix
2019-10-31 23:46:08 +01:00
Antoine GRÉA
f22115792a Add check if middle_text is too short (#811)
* Add check if middle_text is too short

* Use int division as suggested
2019-10-31 23:46:08 +01:00
Otto Winter
82a30558e1 Fix web server transition length truncated (#807)
Fixes https://github.com/esphome/issues/issues/772
2019-10-31 23:46:08 +01:00
Otto Winter
847fe5adca Fix modbus register (#806)
Fixes https://github.com/esphome/feature-requests/issues/49#issuecomment-546555289

Co-Authored-By: tsunglung <tsunglung@users.noreply.github.com>
2019-10-31 23:46:08 +01:00
Otto Winter
775b51c6a1 AS3935 Use normal pin polling for IRQ (#805)
* AS3935 Use normal pin polling for IRQ

See also https://github.com/esphome/feature-requests/issues/452

* Fix tests
2019-10-31 23:46:08 +01:00
Otto Winter
e0ad5a9009 Add Tuya message for no datapoints (#804)
See also https://github.com/esphome/feature-requests/issues/352#issuecomment-546579206
2019-10-31 23:46:07 +01:00
Otto Winter
1bf01a9081 Warn when UART and logger operating on same bus (#803) 2019-10-31 23:46:07 +01:00
Pavel Golovin
6ae59bb43d Fujitsu General climate new component (#677)
* new Fujitsu-General climate component

* Refactor out climate_ir

CC @glmnet

Refactored out climate_ir python files too.
Fixed invalid namespace name for climate_ir.

* Add namespace lint check

* Refactor Fujitsu Climate to climate_ir


Co-authored-by: Otto Winter <otto@otto-winter.com>
2019-10-31 23:46:07 +01:00
Otto Winter
929600d7f7 Fix merge 2019-10-24 22:16:09 +02:00
Otto Winter
163d0c55ab Bump version to v1.14.0b4 2019-10-24 22:02:40 +02:00
Otto Winter
327ccb241e Make file generation saving atomic (#792)
* Make file generation saving atomic

* Lint

* Python 2 Compat

* Fix

* Handle file not found error
2019-10-24 22:02:29 +02:00
Otto Winter
6b3c7b0854 Fix scheduler first execution (#798)
* Fix scheduler first execution not immediately

* Also update sensor filters
2019-10-24 22:02:29 +02:00
Otto Winter
681dcb51da Fix MQTT not showing logs with Python 3 (#797)
* Fix MQTT logging for Python 3

* Also fix captive portal PACKED
2019-10-24 22:02:29 +02:00
Chris Debenham
576d5021fd Add missing include - fixes missing GPIOPin definition (#794) 2019-10-24 22:02:29 +02:00
Otto Winter
6cd76f00ac Implement more dump_configs (#791) 2019-10-24 22:02:29 +02:00
Otto Winter
6f63a62a8d Add lint check for integer constants (#775) 2019-10-24 22:02:23 +02:00
Otto Winter
8867a0fcfb Add additional custom lint checks (#790) 2019-10-24 21:59:24 +02:00
Otto Winter
1ca241615d Bump version to v1.13.6 2019-06-14 12:55:23 +02:00
Otto Winter
b8aa84002a Re-add CustomMQTTDevice class (#640)
* Re-add CustomMQTTDevice class

Fixes https://github.com/esphome/issues/issues/427

* Fix
2019-06-14 12:55:20 +02:00
Otto Winter
10cc0b1d5b Fix remote_receiver raw binary sensor (#639)
* Fix remote_receiver raw binary sensor

Fixes https://github.com/esphome/issues/issues/439

* Lint
2019-06-14 12:55:19 +02:00
Otto Winter
11d9c203c1 Fix version.h file (#630)
* Fix version.h file

* Lint
2019-06-14 12:55:19 +02:00
Otto Winter
c9ab454c3c Fix globals.set (#635)
* Fix globals.set

* Update __init__.py
2019-06-14 12:55:19 +02:00
Otto Winter
4a55692885 Fix russia timezone detection (#637)
Fixes https://github.com/esphome/issues/issues/378#issuecomment-500219634
2019-06-14 12:55:19 +02:00
Otto Winter
88c129e705 Fix ESP32 RCSwitch Dump Stack Smash Protection (#636)
Fixes https://github.com/esphome/issues/issues/366
2019-06-14 12:55:19 +02:00
Otto Winter
80b48f01fb Fix esp8266_restore_from_flash (#638)
Fixes https://github.com/esphome/issues/issues/424
2019-06-14 12:36:30 +02:00
Otto Winter
642bc91a76 Update esp32_ble_tracker.cpp 2019-06-08 17:06:29 +02:00
Otto Winter
d69926ee56 Bump version to v1.13.5 2019-06-08 16:49:04 +02:00
Otto Winter
4758403d44 Work around ESP32 core WiFi Bug (#627)
* Work around ESP32 WiFi Bug

* Lint
2019-06-08 16:49:00 +02:00
Otto Winter
4b0ec5c28a Work around ESP32 BLE issue (#626) 2019-06-08 16:49:00 +02:00
Otto Winter
4b2a9e5e49 Fix status binary sensor for MQTT (#628)
Fixes https://github.com/esphome/issues/issues/417
2019-06-08 16:48:59 +02:00
Otto Winter
1449c51d49 Update base image to 1.8.3 (#625) 2019-06-08 16:48:59 +02:00
Otto Winter
a451705e0b Fix sun default elevation (#620) 2019-06-08 16:48:58 +02:00
Otto Winter
2e6db39173 Fix integration sensor, add test (#619)
* Fix integration sensor, add test

* Fix

* Fix
2019-06-08 16:48:58 +02:00
Otto Winter
373f75253c Update docker base image to 1.8.0 (#618) 2019-06-08 16:48:58 +02:00
Otto Winter
724842084e Make ForCondition a component (#616)
Fixes https://github.com/esphome/issues/issues/396
2019-06-08 16:48:57 +02:00
Otto Winter
8f3635b167 Fix remote_receiver always shows sony (#617)
Fixes https://github.com/esphome/issues/issues/383#issuecomment-498370572
2019-06-08 16:48:57 +02:00
Otto Winter
11605a36f7 Fix Hass.io addon SSL (#613)
Fixes https://github.com/esphome/issues/issues/404
2019-06-08 16:48:56 +02:00
Otto Winter
533f81d625 Template Cover don't auto-set current_operation (#612)
Fixes https://github.com/esphome/issues/issues/408
2019-06-08 16:48:56 +02:00
Otto Winter
aacb9e44e8 DHT22 ignore invalid values (#614)
Fixes https://github.com/esphome/issues/issues/397
2019-06-08 16:48:55 +02:00
Peter Tatrai
c6e3f1bca6 Fix ForCondition time duration check (#610)
According documentation ForCondition should evaluate to true if a nested condition is true for at least the specified time duration and not the less.
2019-06-08 16:48:55 +02:00
Otto Winter
a933d4aeb6 Move ESPHome version define (#607)
* Move ESPHome version define

* Lint
2019-06-08 16:48:55 +02:00
Otto Winter
caa5b20791 Bump version to v1.13.4 2019-06-03 15:24:10 +02:00
Otto Winter
e2ad9ed746 ESP8266 connect fixes (#605)
* ESP8266 Connection Fixes

* Update client.py

* Update mqtt_client.cpp

* Update mqtt_client.cpp

* Fix ping

* Async dump config

* Update base image to 1.7.0

* Update helpers.py

* Updates

* Update Dockerfile.lint
2019-06-03 15:23:57 +02:00
Otto Winter
32c0e7c2ae Fix ADS1115 calculation (#606)
Fixes https://github.com/esphome/issues/issues/393
2019-06-03 15:23:56 +02:00
Otto Winter
6c564c7b7f Fix validation infinite loop with empty platform block (#598)
* Fix validation infinite loop with empty platform block

* Update util.py
2019-06-03 15:23:56 +02:00
Otto Winter
c81e3a3be4 Fix hx711 (#602)
* Fix HX711

* Use signed value

* Update hx711.cpp
2019-06-03 15:23:56 +02:00
Otto Winter
6b1b9ef7ec Fix color wipe effect (#599) 2019-06-03 15:23:56 +02:00
Otto Winter
c26a8b8718 Allow old remote_transmitter repeat schema (#601)
Fixes https://github.com/esphome/issues/issues/389
2019-06-03 15:23:56 +02:00
Otto Winter
4a89a475bd Add better esphomeyaml migration path (#600)
Fixes https://github.com/esphome/issues/issues/387
2019-06-03 15:23:55 +02:00
Otto Winter
8cf15c7f5c Bump version to v1.13.3 2019-06-01 22:02:10 +02:00
Otto Winter
adc76ca1b8 Fix dashboard for Py3 installs (#596)
Fixes https://github.com/esphome/issues/issues/368
2019-06-01 22:02:05 +02:00
Otto Winter
8f8892440c Fix medium fan speed (#595) 2019-06-01 22:02:04 +02:00
Otto Winter
570843150d Fix flicker light effect turning itself off (#594)
Fixes https://github.com/esphome/issues/issues/382
2019-06-01 22:02:04 +02:00
Otto Winter
f3fc9e4142 Fix remote_receiver binary_sensor (#592)
Fixes https://github.com/esphome/issues/issues/369
2019-06-01 22:02:04 +02:00
Otto Winter
075fcb77a8 Fix timezone detection (#586)
* Fix timezone detection

* Update __init__.py
2019-06-01 22:02:04 +02:00
Otto Winter
e5899ff717 Fix scripts circular dependency (#591)
Fixes https://github.com/esphome/issues/issues/370
2019-06-01 22:02:04 +02:00
Otto Winter
2fb3970027 Fix addressable effects (#590) 2019-06-01 22:02:03 +02:00
Marc-Antoine Courteau
1a4efa1b8c List the correct boards when building for ESP32 (#589)
* List the ESP32 boards for ESP32 builds.

* Sort the list of valid boards.
2019-06-01 22:02:03 +02:00
Otto Winter
72f656ffef Bump version to v1.13.2 2019-05-31 16:37:56 +02:00
Otto Winter
b60239d5e5 Fix i2c setup priority (#585)
Fixes https://github.com/esphome/issues/issues/314
2019-05-31 16:37:49 +02:00
Otto Winter
d02e280c3c Fix light partition (#584)
* Fix light partition

Fixes https://github.com/esphome/issues/issues/365

* Lint
2019-05-31 16:37:48 +02:00
Otto Winter
6535b0966e Fix MQTT on_message trigger (#583)
Fixes https://github.com/esphome/issues/issues/363
Fixes https://github.com/esphome/issues/issues/364
2019-05-31 16:37:48 +02:00
Otto Winter
82dbacbee5 Fix travis build (#582) 2019-05-31 16:37:48 +02:00
Otto Winter
2432901974 Fix Rotary Encoder (#580)
Fixes https://github.com/esphome/issues/issues/360
2019-05-31 16:37:48 +02:00
Otto Winter
ebb5d58c14 Fix MQTT client_id changed (#579)
Fixes https://github.com/esphome/issues/issues/323
2019-05-31 16:37:48 +02:00
Otto Winter
605e365405 Fix remote_receiver binary_sensor schema (#578)
Fixes https://github.com/esphome/issues/issues/353#issuecomment-497491863
2019-05-31 16:37:47 +02:00
Otto Winter
5ab995d8ca Bump version to v1.13.1 2019-05-30 22:31:56 +02:00
Otto Winter
4248741b11 Fix waveshare 7.5in model (#576)
* Fix waveshare 7.5in model

Fixes https://github.com/esphome/issues/issues/357

* Fix platformio travis errors
2019-05-30 22:31:54 +02:00
Otto Winter
4b8ecc7634 Dashboard work around Hass.io bug (#575)
* Dashboard work around Hass.io bug

Ref https://github.com/home-assistant/hassio/issues/1103

* Lint
2019-05-30 22:31:53 +02:00
Otto Winter
25d04c759c Fix Sun Trigger (#572)
* Fix Sun Trigger

* Fix cwww lights
2019-05-30 22:31:53 +02:00
Otto Winter
b4ec84030e Fix validation TypeError (#574) 2019-05-30 22:31:53 +02:00
Otto Winter
29e8761373 Fix merge 2019-05-30 14:20:06 +02:00
Otto Winter
a04299c59e Bump version to v1.13.0 2019-05-30 14:15:41 +02:00
Otto Winter
d7bf3c51d9 Merge branch 'beta' 2019-05-30 14:15:28 +02:00
Otto Winter
ac0b095941 Bump version to v1.12.2 2019-03-31 13:13:12 +02:00
Otto Winter
cda9bad233 Upgrade docker base image to 1.4.3 (#499) 2019-03-31 13:13:09 +02:00
Otto Winter
41db8a1264 Fix text sensor MQTT settings (#495)
Fixes https://github.com/esphome/issues/issues/170
2019-03-31 13:13:09 +02:00
Otto Winter
e7e785fd60 Fix dashboard wizard unicode (#494)
* Fix dashboard wizard unicode

Fixes https://github.com/esphome/issues/issues/169

* Fix password md5
2019-03-31 13:13:08 +02:00
Otto Winter
300d3a1f46 Upgrade ESPAsyncTCP to 1.2.0 (#497) 2019-03-31 13:13:08 +02:00
Otto Winter
356554c08d ESP8266 SDK 2.3.0 compat (#490) 2019-03-31 13:13:08 +02:00
Guillermo Ruffino
ced28ad006 Better symlink support under Windows (#487)
* Better symlink support under Windows

* Conditional loading of ctypes wintypes module

* Shortening comment line for pylint

* Adding plint bypass for Python 3
2019-03-31 13:13:08 +02:00
100 changed files with 976 additions and 421 deletions

View File

@@ -364,7 +364,7 @@ def command_update_all(args):
def print_bar(middle_text):
middle_text = " {} ".format(middle_text)
width = len(click.unstyle(middle_text))
half_line = "=" * ((twidth - width) / 2)
half_line = "=" * ((twidth - width) // 2)
click.echo("%s%s%s" % (half_line, middle_text, half_line))
for f in files:

View File

@@ -1,12 +1,11 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_PIN, CONF_INDOOR, CONF_WATCHDOG_THRESHOLD, \
from esphome.const import CONF_INDOOR, CONF_WATCHDOG_THRESHOLD, \
CONF_NOISE_LEVEL, CONF_SPIKE_REJECTION, CONF_LIGHTNING_THRESHOLD, \
CONF_MASK_DISTURBER, CONF_DIV_RATIO, CONF_CAPACITANCE
from esphome.core import coroutine
AUTO_LOAD = ['sensor', 'binary_sensor']
MULTI_CONF = True
@@ -15,10 +14,10 @@ CONF_AS3935_ID = 'as3935_id'
as3935_ns = cg.esphome_ns.namespace('as3935')
AS3935 = as3935_ns.class_('AS3935Component', cg.Component)
CONF_IRQ_PIN = 'irq_pin'
AS3935_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(AS3935),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt),
cv.Required(CONF_IRQ_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_INDOOR, default=True): cv.boolean,
cv.Optional(CONF_NOISE_LEVEL, default=2): cv.int_range(min=1, max=7),
@@ -35,8 +34,8 @@ AS3935_SCHEMA = cv.Schema({
def setup_as3935(var, config):
yield cg.register_component(var, config)
pin = yield cg.gpio_pin_expression(config[CONF_PIN])
cg.add(var.set_pin(pin))
irq_pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN])
cg.add(var.set_irq_pin(irq_pin))
cg.add(var.set_indoor(config[CONF_INDOOR]))
cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL]))
cg.add(var.set_watchdog_threshold(config[CONF_WATCHDOG_THRESHOLD]))

View File

@@ -9,10 +9,8 @@ static const char *TAG = "as3935";
void AS3935Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up AS3935...");
this->pin_->setup();
this->store_.pin = this->pin_->to_isr();
LOG_PIN(" Interrupt Pin: ", this->pin_);
this->pin_->attach_interrupt(AS3935ComponentStore::gpio_intr, &this->store_, RISING);
this->irq_pin_->setup();
LOG_PIN(" IRQ Pin: ", this->irq_pin_);
// Write properties to sensor
this->write_indoor(this->indoor_);
@@ -27,13 +25,13 @@ void AS3935Component::setup() {
void AS3935Component::dump_config() {
ESP_LOGCONFIG(TAG, "AS3935:");
LOG_PIN(" Interrupt Pin: ", this->pin_);
LOG_PIN(" Interrupt Pin: ", this->irq_pin_);
}
float AS3935Component::get_setup_priority() const { return setup_priority::DATA; }
void AS3935Component::loop() {
if (!this->store_.interrupt)
if (!this->irq_pin_->digital_read())
return;
uint8_t int_value = this->read_interrupt_register_();
@@ -53,7 +51,6 @@ void AS3935Component::loop() {
this->energy_sensor_->publish_state(energy);
}
this->thunder_alert_binary_sensor_->publish_state(false);
this->store_.interrupt = false;
}
void AS3935Component::write_indoor(bool indoor) {
@@ -222,7 +219,5 @@ uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) {
return value;
}
void ICACHE_RAM_ATTR AS3935ComponentStore::gpio_intr(AS3935ComponentStore *arg) { arg->interrupt = true; }
} // namespace as3935
} // namespace esphome

View File

@@ -50,14 +50,6 @@ enum AS3935Values {
NOISE_INT = 0x01
};
/// Store data in a class that doesn't use multiple-inheritance (vtables in flash)
struct AS3935ComponentStore {
volatile bool interrupt;
ISRInternalGPIOPin *pin;
static void gpio_intr(AS3935ComponentStore *arg);
};
class AS3935Component : public Component {
public:
void setup() override;
@@ -65,7 +57,7 @@ class AS3935Component : public Component {
float get_setup_priority() const override;
void loop() override;
void set_pin(GPIOPin *pin) { pin_ = pin; }
void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; }
void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; }
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) {
@@ -102,8 +94,7 @@ class AS3935Component : public Component {
sensor::Sensor *distance_sensor_;
sensor::Sensor *energy_sensor_;
binary_sensor::BinarySensor *thunder_alert_binary_sensor_;
GPIOPin *pin_;
AS3935ComponentStore store_;
GPIOPin *irq_pin_;
bool indoor_;
uint8_t noise_level_;

View File

@@ -31,6 +31,10 @@ uint8_t I2CAS3935Component::read_register(uint8_t reg) {
}
return value;
}
void I2CAS3935Component::dump_config() {
AS3935Component::dump_config();
LOG_I2C_DEVICE(this);
}
} // namespace as3935_i2c
} // namespace esphome

View File

@@ -10,6 +10,9 @@ namespace esphome {
namespace as3935_i2c {
class I2CAS3935Component : public as3935::AS3935Component, public i2c::I2CDevice {
public:
void dump_config() override;
protected:
void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) override;
uint8_t read_register(uint8_t reg) override;

View File

@@ -145,6 +145,14 @@ Trigger<> *BangBangClimate::get_cool_trigger() const { return this->cool_trigger
void BangBangClimate::set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; }
Trigger<> *BangBangClimate::get_heat_trigger() const { return this->heat_trigger_; }
void BangBangClimate::set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; }
void BangBangClimate::dump_config() {
LOG_CLIMATE("", "Bang Bang Climate", this);
ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_));
ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_));
ESP_LOGCONFIG(TAG, " Supports AWAY mode: %s", YESNO(this->supports_away_));
ESP_LOGCONFIG(TAG, " Default Target Temperature Low: %.1f°C", this->normal_config_.default_temperature_low);
ESP_LOGCONFIG(TAG, " Default Target Temperature High: %.1f°C", this->normal_config_.default_temperature_high);
}
BangBangClimateTargetTempConfig::BangBangClimateTargetTempConfig() = default;
BangBangClimateTargetTempConfig::BangBangClimateTargetTempConfig(float default_temperature_low,

View File

@@ -21,6 +21,7 @@ class BangBangClimate : public climate::Climate, public Component {
public:
BangBangClimate();
void setup() override;
void dump_config() override;
void set_sensor(sensor::Sensor *sensor);
Trigger<> *get_idle_trigger() const;

View File

@@ -24,4 +24,4 @@ def to_code(config):
if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
cg.add(var.set_oscillation(oscillation_output))
cg.add(var.set_oscillating(oscillation_output))

View File

@@ -23,6 +23,7 @@ IS_PLATFORM_COMPONENT = True
binary_sensor_ns = cg.esphome_ns.namespace('binary_sensor')
BinarySensor = binary_sensor_ns.class_('BinarySensor', cg.Nameable)
BinarySensorInitiallyOff = binary_sensor_ns.class_('BinarySensorInitiallyOff', BinarySensor)
BinarySensorPtr = BinarySensor.operator('ptr')
# Triggers

View File

@@ -10,9 +10,9 @@ namespace binary_sensor {
#define LOG_BINARY_SENSOR(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, prefix type " '%s'", obj->get_name().c_str()); \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, type, obj->get_name().c_str()); \
if (!obj->get_device_class().empty()) { \
ESP_LOGCONFIG(TAG, prefix " Device Class: '%s'", obj->get_device_class().c_str()); \
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str()); \
} \
}
@@ -67,7 +67,7 @@ class BinarySensor : public Nameable {
void send_state_internal(bool state, bool is_initial);
/// Return whether this binary sensor has outputted a state.
bool has_state() const;
virtual bool has_state() const;
virtual bool is_status_binary_sensor() const;
@@ -86,5 +86,10 @@ class BinarySensor : public Nameable {
Deduplicator<bool> publish_dedup_;
};
class BinarySensorInitiallyOff : public BinarySensor {
public:
bool has_state() const override { return true; }
};
} // namespace binary_sensor
} // namespace esphome

View File

@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome.components import sensor, binary_sensor
from esphome.const import CONF_ID, CONF_CHANNELS, CONF_VALUE, CONF_TYPE, UNIT_EMPTY, \
ICON_CHECK_CIRCLE_OUTLINE, CONF_BINARY_SENSOR
ICON_CHECK_CIRCLE_OUTLINE, CONF_BINARY_SENSOR, CONF_GROUP
DEPENDENCIES = ['binary_sensor']
@@ -11,7 +11,6 @@ binary_sensor_map_ns = cg.esphome_ns.namespace('binary_sensor_map')
BinarySensorMap = binary_sensor_map_ns.class_('BinarySensorMap', cg.Component, sensor.Sensor)
SensorMapType = binary_sensor_map_ns.enum('SensorMapType')
CONF_GROUP = 'group'
SENSOR_MAP_TYPES = {
CONF_GROUP: SensorMapType.BINARY_SENSOR_MAP_TYPE_GROUP,
}

View File

@@ -9,7 +9,7 @@
namespace esphome {
namespace ble_presence {
class BLEPresenceDevice : public binary_sensor::BinarySensor,
class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
public esp32_ble_tracker::ESPBTDeviceListener,
public Component {
public:

View File

@@ -166,6 +166,7 @@ float CaptivePortal::get_setup_priority() const {
// Before WiFi
return setup_priority::WIFI + 1.0f;
}
void CaptivePortal::dump_config() { ESP_LOGCONFIG(TAG, "Captive Portal:"); }
CaptivePortal *global_captive_portal = nullptr;

View File

@@ -2,6 +2,7 @@
#include <DNSServer.h>
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include "esphome/components/web_server_base/web_server_base.h"
@@ -18,6 +19,7 @@ class CaptivePortal : public AsyncWebHandler, public Component {
public:
CaptivePortal(web_server_base::WebServerBase *base);
void setup() override;
void dump_config() override;
void loop() override {
if (this->dns_server_ != nullptr)
this->dns_server_->processNextRequest();

View File

@@ -9,6 +9,11 @@
namespace esphome {
namespace climate {
#define LOG_CLIMATE(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, type, obj->get_name().c_str()); \
}
class Climate;
/** This class is used to encode all control actions on a climate device.

View File

@@ -0,0 +1,41 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate, remote_transmitter, remote_receiver, sensor, remote_base
from esphome.components.remote_base import CONF_RECEIVER_ID, CONF_TRANSMITTER_ID
from esphome.const import CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, CONF_SENSOR
from esphome.core import coroutine
AUTO_LOAD = ['sensor', 'remote_base']
climate_ir_ns = cg.esphome_ns.namespace('climate_ir')
ClimateIR = climate_ir_ns.class_('ClimateIR', climate.Climate, cg.Component,
remote_base.RemoteReceiverListener)
CLIMATE_IR_SCHEMA = climate.CLIMATE_SCHEMA.extend({
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),
cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean,
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor),
}).extend(cv.COMPONENT_SCHEMA)
CLIMATE_IR_WITH_RECEIVER_SCHEMA = CLIMATE_IR_SCHEMA.extend({
cv.Optional(CONF_RECEIVER_ID): cv.use_id(remote_receiver.RemoteReceiverComponent),
})
@coroutine
def register_climate_ir(var, config):
yield cg.register_component(var, config)
yield climate.register_climate(var, config)
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
if CONF_SENSOR in config:
sens = yield cg.get_variable(config[CONF_SENSOR])
cg.add(var.set_sensor(sens))
if CONF_RECEIVER_ID in config:
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
cg.add(receiver.register_listener(var))
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
cg.add(var.set_transmitter(transmitter))

View File

@@ -1,7 +1,10 @@
#include "climate_ir.h"
#include "esphome/core/log.h"
namespace esphome {
namespace climate {
namespace climate_ir {
static const char *TAG = "climate_ir";
climate::ClimateTraits ClimateIR::traits() {
auto traits = climate::ClimateTraits();
@@ -52,6 +55,13 @@ void ClimateIR::control(const climate::ClimateCall &call) {
this->transmit_state();
this->publish_state();
}
void ClimateIR::dump_config() {
LOG_CLIMATE("", "IR Climate", this);
ESP_LOGCONFIG(TAG, " Min. Temperature: %.1f°C", this->minimum_temperature_);
ESP_LOGCONFIG(TAG, " Max. Temperature: %.1f°C", this->maximum_temperature_);
ESP_LOGCONFIG(TAG, " Supports HEAT: %s", YESNO(this->supports_heat_));
ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_));
}
} // namespace climate
} // namespace climate_ir
} // namespace esphome

View File

@@ -6,7 +6,7 @@
#include "esphome/components/sensor/sensor.h"
namespace esphome {
namespace climate {
namespace climate_ir {
/* A base for climate which works by sending (and receiving) IR codes
@@ -25,6 +25,7 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
}
void setup() override;
void dump_config() override;
void set_transmitter(remote_transmitter::RemoteTransmitterComponent *transmitter) {
this->transmitter_ = transmitter;
}
@@ -41,7 +42,7 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
climate::ClimateTraits traits() override;
/// Transmit via IR the state of this climate controller.
virtual void transmit_state() {}
virtual void transmit_state() = 0;
bool supports_cool_{true};
bool supports_heat_{true};
@@ -49,5 +50,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
remote_transmitter::RemoteTransmitterComponent *transmitter_;
sensor::Sensor *sensor_{nullptr};
};
} // namespace climate
} // namespace climate_ir
} // namespace esphome

View File

@@ -1,41 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
from esphome.const import CONF_ID, CONF_SENSOR
from esphome.components import climate_ir
from esphome.const import CONF_ID
AUTO_LOAD = ['sensor', 'climate_ir']
AUTO_LOAD = ['climate_ir']
coolix_ns = cg.esphome_ns.namespace('coolix')
CoolixClimate = coolix_ns.class_('CoolixClimate', climate.Climate, cg.Component)
CoolixClimate = coolix_ns.class_('CoolixClimate', climate_ir.ClimateIR)
CONF_TRANSMITTER_ID = 'transmitter_id'
CONF_RECEIVER_ID = 'receiver_id'
CONF_SUPPORTS_HEAT = 'supports_heat'
CONF_SUPPORTS_COOL = 'supports_cool'
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(CoolixClimate),
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),
cv.Optional(CONF_RECEIVER_ID): cv.use_id(remote_receiver.RemoteReceiverComponent),
cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean,
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor),
}).extend(cv.COMPONENT_SCHEMA))
})
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield climate.register_climate(var, config)
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
if CONF_SENSOR in config:
sens = yield cg.get_variable(config[CONF_SENSOR])
cg.add(var.set_sensor(sens))
if CONF_RECEIVER_ID in config:
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
cg.add(receiver.register_listener(var))
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
cg.add(var.set_transmitter(transmitter))
yield climate_ir.register_climate_ir(var, config)

View File

@@ -9,9 +9,9 @@ namespace coolix {
const uint8_t COOLIX_TEMP_MIN = 17; // Celsius
const uint8_t COOLIX_TEMP_MAX = 30; // Celsius
class CoolixClimate : public climate::ClimateIR {
class CoolixClimate : public climate_ir::ClimateIR {
public:
CoolixClimate() : climate::ClimateIR(COOLIX_TEMP_MIN, COOLIX_TEMP_MAX) {}
CoolixClimate() : climate_ir::ClimateIR(COOLIX_TEMP_MIN, COOLIX_TEMP_MAX) {}
protected:
/// Transmit via IR the state of this climate controller.

View File

@@ -13,13 +13,13 @@ const extern float COVER_CLOSED;
#define LOG_COVER(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, prefix type " '%s'", obj->get_name().c_str()); \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, type, obj->get_name().c_str()); \
auto traits_ = obj->get_traits(); \
if (traits_.get_is_assumed_state()) { \
ESP_LOGCONFIG(TAG, prefix " Assumed State: YES"); \
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
} \
if (!obj->get_device_class().empty()) { \
ESP_LOGCONFIG(TAG, prefix " Device Class: '%s'", obj->get_device_class().c_str()); \
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str()); \
} \
}

View File

@@ -1,13 +1,12 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_OUTPUTS, CONF_TYPE
from esphome.const import CONF_ID, CONF_LAMBDA, CONF_OUTPUTS, CONF_TYPE, CONF_BINARY
from .. import custom_ns
CustomBinaryOutputConstructor = custom_ns.class_('CustomBinaryOutputConstructor')
CustomFloatOutputConstructor = custom_ns.class_('CustomFloatOutputConstructor')
CONF_BINARY = 'binary'
CONF_FLOAT = 'float'
CONFIG_SCHEMA = cv.typed_schema({

View File

@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.const import CONF_ID, CONF_TRIGGER_ID
from esphome.const import CONF_ID, CONF_TRIGGER_ID, CONF_FILE, CONF_DEVICE
from esphome.components import uart
DEPENDENCIES = ['uart']
@@ -14,10 +14,8 @@ DFPlayerIsPlayingCondition = dfplayer_ns.class_('DFPlayerIsPlayingCondition', au
MULTI_CONF = True
CONF_FOLDER = 'folder'
CONF_FILE = 'file'
CONF_LOOP = 'loop'
CONF_VOLUME = 'volume'
CONF_DEVICE = 'device'
CONF_EQ_PRESET = 'eq_preset'
CONF_ON_FINISHED_PLAYBACK = 'on_finished_playback'

View File

@@ -115,6 +115,10 @@ void DFPlayer::loop() {
this->read_pos_++;
}
}
void DFPlayer::dump_config() {
ESP_LOGCONFIG(TAG, "DFPlayer:");
this->check_uart_settings(9600);
}
} // namespace dfplayer
} // namespace esphome

View File

@@ -52,6 +52,7 @@ class DFPlayer : public uart::UARTDevice, public Component {
void random() { this->send_cmd_(0x18); }
bool is_playing() { return is_playing_; }
void dump_config() override;
void add_on_finished_playback_callback(std::function<void()> callback) {
this->on_finished_playback_callback_.add(std::move(callback));

View File

@@ -84,8 +84,8 @@ using display_writer_t = std::function<void(DisplayBuffer &)>;
#define LOG_DISPLAY(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, prefix type); \
ESP_LOGCONFIG(TAG, prefix " Rotations: %d °", obj->rotation_); \
ESP_LOGCONFIG(TAG, prefix " Dimensions: %dpx x %dpx", obj->get_width(), obj->get_height()); \
ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, obj->rotation_); \
ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, obj->get_width(), obj->get_height()); \
}
class DisplayBuffer {

View File

@@ -31,6 +31,11 @@ static esp_ble_adv_params_t ble_adv_params = {
static esp_ble_ibeacon_head_t ibeacon_common_head = {
.flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = 0x004C, .beacon_type = 0x1502};
void ESP32BLEBeacon::dump_config() {
ESP_LOGCONFIG(TAG, "ESP32 BLE Beacon:");
ESP_LOGCONFIG(TAG, " Major: %u, Minor: %u", this->major_, this->minor_);
}
void ESP32BLEBeacon::setup() {
ESP_LOGCONFIG(TAG, "Setting up ESP32 BLE beacon...");
global_esp32_ble_beacon = this;
@@ -50,7 +55,7 @@ void ESP32BLEBeacon::ble_core_task(void *params) {
ble_setup();
while (true) {
delay(1000);
delay(1000); // NOLINT
}
}
void ESP32BLEBeacon::ble_setup() {

View File

@@ -34,6 +34,7 @@ class ESP32BLEBeacon : public Component {
explicit ESP32BLEBeacon(const std::array<uint8_t, 16> &uuid) : uuid_(uuid) {}
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void set_major(uint16_t major) { this->major_ = major; }

View File

@@ -134,7 +134,7 @@ bool ESP32BLETracker::ble_setup() {
}
// BLE takes some time to be fully set up, 200ms should be more than enough
delay(200);
delay(200); // NOLINT
return true;
}

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.const import CONF_FREQUENCY, CONF_ID, CONF_NAME, CONF_PIN, CONF_SCL, CONF_SDA, \
ESP_PLATFORM_ESP32
ESP_PLATFORM_ESP32, CONF_DATA_PINS, CONF_RESET_PIN, CONF_RESOLUTION, CONF_BRIGHTNESS
ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
DEPENDENCIES = ['api']
@@ -35,23 +35,19 @@ FRAME_SIZES = {
'UXGA': ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
}
CONF_DATA_PINS = 'data_pins'
CONF_VSYNC_PIN = 'vsync_pin'
CONF_HREF_PIN = 'href_pin'
CONF_PIXEL_CLOCK_PIN = 'pixel_clock_pin'
CONF_EXTERNAL_CLOCK = 'external_clock'
CONF_I2C_PINS = 'i2c_pins'
CONF_RESET_PIN = 'reset_pin'
CONF_POWER_DOWN_PIN = 'power_down_pin'
CONF_MAX_FRAMERATE = 'max_framerate'
CONF_IDLE_FRAMERATE = 'idle_framerate'
CONF_RESOLUTION = 'resolution'
CONF_JPEG_QUALITY = 'jpeg_quality'
CONF_VERTICAL_FLIP = 'vertical_flip'
CONF_HORIZONTAL_MIRROR = 'horizontal_mirror'
CONF_CONTRAST = 'contrast'
CONF_BRIGHTNESS = 'brightness'
CONF_SATURATION = 'saturation'
CONF_TEST_PATTERN = 'test_pattern'

View File

@@ -108,6 +108,8 @@ void ESP32TouchComponent::dump_config() {
}
void ESP32TouchComponent::loop() {
const uint32_t now = millis();
bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250;
for (auto *child : this->children_) {
uint16_t value;
if (this->iir_filter_enabled_()) {
@@ -119,14 +121,14 @@ void ESP32TouchComponent::loop() {
child->value_ = value;
child->publish_state(value < child->get_threshold());
if (this->setup_mode_) {
if (should_print) {
ESP_LOGD(TAG, "Touch Pad '%s' (T%u): %u", child->get_name().c_str(), child->get_touch_pad(), value);
}
}
if (this->setup_mode_) {
if (should_print) {
// Avoid spamming logs
delay(250);
this->setup_mode_last_log_print_ = now;
}
}

View File

@@ -50,6 +50,7 @@ class ESP32TouchComponent : public Component {
touch_volt_atten_t voltage_attenuation_{};
std::vector<ESP32TouchBinarySensor *> children_;
bool setup_mode_{false};
uint32_t setup_mode_last_log_print_{};
uint32_t iir_filter_{0};
};

View File

@@ -0,0 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate_ir
from esphome.const import CONF_ID
AUTO_LOAD = ['climate_ir']
fujitsu_general_ns = cg.esphome_ns.namespace('fujitsu_general')
FujitsuGeneralClimate = fujitsu_general_ns.class_('FujitsuGeneralClimate', climate_ir.ClimateIR)
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(FujitsuGeneralClimate),
})
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield climate_ir.register_climate_ir(var, config)

View File

@@ -0,0 +1,212 @@
#include "fujitsu_general.h"
namespace esphome {
namespace fujitsu_general {
static const char *TAG = "fujitsu_general.climate";
// Control packet
const uint16_t FUJITSU_GENERAL_STATE_LENGTH = 16;
const uint8_t FUJITSU_GENERAL_BASE_BYTE0 = 0x14;
const uint8_t FUJITSU_GENERAL_BASE_BYTE1 = 0x63;
const uint8_t FUJITSU_GENERAL_BASE_BYTE2 = 0x00;
const uint8_t FUJITSU_GENERAL_BASE_BYTE3 = 0x10;
const uint8_t FUJITSU_GENERAL_BASE_BYTE4 = 0x10;
const uint8_t FUJITSU_GENERAL_BASE_BYTE5 = 0xFE;
const uint8_t FUJITSU_GENERAL_BASE_BYTE6 = 0x09;
const uint8_t FUJITSU_GENERAL_BASE_BYTE7 = 0x30;
// Temperature and POWER ON
const uint8_t FUJITSU_GENERAL_POWER_ON_MASK_BYTE8 = 0b00000001;
const uint8_t FUJITSU_GENERAL_BASE_BYTE8 = 0x40;
// Mode
const uint8_t FUJITSU_GENERAL_MODE_AUTO_BYTE9 = 0x00;
const uint8_t FUJITSU_GENERAL_MODE_HEAT_BYTE9 = 0x04;
const uint8_t FUJITSU_GENERAL_MODE_COOL_BYTE9 = 0x01;
const uint8_t FUJITSU_GENERAL_MODE_DRY_BYTE9 = 0x02;
const uint8_t FUJITSU_GENERAL_MODE_FAN_BYTE9 = 0x03;
const uint8_t FUJITSU_GENERAL_MODE_10C_BYTE9 = 0x0B;
const uint8_t FUJITSU_GENERAL_BASE_BYTE9 = 0x01;
// Fan speed and swing
const uint8_t FUJITSU_GENERAL_FAN_AUTO_BYTE10 = 0x00;
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_BASE_BYTE10 = 0x00;
const uint8_t FUJITSU_GENERAL_BASE_BYTE11 = 0x00;
const uint8_t FUJITSU_GENERAL_BASE_BYTE12 = 0x00;
const uint8_t FUJITSU_GENERAL_BASE_BYTE13 = 0x00;
// Outdoor Unit Low Noise
const uint8_t FUJITSU_GENERAL_OUTDOOR_UNIT_LOW_NOISE_BYTE14 = 0xA0;
const uint8_t FUJITSU_GENERAL_BASE_BYTE14 = 0x20;
// CRC
const uint8_t FUJITSU_GENERAL_BASE_BYTE15 = 0x6F;
// Power off packet is specific
const uint16_t FUJITSU_GENERAL_OFF_LENGTH = 7;
const uint8_t FUJITSU_GENERAL_OFF_BYTE0 = FUJITSU_GENERAL_BASE_BYTE0;
const uint8_t FUJITSU_GENERAL_OFF_BYTE1 = FUJITSU_GENERAL_BASE_BYTE1;
const uint8_t FUJITSU_GENERAL_OFF_BYTE2 = FUJITSU_GENERAL_BASE_BYTE2;
const uint8_t FUJITSU_GENERAL_OFF_BYTE3 = FUJITSU_GENERAL_BASE_BYTE3;
const uint8_t FUJITSU_GENERAL_OFF_BYTE4 = FUJITSU_GENERAL_BASE_BYTE4;
const uint8_t FUJITSU_GENERAL_OFF_BYTE5 = 0x02;
const uint8_t FUJITSU_GENERAL_OFF_BYTE6 = 0xFD;
const uint8_t FUJITSU_GENERAL_TEMP_MAX = 30; // Celsius
const uint8_t FUJITSU_GENERAL_TEMP_MIN = 16; // Celsius
const uint16_t FUJITSU_GENERAL_HEADER_MARK = 3300;
const uint16_t FUJITSU_GENERAL_HEADER_SPACE = 1600;
const uint16_t FUJITSU_GENERAL_BIT_MARK = 420;
const uint16_t FUJITSU_GENERAL_ONE_SPACE = 1200;
const uint16_t FUJITSU_GENERAL_ZERO_SPACE = 420;
const uint16_t FUJITSU_GENERAL_TRL_MARK = 420;
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) {}
void FujitsuGeneralClimate::transmit_state() {
if (this->mode == climate::CLIMATE_MODE_OFF) {
this->transmit_off_();
return;
}
uint8_t remote_state[FUJITSU_GENERAL_STATE_LENGTH] = {0};
remote_state[0] = FUJITSU_GENERAL_BASE_BYTE0;
remote_state[1] = FUJITSU_GENERAL_BASE_BYTE1;
remote_state[2] = FUJITSU_GENERAL_BASE_BYTE2;
remote_state[3] = FUJITSU_GENERAL_BASE_BYTE3;
remote_state[4] = FUJITSU_GENERAL_BASE_BYTE4;
remote_state[5] = FUJITSU_GENERAL_BASE_BYTE5;
remote_state[6] = FUJITSU_GENERAL_BASE_BYTE6;
remote_state[7] = FUJITSU_GENERAL_BASE_BYTE7;
remote_state[8] = FUJITSU_GENERAL_BASE_BYTE8;
remote_state[9] = FUJITSU_GENERAL_BASE_BYTE9;
remote_state[10] = FUJITSU_GENERAL_BASE_BYTE10;
remote_state[11] = FUJITSU_GENERAL_BASE_BYTE11;
remote_state[12] = FUJITSU_GENERAL_BASE_BYTE12;
remote_state[13] = FUJITSU_GENERAL_BASE_BYTE13;
remote_state[14] = FUJITSU_GENERAL_BASE_BYTE14;
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);
remote_state[8] = (byte) safecelsius - 16;
remote_state[8] = remote_state[8] << 4;
// If not powered - set power on flag
if (!this->power_) {
remote_state[8] = (byte) remote_state[8] | FUJITSU_GENERAL_POWER_ON_MASK_BYTE8;
}
// Set mode
switch (this->mode) {
case climate::CLIMATE_MODE_COOL:
remote_state[9] = FUJITSU_GENERAL_MODE_COOL_BYTE9;
break;
case climate::CLIMATE_MODE_HEAT:
remote_state[9] = FUJITSU_GENERAL_MODE_HEAT_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: missing support for fan speed
remote_state[10] = FUJITSU_GENERAL_FAN_AUTO_BYTE10;
// TODO: missing support for swing
// remote_state[10] = (byte) remote_state[10] | FUJITSU_GENERAL_SWING_MASK_BYTE10;
// TODO: missing support for outdoor unit low noise
// remote_state[14] = (byte) remote_state[14] | FUJITSU_GENERAL_OUTDOOR_UNIT_LOW_NOISE_BYTE14;
// CRC
remote_state[15] = 0;
for (int i = 7; i < 15; i++) {
remote_state[15] += (byte) remote_state[i]; // Addiction
}
remote_state[15] = 0x100 - remote_state[15]; // mod 256
auto transmit = this->transmitter_->transmit();
auto data = transmit.get_data();
data->set_carrier_frequency(FUJITSU_GENERAL_CARRIER_FREQUENCY);
// Header
data->mark(FUJITSU_GENERAL_HEADER_MARK);
data->space(FUJITSU_GENERAL_HEADER_SPACE);
// Data
for (uint8_t i : remote_state) {
// Send all Bits from Byte Data in Reverse Order
for (uint8_t mask = 00000001; mask > 0; mask <<= 1) { // iterate through bit mask
data->mark(FUJITSU_GENERAL_BIT_MARK);
bool bit = i & mask;
data->space(bit ? FUJITSU_GENERAL_ONE_SPACE : FUJITSU_GENERAL_ZERO_SPACE);
// Next bits
}
}
// Footer
data->mark(FUJITSU_GENERAL_TRL_MARK);
data->space(FUJITSU_GENERAL_TRL_SPACE);
transmit.perform();
this->power_ = true;
}
void FujitsuGeneralClimate::transmit_off_() {
uint8_t remote_state[FUJITSU_GENERAL_OFF_LENGTH] = {0};
remote_state[0] = FUJITSU_GENERAL_OFF_BYTE0;
remote_state[1] = FUJITSU_GENERAL_OFF_BYTE1;
remote_state[2] = FUJITSU_GENERAL_OFF_BYTE2;
remote_state[3] = FUJITSU_GENERAL_OFF_BYTE3;
remote_state[4] = FUJITSU_GENERAL_OFF_BYTE4;
remote_state[5] = FUJITSU_GENERAL_OFF_BYTE5;
remote_state[6] = FUJITSU_GENERAL_OFF_BYTE6;
auto transmit = this->transmitter_->transmit();
auto data = transmit.get_data();
data->set_carrier_frequency(FUJITSU_GENERAL_CARRIER_FREQUENCY);
// Header
data->mark(FUJITSU_GENERAL_HEADER_MARK);
data->space(FUJITSU_GENERAL_HEADER_SPACE);
// Data
for (uint8_t i : remote_state) {
// Send all Bits from Byte Data in Reverse Order
for (uint8_t mask = 00000001; mask > 0; mask <<= 1) { // iterate through bit mask
data->mark(FUJITSU_GENERAL_BIT_MARK);
bool bit = i & mask;
data->space(bit ? FUJITSU_GENERAL_ONE_SPACE : FUJITSU_GENERAL_ZERO_SPACE);
// Next bits
}
}
// Footer
data->mark(FUJITSU_GENERAL_TRL_MARK);
data->space(FUJITSU_GENERAL_TRL_SPACE);
transmit.perform();
this->power_ = false;
}
} // namespace fujitsu_general
} // namespace esphome

View File

@@ -0,0 +1,24 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/climate_ir/climate_ir.h"
namespace esphome {
namespace fujitsu_general {
class FujitsuGeneralClimate : public climate_ir::ClimateIR {
public:
FujitsuGeneralClimate();
protected:
/// Transmit via IR the state of this climate controller.
void transmit_state() override;
/// Transmit via IR power off command.
void transmit_off_();
bool power_{false};
};
} // namespace fujitsu_general
} // namespace esphome

View File

@@ -30,6 +30,7 @@ class Logger : public Component {
/// Manually set the baud rate for serial, set to 0 to disable.
void set_baud_rate(uint32_t baud_rate);
uint32_t get_baud_rate() const { return baud_rate_; }
/// Get the UART used by the logger.
UARTSelection get_uart() const;

View File

@@ -41,3 +41,4 @@ def register_modbus_device(var, config):
parent = yield cg.get_variable(config[CONF_MODBUS_ID])
cg.add(var.set_parent(parent))
cg.add(var.set_address(config[CONF_ADDRESS]))
cg.add(parent.register_device(var))

View File

@@ -10,7 +10,7 @@ void MPR121Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up MPR121...");
// soft reset device
this->write_byte(MPR121_SOFTRESET, 0x63);
delay(100);
delay(100); // NOLINT
if (!this->write_byte(MPR121_ECR, 0x0)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();

View File

@@ -201,7 +201,7 @@ void MQTTClientComponent::check_connected() {
this->status_clear_warning();
ESP_LOGI(TAG, "MQTT Connected!");
// MQTT Client needs some time to be fully set up.
delay(100);
delay(100); // NOLINT
this->resubscribe_subscriptions_();

View File

@@ -19,7 +19,7 @@ void MS5611Component::setup() {
this->mark_failed();
return;
}
delay(100);
delay(100); // NOLINT
for (uint8_t offset = 0; offset < 6; offset++) {
if (!this->read_byte_16(MS5611_CMD_READ_PROM + (offset * 2), &this->prom_[offset])) {
this->mark_failed();

View File

@@ -394,7 +394,7 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
bool wait_for_ack_{true};
};
class NextionTouchComponent : public binary_sensor::BinarySensor {
class NextionTouchComponent : public binary_sensor::BinarySensorInitiallyOff {
public:
void set_page_id(uint8_t page_id) { page_id_ = page_id; }
void set_component_id(uint8_t component_id) { component_id_ = component_id; }

View File

@@ -19,9 +19,9 @@ void NTC::process_(float value) {
return;
}
float lr = logf(value);
float v = this->a_ + this->b_ * lr + this->c_ * lr * lr * lr;
float temp = 1 / v - 273.15f;
double lr = log(double(value));
double v = this->a_ + this->b_ * lr + this->c_ * lr * lr * lr;
auto temp = float(1.0 / v - 273.15);
ESP_LOGD(TAG, "'%s' - Temperature: %.1f°C", this->name_.c_str(), temp);
this->publish_state(temp);

View File

@@ -9,9 +9,9 @@ namespace ntc {
class NTC : public Component, public sensor::Sensor {
public:
void set_sensor(Sensor *sensor) { sensor_ = sensor; }
void set_a(float a) { a_ = a; }
void set_b(float b) { b_ = b; }
void set_c(float c) { c_ = c; }
void set_a(double a) { a_ = a; }
void set_b(double b) { b_ = b; }
void set_c(double c) { c_ = c; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
@@ -20,9 +20,9 @@ class NTC : public Component, public sensor::Sensor {
void process_(float value);
sensor::Sensor *sensor_;
float a_;
float b_;
float c_;
double a_;
double b_;
double c_;
};
} // namespace ntc

View File

@@ -266,7 +266,7 @@ void OTAComponent::handle_() {
delay(10);
ESP_LOGI(TAG, "OTA update finished!");
this->status_clear_warning();
delay(100);
delay(100); // NOLINT
App.safe_reboot();
error:

View File

@@ -12,24 +12,24 @@ pmsx003_ns = cg.esphome_ns.namespace('pmsx003')
PMSX003Component = pmsx003_ns.class_('PMSX003Component', uart.UARTDevice, cg.Component)
PMSX003Sensor = pmsx003_ns.class_('PMSX003Sensor', sensor.Sensor)
CONF_PMSX003 = 'PMSX003'
CONF_PMS5003T = 'PMS5003T'
CONF_PMS5003ST = 'PMS5003ST'
TYPE_PMSX003 = 'PMSX003'
TYPE_PMS5003T = 'PMS5003T'
TYPE_PMS5003ST = 'PMS5003ST'
PMSX003Type = pmsx003_ns.enum('PMSX003Type')
PMSX003_TYPES = {
CONF_PMSX003: PMSX003Type.PMSX003_TYPE_X003,
CONF_PMS5003T: PMSX003Type.PMSX003_TYPE_5003T,
CONF_PMS5003ST: PMSX003Type.PMSX003_TYPE_5003ST,
TYPE_PMSX003: PMSX003Type.PMSX003_TYPE_X003,
TYPE_PMS5003T: PMSX003Type.PMSX003_TYPE_5003T,
TYPE_PMS5003ST: PMSX003Type.PMSX003_TYPE_5003ST,
}
SENSORS_TO_TYPE = {
CONF_PM_1_0: [CONF_PMSX003, CONF_PMS5003ST],
CONF_PM_2_5: [CONF_PMSX003, CONF_PMS5003T, CONF_PMS5003ST],
CONF_PM_10_0: [CONF_PMSX003, CONF_PMS5003ST],
CONF_TEMPERATURE: [CONF_PMS5003T, CONF_PMS5003ST],
CONF_HUMIDITY: [CONF_PMS5003T, CONF_PMS5003ST],
CONF_FORMALDEHYDE: [CONF_PMS5003ST],
CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003ST],
CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST],
CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003ST],
CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST],
CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST],
CONF_FORMALDEHYDE: [TYPE_PMS5003ST],
}

View File

@@ -149,6 +149,7 @@ void PulseCounterSensor::dump_config() {
ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode]);
ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode]);
ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %u µs", this->storage_.filter_us);
LOG_UPDATE_INTERVAL(this);
}
void PulseCounterSensor::update() {

View File

@@ -98,6 +98,12 @@ void PZEM004T::write_state_(PZEM004T::PZEM004TReadState state) {
this->write_array(data);
this->read_state_ = state;
}
void PZEM004T::dump_config() {
ESP_LOGCONFIG(TAG, "PZEM004T:");
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
LOG_SENSOR("", "Current", this->current_sensor_);
LOG_SENSOR("", "Power", this->power_sensor_);
}
} // namespace pzem004t
} // namespace esphome

View File

@@ -17,6 +17,8 @@ class PZEM004T : public PollingComponent, public uart::UARTDevice {
void update() override;
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;

View File

@@ -57,6 +57,15 @@ void PZEMAC::on_modbus_data(const std::vector<uint8_t> &data) {
}
void PZEMAC::update() { this->send(PZEM_CMD_READ_IN_REGISTERS, 0, PZEM_REGISTER_COUNT); }
void PZEMAC::dump_config() {
ESP_LOGCONFIG(TAG, "PZEMAC:");
ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_);
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
LOG_SENSOR("", "Current", this->current_sensor_);
LOG_SENSOR("", "Power", this->power_sensor_);
LOG_SENSOR("", "Frequency", this->frequency_sensor_);
LOG_SENSOR("", "Power Factor", this->power_factor_sensor_);
}
} // namespace pzemac
} // namespace esphome

View File

@@ -19,6 +19,8 @@ class PZEMAC : public PollingComponent, public modbus::ModbusDevice {
void on_modbus_data(const std::vector<uint8_t> &data) override;
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;

View File

@@ -47,6 +47,13 @@ void PZEMDC::on_modbus_data(const std::vector<uint8_t> &data) {
}
void PZEMDC::update() { this->send(PZEM_CMD_READ_IN_REGISTERS, 0, 8); }
void PZEMDC::dump_config() {
ESP_LOGCONFIG(TAG, "PZEMDC:");
ESP_LOGCONFIG(TAG, " Address: 0x%02X", this->address_);
LOG_SENSOR("", "Voltage", this->voltage_sensor_);
LOG_SENSOR("", "Current", this->current_sensor_);
LOG_SENSOR("", "Power", this->power_sensor_);
}
} // namespace pzemdc
} // namespace esphome

View File

@@ -19,6 +19,8 @@ class PZEMDC : public PollingComponent, public modbus::ModbusDevice {
void on_modbus_data(const std::vector<uint8_t> &data) override;
void dump_config() override;
protected:
sensor::Sensor *voltage_sensor_;
sensor::Sensor *current_sensor_;

View File

@@ -28,7 +28,7 @@ class RDM6300Component : public Component, public uart::UARTDevice {
uint32_t last_id_{0};
};
class RDM6300BinarySensor : public binary_sensor::BinarySensor {
class RDM6300BinarySensor : public binary_sensor::BinarySensorInitiallyOff {
public:
void set_id(uint32_t id) { id_ = id; }

View File

@@ -267,11 +267,11 @@ class RemoteReceiverBase : public RemoteComponentBase {
uint8_t tolerance_{25};
};
class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensor,
class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitiallyOff,
public Component,
public RemoteReceiverListener {
public:
explicit RemoteReceiverBinarySensorBase() : BinarySensor() {}
explicit RemoteReceiverBinarySensorBase() : BinarySensorInitiallyOff() {}
void dump_config() override;
virtual bool matches(RemoteReceiveData src) = 0;
bool on_receive(RemoteReceiveData src) override {

View File

@@ -13,8 +13,8 @@ void RestartSwitch::write_state(bool state) {
if (state) {
ESP_LOGI(TAG, "Restarting device...");
// then execute
delay(100); // Let MQTT settle a bit
// Let MQTT settle a bit
delay(100); // NOLINT
App.safe_reboot();
}
}

View File

@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome import pins, automation
from esphome.components import sensor
from esphome.const import CONF_ID, CONF_RESOLUTION, CONF_MIN_VALUE, CONF_MAX_VALUE, UNIT_STEPS, \
ICON_ROTATE_RIGHT, CONF_VALUE
ICON_ROTATE_RIGHT, CONF_VALUE, CONF_PIN_A, CONF_PIN_B
rotary_encoder_ns = cg.esphome_ns.namespace('rotary_encoder')
RotaryEncoderResolution = rotary_encoder_ns.enum('RotaryEncoderResolution')
@@ -13,8 +13,6 @@ RESOLUTIONS = {
4: RotaryEncoderResolution.ROTARY_ENCODER_4_PULSES_PER_CYCLE,
}
CONF_PIN_A = 'pin_a'
CONF_PIN_B = 'pin_b'
CONF_PIN_RESET = 'pin_reset'
RotaryEncoderSensor = rotary_encoder_ns.class_('RotaryEncoderSensor', sensor.Sensor, cg.Component)

View File

@@ -3,15 +3,13 @@ import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import CONF_ID, UNIT_PARTS_PER_MILLION, \
CONF_HUMIDITY, CONF_TEMPERATURE, ICON_PERIODIC_TABLE_CO2, \
UNIT_CELSIUS, ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_PERCENT
UNIT_CELSIUS, ICON_THERMOMETER, ICON_WATER_PERCENT, UNIT_PERCENT, CONF_CO2
DEPENDENCIES = ['i2c']
scd30_ns = cg.esphome_ns.namespace('scd30')
SCD30Component = scd30_ns.class_('SCD30Component', cg.PollingComponent, i2c.I2CDevice)
CONF_CO2 = 'co2'
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(SCD30Component),
cv.Required(CONF_CO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION,

View File

@@ -259,7 +259,7 @@ def setup_sensor_core_(var, config):
if CONF_ACCURACY_DECIMALS in config:
cg.add(var.set_accuracy_decimals(config[CONF_ACCURACY_DECIMALS]))
cg.add(var.set_force_update(config[CONF_FORCE_UPDATE]))
if CONF_FILTERS in config:
if config.get(CONF_FILTERS): # must exist and not be empty
filters = yield build_filters(config[CONF_FILTERS])
cg.add(var.set_filters(filters))

View File

@@ -9,17 +9,17 @@ namespace sensor {
#define LOG_SENSOR(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, prefix type " '%s'", obj->get_name().c_str()); \
ESP_LOGCONFIG(TAG, prefix " Unit of Measurement: '%s'", obj->get_unit_of_measurement().c_str()); \
ESP_LOGCONFIG(TAG, prefix " Accuracy Decimals: %d", obj->get_accuracy_decimals()); \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, type, obj->get_name().c_str()); \
ESP_LOGCONFIG(TAG, "%s Unit of Measurement: '%s'", prefix, obj->get_unit_of_measurement().c_str()); \
ESP_LOGCONFIG(TAG, "%s Accuracy Decimals: %d", prefix, obj->get_accuracy_decimals()); \
if (!obj->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, prefix " Icon: '%s'", obj->get_icon().c_str()); \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); \
} \
if (!obj->unique_id().empty()) { \
ESP_LOGV(TAG, prefix " Unique ID: '%s'", obj->unique_id().c_str()); \
ESP_LOGV(TAG, "%s Unique ID: '%s'", prefix, obj->unique_id().c_str()); \
} \
if (obj->get_force_update()) { \
ESP_LOGV(TAG, prefix " Force Update: YES"); \
ESP_LOGV(TAG, "%s Force Update: YES", prefix); \
} \
}

View File

@@ -14,8 +14,8 @@ CONF_TVOC = 'tvoc'
CONF_BASELINE = 'baseline'
CONF_UPTIME = 'uptime'
CONF_COMPENSATION = 'compensation'
CONF_COMPENSATION_HUMIDITY = 'humidity_source'
CONF_COMPENSATION_TEMPERATURE = 'temperature_source'
CONF_HUMIDITY_SOURCE = 'humidity_source'
CONF_TEMPERATURE_SOURCE = 'temperature_source'
CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(SGP30Component),
@@ -24,8 +24,8 @@ CONFIG_SCHEMA = cv.Schema({
cv.Required(CONF_TVOC): sensor.sensor_schema(UNIT_PARTS_PER_BILLION, ICON_RADIATOR, 0),
cv.Optional(CONF_BASELINE): cv.hex_uint16_t,
cv.Optional(CONF_COMPENSATION): cv.Schema({
cv.Required(CONF_COMPENSATION_HUMIDITY): cv.use_id(sensor.Sensor),
cv.Required(CONF_COMPENSATION_TEMPERATURE): cv.use_id(sensor.Sensor)
cv.Required(CONF_HUMIDITY_SOURCE): cv.use_id(sensor.Sensor),
cv.Required(CONF_TEMPERATURE_SOURCE): cv.use_id(sensor.Sensor)
}),
}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x58))
@@ -48,7 +48,7 @@ def to_code(config):
if CONF_COMPENSATION in config:
compensation_config = config[CONF_COMPENSATION]
sens = yield cg.get_variable(compensation_config[CONF_COMPENSATION_HUMIDITY])
sens = yield cg.get_variable(compensation_config[CONF_HUMIDITY_SOURCE])
cg.add(var.set_humidity_sensor(sens))
sens = yield cg.get_variable(compensation_config[CONF_COMPENSATION_TEMPERATURE])
sens = yield cg.get_variable(compensation_config[CONF_TEMPERATURE_SOURCE])
cg.add(var.set_temperature_sensor(sens))

View File

@@ -14,7 +14,7 @@ void ShutdownSwitch::write_state(bool state) {
if (state) {
ESP_LOGI(TAG, "Shutting down...");
delay(100); // Let MQTT settle a bit
delay(100); // NOLINT
App.run_safe_shutdown_hooks();
#ifdef ARDUINO_ARCH_ESP8266

View File

@@ -255,6 +255,10 @@ void Sim800LComponent::send_sms(std::string recipient, std::string message) {
this->send_pending_ = true;
this->update();
}
void Sim800LComponent::dump_config() {
ESP_LOGCONFIG(TAG, "SIM800L:");
ESP_LOGCONFIG(TAG, " RSSI: %d dB", this->rssi_);
}
} // namespace sim800l
} // namespace esphome

View File

@@ -4,11 +4,11 @@
#include "esphome/components/uart/uart.h"
#include "esphome/core/automation.h"
#define SIM800L_READ_BUFFER_LENGTH 255
namespace esphome {
namespace sim800l {
const uint8_t SIM800L_READ_BUFFER_LENGTH = 255;
enum State {
STATE_IDLE = 0,
STATE_INIT,
@@ -37,6 +37,7 @@ class Sim800LComponent : public uart::UARTDevice, public PollingComponent {
/// Retrieve the latest sensor values. This operation takes approximately 16ms.
void update() override;
void loop() override;
void dump_config() override;
void add_on_sms_received_callback(std::function<void(std::string, std::string)> callback) {
this->callback_.add(std::move(callback));
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/esphal.h"
#include "esphome/components/output/float_output.h"
namespace esphome {

View File

@@ -29,4 +29,4 @@ def to_code(config):
if CONF_OSCILLATION_OUTPUT in config:
oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
cg.add(var.set_oscillation(oscillation_output))
cg.add(var.set_oscillating(oscillation_output))

View File

@@ -14,7 +14,7 @@ void SPISSD1325::setup() {
this->cs_->setup(); // OUTPUT
this->init_reset_();
delay(500);
delay(500); // NOLINT
SSD1325::setup();
}
void SPISSD1325::dump_config() {

View File

@@ -30,7 +30,7 @@ void StatusBinarySensor::loop() {
this->publish_state(status);
}
void StatusBinarySensor::setup() { this->publish_state(false); }
void StatusBinarySensor::setup() { this->publish_initial_state(false); }
void StatusBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Status Binary Sensor", this); }
} // namespace status

View File

@@ -9,15 +9,15 @@ namespace switch_ {
#define LOG_SWITCH(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, prefix type " '%s'", obj->get_name().c_str()); \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, type, obj->get_name().c_str()); \
if (!obj->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, prefix " Icon: '%s'", obj->get_icon().c_str()); \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); \
} \
if (obj->assumed_state()) { \
ESP_LOGCONFIG(TAG, prefix " Assumed State: YES"); \
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \
} \
if (obj->is_inverted()) { \
ESP_LOGCONFIG(TAG, prefix " Inverted: YES"); \
ESP_LOGCONFIG(TAG, "%s Inverted: YES", prefix); \
} \
}

View File

@@ -5,7 +5,7 @@ from esphome.const import CONF_ID
from .. import SX1509Component, sx1509_ns, CONF_SX1509_ID
CONF_ROW = 'row'
CONF_COLUMN = 'col'
CONF_COL = 'col'
DEPENDENCIES = ['sx1509']
@@ -15,7 +15,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(SX1509BinarySensor),
cv.GenerateID(CONF_SX1509_ID): cv.use_id(SX1509Component),
cv.Required(CONF_ROW): cv.int_range(min=0, max=4),
cv.Required(CONF_COLUMN): cv.int_range(min=0, max=4),
cv.Required(CONF_COL): cv.int_range(min=0, max=4),
})
@@ -23,6 +23,6 @@ def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield binary_sensor.register_binary_sensor(var, config)
hub = yield cg.get_variable(config[CONF_SX1509_ID])
cg.add(var.set_row_col(config[CONF_ROW], config[CONF_COLUMN]))
cg.add(var.set_row_col(config[CONF_ROW], config[CONF_COL]))
cg.add(hub.register_keypad_binary_sensor(var))

View File

@@ -1,41 +1,18 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
from esphome.const import CONF_ID, CONF_SENSOR
from esphome.components import climate_ir
from esphome.const import CONF_ID
AUTO_LOAD = ['sensor', 'climate_ir']
AUTO_LOAD = ['climate_ir']
tcl112_ns = cg.esphome_ns.namespace('tcl112')
Tcl112Climate = tcl112_ns.class_('Tcl112Climate', climate.Climate, cg.Component)
Tcl112Climate = tcl112_ns.class_('Tcl112Climate', climate_ir.ClimateIR)
CONF_TRANSMITTER_ID = 'transmitter_id'
CONF_RECEIVER_ID = 'receiver_id'
CONF_SUPPORTS_HEAT = 'supports_heat'
CONF_SUPPORTS_COOL = 'supports_cool'
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(Tcl112Climate),
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),
cv.Optional(CONF_RECEIVER_ID): cv.use_id(remote_receiver.RemoteReceiverComponent),
cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean,
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor),
}).extend(cv.COMPONENT_SCHEMA))
})
def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config)
yield climate.register_climate(var, config)
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
if CONF_SENSOR in config:
sens = yield cg.get_variable(config[CONF_SENSOR])
cg.add(var.set_sensor(sens))
if CONF_RECEIVER_ID in config:
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
cg.add(receiver.register_listener(var))
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
cg.add(var.set_transmitter(transmitter))
yield climate_ir.register_climate_ir(var, config)

View File

@@ -9,9 +9,9 @@ namespace tcl112 {
const float TCL112_TEMP_MAX = 31.0;
const float TCL112_TEMP_MIN = 16.0;
class Tcl112Climate : public climate::ClimateIR {
class Tcl112Climate : public climate_ir::ClimateIR {
public:
Tcl112Climate() : climate::ClimateIR(TCL112_TEMP_MIN, TCL112_TEMP_MAX, .5f) {}
Tcl112Climate() : climate_ir::ClimateIR(TCL112_TEMP_MIN, TCL112_TEMP_MAX, .5f) {}
protected:
/// Transmit via IR the state of this climate controller.

View File

@@ -2,13 +2,12 @@ import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import automation
from esphome.components import output
from esphome.const import CONF_ID, CONF_TYPE
from esphome.const import CONF_ID, CONF_TYPE, CONF_BINARY
from .. import template_ns
TemplateBinaryOutput = template_ns.class_('TemplateBinaryOutput', output.BinaryOutput)
TemplateFloatOutput = template_ns.class_('TemplateFloatOutput', output.FloatOutput)
CONF_BINARY = 'binary'
CONF_FLOAT = 'float'
CONF_WRITE_ACTION = 'write_action'

View File

@@ -8,12 +8,12 @@ namespace text_sensor {
#define LOG_TEXT_SENSOR(prefix, type, obj) \
if (obj != nullptr) { \
ESP_LOGCONFIG(TAG, prefix type " '%s'", obj->get_name().c_str()); \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, type, obj->get_name().c_str()); \
if (!obj->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, prefix " Icon: '%s'", obj->get_icon().c_str()); \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); \
} \
if (!obj->unique_id().empty()) { \
ESP_LOGV(TAG, prefix " Unique ID: '%s'", obj->unique_id().c_str()); \
ESP_LOGV(TAG, "%s Unique ID: '%s'", prefix, obj->unique_id().c_str()); \
} \
}

View File

@@ -36,6 +36,9 @@ void Tuya::dump_config() {
else
ESP_LOGCONFIG(TAG, " Datapoint %d: unknown", info.id);
}
if (this->datapoints_.empty()) {
ESP_LOGCONFIG(TAG, " Received no datapoints! Please make sure this is a supported Tuya device.");
}
this->check_uart_settings(9600);
}

View File

@@ -2,6 +2,11 @@
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
#include "esphome/core/application.h"
#include "esphome/core/defines.h"
#ifdef USE_LOGGER
#include "esphome/components/logger/logger.h"
#endif
namespace esphome {
namespace uart {
@@ -41,6 +46,12 @@ void UARTComponent::dump_config() {
}
ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_);
ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
#ifdef USE_LOGGER
if (this->hw_serial_ == &Serial && logger::global_logger->get_baud_rate() != 0) {
ESP_LOGW(TAG, " You're using the same serial port for logging and the UART component. Please "
"disable logging over the serial port by setting logger->baud_rate to 0.");
}
#endif
}
void UARTComponent::write_byte(uint8_t data) {
@@ -145,6 +156,13 @@ void UARTComponent::dump_config() {
} else {
ESP_LOGCONFIG(TAG, " Using software serial");
}
#ifdef USE_LOGGER
if (this->hw_serial_ == &Serial && logger::global_logger->get_baud_rate() != 0) {
ESP_LOGW(TAG, " You're using the same serial port for logging and the UART component. Please "
"disable logging over the serial port by setting logger->baud_rate to 0.");
}
#endif
}
void UARTComponent::write_byte(uint8_t data) {

View File

@@ -27,6 +27,7 @@ void UptimeSensor::update() {
}
std::string UptimeSensor::unique_id() { return get_mac_address() + "-uptime"; }
float UptimeSensor::get_setup_priority() const { return setup_priority::HARDWARE; }
void UptimeSensor::dump_config() { LOG_SENSOR("", "Uptime Sensor", this); }
} // namespace uptime
} // namespace esphome

View File

@@ -9,6 +9,7 @@ namespace uptime {
class UptimeSensor : public sensor::Sensor, public PollingComponent {
public:
void update() override;
void dump_config() override;
float get_setup_priority() const override;

View File

@@ -45,9 +45,9 @@ class WaveshareEPaper : public PollingComponent,
void reset_() {
if (this->reset_pin_ != nullptr) {
this->reset_pin_->digital_write(false);
delay(200);
delay(200); // NOLINT
this->reset_pin_->digital_write(true);
delay(200);
delay(200); // NOLINT
}
}
@@ -144,7 +144,7 @@ class WaveshareEPaper4P2In : public WaveshareEPaper {
// COMMAND PANEL SETTING
this->command(0x00);
delay(100);
delay(100); // NOLINT
// COMMAND POWER SETTING
this->command(0x01);
@@ -153,7 +153,7 @@ class WaveshareEPaper4P2In : public WaveshareEPaper {
this->data(0x00);
this->data(0x00);
this->data(0x00);
delay(100);
delay(100); // NOLINT
// COMMAND POWER OFF
this->command(0x02);

View File

@@ -416,11 +416,15 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, UrlMatch ma
if (request->hasParam("color_temp"))
call.set_color_temperature(request->getParam("color_temp")->value().toFloat());
if (request->hasParam("flash"))
call.set_flash_length((uint32_t) request->getParam("flash")->value().toFloat() * 1000);
if (request->hasParam("flash")) {
float length_s = request->getParam("flash")->value().toFloat();
call.set_flash_length(static_cast<uint32_t>(length_s * 1000));
}
if (request->hasParam("transition"))
call.set_transition_length((uint32_t) request->getParam("transition")->value().toFloat() * 1000);
if (request->hasParam("transition")) {
float length_s = request->getParam("transition")->value().toFloat();
call.set_transition_length(static_cast<uint32_t>(length_s * 1000));
}
if (request->hasParam("effect")) {
const char *effect = request->getParam("effect")->value().c_str();

View File

@@ -481,7 +481,7 @@ void WiFiComponent::retry_connect() {
// If retry failed for more than 5 times, let's restart STA
ESP_LOGW(TAG, "Restarting WiFi adapter...");
this->wifi_mode_(false, {});
delay(100);
delay(100); // NOLINT
this->num_retried_ = 0;
} else {
this->num_retried_++;

View File

@@ -1,17 +1,14 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate, remote_transmitter, sensor
from esphome.const import CONF_ID, CONF_SENSOR
from esphome.components.remote_base import CONF_TRANSMITTER_ID
from esphome.const import CONF_ID, CONF_SENSOR, CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT
AUTO_LOAD = ['sensor']
yashima_ns = cg.esphome_ns.namespace('yashima')
YashimaClimate = yashima_ns.class_('YashimaClimate', climate.Climate, cg.Component)
CONF_TRANSMITTER_ID = 'transmitter_id'
CONF_SUPPORTS_HEAT = 'supports_heat'
CONF_SUPPORTS_COOL = 'supports_cool'
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(YashimaClimate),
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),

View File

@@ -1,10 +1,10 @@
from __future__ import print_function
import codecs
import json
import os
from esphome.core import CORE, EsphomeError
from esphome.core import CORE
from esphome.helpers import read_file
from esphome.py_compat import safe_input
@@ -20,10 +20,4 @@ def read_config_file(path):
assert data['type'] == 'file_response'
return data['content']
try:
with codecs.open(path, encoding='utf-8') as handle:
return handle.read()
except IOError as exc:
raise EsphomeError(u"Error accessing file {}: {}".format(path, exc))
except UnicodeDecodeError as exc:
raise EsphomeError(u"Unable to read file {}: {}".format(path, exc))
return read_file(path)

View File

@@ -461,6 +461,8 @@ def time_period_str_unit(value):
if isinstance(value, int):
raise Invalid("Don't know what '{0}' means as it has no time *unit*! Did you mean "
"'{0}s'?".format(value))
if isinstance(value, TimePeriod):
value = str(value)
if not isinstance(value, string_types):
raise Invalid("Expected string for time period with unit.")

View File

@@ -3,7 +3,7 @@
MAJOR_VERSION = 1
MINOR_VERSION = 14
PATCH_VERSION = '0b3'
PATCH_VERSION = '0'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
@@ -63,8 +63,8 @@ CONF_BROKER = 'broker'
CONF_BSSID = 'bssid'
CONF_BUFFER_SIZE = 'buffer_size'
CONF_BUILD_PATH = 'build_path'
CONF_BUSY_PIN = 'busy_pin'
CONF_BUS_VOLTAGE = 'bus_voltage'
CONF_BUSY_PIN = 'busy_pin'
CONF_CALIBRATE_LINEAR = 'calibrate_linear'
CONF_CALIBRATION = 'calibration'
CONF_CAPACITANCE = 'capacitance'
@@ -84,23 +84,23 @@ CONF_CO2 = 'co2'
CONF_CODE = 'code'
CONF_COLD_WHITE = 'cold_white'
CONF_COLD_WHITE_COLOR_TEMPERATURE = 'cold_white_color_temperature'
CONF_COLORS = 'colors'
CONF_COLOR_CORRECT = 'color_correct'
CONF_COLOR_TEMPERATURE = 'color_temperature'
CONF_COLORS = 'colors'
CONF_COMMAND = 'command'
CONF_COMMAND_TOPIC = 'command_topic'
CONF_COMMENT = 'comment'
CONF_COMMIT = 'commit'
CONF_COMPONENTS = 'components'
CONF_COMPONENT_ID = 'component_id'
CONF_COMPONENTS = 'components'
CONF_CONDITION = 'condition'
CONF_CONDITION_ID = 'condition_id'
CONF_CONDUCTIVITY = 'conductivity'
CONF_COOL_ACTION = 'cool_action'
CONF_COUNT_MODE = 'count_mode'
CONF_CRON = 'cron'
CONF_CSS_URL = 'css_url'
CONF_CS_PIN = 'cs_pin'
CONF_CSS_URL = 'css_url'
CONF_CURRENT = 'current'
CONF_CURRENT_OPERATION = 'current_operation'
CONF_CURRENT_RESISTOR = 'current_resistor'
@@ -122,12 +122,12 @@ CONF_DELTA = 'delta'
CONF_DEVICE = 'device'
CONF_DEVICE_CLASS = 'device_class'
CONF_DIMENSIONS = 'dimensions'
CONF_DIRECTION = 'direction'
CONF_DIR_PIN = 'dir_pin'
CONF_DIRECTION = 'direction'
CONF_DISCOVERY = 'discovery'
CONF_DISTANCE = 'distance'
CONF_DISCOVERY_PREFIX = 'discovery_prefix'
CONF_DISCOVERY_RETAIN = 'discovery_retain'
CONF_DISTANCE = 'distance'
CONF_DIV_RATIO = 'div_ratio'
CONF_DNS1 = 'dns1'
CONF_DNS2 = 'dns2'
@@ -152,8 +152,8 @@ CONF_FAMILY = 'family'
CONF_FAST_CONNECT = 'fast_connect'
CONF_FILE = 'file'
CONF_FILTER = 'filter'
CONF_FILTERS = 'filters'
CONF_FILTER_OUT = 'filter_out'
CONF_FILTERS = 'filters'
CONF_FLASH_LENGTH = 'flash_length'
CONF_FOR = 'for'
CONF_FORCE_UPDATE = 'force_update'
@@ -172,8 +172,8 @@ CONF_GREEN = 'green'
CONF_GROUP = 'group'
CONF_HARDWARE_UART = 'hardware_uart'
CONF_HEARTBEAT = 'heartbeat'
CONF_HEATER = 'heater'
CONF_HEAT_ACTION = 'heat_action'
CONF_HEATER = 'heater'
CONF_HIDDEN = 'hidden'
CONF_HIGH = 'high'
CONF_HIGH_VOLTAGE_REFERENCE = 'high_voltage_reference'
@@ -207,8 +207,8 @@ CONF_INVERTED = 'inverted'
CONF_IP_ADDRESS = 'ip_address'
CONF_JS_URL = 'js_url'
CONF_JVC = 'jvc'
CONF_KEEPALIVE = 'keepalive'
CONF_KEEP_ON_TIME = 'keep_on_time'
CONF_KEEPALIVE = 'keepalive'
CONF_LAMBDA = 'lambda'
CONF_LEVEL = 'level'
CONF_LG = 'lg'
@@ -218,9 +218,9 @@ CONF_LIGHTNING_ENERGY = 'lightning_energy'
CONF_LIGHTNING_THRESHOLD = 'lightning_threshold'
CONF_LOADED_INTEGRATIONS = 'loaded_integrations'
CONF_LOCAL = 'local'
CONF_LOG_TOPIC = 'log_topic'
CONF_LOGGER = 'logger'
CONF_LOGS = 'logs'
CONF_LOG_TOPIC = 'log_topic'
CONF_LOW = 'low'
CONF_LOW_VOLTAGE_REFERENCE = 'low_voltage_reference'
CONF_MAC_ADDRESS = 'mac_address'
@@ -240,13 +240,13 @@ CONF_MAX_VOLTAGE = 'max_voltage'
CONF_MEASUREMENT_DURATION = 'measurement_duration'
CONF_MEDIUM = 'medium'
CONF_METHOD = 'method'
CONF_MINUTE = 'minute'
CONF_MINUTES = 'minutes'
CONF_MIN_LENGTH = 'min_length'
CONF_MIN_LEVEL = 'min_level'
CONF_MIN_POWER = 'min_power'
CONF_MIN_TEMPERATURE = 'min_temperature'
CONF_MIN_VALUE = 'min_value'
CONF_MINUTE = 'minute'
CONF_MINUTES = 'minutes'
CONF_MISO_PIN = 'miso_pin'
CONF_MODE = 'mode'
CONF_MODEL = 'model'
@@ -262,14 +262,13 @@ CONF_NBITS = 'nbits'
CONF_NEC = 'nec'
CONF_NETWORKS = 'networks'
CONF_NOISE_LEVEL = 'noise_level'
CONF_NUMBER = 'number'
CONF_NUM_ATTEMPTS = 'num_attempts'
CONF_NUM_CHANNELS = 'num_channels'
CONF_NUM_CHIPS = 'num_chips'
CONF_NUM_LEDS = 'num_leds'
CONF_NUMBER = 'number'
CONF_OFFSET = 'offset'
CONF_ON = 'on'
CONF_ONE = 'one'
CONF_ON_BOOT = 'on_boot'
CONF_ON_CLICK = 'on_click'
CONF_ON_DOUBLE_CLICK = 'on_double_click'
@@ -288,6 +287,7 @@ CONF_ON_TURN_OFF = 'on_turn_off'
CONF_ON_TURN_ON = 'on_turn_on'
CONF_ON_VALUE = 'on_value'
CONF_ON_VALUE_RANGE = 'on_value_range'
CONF_ONE = 'one'
CONF_OPEN_ACTION = 'open_action'
CONF_OPEN_DURATION = 'open_duration'
CONF_OPEN_ENDSTOP = 'open_endstop'
@@ -299,11 +299,11 @@ CONF_OSCILLATION_OUTPUT = 'oscillation_output'
CONF_OSCILLATION_STATE_TOPIC = 'oscillation_state_topic'
CONF_OTA = 'ota'
CONF_OUTPUT = 'output'
CONF_OUTPUTS = 'outputs'
CONF_OUTPUT_ID = 'output_id'
CONF_OUTPUTS = 'outputs'
CONF_OVERSAMPLING = 'oversampling'
CONF_PAGES = 'pages'
CONF_PAGE_ID = 'page_id'
CONF_PAGES = 'pages'
CONF_PANASONIC = 'panasonic'
CONF_PASSWORD = 'password'
CONF_PAYLOAD = 'payload'
@@ -311,15 +311,15 @@ CONF_PAYLOAD_AVAILABLE = 'payload_available'
CONF_PAYLOAD_NOT_AVAILABLE = 'payload_not_available'
CONF_PHASE_BALANCER = 'phase_balancer'
CONF_PIN = 'pin'
CONF_PINS = 'pins'
CONF_PIN_A = 'pin_a'
CONF_PIN_B = 'pin_b'
CONF_PIN_C = 'pin_c'
CONF_PIN_D = 'pin_d'
CONF_PINS = 'pins'
CONF_PLATFORM = 'platform'
CONF_PLATFORMIO_OPTIONS = 'platformio_options'
CONF_PM_10_0 = 'pm_10_0'
CONF_PM_1_0 = 'pm_1_0'
CONF_PM_10_0 = 'pm_10_0'
CONF_PM_2_5 = 'pm_2_5'
CONF_PORT = 'port'
CONF_POSITION = 'position'
@@ -353,8 +353,8 @@ CONF_RESTORE_MODE = 'restore_mode'
CONF_RESTORE_STATE = 'restore_state'
CONF_RESTORE_VALUE = 'restore_value'
CONF_RETAIN = 'retain'
CONF_RGBW = 'rgbw'
CONF_RGB_ORDER = 'rgb_order'
CONF_RGBW = 'rgbw'
CONF_RISING_EDGE = 'rising_edge'
CONF_ROTATION = 'rotation'
CONF_RS_PIN = 'rs_pin'
@@ -377,14 +377,14 @@ CONF_SEL_PIN = 'sel_pin'
CONF_SEND_EVERY = 'send_every'
CONF_SEND_FIRST_AT = 'send_first_at'
CONF_SENSOR = 'sensor'
CONF_SENSORS = 'sensors'
CONF_SENSOR_ID = 'sensor_id'
CONF_SENSORS = 'sensors'
CONF_SEQUENCE = 'sequence'
CONF_SERVERS = 'servers'
CONF_SERVICE = 'service'
CONF_SERVICES = 'services'
CONF_SETUP_MODE = 'setup_mode'
CONF_SETUP_PRIORITY = 'setup_priority'
CONF_SEQUENCE = 'sequence'
CONF_SHUNT_RESISTANCE = 'shunt_resistance'
CONF_SHUNT_VOLTAGE = 'shunt_voltage'
CONF_SHUTDOWN_MESSAGE = 'shutdown_message'
@@ -408,6 +408,8 @@ CONF_STEP_PIN = 'step_pin'
CONF_STOP = 'stop'
CONF_STOP_ACTION = 'stop_action'
CONF_SUBNET = 'subnet'
CONF_SUPPORTS_COOL = 'supports_cool'
CONF_SUPPORTS_HEAT = 'supports_heat'
CONF_SWITCHES = 'switches'
CONF_SYNC = 'sync'
CONF_TAG = 'tag'
@@ -425,10 +427,10 @@ CONF_TILT = 'tilt'
CONF_TILT_ACTION = 'tilt_action'
CONF_TILT_LAMBDA = 'tilt_lambda'
CONF_TIME = 'time'
CONF_TIME_ID = 'time_id'
CONF_TIMEOUT = 'timeout'
CONF_TIMES = 'times'
CONF_TIMEZONE = 'timezone'
CONF_TIME_ID = 'time_id'
CONF_TIMING = 'timing'
CONF_TO = 'to'
CONF_TOLERANCE = 'tolerance'
@@ -449,8 +451,8 @@ CONF_UNIQUE = 'unique'
CONF_UNIT_OF_MEASUREMENT = 'unit_of_measurement'
CONF_UPDATE_INTERVAL = 'update_interval'
CONF_UPDATE_ON_BOOT = 'update_on_boot'
CONF_USERNAME = 'username'
CONF_USE_ADDRESS = 'use_address'
CONF_USERNAME = 'username'
CONF_UUID = 'uuid'
CONF_VALUE = 'value'
CONF_VARIABLES = 'variables'
@@ -470,8 +472,8 @@ CONF_WHITE = 'white'
CONF_WIDTH = 'width'
CONF_WIFI = 'wifi'
CONF_WILL_MESSAGE = 'will_message'
CONF_WIND_SPEED = 'wind_speed'
CONF_WIND_DIRECTION_DEGREES = 'wind_direction_degrees'
CONF_WIND_SPEED = 'wind_speed'
CONF_WINDOW_SIZE = 'window_size'
CONF_ZERO = 'zero'
@@ -479,8 +481,8 @@ ICON_ARROW_EXPAND_VERTICAL = 'mdi:arrow-expand-vertical'
ICON_BATTERY = 'mdi:battery'
ICON_BRIEFCASE_DOWNLOAD = 'mdi:briefcase-download'
ICON_BRIGHTNESS_5 = 'mdi:brightness-5'
ICON_CHEMICAL_WEAPON = 'mdi:chemical-weapon'
ICON_CHECK_CIRCLE_OUTLINE = 'mdi:check-circle-outline'
ICON_CHEMICAL_WEAPON = 'mdi:chemical-weapon'
ICON_CURRENT_AC = 'mdi:current-ac'
ICON_EMPTY = ''
ICON_FLASH = 'mdi:flash'
@@ -499,26 +501,26 @@ ICON_RESTART = 'mdi:restart'
ICON_ROTATE_RIGHT = 'mdi:rotate-right'
ICON_SCALE = 'mdi:scale'
ICON_SCREEN_ROTATION = 'mdi:screen-rotation'
ICON_SIGN_DIRECTION = 'mdi:sign-direction'
ICON_SIGNAL = 'mdi: signal-distance-variant'
ICON_SIGNAL_DISTANCE_VARIANT = 'mdi:signal'
ICON_SIGN_DIRECTION = 'mdi:sign-direction'
ICON_WEATHER_SUNSET = 'mdi:weather-sunset'
ICON_WEATHER_SUNSET_DOWN = 'mdi:weather-sunset-down'
ICON_WEATHER_SUNSET_UP = 'mdi:weather-sunset-up'
ICON_THERMOMETER = 'mdi:thermometer'
ICON_TIMER = 'mdi:timer'
ICON_WATER_PERCENT = 'mdi:water-percent'
ICON_WEATHER_SUNSET = 'mdi:weather-sunset'
ICON_WEATHER_SUNSET_DOWN = 'mdi:weather-sunset-down'
ICON_WEATHER_SUNSET_UP = 'mdi:weather-sunset-up'
ICON_WEATHER_WINDY = 'mdi:weather-windy'
ICON_WIFI = 'mdi:wifi'
UNIT_AMPERE = 'A'
UNIT_CELSIUS = u'°C'
UNIT_DECIBEL = 'dB'
UNIT_DEGREES = u'°'
UNIT_DEGREE_PER_SECOND = u'°/s'
UNIT_DEGREES = u'°'
UNIT_EMPTY = ''
UNIT_HZ = 'hz'
UNIT_HECTOPASCAL = 'hPa'
UNIT_HZ = 'hz'
UNIT_KELVIN = 'K'
UNIT_KILOMETER = 'km'
UNIT_KILOMETER_PER_HOUR = 'km/h'
@@ -529,8 +531,8 @@ UNIT_MICROGRAMS_PER_CUBIC_METER = u'µg/m³'
UNIT_MICROSIEMENS_PER_CENTIMETER = u'µS/cm'
UNIT_MICROTESLA = u'µT'
UNIT_OHM = u'Ω'
UNIT_PARTS_PER_MILLION = 'ppm'
UNIT_PARTS_PER_BILLION = 'ppb'
UNIT_PARTS_PER_MILLION = 'ppm'
UNIT_PERCENT = '%'
UNIT_PULSES_PER_MINUTE = 'pulses/min'
UNIT_SECOND = 's'

View File

@@ -97,7 +97,7 @@ void Application::loop() {
if (this->dump_config_at_ >= 0 && this->dump_config_at_ < this->components_.size()) {
if (this->dump_config_at_ == 0) {
ESP_LOGI(TAG, "esphome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
}
this->components_[this->dump_config_at_]->dump_config();

View File

@@ -54,15 +54,15 @@ bool ESPPreferenceObject::save_() {
#ifdef ARDUINO_ARCH_ESP8266
#define ESP_RTC_USER_MEM_START 0x60001200
static const uint32_t ESP_RTC_USER_MEM_START = 0x60001200;
#define ESP_RTC_USER_MEM ((uint32_t *) ESP_RTC_USER_MEM_START)
#define ESP_RTC_USER_MEM_SIZE_WORDS 128
#define ESP_RTC_USER_MEM_SIZE_BYTES ESP_RTC_USER_MEM_SIZE_WORDS * 4
static const uint32_t ESP_RTC_USER_MEM_SIZE_WORDS = 128;
static const uint32_t ESP_RTC_USER_MEM_SIZE_BYTES = ESP_RTC_USER_MEM_SIZE_WORDS * 4;
#ifdef USE_ESP8266_PREFERENCES_FLASH
#define ESP8266_FLASH_STORAGE_SIZE 128
static const uint32_t ESP8266_FLASH_STORAGE_SIZE = 128;
#else
#define ESP8266_FLASH_STORAGE_SIZE 64
static const uint32_t ESP8266_FLASH_STORAGE_SIZE = 64;
#endif
static inline bool esp_rtc_user_mem_read(uint32_t index, uint32_t *dest) {

View File

@@ -9,6 +9,9 @@ static const char *TAG = "scheduler";
static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
// Uncomment to debug scheduler
// #define ESPHOME_DEBUG_SCHEDULER
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout,
std::function<void()> &&func) {
const uint32_t now = this->millis_();
@@ -21,7 +24,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%u)", name.c_str(), timeout);
auto *item = new SchedulerItem();
auto item = make_unique<SchedulerItem>();
item->component = component;
item->name = name;
item->type = SchedulerItem::TIMEOUT;
@@ -30,7 +33,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
item->last_execution_major = this->millis_major_;
item->f = std::move(func);
item->remove = false;
this->push_(item);
this->push_(std::move(item));
}
bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
@@ -52,18 +55,18 @@ void HOT Scheduler::set_interval(Component *component, const std::string &name,
ESP_LOGVV(TAG, "set_interval(name='%s', interval=%u, offset=%u)", name.c_str(), interval, offset);
auto *item = new SchedulerItem();
auto item = make_unique<SchedulerItem>();
item->component = component;
item->name = name;
item->type = SchedulerItem::INTERVAL;
item->interval = interval;
item->last_execution = now - offset;
item->last_execution = now - offset - interval;
item->last_execution_major = this->millis_major_;
if (item->last_execution > now)
item->last_execution_major--;
item->f = std::move(func);
item->remove = false;
this->push_(item);
this->push_(std::move(item));
}
bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
@@ -71,7 +74,7 @@ bool HOT Scheduler::cancel_interval(Component *component, const std::string &nam
optional<uint32_t> HOT Scheduler::next_schedule_in() {
if (this->empty_())
return {};
auto *item = this->items_[0];
auto &item = this->items_[0];
const uint32_t now = this->millis_();
uint32_t next_time = item->last_execution + item->interval;
if (next_time < now)
@@ -82,98 +85,103 @@ void ICACHE_RAM_ATTR HOT Scheduler::call() {
const uint32_t now = this->millis_();
this->process_to_add();
// Uncomment for debugging the scheduler:
#ifdef ESPHOME_DEBUG_SCHEDULER
static uint32_t last_print = 0;
// if (random_uint32() % 400 == 0) {
// std::vector<SchedulerItem *> old_items = this->items_;
// ESP_LOGVV(TAG, "Items: count=%u, now=%u", this->items_.size(), now);
// while (!this->empty_()) {
// auto *item = this->items_[0];
// const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
// ESP_LOGVV(TAG, " %s '%s' interval=%u last_execution=%u (%u) next=%u",
// type, item->name.c_str(), item->interval, item->last_execution, item->last_execution_major,
// item->last_execution + item->interval);
// this->pop_raw_();
// }
// ESP_LOGVV(TAG, "\n");
// this->items_ = old_items;
//}
if (now - last_print > 2000) {
last_print = now;
std::vector<std::unique_ptr<SchedulerItem>> old_items;
ESP_LOGVV(TAG, "Items: count=%u, now=%u", this->items_.size(), now);
while (!this->empty_()) {
auto item = std::move(this->items_[0]);
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
ESP_LOGVV(TAG, " %s '%s' interval=%u last_execution=%u (%u) next=%u (%u)", type, item->name.c_str(),
item->interval, item->last_execution, item->last_execution_major, item->next_execution(),
item->next_execution_major());
this->pop_raw_();
old_items.push_back(std::move(item));
}
ESP_LOGVV(TAG, "\n");
this->items_ = std::move(old_items);
}
#endif // ESPHOME_DEBUG_SCHEDULER
while (!this->empty_()) {
// Don't copy-by value yet
auto *item = this->items_[0];
if ((now - item->last_execution) < item->interval)
// Not reached timeout yet, done for this call
break;
uint8_t major = item->last_execution_major;
if (item->last_execution + item->interval < item->last_execution)
major++;
if (major != this->millis_major_)
break;
// use scoping to indicate visibility of `item` variable
{
// Don't copy-by value yet
auto &item = this->items_[0];
if ((now - item->last_execution) < item->interval)
// Not reached timeout yet, done for this call
break;
uint8_t major = item->next_execution_major();
if (this->millis_major_ - major > 1)
break;
// Don't run on failed components
if (item->component != nullptr && item->component->is_failed()) {
this->pop_raw_();
delete item;
continue;
}
// Don't run on failed components
if (item->component != nullptr && item->component->is_failed()) {
this->pop_raw_();
continue;
}
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item->name.c_str(),
item->interval, item->last_execution, now);
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item->name.c_str(),
item->interval, item->last_execution, now);
#endif
// Warning: During f(), a lot of stuff can happen, including:
// - timeouts/intervals get added, potentially invalidating vector pointers
// - timeouts/intervals get cancelled
item->f();
// Only pop after function call, this ensures we were reachable
// during the function call and know if we were cancelled.
this->pop_raw_();
if (item->remove) {
// We were removed/cancelled in the function call, stop
delete item;
continue;
// Warning: During f(), a lot of stuff can happen, including:
// - timeouts/intervals get added, potentially invalidating vector pointers
// - timeouts/intervals get cancelled
item->f();
}
if (item->type == SchedulerItem::INTERVAL) {
if (item->interval != 0) {
const uint32_t before = item->last_execution;
const uint32_t amount = (now - item->last_execution) / item->interval;
item->last_execution += amount * item->interval;
if (item->last_execution < before)
item->last_execution_major++;
{
// new scope, item from before might have been moved in the vector
auto item = std::move(this->items_[0]);
// Only pop after function call, this ensures we were reachable
// during the function call and know if we were cancelled.
this->pop_raw_();
if (item->remove) {
// We were removed/cancelled in the function call, stop
continue;
}
if (item->type == SchedulerItem::INTERVAL) {
if (item->interval != 0) {
const uint32_t before = item->last_execution;
const uint32_t amount = (now - item->last_execution) / item->interval;
item->last_execution += amount * item->interval;
if (item->last_execution < before)
item->last_execution_major++;
}
this->push_(std::move(item));
}
this->push_(item);
} else {
delete item;
}
}
this->process_to_add();
}
void HOT Scheduler::process_to_add() {
for (auto *it : this->to_add_) {
for (auto &it : this->to_add_) {
if (it->remove) {
delete it;
continue;
}
this->items_.push_back(it);
this->items_.push_back(std::move(it));
std::push_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
}
this->to_add_.clear();
}
void HOT Scheduler::cleanup_() {
while (!this->items_.empty()) {
auto item = this->items_[0];
auto &item = this->items_[0];
if (!item->remove)
return;
delete item;
this->pop_raw_();
}
}
@@ -181,15 +189,15 @@ void HOT Scheduler::pop_raw_() {
std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
this->items_.pop_back();
}
void HOT Scheduler::push_(Scheduler::SchedulerItem *item) { this->to_add_.push_back(item); }
void HOT Scheduler::push_(std::unique_ptr<Scheduler::SchedulerItem> item) { this->to_add_.push_back(std::move(item)); }
bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, Scheduler::SchedulerItem::Type type) {
bool ret = false;
for (auto *it : this->items_)
for (auto &it : this->items_)
if (it->component == component && it->name == name && it->type == type) {
it->remove = true;
ret = true;
}
for (auto *it : this->to_add_)
for (auto &it : this->to_add_)
if (it->component == component && it->name == name && it->type == type) {
it->remove = true;
ret = true;
@@ -206,21 +214,30 @@ uint32_t Scheduler::millis_() {
return now;
}
bool HOT Scheduler::SchedulerItem::cmp(Scheduler::SchedulerItem *a, Scheduler::SchedulerItem *b) {
bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a,
const std::unique_ptr<SchedulerItem> &b) {
// min-heap
// return true if *a* will happen after *b*
uint32_t a_next_exec = a->last_execution + a->timeout;
uint8_t a_next_exec_major = a->last_execution_major;
if (a_next_exec < a->last_execution)
a_next_exec_major++;
uint32_t b_next_exec = b->last_execution + b->timeout;
uint8_t b_next_exec_major = b->last_execution_major;
if (b_next_exec < b->last_execution)
b_next_exec_major++;
uint32_t a_next_exec = a->next_execution();
uint8_t a_next_exec_major = a->next_execution_major();
uint32_t b_next_exec = b->next_execution();
uint8_t b_next_exec_major = b->next_execution_major();
if (a_next_exec_major != b_next_exec_major) {
return a_next_exec_major > b_next_exec_major;
// The "major" calculation is quite complicated.
// Basically, we need to check if the major value lies in the future or
//
// Here are some cases to think about:
// Format: a_major,b_major -> expected result (a-b, b-a)
// a=255,b=0 -> false (255, 1)
// a=0,b=1 -> false (255, 1)
// a=1,b=0 -> true (1, 255)
// a=0,b=255 -> true (1, 255)
uint8_t diff1 = a_next_exec_major - b_next_exec_major;
uint8_t diff2 = b_next_exec_major - a_next_exec_major;
return diff1 < diff2;
}
return a_next_exec > b_next_exec;

View File

@@ -2,6 +2,7 @@
#include "esphome/core/component.h"
#include <vector>
#include <memory>
namespace esphome {
@@ -34,21 +35,30 @@ class Scheduler {
bool remove;
uint8_t last_execution_major;
static bool cmp(SchedulerItem *a, SchedulerItem *b);
inline uint32_t next_execution() { return this->last_execution + this->timeout; }
inline uint8_t next_execution_major() {
uint32_t next_exec = this->next_execution();
uint8_t next_exec_major = this->last_execution_major;
if (next_exec < this->last_execution)
next_exec_major++;
return next_exec_major;
}
static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
};
uint32_t millis_();
void cleanup_();
void pop_raw_();
void push_(SchedulerItem *item);
void push_(std::unique_ptr<SchedulerItem> item);
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
bool empty_() {
this->cleanup_();
return this->items_.empty();
}
std::vector<SchedulerItem *> items_;
std::vector<SchedulerItem *> to_add_;
std::vector<std::unique_ptr<SchedulerItem>> items_;
std::vector<std::unique_ptr<SchedulerItem>> to_add_;
uint32_t last_millis_{0};
uint8_t millis_major_{0};
};

View File

@@ -29,7 +29,7 @@ import tornado.websocket
from esphome import const, util
from esphome.__main__ import get_serial_ports
from esphome.helpers import mkdir_p, get_bool_env, run_system_command
from esphome.py_compat import IS_PY2, decode_text
from esphome.py_compat import IS_PY2, decode_text, encode_text
from esphome.storage_json import EsphomeStorageJSON, StorageJSON, \
esphome_storage_path, ext_storage_path, trash_storage_path
from esphome.util import shlex_quote
@@ -85,12 +85,11 @@ class DashboardSettings(object):
def check_password(self, username, password):
if not self.using_auth:
return True
if username != self.username:
return False
if IS_PY2:
password = hmac.new(password).digest()
else:
password = hmac.new(password.encode()).digest()
return username == self.username and hmac.compare_digest(self.password_digest, password)
password_digest = hmac.new(encode_text(password)).digest()
return hmac.compare_digest(self.password_digest, password_digest)
def rel_path(self, *args):
return os.path.join(self.config_dir, *args)
@@ -610,8 +609,8 @@ class LoginHandler(BaseHandler):
'X-HASSIO-KEY': os.getenv('HASSIO_TOKEN'),
}
data = {
'username': str(self.get_argument('username', '')),
'password': str(self.get_argument('password', ''))
'username': decode_text(self.get_argument('username', '')),
'password': decode_text(self.get_argument('password', ''))
}
try:
req = requests.post('http://hassio/auth', headers=headers, data=data)
@@ -628,8 +627,8 @@ class LoginHandler(BaseHandler):
self.render_login_page(error="Invalid username or password")
def post_native_login(self):
username = str(self.get_argument("username", '').encode('utf-8'))
password = str(self.get_argument("password", '').encode('utf-8'))
username = decode_text(self.get_argument("username", ''))
password = decode_text(self.get_argument("password", ''))
if settings.check_password(username, password):
self.set_secure_cookie("authenticated", cookie_authenticated_yes)
self.redirect("/")

View File

@@ -1,10 +1,11 @@
from __future__ import print_function
import codecs
import logging
import os
from esphome.py_compat import char_to_byte, text_type
from esphome.py_compat import char_to_byte, text_type, IS_PY2, encode_text
_LOGGER = logging.getLogger(__name__)
@@ -79,15 +80,15 @@ def run_system_command(*args):
def mkdir_p(path):
import errno
try:
os.makedirs(path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
except OSError as err:
import errno
if err.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
from esphome.core import EsphomeError
raise EsphomeError(u"Error creating directories {}: {}".format(path, err))
def is_ip_address(host):
@@ -151,17 +152,6 @@ def is_hassio():
return get_bool_env('ESPHOME_IS_HASSIO')
def copy_file_if_changed(src, dst):
src_text = read_file(src)
if os.path.isfile(dst):
dst_text = read_file(dst)
else:
dst_text = None
if src_text == dst_text:
return
write_file(dst, src_text)
def walk_files(path):
for root, _, files in os.walk(path):
for name in files:
@@ -172,28 +162,99 @@ def read_file(path):
try:
with codecs.open(path, 'r', encoding='utf-8') as f_handle:
return f_handle.read()
except OSError:
except OSError as err:
from esphome.core import EsphomeError
raise EsphomeError(u"Could not read file at {}".format(path))
raise EsphomeError(u"Error reading file {}: {}".format(path, err))
except UnicodeDecodeError as err:
from esphome.core import EsphomeError
raise EsphomeError(u"Error reading file {}: {}".format(path, err))
def _write_file(path, text):
import tempfile
directory = os.path.dirname(path)
mkdir_p(directory)
tmp_path = None
data = encode_text(text)
try:
with tempfile.NamedTemporaryFile(mode="wb", dir=directory, delete=False) as f_handle:
tmp_path = f_handle.name
f_handle.write(data)
# Newer tempfile implementations create the file with mode 0o600
os.chmod(tmp_path, 0o644)
if IS_PY2:
if os.path.exists(path):
os.remove(path)
os.rename(tmp_path, path)
else:
# If destination exists, will be overwritten
os.replace(tmp_path, path)
finally:
if tmp_path is not None and os.path.exists(tmp_path):
try:
os.remove(tmp_path)
except OSError as err:
_LOGGER.error("Write file cleanup failed: %s", err)
def write_file(path, text):
try:
mkdir_p(os.path.dirname(path))
with codecs.open(path, 'w+', encoding='utf-8') as f_handle:
f_handle.write(text)
_write_file(path, text)
except OSError:
from esphome.core import EsphomeError
raise EsphomeError(u"Could not write file at {}".format(path))
def write_file_if_changed(text, dst):
def write_file_if_changed(path, text):
src_content = None
if os.path.isfile(dst):
src_content = read_file(dst)
if os.path.isfile(path):
src_content = read_file(path)
if src_content != text:
write_file(dst, text)
write_file(path, text)
def copy_file_if_changed(src, dst):
import shutil
if file_compare(src, dst):
return
mkdir_p(os.path.dirname(dst))
try:
shutil.copy(src, dst)
except OSError as err:
from esphome.core import EsphomeError
raise EsphomeError(u"Error copying file {} to {}: {}".format(src, dst, err))
def list_starts_with(list_, sub):
return len(sub) <= len(list_) and all(list_[i] == x for i, x in enumerate(sub))
def file_compare(path1, path2):
"""Return True if the files path1 and path2 have the same contents."""
import stat
try:
stat1, stat2 = os.stat(path1), os.stat(path2)
except OSError:
# File doesn't exist or another error -> not equal
return False
if stat.S_IFMT(stat1.st_mode) != stat.S_IFREG or stat.S_IFMT(stat2.st_mode) != stat.S_IFREG:
# At least one of them is not a regular file (or does not exist)
return False
if stat1.st_size != stat2.st_size:
# Different sizes
return False
bufsize = 8*1024
# Read files in blocks until a mismatch is found
with open(path1, 'rb') as fh1, open(path2, 'rb') as fh2:
while True:
blob1, blob2 = fh1.read(bufsize), fh2.read(bufsize)
if blob1 != blob2:
# Different content
return False
if not blob1:
# Reached end
return True

View File

@@ -15,6 +15,7 @@ from esphome.const import CONF_BROKER, CONF_DISCOVERY_PREFIX, CONF_ESPHOME, \
CONF_TOPIC, CONF_TOPIC_PREFIX, CONF_USERNAME
from esphome.core import CORE, EsphomeError
from esphome.helpers import color
from esphome.py_compat import decode_text
from esphome.util import safe_print
_LOGGER = logging.getLogger(__name__)
@@ -22,6 +23,7 @@ _LOGGER = logging.getLogger(__name__)
def initialize(config, subscriptions, on_message, username, password, client_id):
def on_connect(client, userdata, flags, return_code):
_LOGGER.info("Connected to MQTT broker!")
for topic in subscriptions:
client.subscribe(topic)
@@ -94,7 +96,8 @@ def show_logs(config, topic=None, username=None, password=None, client_id=None):
def on_message(client, userdata, msg):
time_ = datetime.now().time().strftime(u'[%H:%M:%S]')
message = time_ + msg.payload
payload = decode_text(msg.payload)
message = time_ + payload
safe_print(message)
return initialize(config, [topic], on_message, username, password, client_id)

View File

@@ -1,5 +1,6 @@
import functools
import sys
import codecs
PYTHON_MAJOR = sys.version_info[0]
IS_PY2 = PYTHON_MAJOR == 2
@@ -75,15 +76,14 @@ def indexbytes(buf, i):
return ord(buf[i])
if IS_PY2:
def decode_text(data, encoding='utf-8', errors='strict'):
# type: (str, str, str) -> unicode
if isinstance(data, unicode):
return data
return unicode(data, encoding=encoding, errors=errors)
else:
def decode_text(data, encoding='utf-8', errors='strict'):
# type: (bytes, str, str) -> str
if isinstance(data, str):
return data
return data.decode(encoding=encoding, errors=errors)
def decode_text(data, encoding='utf-8', errors='strict'):
if isinstance(data, text_type):
return data
return codecs.decode(data, encoding, errors)
def encode_text(data, encoding='utf-8', errors='strict'):
if isinstance(data, binary_type):
return data
return codecs.encode(data, encoding, errors)

View File

@@ -7,7 +7,7 @@ import os
from esphome import const
from esphome.core import CORE
from esphome.helpers import mkdir_p
from esphome.helpers import mkdir_p, write_file_if_changed
# pylint: disable=unused-import, wrong-import-order
from esphome.core import CoreType # noqa
@@ -89,8 +89,7 @@ class StorageJSON(object):
def save(self, path):
mkdir_p(os.path.dirname(path))
with codecs.open(path, 'w', encoding='utf-8') as f_handle:
f_handle.write(self.to_json())
write_file_if_changed(path, self.to_json())
@staticmethod
def from_esphome_core(esph, old): # type: (CoreType, Optional[StorageJSON]) -> StorageJSON
@@ -130,8 +129,7 @@ class StorageJSON(object):
@staticmethod
def _load_impl(path): # type: (str) -> Optional[StorageJSON]
with codecs.open(path, 'r', encoding='utf-8') as f_handle:
text = f_handle.read()
storage = json.loads(text, encoding='utf-8')
storage = json.load(f_handle)
storage_version = storage['storage_version']
name = storage.get('name')
comment = storage.get('comment')
@@ -195,15 +193,12 @@ class EsphomeStorageJSON(object):
return json.dumps(self.as_dict(), indent=2) + u'\n'
def save(self, path): # type: (str) -> None
mkdir_p(os.path.dirname(path))
with codecs.open(path, 'w', encoding='utf-8') as f_handle:
f_handle.write(self.to_json())
write_file_if_changed(path, self.to_json())
@staticmethod
def _load_impl(path): # type: (str) -> Optional[EsphomeStorageJSON]
with codecs.open(path, 'r', encoding='utf-8') as f_handle:
text = f_handle.read()
storage = json.loads(text, encoding='utf-8')
storage = json.load(f_handle)
storage_version = storage['storage_version']
cookie_secret = storage.get('cookie_secret')
last_update_check = storage.get('last_update_check')

View File

@@ -1,6 +1,5 @@
from __future__ import print_function
import codecs
import os
import random
import string
@@ -9,7 +8,7 @@ import unicodedata
import voluptuous as vol
import esphome.config_validation as cv
from esphome.helpers import color, get_bool_env
from esphome.helpers import color, get_bool_env, write_file
# pylint: disable=anomalous-backslash-in-string
from esphome.pins import ESP32_BOARD_PINS, ESP8266_BOARD_PINS
from esphome.py_compat import safe_input, text_type
@@ -104,8 +103,7 @@ def wizard_write(path, **kwargs):
kwargs['platform'] = 'ESP8266' if board in ESP8266_BOARD_PINS else 'ESP32'
platform = kwargs['platform']
with codecs.open(path, 'w', 'utf-8') as f_handle:
f_handle.write(wizard_file(**kwargs))
write_file(path, wizard_file(**kwargs))
storage = StorageJSON.from_wizard(name, name + '.local', platform, board)
storage_path = ext_storage_path(os.path.dirname(path), os.path.basename(path))
storage.save(storage_path)

View File

@@ -8,7 +8,8 @@ from esphome.config import iter_components
from esphome.const import CONF_BOARD_FLASH_MODE, CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS, \
HEADER_FILE_EXTENSIONS, SOURCE_FILE_EXTENSIONS, __version__
from esphome.core import CORE, EsphomeError
from esphome.helpers import mkdir_p, read_file, write_file_if_changed, walk_files
from esphome.helpers import mkdir_p, read_file, write_file_if_changed, walk_files, \
copy_file_if_changed
from esphome.storage_json import StorageJSON, storage_path
_LOGGER = logging.getLogger(__name__)
@@ -112,7 +113,7 @@ def migrate_src_version_0_to_1():
"auto-generated again.", main_cpp, main_cpp)
_LOGGER.info("Migration: Added include section to %s", main_cpp)
write_file_if_changed(content, main_cpp)
write_file_if_changed(main_cpp, content)
def migrate_src_version(old, new):
@@ -251,7 +252,7 @@ def write_platformio_ini(content):
content_format = INI_BASE_FORMAT
full_file = content_format[0] + INI_AUTO_GENERATE_BEGIN + '\n' + content
full_file += INI_AUTO_GENERATE_END + content_format[1]
write_file_if_changed(full_file, path)
write_file_if_changed(path, full_file)
def write_platformio_project():
@@ -285,7 +286,6 @@ or use the custom_components folder.
def copy_src_tree():
import filecmp
import shutil
source_files = {}
@@ -321,9 +321,7 @@ def copy_src_tree():
os.remove(path)
else:
src_path = source_files_copy.pop(target)
if not filecmp.cmp(path, src_path):
# Files are not same, copy
shutil.copy(src_path, path)
copy_file_if_changed(src_path, path)
# Now copy new files
for target, src_path in source_files_copy.items():
@@ -332,14 +330,14 @@ def copy_src_tree():
shutil.copy(src_path, dst_path)
# Finally copy defines
write_file_if_changed(generate_defines_h(),
CORE.relative_src_path('esphome', 'core', 'defines.h'))
write_file_if_changed(ESPHOME_README_TXT,
CORE.relative_src_path('esphome', 'README.txt'))
write_file_if_changed(ESPHOME_H_FORMAT.format(include_s),
CORE.relative_src_path('esphome.h'))
write_file_if_changed(VERSION_H_FORMAT.format(__version__),
CORE.relative_src_path('esphome', 'core', 'version.h'))
write_file_if_changed(CORE.relative_src_path('esphome', 'core', 'defines.h'),
generate_defines_h())
write_file_if_changed(CORE.relative_src_path('esphome', 'README.txt'),
ESPHOME_README_TXT)
write_file_if_changed(CORE.relative_src_path('esphome.h'),
ESPHOME_H_FORMAT.format(include_s))
write_file_if_changed(CORE.relative_src_path('esphome', 'core', 'version.h'),
VERSION_H_FORMAT.format(__version__))
def generate_defines_h():
@@ -365,7 +363,7 @@ def write_cpp(code_s):
full_file = code_format[0] + CPP_INCLUDE_BEGIN + u'\n' + global_s + CPP_INCLUDE_END
full_file += code_format[1] + CPP_AUTO_GENERATE_BEGIN + u'\n' + code_s + CPP_AUTO_GENERATE_END
full_file += code_format[2]
write_file_if_changed(full_file, path)
write_file_if_changed(path, full_file)
def clean_build():

View File

@@ -7,6 +7,7 @@ import fnmatch
import os.path
import subprocess
import sys
import re
def find_all(a_str, sub):
@@ -39,6 +40,7 @@ ignore_types = ('.ico', '.woff', '.woff2', '')
LINT_FILE_CHECKS = []
LINT_CONTENT_CHECKS = []
LINT_POST_CHECKS = []
def run_check(lint_obj, fname, *args):
@@ -84,6 +86,31 @@ def lint_content_check(**kwargs):
return decorator
def lint_post_check(func):
_add_check(LINT_POST_CHECKS, func)
return func
def lint_re_check(regex, **kwargs):
prog = re.compile(regex, re.MULTILINE)
decor = lint_content_check(**kwargs)
def decorator(func):
def new_func(fname, content):
errors = []
for match in prog.finditer(content):
if 'NOLINT' in match.group(0):
continue
lineno = content.count("\n", 0, match.start()) + 1
err = func(fname, match)
if err is None:
continue
errors.append("{} See line {}.".format(err, lineno))
return errors
return decor(new_func)
return decorator
def lint_content_find_check(find, **kwargs):
decor = lint_content_check(**kwargs)
@@ -92,9 +119,12 @@ def lint_content_find_check(find, **kwargs):
find_ = find
if callable(find):
find_ = find(fname, content)
errors = []
for line, col in find_all(content, find_):
err = func(fname)
return "{err} See line {line}:{col}.".format(err=err, line=line+1, col=col+1)
errors.append("{err} See line {line}:{col}."
"".format(err=err, line=line+1, col=col+1))
return errors
return decor(new_func)
return decorator
@@ -143,6 +173,98 @@ def lint_end_newline(fname, content):
return None
CPP_RE_EOL = r'\s*?(?://.*?)?$'
def highlight(s):
return '\033[36m{}\033[0m'.format(s)
@lint_re_check(r'^#define\s+([a-zA-Z0-9_]+)\s+([0-9bx]+)' + CPP_RE_EOL,
include=cpp_include, exclude=['esphome/core/log.h'])
def lint_no_defines(fname, match):
s = highlight('static const uint8_t {} = {};'.format(match.group(1), match.group(2)))
return ("#define macros for integer constants are not allowed, please use "
"{} style instead (replace uint8_t with the appropriate "
"datatype). See also Google style guide.".format(s))
@lint_re_check(r'^\s*delay\((\d+)\);' + CPP_RE_EOL, include=cpp_include)
def lint_no_long_delays(fname, match):
duration_ms = int(match.group(1))
if duration_ms < 50:
return None
return (
"{} - long calls to delay() are not allowed in ESPHome because everything executes "
"in one thread. Calling delay() will block the main thread and slow down ESPHome.\n"
"If there's no way to work around the delay() and it doesn't execute often, please add "
"a '// NOLINT' comment to the line."
"".format(highlight(match.group(0).strip()))
)
@lint_content_check(include=['esphome/const.py'])
def lint_const_ordered(fname, content):
lines = content.splitlines()
errors = []
for start in ['CONF_', 'ICON_', 'UNIT_']:
matching = [(i+1, line) for i, line in enumerate(lines) if line.startswith(start)]
ordered = list(sorted(matching, key=lambda x: x[1].replace('_', ' ')))
ordered = [(mi, ol) for (mi, _), (_, ol) in zip(matching, ordered)]
for (mi, ml), (oi, ol) in zip(matching, ordered):
if ml == ol:
continue
target = next(i for i, l in ordered if l == ml)
target_text = next(l for i, l in matching if target == i)
errors.append("Constant {} is not ordered, please make sure all constants are ordered. "
"See line {} (should go to line {}, {})"
"".format(highlight(ml), mi, target, target_text))
return errors
@lint_re_check(r'^\s*CONF_([A-Z_0-9a-z]+)\s+=\s+[\'"](.*?)[\'"]\s*?$', include=['*.py'])
def lint_conf_matches(fname, match):
const = match.group(1)
value = match.group(2)
const_norm = const.lower()
value_norm = value.replace('.', '_')
if const_norm == value_norm:
return None
return ("Constant {} does not match value {}! Please make sure the constant's name matches its "
"value!"
"".format(highlight('CONF_' + const), highlight(value)))
CONF_RE = r'^(CONF_[a-zA-Z0-9_]+)\s*=\s*[\'"].*?[\'"]\s*?$'
with codecs.open('esphome/const.py', 'r', encoding='utf-8') as f_handle:
constants_content = f_handle.read()
CONSTANTS = [m.group(1) for m in re.finditer(CONF_RE, constants_content, re.MULTILINE)]
CONSTANTS_USES = collections.defaultdict(list)
@lint_re_check(CONF_RE, include=['*.py'], exclude=['esphome/const.py'])
def lint_conf_from_const_py(fname, match):
name = match.group(1)
if name not in CONSTANTS:
CONSTANTS_USES[name].append(fname)
return None
return ("Constant {} has already been defined in const.py - please import the constant from "
"const.py directly.".format(highlight(name)))
@lint_post_check
def lint_constants_usage():
errors = []
for constant, uses in CONSTANTS_USES.items():
if len(uses) < 4:
continue
errors.append("Constant {} is defined in {} files. Please move all definitions of the "
"constant to const.py (Uses: {})"
"".format(highlight(constant), len(uses), ', '.join(uses)))
return errors
def relative_cpp_search_text(fname, content):
parts = fname.split('/')
integration = parts[2]
@@ -176,6 +298,19 @@ def lint_relative_py_import(fname):
' from . import abc_ns\n\n')
@lint_content_check(include=['esphome/components/*.h', 'esphome/components/*.cpp',
'esphome/components/*.tcc'])
def lint_namespace(fname, content):
expected_name = re.match(r'^esphome/components/([^/]+)/.*',
fname.replace(os.path.sep, '/')).group(1)
search = 'namespace {}'.format(expected_name)
if search in content:
return None
return 'Invalid namespace found in C++ file. All integration C++ files should put all ' \
'functions in a separate namespace that matches the integration\'s name. ' \
'Please make sure the file contains {}'.format(highlight(search))
@lint_content_find_check('"esphome.h"', include=cpp_include, exclude=['tests/custom.h'])
def lint_esphome_h(fname):
return ("File contains reference to 'esphome.h' - This file is "
@@ -203,6 +338,7 @@ def lint_pragma_once(fname, content):
'esphome/components/stepper/stepper.h',
'esphome/components/switch/switch.h',
'esphome/components/text_sensor/text_sensor.h',
'esphome/components/climate/climate.h',
'esphome/core/component.h',
'esphome/core/esphal.h',
'esphome/core/log.h',
@@ -241,6 +377,8 @@ for fname in files:
continue
run_checks(LINT_CONTENT_CHECKS, fname, fname, content)
run_checks(LINT_POST_CHECKS, 'POST')
for f, errs in sorted(errors.items()):
print("\033[0;32m************* File \033[1;32m{}\033[0m".format(f))
for err in errs:

View File

@@ -172,7 +172,7 @@ dallas:
as3935_spi:
cs_pin: GPIO12
pin: GPIO13
irq_pin: GPIO13
sensor:
- platform: adc

View File

@@ -54,7 +54,7 @@ deep_sleep:
sleep_duration: 50s
as3935_i2c:
pin: GPIO12
irq_pin: GPIO12
sensor: