mirror of
https://github.com/esphome/esphome.git
synced 2025-11-12 12:55:46 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53c231a7eb | ||
|
|
d44ce82aa1 | ||
|
|
a055de48e4 | ||
|
|
37b8d665fe | ||
|
|
dd7c8dabb1 | ||
|
|
e41a9875e3 | ||
|
|
c5c42c4338 | ||
|
|
531428b8b0 | ||
|
|
ea8068e001 | ||
|
|
7842a55c81 | ||
|
|
51d39862b1 | ||
|
|
bfea6ca79b | ||
|
|
6297395018 | ||
|
|
a5b49dbfa6 | ||
|
|
7c0d777173 | ||
|
|
74878276fc | ||
|
|
226e3b1dad | ||
|
|
7752794fc5 | ||
|
|
b3094d6a53 | ||
|
|
e3640e710f | ||
|
|
2ef64b55c5 | ||
|
|
7f6672bb37 | ||
|
|
68a3b31628 | ||
|
|
1b35855e68 | ||
|
|
1e1837000d | ||
|
|
e2d5257632 | ||
|
|
387c75793b | ||
|
|
4f3a74d08a |
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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}),
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -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 ====================
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -211,6 +211,7 @@ uint32_t Scheduler::millis_() {
|
||||
ESP_LOGD(TAG, "Incrementing scheduler major");
|
||||
this->millis_major_++;
|
||||
}
|
||||
this->last_millis_ = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user