1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-12 12:55:46 +00:00

Compare commits

..

28 Commits

Author SHA1 Message Date
Otto Winter
53c231a7eb Revert "Atm90e32 pf fix (#841)"
This reverts commit 7842a55c81.
2019-11-17 23:37:00 +01:00
Otto Winter
d44ce82aa1 Bump version to v1.14.3 2019-11-17 23:34:04 +01:00
Otto Winter
a055de48e4 Change ESP8266 default wifi output power (#862)
See also https://github.com/esphome/issues/issues/455
2019-11-17 23:34:01 +01:00
Otto Winter
37b8d665fe Revert ESP32 BLE Tracker defaults (#863)
Fixes https://github.com/esphome/issues/issues/824
Fixes https://github.com/esphome/issues/issues/851
2019-11-17 23:34:01 +01:00
Otto Winter
dd7c8dabb1 Fix MQTT python 3 stringify IPAddress Type (#864)
Fixes https://github.com/esphome/issues/issues/850
2019-11-17 23:34:01 +01:00
Otto Winter
e41a9875e3 Improve WiFi disconnect messages (#857)
* Improve WiFi disconnect messages

* Fix

* Update wifi_component_esp32.cpp
2019-11-17 23:34:01 +01:00
Brandon Davidson
c5c42c4338 Tuya: Fix init sequence and handle wifi test command (#820)
* Handle WiFi test command

Also rename commands to match Tuya protocol docs

* Fix init sequence and product info check

* Fix clang-format suggestions

* Additional changes based on code review

* Fix temp command buffer scope

* Let the interval timer fire the first heatbeat

* Fix init steps; add logging

* Lint

* Remove setup_priority override

* Add delay to dump_config

* Refactor dump sequence

* Fix verbose logging

* Fix lints

* Don't bother suppressing duplicate config dumps

* nolint


Co-authored-by: Otto Winter <otto@otto-winter.com>
2019-11-17 23:34:00 +01:00
Brandon Davidson
531428b8b0 Fix logger uart conflict check (#858)
* Fix logger uart conflict check

* Fix class for check func

* Fix syntax

Hope lint is OK with moving the end of the conditional outside the #IFDEF

* Move end of conditional inside ifdef and remove extra whitespace

* Simplify

clang-format did not like the ifdefs and was reformatting in a way that killed clang-tidy.

Simple solution is to use logger's hw_serial as source of truth

Also simplifies the code - uart doesn't need to know what the logger uart settings mean
2019-11-17 23:34:00 +01:00
Otto Winter
ea8068e001 Switch to 115200 baud upload if 460800 fails (#856)
* Switch to 115200 baud upload if 460800 fails

* Update __main__.py
2019-11-17 23:34:00 +01:00
Mark
7842a55c81 Atm90e32 pf fix (#841)
* correct set_pf_sensor to set_power_factor_senor

* remove junk files added in error

* correct sensors.yaml reference to set_reactive_power

* Fixes
2019-11-17 23:33:56 +01:00
Samuel Sieb
51d39862b1 add position reporting to the template cover (#821)
* add position reporting to the template cover

* remove duplicate import

* use config flag instead


Co-authored-by: Samuel Sieb <samuel@sieb.net>
2019-11-17 23:33:21 +01:00
Otto Winter
bfea6ca79b Mark python 3.5 support deprecated (#849)
* Mark python 3.5 unsupported

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

* Update .travis.yml

* Update typing dep
2019-11-17 23:33:20 +01:00
Otto Winter
6297395018 Fix PZEM004T v2 (#846)
Fixes https://github.com/esphome/issues/issues/817
2019-11-17 23:33:20 +01:00
Otto Winter
a5b49dbfa6 Adjust some units (#852)
* Adjust some units

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

* Lint
2019-11-17 23:33:12 +01:00
Otto Winter
7c0d777173 Check DHT sensor exists before publishing (#850)
Fixes https://github.com/esphome/issues/issues/841
2019-11-17 23:31:36 +01:00
Otto Winter
74878276fc Web server CORS headers (#840)
* Add CORS header to web server

* Refactor

* Cleanup

See also https://github.com/esphome/issues/issues/806
2019-11-17 23:31:35 +01:00
Otto Winter
226e3b1dad Fix sensor force_update native API (#847)
Fixes https://github.com/esphome/issues/issues/842
2019-11-17 23:31:35 +01:00
Otto Winter
7752794fc5 Fix neopixelbus missing method pins (#848)
Fixes https://github.com/esphome/issues/issues/839
2019-11-17 23:31:35 +01:00
Otto Winter
b3094d6a53 Add missing state attribute (#851)
* Add api missing_state attribute

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

Adds a new property for missing state, so that HA can now when a sensor does not have a state yet.

* Update api.proto
2019-11-17 23:31:35 +01:00
Otto Winter
e3640e710f Add wifi output_power setting (#853)
* Add wifi output_power setting

See also:
 - https://github.com/esphome/feature-requests/issues/471#issuecomment-552350467
 - https://github.com/esp8266/Arduino/issues/6366
 - https://github.com/esp8266/Arduino/issues/6471
 - 849f8cf920/code/espurna/config/general.h (L593-L599)
 - https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/network/esp_wifi.html#_CPPv425esp_wifi_set_max_tx_power6int8_t

* Lint
2019-11-17 23:31:35 +01:00
Guillermo Ruffino
2ef64b55c5 fix missing checks of is_playing condition (#844) 2019-11-17 23:31:34 +01:00
Otto Winter
7f6672bb37 Fix calculations for negative sun declination (#839)
Fixes https://github.com/esphome/issues/issues/793

Also adds a clampd function that operates with doubles, not floats
2019-11-17 23:31:34 +01:00
Otto Winter
68a3b31628 Update variable in scheduler (#838)
Fixes https://github.com/esphome/issues/issues/826
2019-11-17 23:31:34 +01:00
Otto Winter
1b35855e68 Update platformio libraries (#837)
* Update platformio libraries

* Lint
2019-11-17 23:31:34 +01:00
Otto Winter
1e1837000d Fix homeassistant.service schema lambda (#833)
* Fix homeassistant.service schema lambda

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

* Improve

* Fix
2019-11-17 23:31:34 +01:00
Otto Winter
e2d5257632 Fix ESP32 rotary encoder (#834)
* Fix ESP32 rotary encoder

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

* Update rotary_encoder.cpp

* Lint
2019-11-17 23:31:34 +01:00
Otto Winter
387c75793b WiFi AP apply manual ip settings (#836) 2019-11-17 23:31:33 +01:00
Otto Winter
4f3a74d08a ESP8266 remove default opmode check (#835) 2019-11-17 23:31:33 +01:00
42 changed files with 343 additions and 161 deletions

View File

@@ -1,6 +1,6 @@
sudo: false
language: python
python: '3.5'
python: '3.6'
install: script/setup
cache:
directories:
@@ -15,8 +15,8 @@ matrix:
- script/ci-custom.py
- flake8 esphome
- pylint esphome
- python: "3.5"
env: TARGET=Test3.5
- python: "3.6"
env: TARGET=Test3.6
script:
- esphome tests/test1.yaml compile
- esphome tests/test2.yaml compile

View File

@@ -14,7 +14,7 @@ from esphome.const import CONF_BAUD_RATE, CONF_BROKER, CONF_LOGGER, CONF_OTA, \
CONF_PASSWORD, CONF_PORT, CONF_ESPHOME, CONF_PLATFORMIO_OPTIONS
from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority
from esphome.helpers import color, indent
from esphome.py_compat import IS_PY2, safe_input
from esphome.py_compat import IS_PY2, safe_input, IS_PY3
from esphome.util import run_external_command, run_external_process, safe_print, list_yaml_files
_LOGGER = logging.getLogger(__name__)
@@ -165,16 +165,27 @@ def compile_program(args, config):
def upload_using_esptool(config, port):
path = CORE.firmware_bin
cmd = ['esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
'--baud', str(config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get('upload_speed', 460800)),
'--chip', 'esp8266', '--port', port, 'write_flash', '0x0', path]
first_baudrate = config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get('upload_speed', 460800)
if os.environ.get('ESPHOME_USE_SUBPROCESS') is None:
import esptool
# pylint: disable=protected-access
return run_external_command(esptool._main, *cmd)
def run_esptool(baud_rate):
cmd = ['esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
'--baud', str(baud_rate),
'--chip', 'esp8266', '--port', port, 'write_flash', '0x0', path]
return run_external_process(*cmd)
if os.environ.get('ESPHOME_USE_SUBPROCESS') is None:
import esptool
# pylint: disable=protected-access
return run_external_command(esptool._main, *cmd)
return run_external_process(*cmd)
rc = run_esptool(first_baudrate)
if rc == 0 or first_baudrate == 115200:
return rc
# Try with 115200 baud rate, with some serial chips the faster baud rates do not work well
_LOGGER.info("Upload with baud rate %s failed. Trying again with baud rate 115200.",
first_baudrate)
return run_esptool(115200)
def upload_program(config, args, host):
@@ -514,6 +525,10 @@ def run_esphome(argv):
_LOGGER.warning("You're using ESPHome with python 2. Support for python 2 is deprecated "
"and will be removed in 1.15.0. Please reinstall ESPHome with python 3.6 "
"or higher.")
elif IS_PY3 and sys.version_info < (3, 6, 0):
_LOGGER.warning("You're using ESPHome with python 3.5. Support for python 3.5 is "
"deprecated and will be removed in 1.15.0. Please reinstall ESPHome with "
"python 3.6 or higher.")
if args.command in PRE_CONFIG_ACTIONS:
try:

View File

@@ -70,14 +70,14 @@ def to_code(config):
cg.add_global(api_ns.using)
KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string)})
KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string_strict)})
HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema({
cv.GenerateID(): cv.use_id(APIServer),
cv.Required(CONF_SERVICE): cv.templatable(cv.string),
cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA,
cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA,
cv.Optional(CONF_VARIABLES, default={}): KEY_VALUE_SCHEMA,
cv.Optional(CONF_VARIABLES, default={}): cv.Schema({cv.string: cv.returning_lambda}),
})

View File

@@ -216,6 +216,9 @@ message BinarySensorStateResponse {
fixed32 key = 1;
bool state = 2;
// If the binary sensor does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3;
}
// ==================== COVER ====================
@@ -416,6 +419,9 @@ message SensorStateResponse {
fixed32 key = 1;
float state = 2;
// If the sensor does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3;
}
// ==================== SWITCH ====================
@@ -472,6 +478,9 @@ message TextSensorStateResponse {
fixed32 key = 1;
string state = 2;
// If the text sensor does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3;
}
// ==================== SUBSCRIBE LOGS ====================

View File

@@ -163,6 +163,7 @@ bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary
BinarySensorStateResponse resp;
resp.key = binary_sensor->get_object_id_hash();
resp.state = state;
resp.missing_state = !binary_sensor->has_state();
return this->send_binary_sensor_state_response(resp);
}
bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
@@ -362,6 +363,7 @@ bool APIConnection::send_sensor_state(sensor::Sensor *sensor, float state) {
SensorStateResponse resp{};
resp.key = sensor->get_object_id_hash();
resp.state = state;
resp.missing_state = !sensor->has_state();
return this->send_sensor_state_response(resp);
}
bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
@@ -375,6 +377,7 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
msg.icon = sensor->get_icon();
msg.unit_of_measurement = sensor->get_unit_of_measurement();
msg.accuracy_decimals = sensor->get_accuracy_decimals();
msg.force_update = sensor->get_force_update();
return this->send_list_entities_sensor_response(msg);
}
#endif
@@ -419,6 +422,7 @@ bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor,
TextSensorStateResponse resp{};
resp.key = text_sensor->get_object_id_hash();
resp.state = std::move(state);
resp.missing_state = !text_sensor->has_state();
return this->send_text_sensor_state_response(resp);
}
bool APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {

View File

@@ -404,6 +404,10 @@ bool BinarySensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt val
this->state = value.as_bool();
return true;
}
case 3: {
this->missing_state = value.as_bool();
return true;
}
default:
return false;
}
@@ -421,6 +425,7 @@ bool BinarySensorStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value
void BinarySensorStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_bool(2, this->state);
buffer.encode_bool(3, this->missing_state);
}
void BinarySensorStateResponse::dump_to(std::string &out) const {
char buffer[64];
@@ -433,6 +438,10 @@ void BinarySensorStateResponse::dump_to(std::string &out) const {
out.append(" state: ");
out.append(YESNO(this->state));
out.append("\n");
out.append(" missing_state: ");
out.append(YESNO(this->missing_state));
out.append("\n");
out.append("}");
}
bool ListEntitiesCoverResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
@@ -1451,6 +1460,16 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const {
out.append("\n");
out.append("}");
}
bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 3: {
this->missing_state = value.as_bool();
return true;
}
default:
return false;
}
}
bool SensorStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1: {
@@ -1468,6 +1487,7 @@ bool SensorStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
void SensorStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_float(2, this->state);
buffer.encode_bool(3, this->missing_state);
}
void SensorStateResponse::dump_to(std::string &out) const {
char buffer[64];
@@ -1481,6 +1501,10 @@ void SensorStateResponse::dump_to(std::string &out) const {
sprintf(buffer, "%g", this->state);
out.append(buffer);
out.append("\n");
out.append(" missing_state: ");
out.append(YESNO(this->missing_state));
out.append("\n");
out.append("}");
}
bool ListEntitiesSwitchResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
@@ -1700,6 +1724,16 @@ void ListEntitiesTextSensorResponse::dump_to(std::string &out) const {
out.append("\n");
out.append("}");
}
bool TextSensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 3: {
this->missing_state = value.as_bool();
return true;
}
default:
return false;
}
}
bool TextSensorStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
@@ -1723,6 +1757,7 @@ bool TextSensorStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value)
void TextSensorStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_string(2, this->state);
buffer.encode_bool(3, this->missing_state);
}
void TextSensorStateResponse::dump_to(std::string &out) const {
char buffer[64];
@@ -1735,6 +1770,10 @@ void TextSensorStateResponse::dump_to(std::string &out) const {
out.append(" state: ");
out.append("'").append(this->state).append("'");
out.append("\n");
out.append(" missing_state: ");
out.append(YESNO(this->missing_state));
out.append("\n");
out.append("}");
}
bool SubscribeLogsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {

View File

@@ -188,8 +188,9 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage {
};
class BinarySensorStateResponse : public ProtoMessage {
public:
uint32_t key{0}; // NOLINT
bool state{false}; // NOLINT
uint32_t key{0}; // NOLINT
bool state{false}; // NOLINT
bool missing_state{false}; // NOLINT
void encode(ProtoWriteBuffer buffer) const override;
void dump_to(std::string &out) const override;
@@ -380,13 +381,15 @@ class ListEntitiesSensorResponse : public ProtoMessage {
};
class SensorStateResponse : public ProtoMessage {
public:
uint32_t key{0}; // NOLINT
float state{0.0f}; // NOLINT
uint32_t key{0}; // NOLINT
float state{0.0f}; // NOLINT
bool missing_state{false}; // NOLINT
void encode(ProtoWriteBuffer buffer) const override;
void dump_to(std::string &out) const override;
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class ListEntitiesSwitchResponse : public ProtoMessage {
public:
@@ -442,14 +445,16 @@ class ListEntitiesTextSensorResponse : public ProtoMessage {
};
class TextSensorStateResponse : public ProtoMessage {
public:
uint32_t key{0}; // NOLINT
std::string state{}; // NOLINT
uint32_t key{0}; // NOLINT
std::string state{}; // NOLINT
bool missing_state{false}; // NOLINT
void encode(ProtoWriteBuffer buffer) const override;
void dump_to(std::string &out) const override;
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
class SubscribeLogsRequest : public ProtoMessage {
public:

View File

@@ -7,9 +7,6 @@ namespace api {
#ifdef USE_BINARY_SENSOR
bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
if (!binary_sensor->has_state())
return true;
return this->client_->send_binary_sensor_state(binary_sensor, binary_sensor->state);
}
#endif
@@ -24,9 +21,6 @@ bool InitialStateIterator::on_light(light::LightState *light) { return this->cli
#endif
#ifdef USE_SENSOR
bool InitialStateIterator::on_sensor(sensor::Sensor *sensor) {
if (!sensor->has_state())
return true;
return this->client_->send_sensor_state(sensor, sensor->state);
}
#endif
@@ -37,9 +31,6 @@ bool InitialStateIterator::on_switch(switch_::Switch *a_switch) {
#endif
#ifdef USE_TEXT_SENSOR
bool InitialStateIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
if (!text_sensor->has_state())
return true;
return this->client_->send_text_sensor_state(text_sensor, text_sensor->state);
}
#endif

View File

@@ -1,23 +1,13 @@
# Dummy integration to allow relying on AsyncTCP
import esphome.codegen as cg
from esphome.const import ARDUINO_VERSION_ESP32_1_0_0, ARDUINO_VERSION_ESP32_1_0_1, \
ARDUINO_VERSION_ESP32_1_0_2
from esphome.core import CORE, coroutine_with_priority
@coroutine_with_priority(200.0)
def to_code(config):
if CORE.is_esp32:
# https://github.com/me-no-dev/AsyncTCP/blob/master/library.json
versions_requiring_older_asynctcp = [
ARDUINO_VERSION_ESP32_1_0_0,
ARDUINO_VERSION_ESP32_1_0_1,
ARDUINO_VERSION_ESP32_1_0_2,
]
if CORE.arduino_version in versions_requiring_older_asynctcp:
cg.add_library('AsyncTCP', '1.0.3')
else:
cg.add_library('AsyncTCP', '1.1.1')
# https://github.com/OttoWinter/AsyncTCP/blob/master/library.json
cg.add_library('AsyncTCP-esphome', '1.1.1')
elif CORE.is_esp8266:
# https://github.com/OttoWinter/ESPAsyncTCP
cg.add_library('ESPAsyncTCP-esphome', '1.2.2')

View File

@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome.components import sensor, spi
from esphome.const import \
CONF_ID, CONF_VOLTAGE, CONF_CURRENT, CONF_POWER, CONF_FREQUENCY, \
ICON_FLASH, UNIT_HZ, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT
ICON_FLASH, UNIT_VOLT, UNIT_AMPERE, UNIT_WATT, UNIT_HERTZ, ICON_CURRENT_AC
CONF_PHASE_A = 'phase_a'
CONF_PHASE_B = 'phase_b'
@@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_PHASE_A): ATM90E32_PHASE_SCHEMA,
cv.Optional(CONF_PHASE_B): ATM90E32_PHASE_SCHEMA,
cv.Optional(CONF_PHASE_C): ATM90E32_PHASE_SCHEMA,
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(UNIT_HZ, ICON_FLASH, 1),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(UNIT_HERTZ, ICON_CURRENT_AC, 1),
cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True),
cv.Optional(CONF_GAIN_PGA, default='2X'): cv.enum(PGA_GAINS, upper=True),
}).extend(cv.polling_component_schema('60s')).extend(spi.SPI_DEVICE_SCHEMA)

View File

@@ -8,8 +8,10 @@ static const char* TAG = "dfplayer";
void DFPlayer::play_folder(uint16_t folder, uint16_t file) {
if (folder < 100 && file < 256) {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x0F, (uint8_t) folder, (uint8_t) file);
} else if (folder <= 10 && file <= 1000) {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x14, (((uint16_t) folder) << 12) | file);
} else {
ESP_LOGE(TAG, "Cannot play folder %d file %d.", folder, file);
@@ -93,6 +95,10 @@ void DFPlayer::loop() {
ESP_LOGI(TAG, "USB, TF Card available");
}
break;
case 0x40:
ESP_LOGV(TAG, "Nack");
this->ack_set_is_playing_ = false;
this->ack_reset_is_playing_ = false;
case 0x41:
ESP_LOGV(TAG, "Ack ok");
this->is_playing_ |= this->ack_set_is_playing_;

View File

@@ -27,29 +27,56 @@ class DFPlayer : public uart::UARTDevice, public Component {
public:
void loop() override;
void next() { this->send_cmd_(0x01); }
void previous() { this->send_cmd_(0x02); }
void next() {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x01);
}
void previous() {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x02);
}
void play_file(uint16_t file) {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x03, file);
}
void play_file_loop(uint16_t file) { this->send_cmd_(0x08, file); }
void play_file_loop(uint16_t file) {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x08, file);
}
void play_folder(uint16_t folder, uint16_t file);
void play_folder_loop(uint16_t folder) { this->send_cmd_(0x17, folder); }
void play_folder_loop(uint16_t folder) {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x17, folder);
}
void volume_up() { this->send_cmd_(0x04); }
void volume_down() { this->send_cmd_(0x05); }
void set_device(Device device) { this->send_cmd_(0x09, device); }
void set_volume(uint8_t volume) { this->send_cmd_(0x06, volume); }
void set_eq(EqPreset preset) { this->send_cmd_(0x07, preset); }
void sleep() { this->send_cmd_(0x0A); }
void reset() { this->send_cmd_(0x0C); }
void start() { this->send_cmd_(0x0D); }
void sleep() {
this->ack_reset_is_playing_ = true;
this->send_cmd_(0x0A);
}
void reset() {
this->ack_reset_is_playing_ = true;
this->send_cmd_(0x0C);
}
void start() {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x0D);
}
void pause() {
this->ack_reset_is_playing_ = true;
this->send_cmd_(0x0E);
}
void stop() { this->send_cmd_(0x16); }
void random() { this->send_cmd_(0x18); }
void stop() {
this->ack_reset_is_playing_ = true;
this->send_cmd_(0x16);
}
void random() {
this->ack_set_is_playing_ = true;
this->send_cmd_(0x18);
}
bool is_playing() { return is_playing_; }
void dump_config() override;

View File

@@ -47,8 +47,10 @@ void DHT::update() {
if (error) {
ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity);
this->temperature_sensor_->publish_state(temperature);
this->humidity_sensor_->publish_state(humidity);
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(temperature);
if (this->humidity_sensor_ != nullptr)
this->humidity_sensor_->publish_state(humidity);
this->status_clear_warning();
} else {
const char *str = "";
@@ -56,8 +58,10 @@ void DHT::update() {
str = " and consider manually specifying the DHT model using the model option";
}
ESP_LOGW(TAG, "Invalid readings! Please check your wiring (pull-up resistor, pin number)%s.", str);
this->temperature_sensor_->publish_state(NAN);
this->humidity_sensor_->publish_state(NAN);
if (this->temperature_sensor_ != nullptr)
this->temperature_sensor_->publish_state(NAN);
if (this->humidity_sensor_ != nullptr)
this->humidity_sensor_->publish_state(NAN);
this->status_set_warning();
}
}

View File

@@ -37,7 +37,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_SCAN_PARAMETERS, default={}): cv.All(cv.Schema({
cv.Optional(CONF_DURATION, default='5min'): cv.positive_time_period_seconds,
cv.Optional(CONF_INTERVAL, default='320ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_WINDOW, default='200ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_WINDOW, default='30ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_ACTIVE, default=True): cv.boolean,
}), validate_scan_parameters),

View File

@@ -441,8 +441,8 @@ const optional<ESPBTUUID> &ESPBTDevice::get_service_data_uuid() const { return t
void ESP32BLETracker::dump_config() {
ESP_LOGCONFIG(TAG, "BLE Tracker:");
ESP_LOGCONFIG(TAG, " Scan Duration: %u s", this->scan_duration_);
ESP_LOGCONFIG(TAG, " Scan Interval: %u ms", this->scan_interval_);
ESP_LOGCONFIG(TAG, " Scan Window: %u ms", this->scan_window_);
ESP_LOGCONFIG(TAG, " Scan Interval: %.1f ms", this->scan_interval_ * 0.625f);
ESP_LOGCONFIG(TAG, " Scan Window: %.1f ms", this->scan_window_ * 0.625f);
ESP_LOGCONFIG(TAG, " Scan Type: %s", this->scan_active_ ? "ACTIVE" : "PASSIVE");
}
void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) {

View File

@@ -31,6 +31,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_; }
HardwareSerial *get_hw_serial() const { return hw_serial_; }
/// Get the UART used by the logger.
UARTSelection get_uart() const;

View File

@@ -155,7 +155,7 @@ def to_code(config):
yield cg.register_component(var, config)
# https://github.com/OttoWinter/async-mqtt-client/blob/master/library.json
cg.add_library('AsyncMqttClient-esphome', '0.8.3')
cg.add_library('AsyncMqttClient-esphome', '0.8.4')
cg.add_define('USE_MQTT')
cg.add_global(mqtt_ns.using)

View File

@@ -74,7 +74,11 @@ def validate_method_pin(value):
method_pins['BIT_BANG'] = list(range(0, 16))
elif CORE.is_esp32:
method_pins['BIT_BANG'] = list(range(0, 32))
pins_ = method_pins[method]
pins_ = method_pins.get(method)
if pins_ is None:
# all pins allowed for this method
return value
for opt in (CONF_PIN, CONF_CLOCK_PIN, CONF_DATA_PIN):
if opt in value and value[opt] not in pins_:
raise cv.Invalid("Method {} only supports pin(s) {}".format(

View File

@@ -8,7 +8,7 @@ static const char *TAG = "pzem004t";
void PZEM004T::loop() {
const uint32_t now = millis();
if (now - this->last_read_ > 500 && this->available()) {
if (now - this->last_read_ > 500 && this->available() < 7) {
while (this->available())
this->read();
this->last_read_ = now;
@@ -78,7 +78,7 @@ void PZEM004T::loop() {
this->last_read_ = now;
}
}
void PZEM004T::update() { this->write_state_(SET_ADDRESS); }
void PZEM004T::update() { this->write_state_(READ_VOLTAGE); }
void PZEM004T::write_state_(PZEM004T::PZEM004TReadState state) {
if (state == DONE) {
this->read_state_ = state;

View File

@@ -3,7 +3,7 @@ import esphome.config_validation as cv
from esphome.components import sensor, modbus
from esphome.const import CONF_CURRENT, CONF_ID, CONF_POWER, CONF_VOLTAGE, \
CONF_FREQUENCY, UNIT_VOLT, ICON_FLASH, UNIT_AMPERE, UNIT_WATT, UNIT_EMPTY, \
ICON_POWER, CONF_POWER_FACTOR, ICON_CURRENT_AC
ICON_POWER, CONF_POWER_FACTOR, ICON_CURRENT_AC, UNIT_HERTZ
AUTO_LOAD = ['modbus']
@@ -15,7 +15,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(UNIT_VOLT, ICON_FLASH, 1),
cv.Optional(CONF_CURRENT): sensor.sensor_schema(UNIT_AMPERE, ICON_CURRENT_AC, 3),
cv.Optional(CONF_POWER): sensor.sensor_schema(UNIT_WATT, ICON_POWER, 1),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(UNIT_EMPTY, ICON_CURRENT_AC, 1),
cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(UNIT_HERTZ, ICON_CURRENT_AC, 1),
cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema(UNIT_EMPTY, ICON_FLASH, 2),
}).extend(cv.polling_component_schema('60s')).extend(modbus.modbus_device_schema(0x01))

View File

@@ -32,7 +32,13 @@ static const uint16_t STATE_DECREMENT_COUNTER_1 = 0x1000;
// Bit 2&3 (0x0C) encodes state S0-S3
// Bit 4 (0x10) encodes clockwise/counter-clockwise rotation
static const uint16_t STATE_LOOKUP_TABLE[32] = {
// Only apply if DRAM_ATTR exists on this platform (exists on ESP32, not on ESP8266)
#ifndef DRAM_ATTR
#define DRAM_ATTR
#endif
// array needs to be placed in .dram1 for ESP32
// otherwise it will automatically go into flash, and cause cache disabled issues
static const uint16_t DRAM_ATTR STATE_LOOKUP_TABLE[32] = {
// act state S0 in CCW direction
STATE_CCW | STATE_S0, // 0x00: stay here
STATE_CW | STATE_S1 | STATE_INCREMENT_COUNTER_1, // 0x01: goto CW+S1 and increment counter (dir change)

View File

@@ -52,6 +52,14 @@ double Sun::azimuth() {
return NAN;
return this->azimuth_(time);
}
// like clamp, but with doubles
double clampd(double val, double min, double max) {
if (val < min)
return min;
if (val > max)
return max;
return val;
}
double Sun::sun_declination_(double sun_time) {
double n = sun_time - 1.0;
// maximum declination
@@ -67,7 +75,7 @@ double Sun::sun_declination_(double sun_time) {
const double c = TAU / 365.24;
double v = cos(c * days_since_december_solstice + 2 * eccentricity * sin(c * days_since_perihelion));
// Make sure value is in range (double error may lead to results slightly larger than 1)
double x = clamp(tot * v, 0, 1);
double x = clampd(tot * v, -1.0, 1.0);
return asin(x);
}
double Sun::elevation_ratio_(double sun_time) {
@@ -75,7 +83,7 @@ double Sun::elevation_ratio_(double sun_time) {
double hangle = this->hour_angle_(sun_time);
double a = sin(this->latitude_rad_()) * sin(decl);
double b = cos(this->latitude_rad_()) * cos(decl) * cos(hangle);
double val = clamp(a + b, -1.0, 1.0);
double val = clampd(a + b, -1.0, 1.0);
return val;
}
double Sun::latitude_rad_() { return this->latitude_ * TO_RADIANS; }
@@ -92,7 +100,7 @@ double Sun::azimuth_rad_(double sun_time) {
double zen = this->zenith_rad_(sun_time);
double nom = cos(zen) * sin(this->latitude_rad_()) - sin(decl);
double denom = sin(zen) * cos(this->latitude_rad_());
double v = clamp(nom / denom, -1.0, 1.0);
double v = clampd(nom / denom, -1.0, 1.0);
double az = PI - acos(v);
if (hangle > 0)
az = -az;

View File

@@ -16,11 +16,14 @@ RESTORE_MODES = {
'RESTORE_AND_CALL': TemplateCoverRestoreMode.COVER_RESTORE_AND_CALL,
}
CONF_HAS_POSITION = 'has_position'
CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
cv.GenerateID(): cv.declare_id(TemplateCover),
cv.Optional(CONF_LAMBDA): cv.returning_lambda,
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean,
cv.Optional(CONF_HAS_POSITION, default=False): cv.boolean,
cv.Optional(CONF_OPEN_ACTION): automation.validate_automation(single=True),
cv.Optional(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
cv.Optional(CONF_STOP_ACTION): automation.validate_automation(single=True),
@@ -56,6 +59,7 @@ def to_code(config):
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
cg.add(var.set_has_position(config[CONF_HAS_POSITION]))
@automation.register_action('cover.template.publish', cover.CoverPublishAction, cv.Schema({

View File

@@ -8,7 +8,6 @@ namespace tuya {
static const char *TAG = "tuya";
void Tuya::setup() {
this->send_empty_command_(TuyaCommandType::MCU_CONF);
this->set_interval("heartbeat", 1000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
}
@@ -22,8 +21,12 @@ void Tuya::loop() {
void Tuya::dump_config() {
ESP_LOGCONFIG(TAG, "Tuya:");
if ((gpio_status_ != -1) || (gpio_reset_ != -1))
ESP_LOGCONFIG(TAG, " GPIO MCU configuration not supported!");
if (this->init_state_ != TuyaInitState::INIT_DONE) {
ESP_LOGCONFIG(TAG, " Configuration will be reported when setup is complete. Current init_state: %u", // NOLINT
this->init_state_);
ESP_LOGCONFIG(TAG, " If no further output is received, confirm that this is a supported Tuya device.");
return;
}
for (auto &info : this->datapoints_) {
if (info.type == TuyaDatapointType::BOOLEAN)
ESP_LOGCONFIG(TAG, " Datapoint %d: switch (value: %s)", info.id, ONOFF(info.value_bool));
@@ -36,9 +39,11 @@ 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.");
if ((this->gpio_status_ != -1) || (this->gpio_reset_ != -1)) {
ESP_LOGCONFIG(TAG, " GPIO Configuration: status: pin %d, reset: pin %d (not supported)", this->gpio_status_,
this->gpio_reset_);
}
ESP_LOGCONFIG(TAG, " Product: '%s'", this->product_.c_str());
this->check_uart_settings(9600);
}
@@ -89,8 +94,8 @@ bool Tuya::validate_message_() {
// valid message
const uint8_t *message_data = data + 6;
ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s]", command, version,
hexencode(message_data, length).c_str());
ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version, // NOLINT
hexencode(message_data, length).c_str(), this->init_state_);
this->handle_command_(command, version, message_data, length);
// return false to reset rx buffer
@@ -105,41 +110,58 @@ void Tuya::handle_char_(uint8_t c) {
}
void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len) {
uint8_t c;
switch ((TuyaCommandType) command) {
case TuyaCommandType::HEARTBEAT:
ESP_LOGV(TAG, "MCU Heartbeat (0x%02X)", buffer[0]);
if (buffer[0] == 0) {
ESP_LOGI(TAG, "MCU restarted");
this->send_empty_command_(TuyaCommandType::QUERY_STATE);
this->init_state_ = TuyaInitState::INIT_HEARTBEAT;
}
if (this->init_state_ == TuyaInitState::INIT_HEARTBEAT) {
this->init_state_ = TuyaInitState::INIT_PRODUCT;
this->send_empty_command_(TuyaCommandType::PRODUCT_QUERY);
}
break;
case TuyaCommandType::QUERY_PRODUCT: {
// check it is a valid string
bool valid = false;
case TuyaCommandType::PRODUCT_QUERY: {
// check it is a valid string made up of printable characters
bool valid = true;
for (int i = 0; i < len; i++) {
if (buffer[i] == 0x00) {
valid = true;
if (!std::isprint(buffer[i])) {
valid = false;
break;
}
}
if (valid) {
ESP_LOGD(TAG, "Tuya Product Code: %s", reinterpret_cast<const char *>(buffer));
this->product_ = std::string(reinterpret_cast<const char *>(buffer), len);
} else {
this->product_ = R"({"p":"INVALID"})";
}
if (this->init_state_ == TuyaInitState::INIT_PRODUCT) {
this->init_state_ = TuyaInitState::INIT_CONF;
this->send_empty_command_(TuyaCommandType::CONF_QUERY);
}
break;
}
case TuyaCommandType::MCU_CONF:
case TuyaCommandType::CONF_QUERY: {
if (len >= 2) {
gpio_status_ = buffer[0];
gpio_reset_ = buffer[1];
}
// set wifi state LED to off or on depending on the MCU firmware
// but it shouldn't be blinking
c = 0x3;
this->send_command_(TuyaCommandType::WIFI_STATE, &c, 1);
this->send_empty_command_(TuyaCommandType::QUERY_STATE);
if (this->init_state_ == TuyaInitState::INIT_CONF) {
// If we were following the spec to the letter we would send
// state updates until connected to both WiFi and API/MQTT.
// Instead we just claim to be connected immediately and move on.
uint8_t c[] = {0x04};
this->init_state_ = TuyaInitState::INIT_WIFI;
this->send_command_(TuyaCommandType::WIFI_STATE, c, 1);
}
break;
}
case TuyaCommandType::WIFI_STATE:
if (this->init_state_ == TuyaInitState::INIT_WIFI) {
this->init_state_ = TuyaInitState::INIT_DATAPOINT;
this->send_empty_command_(TuyaCommandType::DATAPOINT_QUERY);
}
break;
case TuyaCommandType::WIFI_RESET:
ESP_LOGE(TAG, "TUYA_CMD_WIFI_RESET is not handled");
@@ -147,14 +169,22 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
case TuyaCommandType::WIFI_SELECT:
ESP_LOGE(TAG, "TUYA_CMD_WIFI_SELECT is not handled");
break;
case TuyaCommandType::SET_DATAPOINT:
case TuyaCommandType::DATAPOINT_DELIVER:
break;
case TuyaCommandType::STATE: {
case TuyaCommandType::DATAPOINT_REPORT:
if (this->init_state_ == TuyaInitState::INIT_DATAPOINT) {
this->init_state_ = TuyaInitState::INIT_DONE;
this->set_timeout("datapoint_dump", 1000, [this] { this->dump_config(); });
}
this->handle_datapoint_(buffer, len);
break;
}
case TuyaCommandType::QUERY_STATE:
case TuyaCommandType::DATAPOINT_QUERY:
break;
case TuyaCommandType::WIFI_TEST: {
uint8_t c[] = {0x00, 0x00};
this->send_command_(TuyaCommandType::WIFI_TEST, c, 2);
break;
}
default:
ESP_LOGE(TAG, "invalid command (%02x) received", command);
}
@@ -214,8 +244,6 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) {
}
if (!found) {
this->datapoints_.push_back(datapoint);
// New datapoint found, reprint dump_config after a delay.
this->set_timeout("datapoint_dump", 100, [this] { this->dump_config(); });
}
// Run through listeners
@@ -227,9 +255,12 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) {
void Tuya::send_command_(TuyaCommandType command, const uint8_t *buffer, uint16_t len) {
uint8_t len_hi = len >> 8;
uint8_t len_lo = len >> 0;
this->write_array({0x55, 0xAA,
0x00, // version
(uint8_t) command, len_hi, len_lo});
uint8_t version = 0;
ESP_LOGV(TAG, "Sending Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version, // NOLINT
hexencode(buffer, len).c_str(), this->init_state_);
this->write_array({0x55, 0xAA, version, (uint8_t) command, len_hi, len_lo});
if (len != 0)
this->write_array(buffer, len);
@@ -278,7 +309,7 @@ void Tuya::set_datapoint_value(TuyaDatapoint datapoint) {
buffer.push_back(data.size() >> 8);
buffer.push_back(data.size() >> 0);
buffer.insert(buffer.end(), data.begin(), data.end());
this->send_command_(TuyaCommandType::SET_DATAPOINT, buffer.data(), buffer.size());
this->send_command_(TuyaCommandType::DATAPOINT_DELIVER, buffer.data(), buffer.size());
}
void Tuya::register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func) {

View File

@@ -34,19 +34,29 @@ struct TuyaDatapointListener {
enum class TuyaCommandType : uint8_t {
HEARTBEAT = 0x00,
QUERY_PRODUCT = 0x01,
MCU_CONF = 0x02,
PRODUCT_QUERY = 0x01,
CONF_QUERY = 0x02,
WIFI_STATE = 0x03,
WIFI_RESET = 0x04,
WIFI_SELECT = 0x05,
SET_DATAPOINT = 0x06,
STATE = 0x07,
QUERY_STATE = 0x08,
DATAPOINT_DELIVER = 0x06,
DATAPOINT_REPORT = 0x07,
DATAPOINT_QUERY = 0x08,
WIFI_TEST = 0x0E,
};
enum class TuyaInitState : uint8_t {
INIT_HEARTBEAT = 0x00,
INIT_PRODUCT,
INIT_CONF,
INIT_WIFI,
INIT_DATAPOINT,
INIT_DONE,
};
class Tuya : public Component, public uart::UARTDevice {
public:
float get_setup_priority() const override { return setup_priority::HARDWARE; }
float get_setup_priority() const override { return setup_priority::LATE; }
void setup() override;
void loop() override;
void dump_config() override;
@@ -62,8 +72,10 @@ class Tuya : public Component, public uart::UARTDevice {
void send_command_(TuyaCommandType command, const uint8_t *buffer, uint16_t len);
void send_empty_command_(TuyaCommandType command) { this->send_command_(command, nullptr, 0); }
TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT;
int gpio_status_ = -1;
int gpio_reset_ = -1;
std::string product_ = "";
std::vector<TuyaDatapointListener> listeners_;
std::vector<TuyaDatapoint> datapoints_;
std::vector<uint8_t> rx_message_;

View File

@@ -4,7 +4,7 @@ from esphome import pins
from esphome.components import sensor
from esphome.const import CONF_ID, CONF_WIND_SPEED, CONF_PIN, \
CONF_WIND_DIRECTION_DEGREES, UNIT_KILOMETER_PER_HOUR, \
UNIT_EMPTY, ICON_WEATHER_WINDY, ICON_SIGN_DIRECTION
ICON_WEATHER_WINDY, ICON_SIGN_DIRECTION, UNIT_DEGREES
tx20_ns = cg.esphome_ns.namespace('tx20')
Tx20Component = tx20_ns.class_('Tx20Component', cg.Component)
@@ -14,7 +14,7 @@ CONFIG_SCHEMA = cv.Schema({
cv.Optional(CONF_WIND_SPEED):
sensor.sensor_schema(UNIT_KILOMETER_PER_HOUR, ICON_WEATHER_WINDY, 1),
cv.Optional(CONF_WIND_DIRECTION_DEGREES):
sensor.sensor_schema(UNIT_EMPTY, ICON_SIGN_DIRECTION, 1),
sensor.sensor_schema(UNIT_DEGREES, ICON_SIGN_DIRECTION, 1),
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
pins.validate_has_interrupt),
}).extend(cv.COMPONENT_SCHEMA)

View File

@@ -46,12 +46,7 @@ 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
this->check_logger_conflict_();
}
void UARTComponent::write_byte(uint8_t data) {
@@ -156,13 +151,7 @@ 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
this->check_logger_conflict_();
}
void UARTComponent::write_byte(uint8_t data) {
@@ -378,6 +367,19 @@ int UARTComponent::peek() {
return data;
}
void UARTComponent::check_logger_conflict_() {
#ifdef USE_LOGGER
if (this->hw_serial_ == nullptr || logger::global_logger->get_baud_rate() == 0) {
return;
}
if (this->hw_serial_ == logger::global_logger->get_hw_serial()) {
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 UARTDevice::check_uart_settings(uint32_t baud_rate, uint8_t stop_bits) {
if (this->parent_->baud_rate_ != baud_rate) {
ESP_LOGE(TAG, " Invalid baud_rate: Integration requested baud_rate %u but you have %u!", baud_rate,

View File

@@ -76,6 +76,7 @@ class UARTComponent : public Component, public Stream {
void set_stop_bits(uint8_t stop_bits) { this->stop_bits_ = stop_bits; }
protected:
void check_logger_conflict_();
bool check_read_timeout_(size_t len = 1);
friend class UARTDevice;

View File

@@ -18,6 +18,8 @@ namespace web_server {
static const char *TAG = "web_server";
void write_row(AsyncResponseStream *stream, Nameable *obj, const std::string &klass, const std::string &action) {
if (obj->is_internal())
return;
stream->print("<tr class=\"");
stream->print(klass.c_str());
stream->print("\" id=\"");
@@ -135,41 +137,37 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
stream->print(F("\"></head><body><article class=\"markdown-body\"><h1>"));
stream->print(title.c_str());
stream->print(F("</h1><h2>States</h2><table id=\"states\"><thead><tr><th>Name<th>State<th>Actions<tbody>"));
// All content is controlled and created by user - so allowing all origins is fine here.
stream->addHeader("Access-Control-Allow-Origin", "*");
#ifdef USE_SENSOR
for (auto *obj : App.get_sensors())
if (!obj->is_internal())
write_row(stream, obj, "sensor", "");
write_row(stream, obj, "sensor", "");
#endif
#ifdef USE_SWITCH
for (auto *obj : App.get_switches())
if (!obj->is_internal())
write_row(stream, obj, "switch", "<button>Toggle</button>");
write_row(stream, obj, "switch", "<button>Toggle</button>");
#endif
#ifdef USE_BINARY_SENSOR
for (auto *obj : App.get_binary_sensors())
if (!obj->is_internal())
write_row(stream, obj, "binary_sensor", "");
write_row(stream, obj, "binary_sensor", "");
#endif
#ifdef USE_FAN
for (auto *obj : App.get_fans())
if (!obj->is_internal())
write_row(stream, obj, "fan", "<button>Toggle</button>");
write_row(stream, obj, "fan", "<button>Toggle</button>");
#endif
#ifdef USE_LIGHT
for (auto *obj : App.get_lights())
if (!obj->is_internal())
write_row(stream, obj, "light", "<button>Toggle</button>");
write_row(stream, obj, "light", "<button>Toggle</button>");
#endif
#ifdef USE_TEXT_SENSOR
for (auto *obj : App.get_text_sensors())
if (!obj->is_internal())
write_row(stream, obj, "text_sensor", "");
write_row(stream, obj, "text_sensor", "");
#endif
stream->print(F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/index.html\">ESPHome Web API</a> for "

View File

@@ -23,4 +23,4 @@ def to_code(config):
if CORE.is_esp32:
cg.add_library('FS', None)
# https://github.com/OttoWinter/ESPAsyncWebServer/blob/master/library.json
cg.add_library('ESPAsyncWebServer-esphome', '1.2.5')
cg.add_library('ESPAsyncWebServer-esphome', '1.2.6')

View File

@@ -110,6 +110,7 @@ def validate(config):
return config
CONF_OUTPUT_POWER = 'output_power'
CONFIG_SCHEMA = cv.All(cv.Schema({
cv.GenerateID(): cv.declare_id(WiFiComponent),
cv.Optional(CONF_NETWORKS): cv.ensure_list(WIFI_NETWORK_STA),
@@ -125,6 +126,8 @@ CONFIG_SCHEMA = cv.All(cv.Schema({
cv.enum(WIFI_POWER_SAVE_MODES, upper=True),
cv.Optional(CONF_FAST_CONNECT, default=False): cv.boolean,
cv.Optional(CONF_USE_ADDRESS): cv.string_strict,
cv.SplitDefault(CONF_OUTPUT_POWER, esp8266=20.0): cv.All(
cv.decibel, cv.float_range(min=10.0, max=20.5)),
cv.Optional('hostname'): cv.invalid("The hostname option has been removed in 1.11.0"),
}), validate)
@@ -179,12 +182,15 @@ def to_code(config):
if CONF_AP in config:
conf = config[CONF_AP]
cg.add(var.set_ap(wifi_network(conf, config.get(CONF_MANUAL_IP))))
ip_config = conf.get(CONF_MANUAL_IP, config.get(CONF_MANUAL_IP))
cg.add(var.set_ap(wifi_network(conf, ip_config)))
cg.add(var.set_ap_timeout(conf[CONF_AP_TIMEOUT]))
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
cg.add(var.set_power_save_mode(config[CONF_POWER_SAVE_MODE]))
cg.add(var.set_fast_connect(config[CONF_FAST_CONNECT]))
if CONF_OUTPUT_POWER in config:
cg.add(var.set_output_power(config[CONF_OUTPUT_POWER]))
if CORE.is_esp8266:
cg.add_library('ESP8266WiFi', None)

View File

@@ -36,6 +36,9 @@ void WiFiComponent::setup() {
if (this->has_sta()) {
this->wifi_sta_pre_setup_();
if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) {
ESP_LOGV(TAG, "Setting Power Save Option failed!");
}
if (!this->wifi_apply_power_save_()) {
ESP_LOGV(TAG, "Setting Power Save Option failed!");
@@ -49,6 +52,9 @@ void WiFiComponent::setup() {
}
} else if (this->has_ap()) {
this->setup_ap_config_();
if (this->output_power_.has_value() && !this->wifi_apply_output_power_(*this->output_power_)) {
ESP_LOGV(TAG, "Setting Power Save Option failed!");
}
#ifdef USE_CAPTIVE_PORTAL
if (captive_portal::global_captive_portal != nullptr)
captive_portal::global_captive_portal->start();

View File

@@ -162,6 +162,7 @@ class WiFiComponent : public Component {
bool is_connected();
void set_power_save_mode(WiFiPowerSaveMode power_save);
void set_output_power(float output_power) { output_power_ = output_power; }
// ========== INTERNAL METHODS ==========
// (In most use cases you won't need these)
@@ -217,6 +218,7 @@ class WiFiComponent : public Component {
bool wifi_mode_(optional<bool> sta, optional<bool> ap);
bool wifi_sta_pre_setup_();
bool wifi_apply_output_power_(float output_power);
bool wifi_apply_power_save_();
bool wifi_sta_ip_config_(optional<ManualIP> manual_ip);
IPAddress wifi_sta_ip_();
@@ -260,6 +262,7 @@ class WiFiComponent : public Component {
std::vector<WiFiScanResult> scan_result_;
bool scan_done_{false};
bool ap_setup_{false};
optional<float> output_power_;
};
extern WiFiComponent *global_wifi_component;

View File

@@ -53,6 +53,10 @@ bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
return ret;
}
bool WiFiComponent::wifi_apply_output_power_(float output_power) {
int8_t val = static_cast<uint8_t>(output_power * 4);
return esp_wifi_set_max_tx_power(val) == ESP_OK;
}
bool WiFiComponent::wifi_sta_pre_setup_() {
if (!this->wifi_mode_(true, {}))
return false;
@@ -325,8 +329,12 @@ void WiFiComponent::wifi_event_callback_(system_event_id_t event, system_event_i
char buf[33];
memcpy(buf, it.ssid, it.ssid_len);
buf[it.ssid_len] = '\0';
ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason=%s", buf,
format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
if (it.reason == WIFI_REASON_NO_AP_FOUND) {
ESP_LOGW(TAG, "Event: Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
} else {
ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf,
format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
}
break;
}
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: {

View File

@@ -330,8 +330,12 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
char buf[33];
memcpy(buf, it.ssid, it.ssid_len);
buf[it.ssid_len] = '\0';
ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=%s reason='%s'", buf, format_mac_addr(it.bssid).c_str(),
get_disconnect_reason_str(it.reason));
if (it.reason == REASON_NO_AP_FOUND) {
ESP_LOGW(TAG, "Event: Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
} else {
ESP_LOGW(TAG, "Event: Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf,
format_mac_addr(it.bssid).c_str(), get_disconnect_reason_str(it.reason));
}
break;
}
case EVENT_STAMODE_AUTHMODE_CHANGE: {
@@ -390,6 +394,11 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
WiFiMockClass::_event_callback(event);
}
bool WiFiComponent::wifi_apply_output_power_(float output_power) {
uint8_t val = static_cast<uint8_t>(output_power * 4);
system_phy_set_max_tpw(val);
return true;
}
bool WiFiComponent::wifi_sta_pre_setup_() {
if (!this->wifi_mode_(true, {}))
return false;
@@ -410,19 +419,6 @@ bool WiFiComponent::wifi_sta_pre_setup_() {
void WiFiComponent::wifi_pre_setup_() {
wifi_set_event_handler_cb(&WiFiComponent::wifi_event_callback);
// Make sure the default opmode is OFF
uint8_t default_opmode = wifi_get_opmode_default();
if (default_opmode != 0) {
ESP_LOGV(TAG, "Setting default WiFi Mode to 0 (was %u)", default_opmode);
ETS_UART_INTR_DISABLE();
bool ret = wifi_set_opmode(0);
ETS_UART_INTR_ENABLE();
if (!ret) {
ESP_LOGW(TAG, "Setting default WiFi mode failed!");
}
}
// Make sure WiFi is in clean state before anything starts
this->wifi_mode_(false, false);
@@ -579,7 +575,7 @@ bool WiFiComponent::wifi_start_ap_(const WiFiAP &ap) {
strcpy(reinterpret_cast<char *>(conf.ssid), ap.get_ssid().c_str());
conf.ssid_len = static_cast<uint8>(ap.get_ssid().size());
conf.channel = ap.get_channel().value_or(1);
conf.ssid_hidden = 0;
conf.ssid_hidden = ap.get_hidden();
conf.max_connection = 5;
conf.beacon_interval = 100;

View File

@@ -616,6 +616,7 @@ angle = float_with_unit("angle", u"(°|deg)", optional_unit=True)
_temperature_c = float_with_unit("temperature", u"(°C|° C|°|C)?")
_temperature_k = float_with_unit("temperature", u"(° K|° K|K)?")
_temperature_f = float_with_unit("temperature", u"(°F|° F|F)?")
decibel = float_with_unit("decibel", u"(dB|dBm|db|dbm)", optional_unit=True)
if IS_PY2:
# Override voluptuous invalid to unicode for py2

View File

@@ -3,7 +3,7 @@
MAJOR_VERSION = 1
MINOR_VERSION = 14
PATCH_VERSION = '2'
PATCH_VERSION = '3'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
@@ -520,7 +520,7 @@ UNIT_DEGREE_PER_SECOND = u'°/s'
UNIT_DEGREES = u'°'
UNIT_EMPTY = ''
UNIT_HECTOPASCAL = 'hPa'
UNIT_HZ = 'hz'
UNIT_HERTZ = 'hz'
UNIT_KELVIN = 'K'
UNIT_KILOMETER = 'km'
UNIT_KILOMETER_PER_HOUR = 'km/h'
@@ -538,6 +538,8 @@ UNIT_PULSES_PER_MINUTE = 'pulses/min'
UNIT_SECOND = 's'
UNIT_STEPS = 'steps'
UNIT_VOLT = 'V'
UNIT_VOLT_AMPS = 'VA'
UNIT_VOLT_AMPS_REACTIVE = 'VAR'
UNIT_WATT = 'W'
DEVICE_CLASS_CONNECTIVITY = 'connectivity'

View File

@@ -211,6 +211,7 @@ uint32_t Scheduler::millis_() {
ESP_LOGD(TAG, "Incrementing scheduler major");
this->millis_major_++;
}
this->last_millis_ = now;
return now;
}

View File

@@ -67,7 +67,7 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
tls_version=tls_version, ciphers=None)
try:
client.connect(config[CONF_MQTT][CONF_BROKER], config[CONF_MQTT][CONF_PORT])
client.connect(str(config[CONF_MQTT][CONF_BROKER]), config[CONF_MQTT][CONF_PORT])
except socket.error as err:
raise EsphomeError("Cannot connect to MQTT broker: {}".format(err))
@@ -127,7 +127,7 @@ def clear_topic(config, topic, username=None, password=None, client_id=None):
# From marvinroger/async-mqtt-client -> scripts/get-fingerprint/get-fingerprint.py
def get_fingerprint(config):
addr = config[CONF_MQTT][CONF_BROKER], config[CONF_MQTT][CONF_PORT]
addr = str(config[CONF_MQTT][CONF_BROKER]), config[CONF_MQTT][CONF_PORT]
_LOGGER.info("Getting fingerprint from %s:%s", addr[0], addr[1])
try:
cert_pem = ssl.get_server_certificate(addr)

View File

@@ -184,6 +184,7 @@ def run_external_command(func, *cmd, **kwargs):
except Exception as err: # pylint: disable=broad-except
_LOGGER.error(u"Running command failed: %s", err)
_LOGGER.error(u"Please try running %s locally.", full_cmd)
return 1
finally:
sys.argv = orig_argv
sys.exit = orig_exit
@@ -216,6 +217,7 @@ def run_external_process(*cmd, **kwargs):
except Exception as err: # pylint: disable=broad-except
_LOGGER.error(u"Running command failed: %s", err)
_LOGGER.error(u"Please try running %s locally.", full_cmd)
return 1
finally:
if capture_stdout:
# pylint: disable=lost-exception

View File

@@ -10,10 +10,10 @@ include_dir = include
[common]
lib_deps =
AsyncTCP@1.1.1
AsyncMqttClient-esphome@0.8.3
AsyncTCP-esphome@1.1.1
AsyncMqttClient-esphome@0.8.4
ArduinoJson-esphomelib@5.13.3
ESPAsyncWebServer-esphome@1.2.5
ESPAsyncWebServer-esphome@1.2.6
FastLED@3.2.9
NeoPixelBus-esphome@2.5.2
ESPAsyncTCP-esphome@1.2.2

View File

@@ -28,7 +28,7 @@ REQUIRES = [
'paho-mqtt==1.4.0',
'colorlog==4.0.2',
'tornado==5.1.1',
'typing>=3.6.6;python_version<"3.5"',
'typing>=3.6.6;python_version<"3.6"',
'protobuf==3.10.0',
'tzlocal==2.0.0',
'pytz==2019.3',