mirror of
https://github.com/esphome/esphome.git
synced 2025-11-02 08:01:50 +00:00
Compare commits
119 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 | ||
|
|
fdbc59a159 | ||
|
|
0db37bb55c | ||
|
|
2ff2750628 | ||
|
|
eae5c17b87 | ||
|
|
a59cde91ad | ||
|
|
1f243ae37e | ||
|
|
603f82977e | ||
|
|
2d70422a6f | ||
|
|
e2c8b21195 | ||
|
|
7adaeacd0b | ||
|
|
3aaa92fdff | ||
|
|
5efd076c08 | ||
|
|
5f535e9756 | ||
|
|
70faeb2fa8 | ||
|
|
469c0db981 | ||
|
|
440e428aa4 | ||
|
|
dde70c95a4 | ||
|
|
09d1846261 | ||
|
|
34d26a517d | ||
|
|
d24b88271c | ||
|
|
f22115792a | ||
|
|
82a30558e1 | ||
|
|
847fe5adca | ||
|
|
775b51c6a1 | ||
|
|
e0ad5a9009 | ||
|
|
1bf01a9081 | ||
|
|
6ae59bb43d | ||
|
|
1ca241615d | ||
|
|
b8aa84002a | ||
|
|
10cc0b1d5b | ||
|
|
11d9c203c1 | ||
|
|
c9ab454c3c | ||
|
|
4a55692885 | ||
|
|
88c129e705 | ||
|
|
80b48f01fb | ||
|
|
642bc91a76 | ||
|
|
d69926ee56 | ||
|
|
4758403d44 | ||
|
|
4b0ec5c28a | ||
|
|
4b2a9e5e49 | ||
|
|
1449c51d49 | ||
|
|
a451705e0b | ||
|
|
2e6db39173 | ||
|
|
373f75253c | ||
|
|
724842084e | ||
|
|
8f3635b167 | ||
|
|
11605a36f7 | ||
|
|
533f81d625 | ||
|
|
aacb9e44e8 | ||
|
|
c6e3f1bca6 | ||
|
|
a933d4aeb6 | ||
|
|
caa5b20791 | ||
|
|
e2ad9ed746 | ||
|
|
32c0e7c2ae | ||
|
|
6c564c7b7f | ||
|
|
c81e3a3be4 | ||
|
|
6b1b9ef7ec | ||
|
|
c26a8b8718 | ||
|
|
4a89a475bd | ||
|
|
8cf15c7f5c | ||
|
|
adc76ca1b8 | ||
|
|
8f8892440c | ||
|
|
570843150d | ||
|
|
f3fc9e4142 | ||
|
|
075fcb77a8 | ||
|
|
e5899ff717 | ||
|
|
2fb3970027 | ||
|
|
1a4efa1b8c | ||
|
|
72f656ffef | ||
|
|
b60239d5e5 | ||
|
|
d02e280c3c | ||
|
|
6535b0966e | ||
|
|
82dbacbee5 | ||
|
|
2432901974 | ||
|
|
ebb5d58c14 | ||
|
|
605e365405 | ||
|
|
5ab995d8ca | ||
|
|
4248741b11 | ||
|
|
4b8ecc7634 | ||
|
|
25d04c759c | ||
|
|
b4ec84030e | ||
|
|
29e8761373 | ||
|
|
a04299c59e | ||
|
|
d7bf3c51d9 | ||
|
|
ac0b095941 | ||
|
|
cda9bad233 | ||
|
|
41db8a1264 | ||
|
|
e7e785fd60 | ||
|
|
300d3a1f46 | ||
|
|
356554c08d | ||
|
|
ced28ad006 |
@@ -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):
|
||||
@@ -364,14 +375,15 @@ def command_update_all(args):
|
||||
def print_bar(middle_text):
|
||||
middle_text = " {} ".format(middle_text)
|
||||
width = len(click.unstyle(middle_text))
|
||||
half_line = "=" * ((twidth - width) / 2)
|
||||
half_line = "=" * ((twidth - width) // 2)
|
||||
click.echo("%s%s%s" % (half_line, middle_text, half_line))
|
||||
|
||||
for f in files:
|
||||
print("Updating {}".format(color('cyan', f)))
|
||||
print('-' * twidth)
|
||||
print()
|
||||
rc = run_external_process('esphome', '--dashboard', f, 'run', '--no-logs')
|
||||
rc = run_external_process('esphome', '--dashboard', f, 'run', '--no-logs', '--upload-port',
|
||||
'OTA')
|
||||
if rc == 0:
|
||||
print_bar("[{}] {}".format(color('bold_green', 'SUCCESS'), f))
|
||||
success[f] = True
|
||||
@@ -513,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) {
|
||||
@@ -185,11 +186,12 @@ bool APIConnection::send_cover_state(cover::Cover *cover) {
|
||||
auto traits = cover->get_traits();
|
||||
CoverStateResponse resp{};
|
||||
resp.key = cover->get_object_id_hash();
|
||||
resp.legacy_state = (cover->position == cover::COVER_OPEN) ? LEGACY_COVER_STATE_OPEN : LEGACY_COVER_STATE_CLOSED;
|
||||
resp.legacy_state =
|
||||
(cover->position == cover::COVER_OPEN) ? enums::LEGACY_COVER_STATE_OPEN : enums::LEGACY_COVER_STATE_CLOSED;
|
||||
resp.position = cover->position;
|
||||
if (traits.get_supports_tilt())
|
||||
resp.tilt = cover->tilt;
|
||||
resp.current_operation = static_cast<EnumCoverOperation>(cover->current_operation);
|
||||
resp.current_operation = static_cast<enums::CoverOperation>(cover->current_operation);
|
||||
return this->send_cover_state_response(resp);
|
||||
}
|
||||
bool APIConnection::send_cover_info(cover::Cover *cover) {
|
||||
@@ -213,13 +215,13 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
|
||||
auto call = cover->make_call();
|
||||
if (msg.has_legacy_command) {
|
||||
switch (msg.legacy_command) {
|
||||
case LEGACY_COVER_COMMAND_OPEN:
|
||||
case enums::LEGACY_COVER_COMMAND_OPEN:
|
||||
call.set_command_open();
|
||||
break;
|
||||
case LEGACY_COVER_COMMAND_CLOSE:
|
||||
case enums::LEGACY_COVER_COMMAND_CLOSE:
|
||||
call.set_command_close();
|
||||
break;
|
||||
case LEGACY_COVER_COMMAND_STOP:
|
||||
case enums::LEGACY_COVER_COMMAND_STOP:
|
||||
call.set_command_stop();
|
||||
break;
|
||||
}
|
||||
@@ -246,7 +248,7 @@ bool APIConnection::send_fan_state(fan::FanState *fan) {
|
||||
if (traits.supports_oscillation())
|
||||
resp.oscillating = fan->oscillating;
|
||||
if (traits.supports_speed())
|
||||
resp.speed = static_cast<EnumFanSpeed>(fan->speed);
|
||||
resp.speed = static_cast<enums::FanSpeed>(fan->speed);
|
||||
return this->send_fan_state_response(resp);
|
||||
}
|
||||
bool APIConnection::send_fan_info(fan::FanState *fan) {
|
||||
@@ -361,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) {
|
||||
@@ -374,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
|
||||
@@ -418,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) {
|
||||
@@ -441,8 +446,8 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
|
||||
auto traits = climate->get_traits();
|
||||
ClimateStateResponse resp{};
|
||||
resp.key = climate->get_object_id_hash();
|
||||
resp.mode = static_cast<EnumClimateMode>(climate->mode);
|
||||
resp.action = static_cast<EnumClimateAction>(climate->action);
|
||||
resp.mode = static_cast<enums::ClimateMode>(climate->mode);
|
||||
resp.action = static_cast<enums::ClimateAction>(climate->action);
|
||||
if (traits.get_supports_current_temperature())
|
||||
resp.current_temperature = climate->current_temperature;
|
||||
if (traits.get_supports_two_point_target_temperature()) {
|
||||
@@ -467,7 +472,7 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
||||
for (auto mode : {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL,
|
||||
climate::CLIMATE_MODE_HEAT}) {
|
||||
if (traits.supports_mode(mode))
|
||||
msg.supported_modes.push_back(static_cast<EnumClimateMode>(mode));
|
||||
msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
|
||||
}
|
||||
msg.visual_min_temperature = traits.get_visual_min_temperature();
|
||||
msg.visual_max_temperature = traits.get_visual_max_temperature();
|
||||
|
||||
@@ -4,115 +4,115 @@
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
template<> const char *proto_enum_to_string<EnumLegacyCoverState>(EnumLegacyCoverState value) {
|
||||
template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::LegacyCoverState value) {
|
||||
switch (value) {
|
||||
case LEGACY_COVER_STATE_OPEN:
|
||||
case enums::LEGACY_COVER_STATE_OPEN:
|
||||
return "LEGACY_COVER_STATE_OPEN";
|
||||
case LEGACY_COVER_STATE_CLOSED:
|
||||
case enums::LEGACY_COVER_STATE_CLOSED:
|
||||
return "LEGACY_COVER_STATE_CLOSED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumCoverOperation>(EnumCoverOperation value) {
|
||||
template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverOperation value) {
|
||||
switch (value) {
|
||||
case COVER_OPERATION_IDLE:
|
||||
case enums::COVER_OPERATION_IDLE:
|
||||
return "COVER_OPERATION_IDLE";
|
||||
case COVER_OPERATION_IS_OPENING:
|
||||
case enums::COVER_OPERATION_IS_OPENING:
|
||||
return "COVER_OPERATION_IS_OPENING";
|
||||
case COVER_OPERATION_IS_CLOSING:
|
||||
case enums::COVER_OPERATION_IS_CLOSING:
|
||||
return "COVER_OPERATION_IS_CLOSING";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumLegacyCoverCommand>(EnumLegacyCoverCommand value) {
|
||||
template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::LegacyCoverCommand value) {
|
||||
switch (value) {
|
||||
case LEGACY_COVER_COMMAND_OPEN:
|
||||
case enums::LEGACY_COVER_COMMAND_OPEN:
|
||||
return "LEGACY_COVER_COMMAND_OPEN";
|
||||
case LEGACY_COVER_COMMAND_CLOSE:
|
||||
case enums::LEGACY_COVER_COMMAND_CLOSE:
|
||||
return "LEGACY_COVER_COMMAND_CLOSE";
|
||||
case LEGACY_COVER_COMMAND_STOP:
|
||||
case enums::LEGACY_COVER_COMMAND_STOP:
|
||||
return "LEGACY_COVER_COMMAND_STOP";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumFanSpeed>(EnumFanSpeed value) {
|
||||
template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed value) {
|
||||
switch (value) {
|
||||
case FAN_SPEED_LOW:
|
||||
case enums::FAN_SPEED_LOW:
|
||||
return "FAN_SPEED_LOW";
|
||||
case FAN_SPEED_MEDIUM:
|
||||
case enums::FAN_SPEED_MEDIUM:
|
||||
return "FAN_SPEED_MEDIUM";
|
||||
case FAN_SPEED_HIGH:
|
||||
case enums::FAN_SPEED_HIGH:
|
||||
return "FAN_SPEED_HIGH";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumLogLevel>(EnumLogLevel value) {
|
||||
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
|
||||
switch (value) {
|
||||
case LOG_LEVEL_NONE:
|
||||
case enums::LOG_LEVEL_NONE:
|
||||
return "LOG_LEVEL_NONE";
|
||||
case LOG_LEVEL_ERROR:
|
||||
case enums::LOG_LEVEL_ERROR:
|
||||
return "LOG_LEVEL_ERROR";
|
||||
case LOG_LEVEL_WARN:
|
||||
case enums::LOG_LEVEL_WARN:
|
||||
return "LOG_LEVEL_WARN";
|
||||
case LOG_LEVEL_INFO:
|
||||
case enums::LOG_LEVEL_INFO:
|
||||
return "LOG_LEVEL_INFO";
|
||||
case LOG_LEVEL_DEBUG:
|
||||
case enums::LOG_LEVEL_DEBUG:
|
||||
return "LOG_LEVEL_DEBUG";
|
||||
case LOG_LEVEL_VERBOSE:
|
||||
case enums::LOG_LEVEL_VERBOSE:
|
||||
return "LOG_LEVEL_VERBOSE";
|
||||
case LOG_LEVEL_VERY_VERBOSE:
|
||||
case enums::LOG_LEVEL_VERY_VERBOSE:
|
||||
return "LOG_LEVEL_VERY_VERBOSE";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumServiceArgType>(EnumServiceArgType value) {
|
||||
template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) {
|
||||
switch (value) {
|
||||
case SERVICE_ARG_TYPE_BOOL:
|
||||
case enums::SERVICE_ARG_TYPE_BOOL:
|
||||
return "SERVICE_ARG_TYPE_BOOL";
|
||||
case SERVICE_ARG_TYPE_INT:
|
||||
case enums::SERVICE_ARG_TYPE_INT:
|
||||
return "SERVICE_ARG_TYPE_INT";
|
||||
case SERVICE_ARG_TYPE_FLOAT:
|
||||
case enums::SERVICE_ARG_TYPE_FLOAT:
|
||||
return "SERVICE_ARG_TYPE_FLOAT";
|
||||
case SERVICE_ARG_TYPE_STRING:
|
||||
case enums::SERVICE_ARG_TYPE_STRING:
|
||||
return "SERVICE_ARG_TYPE_STRING";
|
||||
case SERVICE_ARG_TYPE_BOOL_ARRAY:
|
||||
case enums::SERVICE_ARG_TYPE_BOOL_ARRAY:
|
||||
return "SERVICE_ARG_TYPE_BOOL_ARRAY";
|
||||
case SERVICE_ARG_TYPE_INT_ARRAY:
|
||||
case enums::SERVICE_ARG_TYPE_INT_ARRAY:
|
||||
return "SERVICE_ARG_TYPE_INT_ARRAY";
|
||||
case SERVICE_ARG_TYPE_FLOAT_ARRAY:
|
||||
case enums::SERVICE_ARG_TYPE_FLOAT_ARRAY:
|
||||
return "SERVICE_ARG_TYPE_FLOAT_ARRAY";
|
||||
case SERVICE_ARG_TYPE_STRING_ARRAY:
|
||||
case enums::SERVICE_ARG_TYPE_STRING_ARRAY:
|
||||
return "SERVICE_ARG_TYPE_STRING_ARRAY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumClimateMode>(EnumClimateMode value) {
|
||||
template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) {
|
||||
switch (value) {
|
||||
case CLIMATE_MODE_OFF:
|
||||
case enums::CLIMATE_MODE_OFF:
|
||||
return "CLIMATE_MODE_OFF";
|
||||
case CLIMATE_MODE_AUTO:
|
||||
case enums::CLIMATE_MODE_AUTO:
|
||||
return "CLIMATE_MODE_AUTO";
|
||||
case CLIMATE_MODE_COOL:
|
||||
case enums::CLIMATE_MODE_COOL:
|
||||
return "CLIMATE_MODE_COOL";
|
||||
case CLIMATE_MODE_HEAT:
|
||||
case enums::CLIMATE_MODE_HEAT:
|
||||
return "CLIMATE_MODE_HEAT";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<EnumClimateAction>(EnumClimateAction value) {
|
||||
template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::ClimateAction value) {
|
||||
switch (value) {
|
||||
case CLIMATE_ACTION_OFF:
|
||||
case enums::CLIMATE_ACTION_OFF:
|
||||
return "CLIMATE_ACTION_OFF";
|
||||
case CLIMATE_ACTION_COOLING:
|
||||
case enums::CLIMATE_ACTION_COOLING:
|
||||
return "CLIMATE_ACTION_COOLING";
|
||||
case CLIMATE_ACTION_HEATING:
|
||||
case enums::CLIMATE_ACTION_HEATING:
|
||||
return "CLIMATE_ACTION_HEATING";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
@@ -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) {
|
||||
@@ -535,11 +544,11 @@ void ListEntitiesCoverResponse::dump_to(std::string &out) const {
|
||||
bool CoverStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 2: {
|
||||
this->legacy_state = value.as_enum<EnumLegacyCoverState>();
|
||||
this->legacy_state = value.as_enum<enums::LegacyCoverState>();
|
||||
return true;
|
||||
}
|
||||
case 5: {
|
||||
this->current_operation = value.as_enum<EnumCoverOperation>();
|
||||
this->current_operation = value.as_enum<enums::CoverOperation>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
@@ -566,10 +575,10 @@ bool CoverStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
}
|
||||
void CoverStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.encode_enum<EnumLegacyCoverState>(2, this->legacy_state);
|
||||
buffer.encode_enum<enums::LegacyCoverState>(2, this->legacy_state);
|
||||
buffer.encode_float(3, this->position);
|
||||
buffer.encode_float(4, this->tilt);
|
||||
buffer.encode_enum<EnumCoverOperation>(5, this->current_operation);
|
||||
buffer.encode_enum<enums::CoverOperation>(5, this->current_operation);
|
||||
}
|
||||
void CoverStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@@ -580,7 +589,7 @@ void CoverStateResponse::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" legacy_state: ");
|
||||
out.append(proto_enum_to_string<EnumLegacyCoverState>(this->legacy_state));
|
||||
out.append(proto_enum_to_string<enums::LegacyCoverState>(this->legacy_state));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" position: ");
|
||||
@@ -594,7 +603,7 @@ void CoverStateResponse::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" current_operation: ");
|
||||
out.append(proto_enum_to_string<EnumCoverOperation>(this->current_operation));
|
||||
out.append(proto_enum_to_string<enums::CoverOperation>(this->current_operation));
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
@@ -605,7 +614,7 @@ bool CoverCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->legacy_command = value.as_enum<EnumLegacyCoverCommand>();
|
||||
this->legacy_command = value.as_enum<enums::LegacyCoverCommand>();
|
||||
return true;
|
||||
}
|
||||
case 4: {
|
||||
@@ -645,7 +654,7 @@ bool CoverCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
void CoverCommandRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.encode_bool(2, this->has_legacy_command);
|
||||
buffer.encode_enum<EnumLegacyCoverCommand>(3, this->legacy_command);
|
||||
buffer.encode_enum<enums::LegacyCoverCommand>(3, this->legacy_command);
|
||||
buffer.encode_bool(4, this->has_position);
|
||||
buffer.encode_float(5, this->position);
|
||||
buffer.encode_bool(6, this->has_tilt);
|
||||
@@ -665,7 +674,7 @@ void CoverCommandRequest::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" legacy_command: ");
|
||||
out.append(proto_enum_to_string<EnumLegacyCoverCommand>(this->legacy_command));
|
||||
out.append(proto_enum_to_string<enums::LegacyCoverCommand>(this->legacy_command));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_position: ");
|
||||
@@ -781,7 +790,7 @@ bool FanStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
return true;
|
||||
}
|
||||
case 4: {
|
||||
this->speed = value.as_enum<EnumFanSpeed>();
|
||||
this->speed = value.as_enum<enums::FanSpeed>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
@@ -802,7 +811,7 @@ void FanStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.encode_bool(2, this->state);
|
||||
buffer.encode_bool(3, this->oscillating);
|
||||
buffer.encode_enum<EnumFanSpeed>(4, this->speed);
|
||||
buffer.encode_enum<enums::FanSpeed>(4, this->speed);
|
||||
}
|
||||
void FanStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@@ -821,7 +830,7 @@ void FanStateResponse::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" speed: ");
|
||||
out.append(proto_enum_to_string<EnumFanSpeed>(this->speed));
|
||||
out.append(proto_enum_to_string<enums::FanSpeed>(this->speed));
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
@@ -840,7 +849,7 @@ bool FanCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
return true;
|
||||
}
|
||||
case 5: {
|
||||
this->speed = value.as_enum<EnumFanSpeed>();
|
||||
this->speed = value.as_enum<enums::FanSpeed>();
|
||||
return true;
|
||||
}
|
||||
case 6: {
|
||||
@@ -870,7 +879,7 @@ void FanCommandRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(2, this->has_state);
|
||||
buffer.encode_bool(3, this->state);
|
||||
buffer.encode_bool(4, this->has_speed);
|
||||
buffer.encode_enum<EnumFanSpeed>(5, this->speed);
|
||||
buffer.encode_enum<enums::FanSpeed>(5, this->speed);
|
||||
buffer.encode_bool(6, this->has_oscillating);
|
||||
buffer.encode_bool(7, this->oscillating);
|
||||
}
|
||||
@@ -895,7 +904,7 @@ void FanCommandRequest::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" speed: ");
|
||||
out.append(proto_enum_to_string<EnumFanSpeed>(this->speed));
|
||||
out.append(proto_enum_to_string<enums::FanSpeed>(this->speed));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_oscillating: ");
|
||||
@@ -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,12 +1770,16 @@ 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) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->level = value.as_enum<EnumLogLevel>();
|
||||
this->level = value.as_enum<enums::LogLevel>();
|
||||
return true;
|
||||
}
|
||||
case 2: {
|
||||
@@ -1752,14 +1791,14 @@ bool SubscribeLogsRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
}
|
||||
}
|
||||
void SubscribeLogsRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_enum<EnumLogLevel>(1, this->level);
|
||||
buffer.encode_enum<enums::LogLevel>(1, this->level);
|
||||
buffer.encode_bool(2, this->dump_config);
|
||||
}
|
||||
void SubscribeLogsRequest::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
out.append("SubscribeLogsRequest {\n");
|
||||
out.append(" level: ");
|
||||
out.append(proto_enum_to_string<EnumLogLevel>(this->level));
|
||||
out.append(proto_enum_to_string<enums::LogLevel>(this->level));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" dump_config: ");
|
||||
@@ -1770,7 +1809,7 @@ void SubscribeLogsRequest::dump_to(std::string &out) const {
|
||||
bool SubscribeLogsResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
this->level = value.as_enum<EnumLogLevel>();
|
||||
this->level = value.as_enum<enums::LogLevel>();
|
||||
return true;
|
||||
}
|
||||
case 4: {
|
||||
@@ -1796,7 +1835,7 @@ bool SubscribeLogsResponse::decode_length(uint32_t field_id, ProtoLengthDelimite
|
||||
}
|
||||
}
|
||||
void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_enum<EnumLogLevel>(1, this->level);
|
||||
buffer.encode_enum<enums::LogLevel>(1, this->level);
|
||||
buffer.encode_string(2, this->tag);
|
||||
buffer.encode_string(3, this->message);
|
||||
buffer.encode_bool(4, this->send_failed);
|
||||
@@ -1805,7 +1844,7 @@ void SubscribeLogsResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
out.append("SubscribeLogsResponse {\n");
|
||||
out.append(" level: ");
|
||||
out.append(proto_enum_to_string<EnumLogLevel>(this->level));
|
||||
out.append(proto_enum_to_string<enums::LogLevel>(this->level));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" tag: ");
|
||||
@@ -2010,7 +2049,7 @@ void GetTimeResponse::dump_to(std::string &out) const {
|
||||
bool ListEntitiesServicesArgument::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 2: {
|
||||
this->type = value.as_enum<EnumServiceArgType>();
|
||||
this->type = value.as_enum<enums::ServiceArgType>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
@@ -2029,7 +2068,7 @@ bool ListEntitiesServicesArgument::decode_length(uint32_t field_id, ProtoLengthD
|
||||
}
|
||||
void ListEntitiesServicesArgument::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_string(1, this->name);
|
||||
buffer.encode_enum<EnumServiceArgType>(2, this->type);
|
||||
buffer.encode_enum<enums::ServiceArgType>(2, this->type);
|
||||
}
|
||||
void ListEntitiesServicesArgument::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@@ -2039,7 +2078,7 @@ void ListEntitiesServicesArgument::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" type: ");
|
||||
out.append(proto_enum_to_string<EnumServiceArgType>(this->type));
|
||||
out.append(proto_enum_to_string<enums::ServiceArgType>(this->type));
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
@@ -2408,7 +2447,7 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v
|
||||
return true;
|
||||
}
|
||||
case 7: {
|
||||
this->supported_modes.push_back(value.as_enum<EnumClimateMode>());
|
||||
this->supported_modes.push_back(value.as_enum<enums::ClimateMode>());
|
||||
return true;
|
||||
}
|
||||
case 11: {
|
||||
@@ -2471,7 +2510,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(5, this->supports_current_temperature);
|
||||
buffer.encode_bool(6, this->supports_two_point_target_temperature);
|
||||
for (auto &it : this->supported_modes) {
|
||||
buffer.encode_enum<EnumClimateMode>(7, it, true);
|
||||
buffer.encode_enum<enums::ClimateMode>(7, it, true);
|
||||
}
|
||||
buffer.encode_float(8, this->visual_min_temperature);
|
||||
buffer.encode_float(9, this->visual_max_temperature);
|
||||
@@ -2509,7 +2548,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
|
||||
for (const auto &it : this->supported_modes) {
|
||||
out.append(" supported_modes: ");
|
||||
out.append(proto_enum_to_string<EnumClimateMode>(it));
|
||||
out.append(proto_enum_to_string<enums::ClimateMode>(it));
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
@@ -2540,7 +2579,7 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
case 2: {
|
||||
this->mode = value.as_enum<EnumClimateMode>();
|
||||
this->mode = value.as_enum<enums::ClimateMode>();
|
||||
return true;
|
||||
}
|
||||
case 7: {
|
||||
@@ -2548,7 +2587,7 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
return true;
|
||||
}
|
||||
case 8: {
|
||||
this->action = value.as_enum<EnumClimateAction>();
|
||||
this->action = value.as_enum<enums::ClimateAction>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
@@ -2583,13 +2622,13 @@ bool ClimateStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
}
|
||||
void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.encode_enum<EnumClimateMode>(2, this->mode);
|
||||
buffer.encode_enum<enums::ClimateMode>(2, this->mode);
|
||||
buffer.encode_float(3, this->current_temperature);
|
||||
buffer.encode_float(4, this->target_temperature);
|
||||
buffer.encode_float(5, this->target_temperature_low);
|
||||
buffer.encode_float(6, this->target_temperature_high);
|
||||
buffer.encode_bool(7, this->away);
|
||||
buffer.encode_enum<EnumClimateAction>(8, this->action);
|
||||
buffer.encode_enum<enums::ClimateAction>(8, this->action);
|
||||
}
|
||||
void ClimateStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
@@ -2600,7 +2639,7 @@ void ClimateStateResponse::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" mode: ");
|
||||
out.append(proto_enum_to_string<EnumClimateMode>(this->mode));
|
||||
out.append(proto_enum_to_string<enums::ClimateMode>(this->mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" current_temperature: ");
|
||||
@@ -2628,7 +2667,7 @@ void ClimateStateResponse::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" action: ");
|
||||
out.append(proto_enum_to_string<EnumClimateAction>(this->action));
|
||||
out.append(proto_enum_to_string<enums::ClimateAction>(this->action));
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
@@ -2639,7 +2678,7 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
|
||||
return true;
|
||||
}
|
||||
case 3: {
|
||||
this->mode = value.as_enum<EnumClimateMode>();
|
||||
this->mode = value.as_enum<enums::ClimateMode>();
|
||||
return true;
|
||||
}
|
||||
case 4: {
|
||||
@@ -2691,7 +2730,7 @@ bool ClimateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
|
||||
void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_fixed32(1, this->key);
|
||||
buffer.encode_bool(2, this->has_mode);
|
||||
buffer.encode_enum<EnumClimateMode>(3, this->mode);
|
||||
buffer.encode_enum<enums::ClimateMode>(3, this->mode);
|
||||
buffer.encode_bool(4, this->has_target_temperature);
|
||||
buffer.encode_float(5, this->target_temperature);
|
||||
buffer.encode_bool(6, this->has_target_temperature_low);
|
||||
@@ -2714,7 +2753,7 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
|
||||
out.append("\n");
|
||||
|
||||
out.append(" mode: ");
|
||||
out.append(proto_enum_to_string<EnumClimateMode>(this->mode));
|
||||
out.append(proto_enum_to_string<enums::ClimateMode>(this->mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_target_temperature: ");
|
||||
|
||||
@@ -5,26 +5,28 @@
|
||||
namespace esphome {
|
||||
namespace api {
|
||||
|
||||
enum EnumLegacyCoverState : uint32_t {
|
||||
namespace enums {
|
||||
|
||||
enum LegacyCoverState : uint32_t {
|
||||
LEGACY_COVER_STATE_OPEN = 0,
|
||||
LEGACY_COVER_STATE_CLOSED = 1,
|
||||
};
|
||||
enum EnumCoverOperation : uint32_t {
|
||||
enum CoverOperation : uint32_t {
|
||||
COVER_OPERATION_IDLE = 0,
|
||||
COVER_OPERATION_IS_OPENING = 1,
|
||||
COVER_OPERATION_IS_CLOSING = 2,
|
||||
};
|
||||
enum EnumLegacyCoverCommand : uint32_t {
|
||||
enum LegacyCoverCommand : uint32_t {
|
||||
LEGACY_COVER_COMMAND_OPEN = 0,
|
||||
LEGACY_COVER_COMMAND_CLOSE = 1,
|
||||
LEGACY_COVER_COMMAND_STOP = 2,
|
||||
};
|
||||
enum EnumFanSpeed : uint32_t {
|
||||
enum FanSpeed : uint32_t {
|
||||
FAN_SPEED_LOW = 0,
|
||||
FAN_SPEED_MEDIUM = 1,
|
||||
FAN_SPEED_HIGH = 2,
|
||||
};
|
||||
enum EnumLogLevel : uint32_t {
|
||||
enum LogLevel : uint32_t {
|
||||
LOG_LEVEL_NONE = 0,
|
||||
LOG_LEVEL_ERROR = 1,
|
||||
LOG_LEVEL_WARN = 2,
|
||||
@@ -33,7 +35,7 @@ enum EnumLogLevel : uint32_t {
|
||||
LOG_LEVEL_VERBOSE = 5,
|
||||
LOG_LEVEL_VERY_VERBOSE = 6,
|
||||
};
|
||||
enum EnumServiceArgType : uint32_t {
|
||||
enum ServiceArgType : uint32_t {
|
||||
SERVICE_ARG_TYPE_BOOL = 0,
|
||||
SERVICE_ARG_TYPE_INT = 1,
|
||||
SERVICE_ARG_TYPE_FLOAT = 2,
|
||||
@@ -43,17 +45,20 @@ enum EnumServiceArgType : uint32_t {
|
||||
SERVICE_ARG_TYPE_FLOAT_ARRAY = 6,
|
||||
SERVICE_ARG_TYPE_STRING_ARRAY = 7,
|
||||
};
|
||||
enum EnumClimateMode : uint32_t {
|
||||
enum ClimateMode : uint32_t {
|
||||
CLIMATE_MODE_OFF = 0,
|
||||
CLIMATE_MODE_AUTO = 1,
|
||||
CLIMATE_MODE_COOL = 2,
|
||||
CLIMATE_MODE_HEAT = 3,
|
||||
};
|
||||
enum EnumClimateAction : uint32_t {
|
||||
enum ClimateAction : uint32_t {
|
||||
CLIMATE_ACTION_OFF = 0,
|
||||
CLIMATE_ACTION_COOLING = 2,
|
||||
CLIMATE_ACTION_HEATING = 3,
|
||||
};
|
||||
|
||||
} // namespace enums
|
||||
|
||||
class HelloRequest : public ProtoMessage {
|
||||
public:
|
||||
std::string client_info{}; // NOLINT
|
||||
@@ -183,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;
|
||||
|
||||
@@ -212,11 +218,11 @@ class ListEntitiesCoverResponse : public ProtoMessage {
|
||||
};
|
||||
class CoverStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
EnumLegacyCoverState legacy_state{}; // NOLINT
|
||||
float position{0.0f}; // NOLINT
|
||||
float tilt{0.0f}; // NOLINT
|
||||
EnumCoverOperation current_operation{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
enums::LegacyCoverState legacy_state{}; // NOLINT
|
||||
float position{0.0f}; // NOLINT
|
||||
float tilt{0.0f}; // NOLINT
|
||||
enums::CoverOperation current_operation{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@@ -226,14 +232,14 @@ class CoverStateResponse : public ProtoMessage {
|
||||
};
|
||||
class CoverCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_legacy_command{false}; // NOLINT
|
||||
EnumLegacyCoverCommand legacy_command{}; // NOLINT
|
||||
bool has_position{false}; // NOLINT
|
||||
float position{0.0f}; // NOLINT
|
||||
bool has_tilt{false}; // NOLINT
|
||||
float tilt{0.0f}; // NOLINT
|
||||
bool stop{false}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_legacy_command{false}; // NOLINT
|
||||
enums::LegacyCoverCommand legacy_command{}; // NOLINT
|
||||
bool has_position{false}; // NOLINT
|
||||
float position{0.0f}; // NOLINT
|
||||
bool has_tilt{false}; // NOLINT
|
||||
float tilt{0.0f}; // NOLINT
|
||||
bool stop{false}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@@ -262,7 +268,7 @@ class FanStateResponse : public ProtoMessage {
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
bool oscillating{false}; // NOLINT
|
||||
EnumFanSpeed speed{}; // NOLINT
|
||||
enums::FanSpeed speed{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@@ -276,7 +282,7 @@ class FanCommandRequest : public ProtoMessage {
|
||||
bool has_state{false}; // NOLINT
|
||||
bool state{false}; // NOLINT
|
||||
bool has_speed{false}; // NOLINT
|
||||
EnumFanSpeed speed{}; // NOLINT
|
||||
enums::FanSpeed speed{}; // NOLINT
|
||||
bool has_oscillating{false}; // NOLINT
|
||||
bool oscillating{false}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
@@ -375,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:
|
||||
@@ -437,18 +445,20 @@ 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:
|
||||
EnumLogLevel level{}; // NOLINT
|
||||
enums::LogLevel level{}; // NOLINT
|
||||
bool dump_config{false}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
@@ -458,7 +468,7 @@ class SubscribeLogsRequest : public ProtoMessage {
|
||||
};
|
||||
class SubscribeLogsResponse : public ProtoMessage {
|
||||
public:
|
||||
EnumLogLevel level{}; // NOLINT
|
||||
enums::LogLevel level{}; // NOLINT
|
||||
std::string tag{}; // NOLINT
|
||||
std::string message{}; // NOLINT
|
||||
bool send_failed{false}; // NOLINT
|
||||
@@ -544,8 +554,8 @@ class GetTimeResponse : public ProtoMessage {
|
||||
};
|
||||
class ListEntitiesServicesArgument : public ProtoMessage {
|
||||
public:
|
||||
std::string name{}; // NOLINT
|
||||
EnumServiceArgType type{}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
enums::ServiceArgType type{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@@ -639,7 +649,7 @@ class ListEntitiesClimateResponse : public ProtoMessage {
|
||||
std::string unique_id{}; // NOLINT
|
||||
bool supports_current_temperature{false}; // NOLINT
|
||||
bool supports_two_point_target_temperature{false}; // NOLINT
|
||||
std::vector<EnumClimateMode> supported_modes{}; // NOLINT
|
||||
std::vector<enums::ClimateMode> supported_modes{}; // NOLINT
|
||||
float visual_min_temperature{0.0f}; // NOLINT
|
||||
float visual_max_temperature{0.0f}; // NOLINT
|
||||
float visual_temperature_step{0.0f}; // NOLINT
|
||||
@@ -656,13 +666,13 @@ class ListEntitiesClimateResponse : public ProtoMessage {
|
||||
class ClimateStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
EnumClimateMode mode{}; // NOLINT
|
||||
enums::ClimateMode mode{}; // NOLINT
|
||||
float current_temperature{0.0f}; // NOLINT
|
||||
float target_temperature{0.0f}; // NOLINT
|
||||
float target_temperature_low{0.0f}; // NOLINT
|
||||
float target_temperature_high{0.0f}; // NOLINT
|
||||
bool away{false}; // NOLINT
|
||||
EnumClimateAction action{}; // NOLINT
|
||||
enums::ClimateAction action{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
@@ -674,7 +684,7 @@ class ClimateCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_mode{false}; // NOLINT
|
||||
EnumClimateMode mode{}; // NOLINT
|
||||
enums::ClimateMode mode{}; // NOLINT
|
||||
bool has_target_temperature{false}; // NOLINT
|
||||
float target_temperature{0.0f}; // NOLINT
|
||||
bool has_target_temperature_low{false}; // NOLINT
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,14 +25,18 @@ template<> std::vector<std::string> get_execute_arg_value<std::vector<std::strin
|
||||
return arg.string_array;
|
||||
}
|
||||
|
||||
template<> EnumServiceArgType to_service_arg_type<bool>() { return SERVICE_ARG_TYPE_BOOL; }
|
||||
template<> EnumServiceArgType to_service_arg_type<int>() { return SERVICE_ARG_TYPE_INT; }
|
||||
template<> EnumServiceArgType to_service_arg_type<float>() { return SERVICE_ARG_TYPE_FLOAT; }
|
||||
template<> EnumServiceArgType to_service_arg_type<std::string>() { return SERVICE_ARG_TYPE_STRING; }
|
||||
template<> EnumServiceArgType to_service_arg_type<std::vector<bool>>() { return SERVICE_ARG_TYPE_BOOL_ARRAY; }
|
||||
template<> EnumServiceArgType to_service_arg_type<std::vector<int>>() { return SERVICE_ARG_TYPE_INT_ARRAY; }
|
||||
template<> EnumServiceArgType to_service_arg_type<std::vector<float>>() { return SERVICE_ARG_TYPE_FLOAT_ARRAY; }
|
||||
template<> EnumServiceArgType to_service_arg_type<std::vector<std::string>>() { return SERVICE_ARG_TYPE_STRING_ARRAY; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<bool>() { return enums::SERVICE_ARG_TYPE_BOOL; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<int>() { return enums::SERVICE_ARG_TYPE_INT; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<float>() { return enums::SERVICE_ARG_TYPE_FLOAT; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<std::string>() { return enums::SERVICE_ARG_TYPE_STRING; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<std::vector<bool>>() { return enums::SERVICE_ARG_TYPE_BOOL_ARRAY; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<std::vector<int>>() { return enums::SERVICE_ARG_TYPE_INT_ARRAY; }
|
||||
template<> enums::ServiceArgType to_service_arg_type<std::vector<float>>() {
|
||||
return enums::SERVICE_ARG_TYPE_FLOAT_ARRAY;
|
||||
}
|
||||
template<> enums::ServiceArgType to_service_arg_type<std::vector<std::string>>() {
|
||||
return enums::SERVICE_ARG_TYPE_STRING_ARRAY;
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
} // namespace esphome
|
||||
|
||||
@@ -16,7 +16,7 @@ class UserServiceDescriptor {
|
||||
|
||||
template<typename T> T get_execute_arg_value(const ExecuteServiceArgument &arg);
|
||||
|
||||
template<typename T> EnumServiceArgType to_service_arg_type();
|
||||
template<typename T> enums::ServiceArgType to_service_arg_type();
|
||||
|
||||
template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
|
||||
public:
|
||||
@@ -29,7 +29,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
|
||||
ListEntitiesServicesResponse msg;
|
||||
msg.name = this->name_;
|
||||
msg.key = this->key_;
|
||||
std::array<EnumServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
|
||||
std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
|
||||
for (int i = 0; i < sizeof...(Ts); i++) {
|
||||
ListEntitiesServicesArgument arg;
|
||||
arg.type = arg_types[i];
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.const import CONF_PIN, CONF_INDOOR, CONF_WATCHDOG_THRESHOLD, \
|
||||
from esphome.const import CONF_INDOOR, CONF_WATCHDOG_THRESHOLD, \
|
||||
CONF_NOISE_LEVEL, CONF_SPIKE_REJECTION, CONF_LIGHTNING_THRESHOLD, \
|
||||
CONF_MASK_DISTURBER, CONF_DIV_RATIO, CONF_CAPACITANCE
|
||||
from esphome.core import coroutine
|
||||
|
||||
|
||||
AUTO_LOAD = ['sensor', 'binary_sensor']
|
||||
MULTI_CONF = True
|
||||
|
||||
@@ -15,10 +14,10 @@ CONF_AS3935_ID = 'as3935_id'
|
||||
as3935_ns = cg.esphome_ns.namespace('as3935')
|
||||
AS3935 = as3935_ns.class_('AS3935Component', cg.Component)
|
||||
|
||||
CONF_IRQ_PIN = 'irq_pin'
|
||||
AS3935_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.declare_id(AS3935),
|
||||
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
|
||||
pins.validate_has_interrupt),
|
||||
cv.Required(CONF_IRQ_PIN): pins.gpio_input_pin_schema,
|
||||
|
||||
cv.Optional(CONF_INDOOR, default=True): cv.boolean,
|
||||
cv.Optional(CONF_NOISE_LEVEL, default=2): cv.int_range(min=1, max=7),
|
||||
@@ -35,8 +34,8 @@ AS3935_SCHEMA = cv.Schema({
|
||||
def setup_as3935(var, config):
|
||||
yield cg.register_component(var, config)
|
||||
|
||||
pin = yield cg.gpio_pin_expression(config[CONF_PIN])
|
||||
cg.add(var.set_pin(pin))
|
||||
irq_pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN])
|
||||
cg.add(var.set_irq_pin(irq_pin))
|
||||
cg.add(var.set_indoor(config[CONF_INDOOR]))
|
||||
cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL]))
|
||||
cg.add(var.set_watchdog_threshold(config[CONF_WATCHDOG_THRESHOLD]))
|
||||
|
||||
@@ -9,10 +9,8 @@ static const char *TAG = "as3935";
|
||||
void AS3935Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up AS3935...");
|
||||
|
||||
this->pin_->setup();
|
||||
this->store_.pin = this->pin_->to_isr();
|
||||
LOG_PIN(" Interrupt Pin: ", this->pin_);
|
||||
this->pin_->attach_interrupt(AS3935ComponentStore::gpio_intr, &this->store_, RISING);
|
||||
this->irq_pin_->setup();
|
||||
LOG_PIN(" IRQ Pin: ", this->irq_pin_);
|
||||
|
||||
// Write properties to sensor
|
||||
this->write_indoor(this->indoor_);
|
||||
@@ -27,13 +25,13 @@ void AS3935Component::setup() {
|
||||
|
||||
void AS3935Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "AS3935:");
|
||||
LOG_PIN(" Interrupt Pin: ", this->pin_);
|
||||
LOG_PIN(" Interrupt Pin: ", this->irq_pin_);
|
||||
}
|
||||
|
||||
float AS3935Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
void AS3935Component::loop() {
|
||||
if (!this->store_.interrupt)
|
||||
if (!this->irq_pin_->digital_read())
|
||||
return;
|
||||
|
||||
uint8_t int_value = this->read_interrupt_register_();
|
||||
@@ -53,7 +51,6 @@ void AS3935Component::loop() {
|
||||
this->energy_sensor_->publish_state(energy);
|
||||
}
|
||||
this->thunder_alert_binary_sensor_->publish_state(false);
|
||||
this->store_.interrupt = false;
|
||||
}
|
||||
|
||||
void AS3935Component::write_indoor(bool indoor) {
|
||||
@@ -222,7 +219,5 @@ uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR AS3935ComponentStore::gpio_intr(AS3935ComponentStore *arg) { arg->interrupt = true; }
|
||||
|
||||
} // namespace as3935
|
||||
} // namespace esphome
|
||||
|
||||
@@ -50,14 +50,6 @@ enum AS3935Values {
|
||||
NOISE_INT = 0x01
|
||||
};
|
||||
|
||||
/// Store data in a class that doesn't use multiple-inheritance (vtables in flash)
|
||||
struct AS3935ComponentStore {
|
||||
volatile bool interrupt;
|
||||
|
||||
ISRInternalGPIOPin *pin;
|
||||
static void gpio_intr(AS3935ComponentStore *arg);
|
||||
};
|
||||
|
||||
class AS3935Component : public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
@@ -65,7 +57,7 @@ class AS3935Component : public Component {
|
||||
float get_setup_priority() const override;
|
||||
void loop() override;
|
||||
|
||||
void set_pin(GPIOPin *pin) { pin_ = pin; }
|
||||
void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; }
|
||||
void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; }
|
||||
void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; }
|
||||
void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) {
|
||||
@@ -102,8 +94,7 @@ class AS3935Component : public Component {
|
||||
sensor::Sensor *distance_sensor_;
|
||||
sensor::Sensor *energy_sensor_;
|
||||
binary_sensor::BinarySensor *thunder_alert_binary_sensor_;
|
||||
GPIOPin *pin_;
|
||||
AS3935ComponentStore store_;
|
||||
GPIOPin *irq_pin_;
|
||||
|
||||
bool indoor_;
|
||||
uint8_t noise_level_;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -24,4 +24,4 @@ def to_code(config):
|
||||
|
||||
if CONF_OSCILLATION_OUTPUT in config:
|
||||
oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
|
||||
cg.add(var.set_oscillation(oscillation_output))
|
||||
cg.add(var.set_oscillating(oscillation_output))
|
||||
|
||||
@@ -23,6 +23,7 @@ IS_PLATFORM_COMPONENT = True
|
||||
|
||||
binary_sensor_ns = cg.esphome_ns.namespace('binary_sensor')
|
||||
BinarySensor = binary_sensor_ns.class_('BinarySensor', cg.Nameable)
|
||||
BinarySensorInitiallyOff = binary_sensor_ns.class_('BinarySensorInitiallyOff', BinarySensor)
|
||||
BinarySensorPtr = BinarySensor.operator('ptr')
|
||||
|
||||
# Triggers
|
||||
|
||||
@@ -67,7 +67,7 @@ class BinarySensor : public Nameable {
|
||||
void send_state_internal(bool state, bool is_initial);
|
||||
|
||||
/// Return whether this binary sensor has outputted a state.
|
||||
bool has_state() const;
|
||||
virtual bool has_state() const;
|
||||
|
||||
virtual bool is_status_binary_sensor() const;
|
||||
|
||||
@@ -86,5 +86,10 @@ class BinarySensor : public Nameable {
|
||||
Deduplicator<bool> publish_dedup_;
|
||||
};
|
||||
|
||||
class BinarySensorInitiallyOff : public BinarySensor {
|
||||
public:
|
||||
bool has_state() const override { return true; }
|
||||
};
|
||||
|
||||
} // namespace binary_sensor
|
||||
} // namespace esphome
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace esphome {
|
||||
namespace ble_presence {
|
||||
|
||||
class BLEPresenceDevice : public binary_sensor::BinarySensor,
|
||||
class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
|
||||
public esp32_ble_tracker::ESPBTDeviceListener,
|
||||
public Component {
|
||||
public:
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate, remote_transmitter, remote_receiver, sensor, remote_base
|
||||
from esphome.components.remote_base import CONF_RECEIVER_ID, CONF_TRANSMITTER_ID
|
||||
from esphome.const import CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, CONF_SENSOR
|
||||
from esphome.core import coroutine
|
||||
|
||||
AUTO_LOAD = ['sensor', 'remote_base']
|
||||
|
||||
climate_ir_ns = cg.esphome_ns.namespace('climate_ir')
|
||||
ClimateIR = climate_ir_ns.class_('ClimateIR', climate.Climate, cg.Component,
|
||||
remote_base.RemoteReceiverListener)
|
||||
|
||||
CLIMATE_IR_SCHEMA = climate.CLIMATE_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),
|
||||
cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
CLIMATE_IR_WITH_RECEIVER_SCHEMA = CLIMATE_IR_SCHEMA.extend({
|
||||
cv.Optional(CONF_RECEIVER_ID): cv.use_id(remote_receiver.RemoteReceiverComponent),
|
||||
})
|
||||
|
||||
|
||||
@coroutine
|
||||
def register_climate_ir(var, config):
|
||||
yield cg.register_component(var, config)
|
||||
yield climate.register_climate(var, config)
|
||||
|
||||
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
|
||||
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
|
||||
if CONF_SENSOR in config:
|
||||
sens = yield cg.get_variable(config[CONF_SENSOR])
|
||||
cg.add(var.set_sensor(sens))
|
||||
if CONF_RECEIVER_ID in config:
|
||||
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
|
||||
cg.add(receiver.register_listener(var))
|
||||
|
||||
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
|
||||
cg.add(var.set_transmitter(transmitter))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace climate {
|
||||
namespace climate_ir {
|
||||
|
||||
static const char *TAG = "climate_ir";
|
||||
|
||||
@@ -63,5 +63,5 @@ void ClimateIR::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Supports COOL: %s", YESNO(this->supports_cool_));
|
||||
}
|
||||
|
||||
} // namespace climate
|
||||
} // namespace climate_ir
|
||||
} // namespace esphome
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace climate {
|
||||
namespace climate_ir {
|
||||
|
||||
/* A base for climate which works by sending (and receiving) IR codes
|
||||
|
||||
@@ -42,7 +42,7 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
|
||||
climate::ClimateTraits traits() override;
|
||||
|
||||
/// Transmit via IR the state of this climate controller.
|
||||
virtual void transmit_state() {}
|
||||
virtual void transmit_state() = 0;
|
||||
|
||||
bool supports_cool_{true};
|
||||
bool supports_heat_{true};
|
||||
@@ -50,5 +50,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
|
||||
remote_transmitter::RemoteTransmitterComponent *transmitter_;
|
||||
sensor::Sensor *sensor_{nullptr};
|
||||
};
|
||||
} // namespace climate
|
||||
|
||||
} // namespace climate_ir
|
||||
} // namespace esphome
|
||||
|
||||
@@ -1,37 +1,18 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
|
||||
from esphome.components.remote_base import CONF_TRANSMITTER_ID, CONF_RECEIVER_ID
|
||||
from esphome.const import CONF_ID, CONF_SENSOR, CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT
|
||||
from esphome.components import climate_ir
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ['sensor', 'climate_ir']
|
||||
AUTO_LOAD = ['climate_ir']
|
||||
|
||||
coolix_ns = cg.esphome_ns.namespace('coolix')
|
||||
CoolixClimate = coolix_ns.class_('CoolixClimate', climate.Climate, cg.Component)
|
||||
CoolixClimate = coolix_ns.class_('CoolixClimate', climate_ir.ClimateIR)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
|
||||
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(CoolixClimate),
|
||||
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),
|
||||
cv.Optional(CONF_RECEIVER_ID): cv.use_id(remote_receiver.RemoteReceiverComponent),
|
||||
cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
||||
}).extend(cv.COMPONENT_SCHEMA))
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield climate.register_climate(var, config)
|
||||
|
||||
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
|
||||
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
|
||||
if CONF_SENSOR in config:
|
||||
sens = yield cg.get_variable(config[CONF_SENSOR])
|
||||
cg.add(var.set_sensor(sens))
|
||||
if CONF_RECEIVER_ID in config:
|
||||
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
|
||||
cg.add(receiver.register_listener(var))
|
||||
|
||||
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
|
||||
cg.add(var.set_transmitter(transmitter))
|
||||
yield climate_ir.register_climate_ir(var, config)
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace coolix {
|
||||
const uint8_t COOLIX_TEMP_MIN = 17; // Celsius
|
||||
const uint8_t COOLIX_TEMP_MAX = 30; // Celsius
|
||||
|
||||
class CoolixClimate : public climate::ClimateIR {
|
||||
class CoolixClimate : public climate_ir::ClimateIR {
|
||||
public:
|
||||
CoolixClimate() : climate::ClimateIR(COOLIX_TEMP_MIN, COOLIX_TEMP_MAX) {}
|
||||
CoolixClimate() : climate_ir::ClimateIR(COOLIX_TEMP_MIN, COOLIX_TEMP_MAX) {}
|
||||
|
||||
protected:
|
||||
/// Transmit via IR the state of this climate controller.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
0
esphome/components/fujitsu_general/__init__.py
Normal file
0
esphome/components/fujitsu_general/__init__.py
Normal file
18
esphome/components/fujitsu_general/climate.py
Normal file
18
esphome/components/fujitsu_general/climate.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate_ir
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ['climate_ir']
|
||||
|
||||
fujitsu_general_ns = cg.esphome_ns.namespace('fujitsu_general')
|
||||
FujitsuGeneralClimate = fujitsu_general_ns.class_('FujitsuGeneralClimate', climate_ir.ClimateIR)
|
||||
|
||||
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(FujitsuGeneralClimate),
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield climate_ir.register_climate_ir(var, config)
|
||||
212
esphome/components/fujitsu_general/fujitsu_general.cpp
Normal file
212
esphome/components/fujitsu_general/fujitsu_general.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
#include "fujitsu_general.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace fujitsu_general {
|
||||
|
||||
static const char *TAG = "fujitsu_general.climate";
|
||||
|
||||
// Control packet
|
||||
const uint16_t FUJITSU_GENERAL_STATE_LENGTH = 16;
|
||||
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE0 = 0x14;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE1 = 0x63;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE2 = 0x00;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE3 = 0x10;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE4 = 0x10;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE5 = 0xFE;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE6 = 0x09;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE7 = 0x30;
|
||||
|
||||
// Temperature and POWER ON
|
||||
const uint8_t FUJITSU_GENERAL_POWER_ON_MASK_BYTE8 = 0b00000001;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE8 = 0x40;
|
||||
|
||||
// Mode
|
||||
const uint8_t FUJITSU_GENERAL_MODE_AUTO_BYTE9 = 0x00;
|
||||
const uint8_t FUJITSU_GENERAL_MODE_HEAT_BYTE9 = 0x04;
|
||||
const uint8_t FUJITSU_GENERAL_MODE_COOL_BYTE9 = 0x01;
|
||||
const uint8_t FUJITSU_GENERAL_MODE_DRY_BYTE9 = 0x02;
|
||||
const uint8_t FUJITSU_GENERAL_MODE_FAN_BYTE9 = 0x03;
|
||||
const uint8_t FUJITSU_GENERAL_MODE_10C_BYTE9 = 0x0B;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE9 = 0x01;
|
||||
|
||||
// Fan speed and swing
|
||||
const uint8_t FUJITSU_GENERAL_FAN_AUTO_BYTE10 = 0x00;
|
||||
const uint8_t FUJITSU_GENERAL_FAN_HIGH_BYTE10 = 0x01;
|
||||
const uint8_t FUJITSU_GENERAL_FAN_MEDIUM_BYTE10 = 0x02;
|
||||
const uint8_t FUJITSU_GENERAL_FAN_LOW_BYTE10 = 0x03;
|
||||
const uint8_t FUJITSU_GENERAL_FAN_SILENT_BYTE10 = 0x04;
|
||||
const uint8_t FUJITSU_GENERAL_SWING_MASK_BYTE10 = 0b00010000;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE10 = 0x00;
|
||||
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE11 = 0x00;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE12 = 0x00;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE13 = 0x00;
|
||||
|
||||
// Outdoor Unit Low Noise
|
||||
const uint8_t FUJITSU_GENERAL_OUTDOOR_UNIT_LOW_NOISE_BYTE14 = 0xA0;
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE14 = 0x20;
|
||||
|
||||
// CRC
|
||||
const uint8_t FUJITSU_GENERAL_BASE_BYTE15 = 0x6F;
|
||||
|
||||
// Power off packet is specific
|
||||
const uint16_t FUJITSU_GENERAL_OFF_LENGTH = 7;
|
||||
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE0 = FUJITSU_GENERAL_BASE_BYTE0;
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE1 = FUJITSU_GENERAL_BASE_BYTE1;
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE2 = FUJITSU_GENERAL_BASE_BYTE2;
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE3 = FUJITSU_GENERAL_BASE_BYTE3;
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE4 = FUJITSU_GENERAL_BASE_BYTE4;
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE5 = 0x02;
|
||||
const uint8_t FUJITSU_GENERAL_OFF_BYTE6 = 0xFD;
|
||||
|
||||
const uint8_t FUJITSU_GENERAL_TEMP_MAX = 30; // Celsius
|
||||
const uint8_t FUJITSU_GENERAL_TEMP_MIN = 16; // Celsius
|
||||
|
||||
const uint16_t FUJITSU_GENERAL_HEADER_MARK = 3300;
|
||||
const uint16_t FUJITSU_GENERAL_HEADER_SPACE = 1600;
|
||||
const uint16_t FUJITSU_GENERAL_BIT_MARK = 420;
|
||||
const uint16_t FUJITSU_GENERAL_ONE_SPACE = 1200;
|
||||
const uint16_t FUJITSU_GENERAL_ZERO_SPACE = 420;
|
||||
const uint16_t FUJITSU_GENERAL_TRL_MARK = 420;
|
||||
const uint16_t FUJITSU_GENERAL_TRL_SPACE = 8000;
|
||||
|
||||
const uint32_t FUJITSU_GENERAL_CARRIER_FREQUENCY = 38000;
|
||||
|
||||
FujitsuGeneralClimate::FujitsuGeneralClimate() : ClimateIR(FUJITSU_GENERAL_TEMP_MIN, FUJITSU_GENERAL_TEMP_MAX, 1) {}
|
||||
|
||||
void FujitsuGeneralClimate::transmit_state() {
|
||||
if (this->mode == climate::CLIMATE_MODE_OFF) {
|
||||
this->transmit_off_();
|
||||
return;
|
||||
}
|
||||
uint8_t remote_state[FUJITSU_GENERAL_STATE_LENGTH] = {0};
|
||||
|
||||
remote_state[0] = FUJITSU_GENERAL_BASE_BYTE0;
|
||||
remote_state[1] = FUJITSU_GENERAL_BASE_BYTE1;
|
||||
remote_state[2] = FUJITSU_GENERAL_BASE_BYTE2;
|
||||
remote_state[3] = FUJITSU_GENERAL_BASE_BYTE3;
|
||||
remote_state[4] = FUJITSU_GENERAL_BASE_BYTE4;
|
||||
remote_state[5] = FUJITSU_GENERAL_BASE_BYTE5;
|
||||
remote_state[6] = FUJITSU_GENERAL_BASE_BYTE6;
|
||||
remote_state[7] = FUJITSU_GENERAL_BASE_BYTE7;
|
||||
remote_state[8] = FUJITSU_GENERAL_BASE_BYTE8;
|
||||
remote_state[9] = FUJITSU_GENERAL_BASE_BYTE9;
|
||||
remote_state[10] = FUJITSU_GENERAL_BASE_BYTE10;
|
||||
remote_state[11] = FUJITSU_GENERAL_BASE_BYTE11;
|
||||
remote_state[12] = FUJITSU_GENERAL_BASE_BYTE12;
|
||||
remote_state[13] = FUJITSU_GENERAL_BASE_BYTE13;
|
||||
remote_state[14] = FUJITSU_GENERAL_BASE_BYTE14;
|
||||
remote_state[15] = FUJITSU_GENERAL_BASE_BYTE15;
|
||||
|
||||
// Set temperature
|
||||
uint8_t safecelsius = std::max((uint8_t) this->target_temperature, FUJITSU_GENERAL_TEMP_MIN);
|
||||
safecelsius = std::min(safecelsius, FUJITSU_GENERAL_TEMP_MAX);
|
||||
remote_state[8] = (byte) safecelsius - 16;
|
||||
remote_state[8] = remote_state[8] << 4;
|
||||
|
||||
// If not powered - set power on flag
|
||||
if (!this->power_) {
|
||||
remote_state[8] = (byte) remote_state[8] | FUJITSU_GENERAL_POWER_ON_MASK_BYTE8;
|
||||
}
|
||||
|
||||
// Set mode
|
||||
switch (this->mode) {
|
||||
case climate::CLIMATE_MODE_COOL:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_COOL_BYTE9;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_HEAT:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_HEAT_BYTE9;
|
||||
break;
|
||||
case climate::CLIMATE_MODE_AUTO:
|
||||
default:
|
||||
remote_state[9] = FUJITSU_GENERAL_MODE_AUTO_BYTE9;
|
||||
break;
|
||||
// TODO: CLIMATE_MODE_FAN_ONLY, CLIMATE_MODE_DRY, CLIMATE_MODE_10C are missing in esphome
|
||||
}
|
||||
|
||||
// TODO: missing support for fan speed
|
||||
remote_state[10] = FUJITSU_GENERAL_FAN_AUTO_BYTE10;
|
||||
|
||||
// TODO: missing support for swing
|
||||
// remote_state[10] = (byte) remote_state[10] | FUJITSU_GENERAL_SWING_MASK_BYTE10;
|
||||
|
||||
// TODO: missing support for outdoor unit low noise
|
||||
// remote_state[14] = (byte) remote_state[14] | FUJITSU_GENERAL_OUTDOOR_UNIT_LOW_NOISE_BYTE14;
|
||||
|
||||
// CRC
|
||||
remote_state[15] = 0;
|
||||
for (int i = 7; i < 15; i++) {
|
||||
remote_state[15] += (byte) remote_state[i]; // Addiction
|
||||
}
|
||||
remote_state[15] = 0x100 - remote_state[15]; // mod 256
|
||||
|
||||
auto transmit = this->transmitter_->transmit();
|
||||
auto data = transmit.get_data();
|
||||
|
||||
data->set_carrier_frequency(FUJITSU_GENERAL_CARRIER_FREQUENCY);
|
||||
|
||||
// Header
|
||||
data->mark(FUJITSU_GENERAL_HEADER_MARK);
|
||||
data->space(FUJITSU_GENERAL_HEADER_SPACE);
|
||||
// Data
|
||||
for (uint8_t i : remote_state) {
|
||||
// Send all Bits from Byte Data in Reverse Order
|
||||
for (uint8_t mask = 00000001; mask > 0; mask <<= 1) { // iterate through bit mask
|
||||
data->mark(FUJITSU_GENERAL_BIT_MARK);
|
||||
bool bit = i & mask;
|
||||
data->space(bit ? FUJITSU_GENERAL_ONE_SPACE : FUJITSU_GENERAL_ZERO_SPACE);
|
||||
// Next bits
|
||||
}
|
||||
}
|
||||
// Footer
|
||||
data->mark(FUJITSU_GENERAL_TRL_MARK);
|
||||
data->space(FUJITSU_GENERAL_TRL_SPACE);
|
||||
|
||||
transmit.perform();
|
||||
|
||||
this->power_ = true;
|
||||
}
|
||||
|
||||
void FujitsuGeneralClimate::transmit_off_() {
|
||||
uint8_t remote_state[FUJITSU_GENERAL_OFF_LENGTH] = {0};
|
||||
|
||||
remote_state[0] = FUJITSU_GENERAL_OFF_BYTE0;
|
||||
remote_state[1] = FUJITSU_GENERAL_OFF_BYTE1;
|
||||
remote_state[2] = FUJITSU_GENERAL_OFF_BYTE2;
|
||||
remote_state[3] = FUJITSU_GENERAL_OFF_BYTE3;
|
||||
remote_state[4] = FUJITSU_GENERAL_OFF_BYTE4;
|
||||
remote_state[5] = FUJITSU_GENERAL_OFF_BYTE5;
|
||||
remote_state[6] = FUJITSU_GENERAL_OFF_BYTE6;
|
||||
|
||||
auto transmit = this->transmitter_->transmit();
|
||||
auto data = transmit.get_data();
|
||||
|
||||
data->set_carrier_frequency(FUJITSU_GENERAL_CARRIER_FREQUENCY);
|
||||
|
||||
// Header
|
||||
data->mark(FUJITSU_GENERAL_HEADER_MARK);
|
||||
data->space(FUJITSU_GENERAL_HEADER_SPACE);
|
||||
|
||||
// Data
|
||||
for (uint8_t i : remote_state) {
|
||||
// Send all Bits from Byte Data in Reverse Order
|
||||
for (uint8_t mask = 00000001; mask > 0; mask <<= 1) { // iterate through bit mask
|
||||
data->mark(FUJITSU_GENERAL_BIT_MARK);
|
||||
bool bit = i & mask;
|
||||
data->space(bit ? FUJITSU_GENERAL_ONE_SPACE : FUJITSU_GENERAL_ZERO_SPACE);
|
||||
// Next bits
|
||||
}
|
||||
}
|
||||
// Footer
|
||||
data->mark(FUJITSU_GENERAL_TRL_MARK);
|
||||
data->space(FUJITSU_GENERAL_TRL_SPACE);
|
||||
|
||||
transmit.perform();
|
||||
|
||||
this->power_ = false;
|
||||
}
|
||||
|
||||
} // namespace fujitsu_general
|
||||
} // namespace esphome
|
||||
24
esphome/components/fujitsu_general/fujitsu_general.h
Normal file
24
esphome/components/fujitsu_general/fujitsu_general.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/components/climate_ir/climate_ir.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace fujitsu_general {
|
||||
|
||||
class FujitsuGeneralClimate : public climate_ir::ClimateIR {
|
||||
public:
|
||||
FujitsuGeneralClimate();
|
||||
|
||||
protected:
|
||||
/// Transmit via IR the state of this climate controller.
|
||||
void transmit_state() override;
|
||||
/// Transmit via IR power off command.
|
||||
void transmit_off_();
|
||||
|
||||
bool power_{false};
|
||||
};
|
||||
|
||||
} // namespace fujitsu_general
|
||||
} // namespace esphome
|
||||
@@ -30,6 +30,8 @@ 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;
|
||||
|
||||
@@ -41,3 +41,4 @@ def register_modbus_device(var, config):
|
||||
parent = yield cg.get_variable(config[CONF_MODBUS_ID])
|
||||
cg.add(var.set_parent(parent))
|
||||
cg.add(var.set_address(config[CONF_ADDRESS]))
|
||||
cg.add(parent.register_device(var))
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -394,7 +394,7 @@ class Nextion : public PollingComponent, public uart::UARTDevice {
|
||||
bool wait_for_ack_{true};
|
||||
};
|
||||
|
||||
class NextionTouchComponent : public binary_sensor::BinarySensor {
|
||||
class NextionTouchComponent : public binary_sensor::BinarySensorInitiallyOff {
|
||||
public:
|
||||
void set_page_id(uint8_t page_id) { page_id_ = page_id; }
|
||||
void set_component_id(uint8_t component_id) { component_id_ = component_id; }
|
||||
|
||||
@@ -11,7 +11,6 @@ pcf8574_ns = cg.esphome_ns.namespace('pcf8574')
|
||||
PCF8574GPIOMode = pcf8574_ns.enum('PCF8574GPIOMode')
|
||||
PCF8674_GPIO_MODES = {
|
||||
'INPUT': PCF8574GPIOMode.PCF8574_INPUT,
|
||||
'INPUT_PULLUP': PCF8574GPIOMode.PCF8574_INPUT_PULLUP,
|
||||
'OUTPUT': PCF8574GPIOMode.PCF8574_OUTPUT,
|
||||
}
|
||||
|
||||
@@ -33,16 +32,24 @@ def to_code(config):
|
||||
cg.add(var.set_pcf8575(config[CONF_PCF8575]))
|
||||
|
||||
|
||||
def validate_pcf8574_gpio_mode(value):
|
||||
value = cv.string(value)
|
||||
if value.upper() == 'INPUT_PULLUP':
|
||||
raise cv.Invalid("INPUT_PULLUP mode has been removed in 1.14 and been combined into "
|
||||
"INPUT mode (they were the same thing). Please use INPUT instead.")
|
||||
return cv.enum(PCF8674_GPIO_MODES, upper=True)(value)
|
||||
|
||||
|
||||
PCF8574_OUTPUT_PIN_SCHEMA = cv.Schema({
|
||||
cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="OUTPUT"): cv.enum(PCF8674_GPIO_MODES, upper=True),
|
||||
cv.Optional(CONF_MODE, default="OUTPUT"): validate_pcf8574_gpio_mode,
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
})
|
||||
PCF8574_INPUT_PIN_SCHEMA = cv.Schema({
|
||||
cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component),
|
||||
cv.Required(CONF_NUMBER): cv.int_,
|
||||
cv.Optional(CONF_MODE, default="INPUT"): cv.enum(PCF8674_GPIO_MODES, upper=True),
|
||||
cv.Optional(CONF_MODE, default="INPUT"): validate_pcf8574_gpio_mode,
|
||||
cv.Optional(CONF_INVERTED, default=False): cv.boolean,
|
||||
})
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ bool PCF8574Component::digital_read(uint8_t pin) {
|
||||
}
|
||||
void PCF8574Component::digital_write(uint8_t pin, bool value) {
|
||||
if (value) {
|
||||
this->port_mask_ |= (1 << pin);
|
||||
this->output_mask_ |= (1 << pin);
|
||||
} else {
|
||||
this->port_mask_ &= ~(1 << pin);
|
||||
this->output_mask_ &= ~(1 << pin);
|
||||
}
|
||||
|
||||
this->write_gpio_();
|
||||
@@ -41,16 +41,14 @@ void PCF8574Component::digital_write(uint8_t pin, bool value) {
|
||||
void PCF8574Component::pin_mode(uint8_t pin, uint8_t mode) {
|
||||
switch (mode) {
|
||||
case PCF8574_INPUT:
|
||||
this->ddr_mask_ &= ~(1 << pin);
|
||||
this->port_mask_ &= ~(1 << pin);
|
||||
break;
|
||||
case PCF8574_INPUT_PULLUP:
|
||||
this->ddr_mask_ &= ~(1 << pin);
|
||||
this->port_mask_ |= (1 << pin);
|
||||
// Clear mode mask bit
|
||||
this->mode_mask_ &= ~(1 << pin);
|
||||
// Write GPIO to enable input mode
|
||||
this->write_gpio_();
|
||||
break;
|
||||
case PCF8574_OUTPUT:
|
||||
this->ddr_mask_ |= (1 << pin);
|
||||
this->port_mask_ &= ~(1 << pin);
|
||||
// Set mode mask bit
|
||||
this->mode_mask_ |= 1 << pin;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -59,21 +57,20 @@ void PCF8574Component::pin_mode(uint8_t pin, uint8_t mode) {
|
||||
bool PCF8574Component::read_gpio_() {
|
||||
if (this->is_failed())
|
||||
return false;
|
||||
|
||||
bool success;
|
||||
uint8_t data[2];
|
||||
if (this->pcf8575_) {
|
||||
if (!this->parent_->raw_receive_16(this->address_, &this->input_mask_, 1)) {
|
||||
this->status_set_warning();
|
||||
return false;
|
||||
}
|
||||
success = this->read_bytes_raw(data, 2);
|
||||
this->input_mask_ = (uint16_t(data[1]) << 8) | (uint16_t(data[0]) << 0);
|
||||
} else {
|
||||
uint8_t data;
|
||||
if (!this->parent_->raw_receive(this->address_, &data, 1)) {
|
||||
this->status_set_warning();
|
||||
return false;
|
||||
}
|
||||
this->input_mask_ = data;
|
||||
success = this->read_bytes_raw(data, 1);
|
||||
this->input_mask_ = data[0];
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
this->status_set_warning();
|
||||
return false;
|
||||
}
|
||||
this->status_clear_warning();
|
||||
return true;
|
||||
}
|
||||
@@ -81,20 +78,20 @@ bool PCF8574Component::write_gpio_() {
|
||||
if (this->is_failed())
|
||||
return false;
|
||||
|
||||
uint16_t value = (this->input_mask_ & ~this->ddr_mask_) | this->port_mask_;
|
||||
uint16_t value = 0;
|
||||
// Pins in OUTPUT mode and where pin is HIGH.
|
||||
value |= this->mode_mask_ & this->output_mask_;
|
||||
// Pins in INPUT mode must also be set here
|
||||
value |= ~this->mode_mask_;
|
||||
|
||||
this->parent_->raw_begin_transmission(this->address_);
|
||||
uint8_t data = value & 0xFF;
|
||||
this->parent_->raw_write(this->address_, &data, 1);
|
||||
|
||||
if (this->pcf8575_) {
|
||||
data = (value >> 8) & 0xFF;
|
||||
this->parent_->raw_write(this->address_, &data, 1);
|
||||
}
|
||||
if (!this->parent_->raw_end_transmission(this->address_)) {
|
||||
uint8_t data[2];
|
||||
data[0] = value;
|
||||
data[1] = value >> 8;
|
||||
if (!this->write_bytes_raw(data, this->pcf8575_ ? 2 : 1)) {
|
||||
this->status_set_warning();
|
||||
return false;
|
||||
}
|
||||
|
||||
this->status_clear_warning();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace pcf8574 {
|
||||
/// Modes for PCF8574 pins
|
||||
enum PCF8574GPIOMode : uint8_t {
|
||||
PCF8574_INPUT = INPUT,
|
||||
PCF8574_INPUT_PULLUP = INPUT_PULLUP,
|
||||
PCF8574_OUTPUT = OUTPUT,
|
||||
};
|
||||
|
||||
@@ -38,9 +37,12 @@ class PCF8574Component : public Component, public i2c::I2CDevice {
|
||||
|
||||
bool write_gpio_();
|
||||
|
||||
uint16_t ddr_mask_{0x00};
|
||||
/// Mask for the pin mode - 1 means output, 0 means input
|
||||
uint16_t mode_mask_{0x00};
|
||||
/// The mask to write as output state - 1 means HIGH, 0 means LOW
|
||||
uint16_t output_mask_{0x00};
|
||||
/// The state read in read_gpio_ - 1 means HIGH, 0 means LOW
|
||||
uint16_t input_mask_{0x00};
|
||||
uint16_t port_mask_{0x00};
|
||||
bool pcf8575_; ///< TRUE->16-channel PCF8575, FALSE->8-channel PCF8574
|
||||
};
|
||||
|
||||
|
||||
@@ -149,6 +149,7 @@ void PulseCounterSensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Rising Edge: %s", EDGE_MODE_TO_STRING[this->storage_.rising_edge_mode]);
|
||||
ESP_LOGCONFIG(TAG, " Falling Edge: %s", EDGE_MODE_TO_STRING[this->storage_.falling_edge_mode]);
|
||||
ESP_LOGCONFIG(TAG, " Filtering pulses shorter than %u µs", this->storage_.filter_us);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void PulseCounterSensor::update() {
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class RDM6300Component : public Component, public uart::UARTDevice {
|
||||
uint32_t last_id_{0};
|
||||
};
|
||||
|
||||
class RDM6300BinarySensor : public binary_sensor::BinarySensor {
|
||||
class RDM6300BinarySensor : public binary_sensor::BinarySensorInitiallyOff {
|
||||
public:
|
||||
void set_id(uint32_t id) { id_ = id; }
|
||||
|
||||
|
||||
@@ -267,11 +267,11 @@ class RemoteReceiverBase : public RemoteComponentBase {
|
||||
uint8_t tolerance_{25};
|
||||
};
|
||||
|
||||
class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensor,
|
||||
class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitiallyOff,
|
||||
public Component,
|
||||
public RemoteReceiverListener {
|
||||
public:
|
||||
explicit RemoteReceiverBinarySensorBase() : BinarySensor() {}
|
||||
explicit RemoteReceiverBinarySensorBase() : BinarySensorInitiallyOff() {}
|
||||
void dump_config() override;
|
||||
virtual bool matches(RemoteReceiveData src) = 0;
|
||||
bool on_receive(RemoteReceiveData src) override {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -4,7 +4,7 @@ from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
from esphome.components.output import FloatOutput
|
||||
from esphome.const import CONF_ID, CONF_IDLE_LEVEL, CONF_MAX_LEVEL, CONF_MIN_LEVEL, CONF_OUTPUT, \
|
||||
CONF_LEVEL
|
||||
CONF_LEVEL, CONF_RESTORE
|
||||
|
||||
servo_ns = cg.esphome_ns.namespace('servo')
|
||||
Servo = servo_ns.class_('Servo', cg.Component)
|
||||
@@ -18,6 +18,7 @@ CONFIG_SCHEMA = cv.Schema({
|
||||
cv.Optional(CONF_MIN_LEVEL, default='3%'): cv.percentage,
|
||||
cv.Optional(CONF_IDLE_LEVEL, default='7.5%'): cv.percentage,
|
||||
cv.Optional(CONF_MAX_LEVEL, default='12%'): cv.percentage,
|
||||
cv.Optional(CONF_RESTORE, default=False): cv.boolean,
|
||||
}).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
@@ -30,6 +31,7 @@ def to_code(config):
|
||||
cg.add(var.set_min_level(config[CONF_MIN_LEVEL]))
|
||||
cg.add(var.set_idle_level(config[CONF_IDLE_LEVEL]))
|
||||
cg.add(var.set_max_level(config[CONF_MAX_LEVEL]))
|
||||
cg.add(var.set_restore(config[CONF_RESTORE]))
|
||||
|
||||
|
||||
@automation.register_action('servo.write', ServoWriteAction, cv.Schema({
|
||||
|
||||
@@ -47,6 +47,7 @@ class Servo : public Component {
|
||||
void set_min_level(float min_level) { min_level_ = min_level; }
|
||||
void set_idle_level(float idle_level) { idle_level_ = idle_level; }
|
||||
void set_max_level(float max_level) { max_level_ = max_level; }
|
||||
void set_restore(bool restore) { restore_ = restore; }
|
||||
|
||||
protected:
|
||||
void save_level_(float v) { this->rtc_.save(&v); }
|
||||
|
||||
@@ -29,4 +29,4 @@ def to_code(config):
|
||||
|
||||
if CONF_OSCILLATION_OUTPUT in config:
|
||||
oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
|
||||
cg.add(var.set_oscillation(oscillation_output))
|
||||
cg.add(var.set_oscillating(oscillation_output))
|
||||
|
||||
@@ -30,7 +30,7 @@ void StatusBinarySensor::loop() {
|
||||
|
||||
this->publish_state(status);
|
||||
}
|
||||
void StatusBinarySensor::setup() { this->publish_state(false); }
|
||||
void StatusBinarySensor::setup() { this->publish_initial_state(false); }
|
||||
void StatusBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Status Binary Sensor", this); }
|
||||
|
||||
} // namespace status
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,37 +1,18 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate, remote_transmitter, remote_receiver, sensor
|
||||
from esphome.components.remote_base import CONF_TRANSMITTER_ID, CONF_RECEIVER_ID
|
||||
from esphome.const import CONF_ID, CONF_SENSOR, CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT
|
||||
from esphome.components import climate_ir
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
AUTO_LOAD = ['sensor', 'climate_ir']
|
||||
AUTO_LOAD = ['climate_ir']
|
||||
|
||||
tcl112_ns = cg.esphome_ns.namespace('tcl112')
|
||||
Tcl112Climate = tcl112_ns.class_('Tcl112Climate', climate.Climate, cg.Component)
|
||||
Tcl112Climate = tcl112_ns.class_('Tcl112Climate', climate_ir.ClimateIR)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(climate.CLIMATE_SCHEMA.extend({
|
||||
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_id(Tcl112Climate),
|
||||
cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(remote_transmitter.RemoteTransmitterComponent),
|
||||
cv.Optional(CONF_RECEIVER_ID): cv.use_id(remote_receiver.RemoteReceiverComponent),
|
||||
cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
|
||||
cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
||||
}).extend(cv.COMPONENT_SCHEMA))
|
||||
})
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
yield cg.register_component(var, config)
|
||||
yield climate.register_climate(var, config)
|
||||
|
||||
cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL]))
|
||||
cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT]))
|
||||
if CONF_SENSOR in config:
|
||||
sens = yield cg.get_variable(config[CONF_SENSOR])
|
||||
cg.add(var.set_sensor(sens))
|
||||
if CONF_RECEIVER_ID in config:
|
||||
receiver = yield cg.get_variable(config[CONF_RECEIVER_ID])
|
||||
cg.add(receiver.register_listener(var))
|
||||
|
||||
transmitter = yield cg.get_variable(config[CONF_TRANSMITTER_ID])
|
||||
cg.add(var.set_transmitter(transmitter))
|
||||
yield climate_ir.register_climate_ir(var, config)
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace tcl112 {
|
||||
const float TCL112_TEMP_MAX = 31.0;
|
||||
const float TCL112_TEMP_MIN = 16.0;
|
||||
|
||||
class Tcl112Climate : public climate::ClimateIR {
|
||||
class Tcl112Climate : public climate_ir::ClimateIR {
|
||||
public:
|
||||
Tcl112Climate() : climate::ClimateIR(TCL112_TEMP_MIN, TCL112_TEMP_MAX, .5f) {}
|
||||
Tcl112Climate() : climate_ir::ClimateIR(TCL112_TEMP_MIN, TCL112_TEMP_MAX, .5f) {}
|
||||
|
||||
protected:
|
||||
/// Transmit via IR the state of this climate controller.
|
||||
|
||||
@@ -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,6 +39,11 @@ void Tuya::dump_config() {
|
||||
else
|
||||
ESP_LOGCONFIG(TAG, " Datapoint %d: unknown", info.id);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -86,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
|
||||
@@ -102,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");
|
||||
@@ -144,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);
|
||||
}
|
||||
@@ -211,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
|
||||
@@ -224,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);
|
||||
|
||||
@@ -275,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)
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
#include "esphome/components/logger/logger.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace uart {
|
||||
@@ -41,6 +46,7 @@ void UARTComponent::dump_config() {
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_);
|
||||
ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
|
||||
this->check_logger_conflict_();
|
||||
}
|
||||
|
||||
void UARTComponent::write_byte(uint8_t data) {
|
||||
@@ -145,6 +151,7 @@ void UARTComponent::dump_config() {
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, " Using software serial");
|
||||
}
|
||||
this->check_logger_conflict_();
|
||||
}
|
||||
|
||||
void UARTComponent::write_byte(uint8_t data) {
|
||||
@@ -360,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 "
|
||||
@@ -416,11 +414,15 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, UrlMatch ma
|
||||
if (request->hasParam("color_temp"))
|
||||
call.set_color_temperature(request->getParam("color_temp")->value().toFloat());
|
||||
|
||||
if (request->hasParam("flash"))
|
||||
call.set_flash_length((uint32_t) request->getParam("flash")->value().toFloat() * 1000);
|
||||
if (request->hasParam("flash")) {
|
||||
float length_s = request->getParam("flash")->value().toFloat();
|
||||
call.set_flash_length(static_cast<uint32_t>(length_s * 1000));
|
||||
}
|
||||
|
||||
if (request->hasParam("transition"))
|
||||
call.set_transition_length((uint32_t) request->getParam("transition")->value().toFloat() * 1000);
|
||||
if (request->hasParam("transition")) {
|
||||
float length_s = request->getParam("transition")->value().toFloat();
|
||||
call.set_transition_length(static_cast<uint32_t>(length_s * 1000));
|
||||
}
|
||||
|
||||
if (request->hasParam("effect")) {
|
||||
const char *effect = request->getParam("effect")->value().c_str();
|
||||
|
||||
@@ -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,28 +394,15 @@ 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;
|
||||
|
||||
// Clear saved STA config
|
||||
station_config default_config{};
|
||||
wifi_station_get_config_default(&default_config);
|
||||
bool is_zero = default_config.ssid[0] == '\0' && default_config.password[0] == '\0' && default_config.bssid[0] == 0 &&
|
||||
default_config.bssid_set == 0;
|
||||
if (!is_zero) {
|
||||
ESP_LOGV(TAG, "Clearing default wifi STA config");
|
||||
|
||||
memset(&default_config, 0, sizeof(default_config));
|
||||
ETS_UART_INTR_DISABLE();
|
||||
bool ret = wifi_station_set_config(&default_config);
|
||||
ETS_UART_INTR_ENABLE();
|
||||
|
||||
if (!ret) {
|
||||
ESP_LOGW(TAG, "Clearing default wif STA config failed!");
|
||||
}
|
||||
}
|
||||
|
||||
bool ret1, ret2;
|
||||
ETS_UART_INTR_DISABLE();
|
||||
ret1 = wifi_station_set_auto_connect(0);
|
||||
@@ -428,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);
|
||||
@@ -496,11 +474,14 @@ bool WiFiComponent::wifi_scan_start_() {
|
||||
return ret;
|
||||
}
|
||||
bool WiFiComponent::wifi_disconnect_() {
|
||||
bool ret = true;
|
||||
// Only call disconnect if interface is up
|
||||
if (wifi_get_opmode() & WIFI_STA)
|
||||
ret = wifi_station_disconnect();
|
||||
station_config conf{};
|
||||
memset(&conf, 0, sizeof(conf));
|
||||
ETS_UART_INTR_DISABLE();
|
||||
wifi_station_set_config(&conf);
|
||||
bool ret = wifi_station_disconnect();
|
||||
wifi_station_set_config_current(&conf);
|
||||
ETS_UART_INTR_ENABLE();
|
||||
return ret;
|
||||
}
|
||||
@@ -594,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;
|
||||
|
||||
|
||||
@@ -91,17 +91,6 @@ optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d
|
||||
return {};
|
||||
}
|
||||
|
||||
uint8_t raw_offset = is_lywsdcgq || is_cgg1 ? 11 : 12;
|
||||
|
||||
const uint8_t raw_type = raw[raw_offset];
|
||||
const uint8_t data_length = raw[raw_offset + 2];
|
||||
const uint8_t *data = &raw[raw_offset + 3];
|
||||
const uint8_t expected_length = data_length + raw_offset + 3;
|
||||
const uint8_t actual_length = device.get_service_data().size();
|
||||
if (expected_length != actual_length) {
|
||||
// ESP_LOGV(TAG, "Xiaomi %s data length mismatch (%u != %d)", type, expected_length, actual_length);
|
||||
return {};
|
||||
}
|
||||
XiaomiParseResult result;
|
||||
result.type = XiaomiParseResult::TYPE_HHCCJCY01;
|
||||
if (is_lywsdcgq) {
|
||||
@@ -111,7 +100,42 @@ optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d
|
||||
} else if (is_cgg1) {
|
||||
result.type = XiaomiParseResult::TYPE_CGG1;
|
||||
}
|
||||
bool success = parse_xiaomi_data_byte(raw_type, data, data_length, result);
|
||||
|
||||
uint8_t raw_offset = is_lywsdcgq || is_cgg1 ? 11 : 12;
|
||||
|
||||
// Data point specs
|
||||
// Byte 0: type
|
||||
// Byte 1: fixed 0x10
|
||||
// Byte 2: length
|
||||
// Byte 3..3+len-1: data point value
|
||||
|
||||
const uint8_t *raw_data = &raw[raw_offset];
|
||||
uint8_t data_offset = 0;
|
||||
uint8_t data_length = device.get_service_data().size() - raw_offset;
|
||||
bool success = false;
|
||||
|
||||
while (true) {
|
||||
if (data_length < 4)
|
||||
// at least 4 bytes required
|
||||
// type, fixed 0x10, length, 1 byte value
|
||||
break;
|
||||
|
||||
const uint8_t datapoint_type = raw_data[data_offset + 0];
|
||||
const uint8_t datapoint_length = raw_data[data_offset + 2];
|
||||
|
||||
if (data_length < 3 + datapoint_length)
|
||||
// 3 fixed bytes plus value length
|
||||
break;
|
||||
|
||||
const uint8_t *datapoint_data = &raw_data[data_offset + 3];
|
||||
|
||||
if (parse_xiaomi_data_byte(datapoint_type, datapoint_data, datapoint_length, result))
|
||||
success = true;
|
||||
|
||||
data_length -= data_offset + 3 + datapoint_length;
|
||||
data_offset += 3 + datapoint_length;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
return {};
|
||||
return result;
|
||||
|
||||
@@ -461,6 +461,8 @@ def time_period_str_unit(value):
|
||||
if isinstance(value, int):
|
||||
raise Invalid("Don't know what '{0}' means as it has no time *unit*! Did you mean "
|
||||
"'{0}s'?".format(value))
|
||||
if isinstance(value, TimePeriod):
|
||||
value = str(value)
|
||||
if not isinstance(value, string_types):
|
||||
raise Invalid("Expected string for time period with unit.")
|
||||
|
||||
@@ -614,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 = '0b4'
|
||||
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'
|
||||
|
||||
@@ -97,7 +97,7 @@ void Application::loop() {
|
||||
|
||||
if (this->dump_config_at_ >= 0 && this->dump_config_at_ < this->components_.size()) {
|
||||
if (this->dump_config_at_ == 0) {
|
||||
ESP_LOGI(TAG, "esphome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
|
||||
ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", this->compilation_time_.c_str());
|
||||
}
|
||||
|
||||
this->components_[this->dump_config_at_]->dump_config();
|
||||
|
||||
@@ -9,6 +9,9 @@ static const char *TAG = "scheduler";
|
||||
|
||||
static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
|
||||
|
||||
// Uncomment to debug scheduler
|
||||
// #define ESPHOME_DEBUG_SCHEDULER
|
||||
|
||||
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout,
|
||||
std::function<void()> &&func) {
|
||||
const uint32_t now = this->millis_();
|
||||
@@ -21,7 +24,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
|
||||
|
||||
ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%u)", name.c_str(), timeout);
|
||||
|
||||
auto *item = new SchedulerItem();
|
||||
auto item = make_unique<SchedulerItem>();
|
||||
item->component = component;
|
||||
item->name = name;
|
||||
item->type = SchedulerItem::TIMEOUT;
|
||||
@@ -30,7 +33,7 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
|
||||
item->last_execution_major = this->millis_major_;
|
||||
item->f = std::move(func);
|
||||
item->remove = false;
|
||||
this->push_(item);
|
||||
this->push_(std::move(item));
|
||||
}
|
||||
bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
|
||||
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
|
||||
@@ -52,7 +55,7 @@ void HOT Scheduler::set_interval(Component *component, const std::string &name,
|
||||
|
||||
ESP_LOGVV(TAG, "set_interval(name='%s', interval=%u, offset=%u)", name.c_str(), interval, offset);
|
||||
|
||||
auto *item = new SchedulerItem();
|
||||
auto item = make_unique<SchedulerItem>();
|
||||
item->component = component;
|
||||
item->name = name;
|
||||
item->type = SchedulerItem::INTERVAL;
|
||||
@@ -63,7 +66,7 @@ void HOT Scheduler::set_interval(Component *component, const std::string &name,
|
||||
item->last_execution_major--;
|
||||
item->f = std::move(func);
|
||||
item->remove = false;
|
||||
this->push_(item);
|
||||
this->push_(std::move(item));
|
||||
}
|
||||
bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
|
||||
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
|
||||
@@ -71,7 +74,7 @@ bool HOT Scheduler::cancel_interval(Component *component, const std::string &nam
|
||||
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
||||
if (this->empty_())
|
||||
return {};
|
||||
auto *item = this->items_[0];
|
||||
auto &item = this->items_[0];
|
||||
const uint32_t now = this->millis_();
|
||||
uint32_t next_time = item->last_execution + item->interval;
|
||||
if (next_time < now)
|
||||
@@ -82,98 +85,103 @@ void ICACHE_RAM_ATTR HOT Scheduler::call() {
|
||||
const uint32_t now = this->millis_();
|
||||
this->process_to_add();
|
||||
|
||||
// Uncomment for debugging the scheduler:
|
||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||
static uint32_t last_print = 0;
|
||||
|
||||
// if (random_uint32() % 400 == 0) {
|
||||
// std::vector<SchedulerItem *> old_items = this->items_;
|
||||
// ESP_LOGVV(TAG, "Items: count=%u, now=%u", this->items_.size(), now);
|
||||
// while (!this->empty_()) {
|
||||
// auto *item = this->items_[0];
|
||||
// const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
// ESP_LOGVV(TAG, " %s '%s' interval=%u last_execution=%u (%u) next=%u",
|
||||
// type, item->name.c_str(), item->interval, item->last_execution, item->last_execution_major,
|
||||
// item->last_execution + item->interval);
|
||||
// this->pop_raw_();
|
||||
// }
|
||||
// ESP_LOGVV(TAG, "\n");
|
||||
// this->items_ = old_items;
|
||||
//}
|
||||
if (now - last_print > 2000) {
|
||||
last_print = now;
|
||||
std::vector<std::unique_ptr<SchedulerItem>> old_items;
|
||||
ESP_LOGVV(TAG, "Items: count=%u, now=%u", this->items_.size(), now);
|
||||
while (!this->empty_()) {
|
||||
auto item = std::move(this->items_[0]);
|
||||
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
ESP_LOGVV(TAG, " %s '%s' interval=%u last_execution=%u (%u) next=%u (%u)", type, item->name.c_str(),
|
||||
item->interval, item->last_execution, item->last_execution_major, item->next_execution(),
|
||||
item->next_execution_major());
|
||||
|
||||
this->pop_raw_();
|
||||
old_items.push_back(std::move(item));
|
||||
}
|
||||
ESP_LOGVV(TAG, "\n");
|
||||
this->items_ = std::move(old_items);
|
||||
}
|
||||
#endif // ESPHOME_DEBUG_SCHEDULER
|
||||
|
||||
while (!this->empty_()) {
|
||||
// Don't copy-by value yet
|
||||
auto *item = this->items_[0];
|
||||
if ((now - item->last_execution) < item->interval)
|
||||
// Not reached timeout yet, done for this call
|
||||
break;
|
||||
uint8_t major = item->last_execution_major;
|
||||
if (item->last_execution > now)
|
||||
major++;
|
||||
if (major != this->millis_major_)
|
||||
break;
|
||||
// use scoping to indicate visibility of `item` variable
|
||||
{
|
||||
// Don't copy-by value yet
|
||||
auto &item = this->items_[0];
|
||||
if ((now - item->last_execution) < item->interval)
|
||||
// Not reached timeout yet, done for this call
|
||||
break;
|
||||
uint8_t major = item->next_execution_major();
|
||||
if (this->millis_major_ - major > 1)
|
||||
break;
|
||||
|
||||
// Don't run on failed components
|
||||
if (item->component != nullptr && item->component->is_failed()) {
|
||||
this->pop_raw_();
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
// Don't run on failed components
|
||||
if (item->component != nullptr && item->component->is_failed()) {
|
||||
this->pop_raw_();
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item->name.c_str(),
|
||||
item->interval, item->last_execution, now);
|
||||
const char *type = item->type == SchedulerItem::INTERVAL ? "interval" : "timeout";
|
||||
ESP_LOGVV(TAG, "Running %s '%s' with interval=%u last_execution=%u (now=%u)", type, item->name.c_str(),
|
||||
item->interval, item->last_execution, now);
|
||||
#endif
|
||||
|
||||
// Warning: During f(), a lot of stuff can happen, including:
|
||||
// - timeouts/intervals get added, potentially invalidating vector pointers
|
||||
// - timeouts/intervals get cancelled
|
||||
item->f();
|
||||
|
||||
// Only pop after function call, this ensures we were reachable
|
||||
// during the function call and know if we were cancelled.
|
||||
this->pop_raw_();
|
||||
|
||||
if (item->remove) {
|
||||
// We were removed/cancelled in the function call, stop
|
||||
delete item;
|
||||
continue;
|
||||
// Warning: During f(), a lot of stuff can happen, including:
|
||||
// - timeouts/intervals get added, potentially invalidating vector pointers
|
||||
// - timeouts/intervals get cancelled
|
||||
item->f();
|
||||
}
|
||||
|
||||
if (item->type == SchedulerItem::INTERVAL) {
|
||||
if (item->interval != 0) {
|
||||
const uint32_t before = item->last_execution;
|
||||
const uint32_t amount = (now - item->last_execution) / item->interval;
|
||||
item->last_execution += amount * item->interval;
|
||||
if (item->last_execution < before)
|
||||
item->last_execution_major++;
|
||||
{
|
||||
// new scope, item from before might have been moved in the vector
|
||||
auto item = std::move(this->items_[0]);
|
||||
|
||||
// Only pop after function call, this ensures we were reachable
|
||||
// during the function call and know if we were cancelled.
|
||||
this->pop_raw_();
|
||||
|
||||
if (item->remove) {
|
||||
// We were removed/cancelled in the function call, stop
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->type == SchedulerItem::INTERVAL) {
|
||||
if (item->interval != 0) {
|
||||
const uint32_t before = item->last_execution;
|
||||
const uint32_t amount = (now - item->last_execution) / item->interval;
|
||||
item->last_execution += amount * item->interval;
|
||||
if (item->last_execution < before)
|
||||
item->last_execution_major++;
|
||||
}
|
||||
this->push_(std::move(item));
|
||||
}
|
||||
this->push_(item);
|
||||
} else {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
this->process_to_add();
|
||||
}
|
||||
void HOT Scheduler::process_to_add() {
|
||||
for (auto *it : this->to_add_) {
|
||||
for (auto &it : this->to_add_) {
|
||||
if (it->remove) {
|
||||
delete it;
|
||||
continue;
|
||||
}
|
||||
|
||||
this->items_.push_back(it);
|
||||
this->items_.push_back(std::move(it));
|
||||
std::push_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
||||
}
|
||||
this->to_add_.clear();
|
||||
}
|
||||
void HOT Scheduler::cleanup_() {
|
||||
while (!this->items_.empty()) {
|
||||
auto item = this->items_[0];
|
||||
auto &item = this->items_[0];
|
||||
if (!item->remove)
|
||||
return;
|
||||
|
||||
delete item;
|
||||
this->pop_raw_();
|
||||
}
|
||||
}
|
||||
@@ -181,15 +189,15 @@ void HOT Scheduler::pop_raw_() {
|
||||
std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
||||
this->items_.pop_back();
|
||||
}
|
||||
void HOT Scheduler::push_(Scheduler::SchedulerItem *item) { this->to_add_.push_back(item); }
|
||||
void HOT Scheduler::push_(std::unique_ptr<Scheduler::SchedulerItem> item) { this->to_add_.push_back(std::move(item)); }
|
||||
bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, Scheduler::SchedulerItem::Type type) {
|
||||
bool ret = false;
|
||||
for (auto *it : this->items_)
|
||||
for (auto &it : this->items_)
|
||||
if (it->component == component && it->name == name && it->type == type) {
|
||||
it->remove = true;
|
||||
ret = true;
|
||||
}
|
||||
for (auto *it : this->to_add_)
|
||||
for (auto &it : this->to_add_)
|
||||
if (it->component == component && it->name == name && it->type == type) {
|
||||
it->remove = true;
|
||||
ret = true;
|
||||
@@ -203,24 +211,34 @@ uint32_t Scheduler::millis_() {
|
||||
ESP_LOGD(TAG, "Incrementing scheduler major");
|
||||
this->millis_major_++;
|
||||
}
|
||||
this->last_millis_ = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
bool HOT Scheduler::SchedulerItem::cmp(Scheduler::SchedulerItem *a, Scheduler::SchedulerItem *b) {
|
||||
bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a,
|
||||
const std::unique_ptr<SchedulerItem> &b) {
|
||||
// min-heap
|
||||
// return true if *a* will happen after *b*
|
||||
uint32_t a_next_exec = a->last_execution + a->timeout;
|
||||
uint8_t a_next_exec_major = a->last_execution_major;
|
||||
if (a_next_exec < a->last_execution)
|
||||
a_next_exec_major++;
|
||||
|
||||
uint32_t b_next_exec = b->last_execution + b->timeout;
|
||||
uint8_t b_next_exec_major = b->last_execution_major;
|
||||
if (b_next_exec < b->last_execution)
|
||||
b_next_exec_major++;
|
||||
uint32_t a_next_exec = a->next_execution();
|
||||
uint8_t a_next_exec_major = a->next_execution_major();
|
||||
uint32_t b_next_exec = b->next_execution();
|
||||
uint8_t b_next_exec_major = b->next_execution_major();
|
||||
|
||||
if (a_next_exec_major != b_next_exec_major) {
|
||||
return a_next_exec_major > b_next_exec_major;
|
||||
// The "major" calculation is quite complicated.
|
||||
// Basically, we need to check if the major value lies in the future or
|
||||
//
|
||||
|
||||
// Here are some cases to think about:
|
||||
// Format: a_major,b_major -> expected result (a-b, b-a)
|
||||
// a=255,b=0 -> false (255, 1)
|
||||
// a=0,b=1 -> false (255, 1)
|
||||
// a=1,b=0 -> true (1, 255)
|
||||
// a=0,b=255 -> true (1, 255)
|
||||
|
||||
uint8_t diff1 = a_next_exec_major - b_next_exec_major;
|
||||
uint8_t diff2 = b_next_exec_major - a_next_exec_major;
|
||||
return diff1 < diff2;
|
||||
}
|
||||
|
||||
return a_next_exec > b_next_exec;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
@@ -34,21 +35,30 @@ class Scheduler {
|
||||
bool remove;
|
||||
uint8_t last_execution_major;
|
||||
|
||||
static bool cmp(SchedulerItem *a, SchedulerItem *b);
|
||||
inline uint32_t next_execution() { return this->last_execution + this->timeout; }
|
||||
inline uint8_t next_execution_major() {
|
||||
uint32_t next_exec = this->next_execution();
|
||||
uint8_t next_exec_major = this->last_execution_major;
|
||||
if (next_exec < this->last_execution)
|
||||
next_exec_major++;
|
||||
return next_exec_major;
|
||||
}
|
||||
|
||||
static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
|
||||
};
|
||||
|
||||
uint32_t millis_();
|
||||
void cleanup_();
|
||||
void pop_raw_();
|
||||
void push_(SchedulerItem *item);
|
||||
void push_(std::unique_ptr<SchedulerItem> item);
|
||||
bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
|
||||
bool empty_() {
|
||||
this->cleanup_();
|
||||
return this->items_.empty();
|
||||
}
|
||||
|
||||
std::vector<SchedulerItem *> items_;
|
||||
std::vector<SchedulerItem *> to_add_;
|
||||
std::vector<std::unique_ptr<SchedulerItem>> items_;
|
||||
std::vector<std::unique_ptr<SchedulerItem>> to_add_;
|
||||
uint32_t last_millis_{0};
|
||||
uint8_t millis_major_{0};
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ import tornado.websocket
|
||||
from esphome import const, util
|
||||
from esphome.__main__ import get_serial_ports
|
||||
from esphome.helpers import mkdir_p, get_bool_env, run_system_command
|
||||
from esphome.py_compat import IS_PY2, decode_text
|
||||
from esphome.py_compat import IS_PY2, decode_text, encode_text
|
||||
from esphome.storage_json import EsphomeStorageJSON, StorageJSON, \
|
||||
esphome_storage_path, ext_storage_path, trash_storage_path
|
||||
from esphome.util import shlex_quote
|
||||
@@ -85,12 +85,11 @@ class DashboardSettings(object):
|
||||
def check_password(self, username, password):
|
||||
if not self.using_auth:
|
||||
return True
|
||||
if username != self.username:
|
||||
return False
|
||||
|
||||
if IS_PY2:
|
||||
password = hmac.new(password).digest()
|
||||
else:
|
||||
password = hmac.new(password.encode()).digest()
|
||||
return username == self.username and hmac.compare_digest(self.password_digest, password)
|
||||
password_digest = hmac.new(encode_text(password)).digest()
|
||||
return hmac.compare_digest(self.password_digest, password_digest)
|
||||
|
||||
def rel_path(self, *args):
|
||||
return os.path.join(self.config_dir, *args)
|
||||
@@ -610,8 +609,8 @@ class LoginHandler(BaseHandler):
|
||||
'X-HASSIO-KEY': os.getenv('HASSIO_TOKEN'),
|
||||
}
|
||||
data = {
|
||||
'username': str(self.get_argument('username', '')),
|
||||
'password': str(self.get_argument('password', ''))
|
||||
'username': decode_text(self.get_argument('username', '')),
|
||||
'password': decode_text(self.get_argument('password', ''))
|
||||
}
|
||||
try:
|
||||
req = requests.post('http://hassio/auth', headers=headers, data=data)
|
||||
@@ -628,8 +627,8 @@ class LoginHandler(BaseHandler):
|
||||
self.render_login_page(error="Invalid username or password")
|
||||
|
||||
def post_native_login(self):
|
||||
username = str(self.get_argument("username", '').encode('utf-8'))
|
||||
password = str(self.get_argument("password", '').encode('utf-8'))
|
||||
username = decode_text(self.get_argument("username", ''))
|
||||
password = decode_text(self.get_argument("password", ''))
|
||||
if settings.check_password(username, password):
|
||||
self.set_secure_cookie("authenticated", cookie_authenticated_yes)
|
||||
self.redirect("/")
|
||||
|
||||
@@ -80,6 +80,9 @@ def run_system_command(*args):
|
||||
|
||||
|
||||
def mkdir_p(path):
|
||||
if not path:
|
||||
# Empty path - means create current dir
|
||||
return
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as err:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -101,12 +101,14 @@ def run_idedata(config):
|
||||
args = ['-t', 'idedata']
|
||||
stdout = run_platformio_cli_run(config, False, *args, capture_stdout=True)
|
||||
stdout = decode_text(stdout)
|
||||
match = re.search(r'{.*}', stdout)
|
||||
match = re.search(r'{\s*".*}', stdout)
|
||||
if match is None:
|
||||
_LOGGER.debug("Could not match IDEData for %s", stdout)
|
||||
return IDEData(None)
|
||||
try:
|
||||
return IDEData(json.loads(match.group()))
|
||||
except ValueError:
|
||||
_LOGGER.debug("Could not load IDEData for %s", stdout, exc_info=1)
|
||||
return IDEData(None)
|
||||
|
||||
|
||||
@@ -165,11 +167,13 @@ ESP8266_EXCEPTION_CODES = {
|
||||
def _decode_pc(config, addr):
|
||||
idedata = get_idedata(config)
|
||||
if not idedata.addr2line_path or not idedata.firmware_elf_path:
|
||||
_LOGGER.debug("decode_pc no addr2line")
|
||||
return
|
||||
command = [idedata.addr2line_path, '-pfiaC', '-e', idedata.firmware_elf_path, addr]
|
||||
try:
|
||||
translation = subprocess.check_output(command).strip()
|
||||
translation = decode_text(subprocess.check_output(command)).strip()
|
||||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.debug("Caught exception for command %s", command, exc_info=1)
|
||||
return
|
||||
|
||||
if "?? ??:0" in translation:
|
||||
|
||||
@@ -7,7 +7,7 @@ import os
|
||||
|
||||
from esphome import const
|
||||
from esphome.core import CORE
|
||||
from esphome.helpers import mkdir_p, write_file_if_changed
|
||||
from esphome.helpers import write_file_if_changed
|
||||
|
||||
# pylint: disable=unused-import, wrong-import-order
|
||||
from esphome.core import CoreType # noqa
|
||||
@@ -88,7 +88,6 @@ class StorageJSON(object):
|
||||
return json.dumps(self.as_dict(), indent=2) + u'\n'
|
||||
|
||||
def save(self, path):
|
||||
mkdir_p(os.path.dirname(path))
|
||||
write_file_if_changed(path, self.to_json())
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -286,8 +286,6 @@ or use the custom_components folder.
|
||||
|
||||
|
||||
def copy_src_tree():
|
||||
import shutil
|
||||
|
||||
source_files = {}
|
||||
for _, component, _ in iter_components(CORE.config):
|
||||
source_files.update(component.source_files)
|
||||
@@ -326,8 +324,7 @@ def copy_src_tree():
|
||||
# Now copy new files
|
||||
for target, src_path in source_files_copy.items():
|
||||
dst_path = CORE.relative_src_path(*target.split('/'))
|
||||
mkdir_p(os.path.dirname(dst_path))
|
||||
shutil.copy(src_path, dst_path)
|
||||
copy_file_if_changed(src_path, dst_path)
|
||||
|
||||
# Finally copy defines
|
||||
write_file_if_changed(CORE.relative_src_path('esphome', 'core', 'defines.h'),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -344,7 +344,7 @@ class UInt32Type(TypeInfo):
|
||||
class EnumType(TypeInfo):
|
||||
@property
|
||||
def cpp_type(self):
|
||||
return "Enum" + self._field.type_name[1:]
|
||||
return f'enums::{self._field.type_name[1:]}'
|
||||
|
||||
@property
|
||||
def decode_varint(self):
|
||||
@@ -497,17 +497,17 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
|
||||
|
||||
def build_enum_type(desc):
|
||||
name = "Enum" + desc.name
|
||||
name = desc.name
|
||||
out = f"enum {name} : uint32_t {{\n"
|
||||
for v in desc.value:
|
||||
out += f' {v.name} = {v.number},\n'
|
||||
out += '};\n'
|
||||
|
||||
cpp = f"template<>\n"
|
||||
cpp += f"const char *proto_enum_to_string<{name}>({name} value) {{\n"
|
||||
cpp += f"const char *proto_enum_to_string<enums::{name}>(enums::{name} value) {{\n"
|
||||
cpp += f" switch (value) {{\n"
|
||||
for v in desc.value:
|
||||
cpp += f' case {v.name}: return "{v.name}";\n'
|
||||
cpp += f' case enums::{v.name}: return "{v.name}";\n'
|
||||
cpp += f' default: return "UNKNOWN";\n'
|
||||
cpp += f' }}\n'
|
||||
cpp += f'}}\n'
|
||||
@@ -636,11 +636,15 @@ namespace api {
|
||||
|
||||
'''
|
||||
|
||||
content += 'namespace enums {\n\n'
|
||||
|
||||
for enum in file.enum_type:
|
||||
s, c = build_enum_type(enum)
|
||||
content += s
|
||||
cpp += c
|
||||
|
||||
content += '\n} // namespace enums\n\n'
|
||||
|
||||
mt = file.message_type
|
||||
|
||||
for m in mt:
|
||||
|
||||
@@ -298,6 +298,19 @@ def lint_relative_py_import(fname):
|
||||
' from . import abc_ns\n\n')
|
||||
|
||||
|
||||
@lint_content_check(include=['esphome/components/*.h', 'esphome/components/*.cpp',
|
||||
'esphome/components/*.tcc'])
|
||||
def lint_namespace(fname, content):
|
||||
expected_name = re.match(r'^esphome/components/([^/]+)/.*',
|
||||
fname.replace(os.path.sep, '/')).group(1)
|
||||
search = 'namespace {}'.format(expected_name)
|
||||
if search in content:
|
||||
return None
|
||||
return 'Invalid namespace found in C++ file. All integration C++ files should put all ' \
|
||||
'functions in a separate namespace that matches the integration\'s name. ' \
|
||||
'Please make sure the file contains {}'.format(highlight(search))
|
||||
|
||||
|
||||
@lint_content_find_check('"esphome.h"', include=cpp_include, exclude=['tests/custom.h'])
|
||||
def lint_esphome_h(fname):
|
||||
return ("File contains reference to 'esphome.h' - This file is "
|
||||
|
||||
2
setup.py
2
setup.py
@@ -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',
|
||||
|
||||
@@ -172,7 +172,7 @@ dallas:
|
||||
|
||||
as3935_spi:
|
||||
cs_pin: GPIO12
|
||||
pin: GPIO13
|
||||
irq_pin: GPIO13
|
||||
|
||||
sensor:
|
||||
- platform: adc
|
||||
|
||||
@@ -54,7 +54,7 @@ deep_sleep:
|
||||
sleep_duration: 50s
|
||||
|
||||
as3935_i2c:
|
||||
pin: GPIO12
|
||||
irq_pin: GPIO12
|
||||
|
||||
|
||||
sensor:
|
||||
|
||||
@@ -620,6 +620,7 @@ light:
|
||||
servo:
|
||||
id: my_servo
|
||||
output: out
|
||||
restore: true
|
||||
|
||||
ttp229_lsf:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user