mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			120 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					51ab0f0b78 | ||
| 
						 | 
					bf0cce4ad8 | ||
| 
						 | 
					60e6366521 | ||
| 
						 | 
					072b2c445c | ||
| 
						 | 
					219fe41831 | ||
| 
						 | 
					dcc8bb83af | ||
| 
						 | 
					a8e3521f3c | ||
| 
						 | 
					706dc6d116 | ||
| 
						 | 
					84accb6df6 | ||
| 
						 | 
					8421570b18 | ||
| 
						 | 
					d355543ac9 | ||
| 
						 | 
					3a597c5aa6 | ||
| 
						 | 
					c7dddaded4 | ||
| 
						 | 
					aae4b2ea5d | ||
| 
						 | 
					310e2a0b20 | ||
| 
						 | 
					0b04d143ac | ||
| 
						 | 
					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 | ||
| 
						 | 
					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
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -114,3 +114,4 @@ config/
 | 
			
		||||
tests/build/
 | 
			
		||||
tests/.esphome/
 | 
			
		||||
/.temp-clang-tidy.cpp
 | 
			
		||||
/.idea/
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
variables:
 | 
			
		||||
  DOCKER_DRIVER: overlay2
 | 
			
		||||
  DOCKER_HOST: tcp://docker:2375/
 | 
			
		||||
  BASE_VERSION: '2.0.1'
 | 
			
		||||
  BASE_VERSION: '2.1.1'
 | 
			
		||||
  TZ: UTC
 | 
			
		||||
 | 
			
		||||
stages:
 | 
			
		||||
@@ -33,7 +33,7 @@ stages:
 | 
			
		||||
    - docker info
 | 
			
		||||
    - docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
 | 
			
		||||
  script:
 | 
			
		||||
    - docker run --rm --privileged multiarch/qemu-user-static:4.1.0-1 --reset -p yes
 | 
			
		||||
    - docker run --rm --privileged multiarch/qemu-user-static:5.0.0-2 --reset -p yes
 | 
			
		||||
    - TAG="${CI_COMMIT_TAG#v}"
 | 
			
		||||
    - TAG="${TAG:-${CI_COMMIT_SHA:0:7}}"
 | 
			
		||||
    - echo "Tag ${TAG}"
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
ARG BUILD_FROM=esphome/esphome-base-amd64:2.0.1
 | 
			
		||||
ARG BUILD_FROM=esphome/esphome-base-amd64:2.1.1
 | 
			
		||||
FROM ${BUILD_FROM}
 | 
			
		||||
 | 
			
		||||
COPY . .
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
FROM esphome/esphome-base-amd64:2.0.1
 | 
			
		||||
FROM esphome/esphome-base-amd64:2.1.1
 | 
			
		||||
 | 
			
		||||
RUN \
 | 
			
		||||
    apt-get update \
 | 
			
		||||
 
 | 
			
		||||
@@ -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,8 +165,11 @@ def compile_program(args, config):
 | 
			
		||||
 | 
			
		||||
def upload_using_esptool(config, port):
 | 
			
		||||
    path = CORE.firmware_bin
 | 
			
		||||
    first_baudrate = config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get('upload_speed', 460800)
 | 
			
		||||
 | 
			
		||||
    def run_esptool(baud_rate):
 | 
			
		||||
        cmd = ['esptool.py', '--before', 'default_reset', '--after', 'hard_reset',
 | 
			
		||||
           '--baud', str(config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get('upload_speed', 460800)),
 | 
			
		||||
               '--baud', str(baud_rate),
 | 
			
		||||
               '--chip', 'esp8266', '--port', port, 'write_flash', '0x0', path]
 | 
			
		||||
 | 
			
		||||
        if os.environ.get('ESPHOME_USE_SUBPROCESS') is None:
 | 
			
		||||
@@ -176,6 +179,14 @@ def upload_using_esptool(config, port):
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
    # if upload is to a serial port use platformio, otherwise assume ota
 | 
			
		||||
@@ -371,7 +382,8 @@ def command_update_all(args):
 | 
			
		||||
        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
 | 
			
		||||
@@ -185,6 +190,7 @@ class BinarySensorStateResponse : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
@@ -213,10 +219,10 @@ class ListEntitiesCoverResponse : public ProtoMessage {
 | 
			
		||||
class CoverStateResponse : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  uint32_t key{0};                            // NOLINT
 | 
			
		||||
  EnumLegacyCoverState legacy_state{};     // NOLINT
 | 
			
		||||
  enums::LegacyCoverState legacy_state{};     // NOLINT
 | 
			
		||||
  float position{0.0f};                       // NOLINT
 | 
			
		||||
  float tilt{0.0f};                           // NOLINT
 | 
			
		||||
  EnumCoverOperation current_operation{};  // NOLINT
 | 
			
		||||
  enums::CoverOperation current_operation{};  // NOLINT
 | 
			
		||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
			
		||||
  void dump_to(std::string &out) const override;
 | 
			
		||||
 | 
			
		||||
@@ -228,7 +234,7 @@ class CoverCommandRequest : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  uint32_t key{0};                             // NOLINT
 | 
			
		||||
  bool has_legacy_command{false};              // NOLINT
 | 
			
		||||
  EnumLegacyCoverCommand legacy_command{};  // NOLINT
 | 
			
		||||
  enums::LegacyCoverCommand legacy_command{};  // NOLINT
 | 
			
		||||
  bool has_position{false};                    // NOLINT
 | 
			
		||||
  float position{0.0f};                        // NOLINT
 | 
			
		||||
  bool has_tilt{false};                        // NOLINT
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -377,11 +383,13 @@ class SensorStateResponse : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  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:
 | 
			
		||||
@@ -439,16 +447,18 @@ class TextSensorStateResponse : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  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
 | 
			
		||||
@@ -545,7 +555,7 @@ class GetTimeResponse : public ProtoMessage {
 | 
			
		||||
class ListEntitiesServicesArgument : public ProtoMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  std::string name{};            // NOLINT
 | 
			
		||||
  EnumServiceArgType type{};  // 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,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,9 @@ class ClimateIR : public climate::Climate, public Component, public remote_base:
 | 
			
		||||
  /// Transmit via IR the state of this climate controller.
 | 
			
		||||
  virtual void transmit_state() = 0;
 | 
			
		||||
 | 
			
		||||
  // Dummy implement on_receive so implementation is optional for inheritors
 | 
			
		||||
  bool on_receive(remote_base::RemoteReceiveData data) override { return false; };
 | 
			
		||||
 | 
			
		||||
  bool supports_cool_{true};
 | 
			
		||||
  bool supports_heat_{true};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -32,9 +32,11 @@ void DallasComponent::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up DallasComponent...");
 | 
			
		||||
 | 
			
		||||
  yield();
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  std::vector<uint64_t> raw_sensors = this->one_wire_->search_vec();
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  std::vector<uint64_t> raw_sensors;
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    raw_sensors = this->one_wire_->search_vec();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (auto &address : raw_sensors) {
 | 
			
		||||
    std::string s = uint64_to_string(address);
 | 
			
		||||
@@ -108,8 +110,9 @@ DallasTemperatureSensor *DallasComponent::get_sensor_by_index(uint8_t index, uin
 | 
			
		||||
void DallasComponent::update() {
 | 
			
		||||
  this->status_clear_warning();
 | 
			
		||||
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  bool result;
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    if (!this->one_wire_->reset()) {
 | 
			
		||||
      result = false;
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -117,7 +120,7 @@ void DallasComponent::update() {
 | 
			
		||||
      this->one_wire_->skip();
 | 
			
		||||
      this->one_wire_->write8(DALLAS_COMMAND_START_CONVERSION);
 | 
			
		||||
    }
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!result) {
 | 
			
		||||
    ESP_LOGE(TAG, "Requesting conversion failed");
 | 
			
		||||
@@ -127,9 +130,11 @@ void DallasComponent::update() {
 | 
			
		||||
 | 
			
		||||
  for (auto *sensor : this->sensors_) {
 | 
			
		||||
    this->set_timeout(sensor->get_address_name(), sensor->millis_to_wait_for_conversion(), [this, sensor] {
 | 
			
		||||
      disable_interrupts();
 | 
			
		||||
      bool res = sensor->read_scratch_pad();
 | 
			
		||||
      enable_interrupts();
 | 
			
		||||
      bool res;
 | 
			
		||||
      {
 | 
			
		||||
        InterruptLock lock;
 | 
			
		||||
        res = sensor->read_scratch_pad();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!res) {
 | 
			
		||||
        ESP_LOGW(TAG, "'%s' - Reseting bus for read failed!", sensor->get_name().c_str());
 | 
			
		||||
@@ -170,7 +175,7 @@ const std::string &DallasTemperatureSensor::get_address_name() {
 | 
			
		||||
 | 
			
		||||
  return this->address_name_;
 | 
			
		||||
}
 | 
			
		||||
bool DallasTemperatureSensor::read_scratch_pad() {
 | 
			
		||||
bool ICACHE_RAM_ATTR DallasTemperatureSensor::read_scratch_pad() {
 | 
			
		||||
  ESPOneWire *wire = this->parent_->one_wire_;
 | 
			
		||||
  if (!wire->reset()) {
 | 
			
		||||
    return false;
 | 
			
		||||
@@ -185,9 +190,11 @@ bool DallasTemperatureSensor::read_scratch_pad() {
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
bool DallasTemperatureSensor::setup_sensor() {
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  bool r = this->read_scratch_pad();
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  bool r;
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    r = this->read_scratch_pad();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!r) {
 | 
			
		||||
    ESP_LOGE(TAG, "Reading scratchpad failed: reset");
 | 
			
		||||
@@ -222,7 +229,8 @@ bool DallasTemperatureSensor::setup_sensor() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ESPOneWire *wire = this->parent_->one_wire_;
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    if (wire->reset()) {
 | 
			
		||||
      wire->select(this->address_);
 | 
			
		||||
      wire->write8(DALLAS_COMMAND_WRITE_SCRATCH_PAD);
 | 
			
		||||
@@ -235,7 +243,7 @@ bool DallasTemperatureSensor::setup_sensor() {
 | 
			
		||||
      wire->select(this->address_);
 | 
			
		||||
      wire->write8(0x48);
 | 
			
		||||
    }
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  delay(20);  // allow it to finish operation
 | 
			
		||||
  wire->reset();
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ const int ONE_WIRE_ROM_SEARCH = 0xF0;
 | 
			
		||||
 | 
			
		||||
ESPOneWire::ESPOneWire(GPIOPin *pin) : pin_(pin) {}
 | 
			
		||||
 | 
			
		||||
bool HOT ESPOneWire::reset() {
 | 
			
		||||
bool HOT ICACHE_RAM_ATTR ESPOneWire::reset() {
 | 
			
		||||
  uint8_t retries = 125;
 | 
			
		||||
 | 
			
		||||
  // Wait for communication to clear
 | 
			
		||||
@@ -39,7 +39,7 @@ bool HOT ESPOneWire::reset() {
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HOT ESPOneWire::write_bit(bool bit) {
 | 
			
		||||
void HOT ICACHE_RAM_ATTR ESPOneWire::write_bit(bool bit) {
 | 
			
		||||
  // Initiate write/read by pulling low.
 | 
			
		||||
  this->pin_->pin_mode(OUTPUT);
 | 
			
		||||
  this->pin_->digital_write(false);
 | 
			
		||||
@@ -60,7 +60,7 @@ void HOT ESPOneWire::write_bit(bool bit) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HOT ESPOneWire::read_bit() {
 | 
			
		||||
bool HOT ICACHE_RAM_ATTR ESPOneWire::read_bit() {
 | 
			
		||||
  // Initiate read slot by pulling LOW for at least 1µs
 | 
			
		||||
  this->pin_->pin_mode(OUTPUT);
 | 
			
		||||
  this->pin_->digital_write(false);
 | 
			
		||||
@@ -76,43 +76,43 @@ bool HOT ESPOneWire::read_bit() {
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESPOneWire::write8(uint8_t val) {
 | 
			
		||||
void ICACHE_RAM_ATTR ESPOneWire::write8(uint8_t val) {
 | 
			
		||||
  for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
    this->write_bit(bool((1u << i) & val));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESPOneWire::write64(uint64_t val) {
 | 
			
		||||
void ICACHE_RAM_ATTR ESPOneWire::write64(uint64_t val) {
 | 
			
		||||
  for (uint8_t i = 0; i < 64; i++) {
 | 
			
		||||
    this->write_bit(bool((1ULL << i) & val));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ESPOneWire::read8() {
 | 
			
		||||
uint8_t ICACHE_RAM_ATTR ESPOneWire::read8() {
 | 
			
		||||
  uint8_t ret = 0;
 | 
			
		||||
  for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
    ret |= (uint8_t(this->read_bit()) << i);
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
uint64_t ESPOneWire::read64() {
 | 
			
		||||
uint64_t ICACHE_RAM_ATTR ESPOneWire::read64() {
 | 
			
		||||
  uint64_t ret = 0;
 | 
			
		||||
  for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
    ret |= (uint64_t(this->read_bit()) << i);
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
void ESPOneWire::select(uint64_t address) {
 | 
			
		||||
void ICACHE_RAM_ATTR ESPOneWire::select(uint64_t address) {
 | 
			
		||||
  this->write8(ONE_WIRE_ROM_SELECT);
 | 
			
		||||
  this->write64(address);
 | 
			
		||||
}
 | 
			
		||||
void ESPOneWire::reset_search() {
 | 
			
		||||
void ICACHE_RAM_ATTR ESPOneWire::reset_search() {
 | 
			
		||||
  this->last_discrepancy_ = 0;
 | 
			
		||||
  this->last_device_flag_ = false;
 | 
			
		||||
  this->last_family_discrepancy_ = 0;
 | 
			
		||||
  this->rom_number_ = 0;
 | 
			
		||||
}
 | 
			
		||||
uint64_t HOT ESPOneWire::search() {
 | 
			
		||||
uint64_t HOT ICACHE_RAM_ATTR ESPOneWire::search() {
 | 
			
		||||
  if (this->last_device_flag_) {
 | 
			
		||||
    return 0u;
 | 
			
		||||
  }
 | 
			
		||||
@@ -196,7 +196,7 @@ uint64_t HOT ESPOneWire::search() {
 | 
			
		||||
 | 
			
		||||
  return this->rom_number_;
 | 
			
		||||
}
 | 
			
		||||
std::vector<uint64_t> ESPOneWire::search_vec() {
 | 
			
		||||
std::vector<uint64_t> ICACHE_RAM_ATTR ESPOneWire::search_vec() {
 | 
			
		||||
  std::vector<uint64_t> res;
 | 
			
		||||
 | 
			
		||||
  this->reset_search();
 | 
			
		||||
@@ -206,12 +206,12 @@ std::vector<uint64_t> ESPOneWire::search_vec() {
 | 
			
		||||
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
void ESPOneWire::skip() {
 | 
			
		||||
void ICACHE_RAM_ATTR ESPOneWire::skip() {
 | 
			
		||||
  this->write8(0xCC);  // skip ROM
 | 
			
		||||
}
 | 
			
		||||
GPIOPin *ESPOneWire::get_pin() { return this->pin_; }
 | 
			
		||||
 | 
			
		||||
uint8_t *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); }
 | 
			
		||||
uint8_t ICACHE_RAM_ATTR *ESPOneWire::rom_number8_() { return reinterpret_cast<uint8_t *>(&this->rom_number_); }
 | 
			
		||||
 | 
			
		||||
}  // namespace dallas
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -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,7 +47,9 @@ void DHT::update() {
 | 
			
		||||
  if (error) {
 | 
			
		||||
    ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, 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 {
 | 
			
		||||
@@ -56,7 +58,9 @@ 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);
 | 
			
		||||
    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();
 | 
			
		||||
  }
 | 
			
		||||
@@ -67,11 +71,17 @@ void DHT::set_dht_model(DHTModel model) {
 | 
			
		||||
  this->model_ = model;
 | 
			
		||||
  this->is_auto_detect_ = model == DHT_MODEL_AUTO_DETECT;
 | 
			
		||||
}
 | 
			
		||||
bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) {
 | 
			
		||||
bool HOT ICACHE_RAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool report_errors) {
 | 
			
		||||
  *humidity = NAN;
 | 
			
		||||
  *temperature = NAN;
 | 
			
		||||
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  int error_code = 0;
 | 
			
		||||
  int8_t i = 0;
 | 
			
		||||
  uint8_t data[5] = {0, 0, 0, 0, 0};
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
 | 
			
		||||
    this->pin_->digital_write(false);
 | 
			
		||||
    this->pin_->pin_mode(OUTPUT);
 | 
			
		||||
    this->pin_->digital_write(false);
 | 
			
		||||
@@ -88,27 +98,24 @@ bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_erro
 | 
			
		||||
    this->pin_->pin_mode(INPUT_PULLUP);
 | 
			
		||||
    delayMicroseconds(40);
 | 
			
		||||
 | 
			
		||||
  uint8_t data[5] = {0, 0, 0, 0, 0};
 | 
			
		||||
    uint8_t bit = 7;
 | 
			
		||||
    uint8_t byte = 0;
 | 
			
		||||
 | 
			
		||||
  for (int8_t i = -1; i < 40; i++) {
 | 
			
		||||
    for (i = -1; i < 40; i++) {
 | 
			
		||||
      uint32_t start_time = micros();
 | 
			
		||||
 | 
			
		||||
      // Wait for rising edge
 | 
			
		||||
      while (!this->pin_->digital_read()) {
 | 
			
		||||
        if (micros() - start_time > 90) {
 | 
			
		||||
        enable_interrupts();
 | 
			
		||||
        if (report_errors) {
 | 
			
		||||
          if (i < 0) {
 | 
			
		||||
            ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!");
 | 
			
		||||
          } else {
 | 
			
		||||
            ESP_LOGW(TAG, "Rising edge for bit %d failed!", i);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
          if (i < 0)
 | 
			
		||||
            error_code = 1;
 | 
			
		||||
          else
 | 
			
		||||
            error_code = 2;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (error_code != 0)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      start_time = micros();
 | 
			
		||||
      uint32_t end_time = start_time;
 | 
			
		||||
@@ -116,17 +123,15 @@ bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_erro
 | 
			
		||||
      // Wait for falling edge
 | 
			
		||||
      while (this->pin_->digital_read()) {
 | 
			
		||||
        if ((end_time = micros()) - start_time > 90) {
 | 
			
		||||
        enable_interrupts();
 | 
			
		||||
        if (report_errors) {
 | 
			
		||||
          if (i < 0) {
 | 
			
		||||
            ESP_LOGW(TAG, "Requesting data from DHT failed!");
 | 
			
		||||
          } else {
 | 
			
		||||
            ESP_LOGW(TAG, "Falling edge for bit %d failed!", i);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
          if (i < 0)
 | 
			
		||||
            error_code = 3;
 | 
			
		||||
          else
 | 
			
		||||
            error_code = 4;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (error_code != 0)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      if (i < 0)
 | 
			
		||||
        continue;
 | 
			
		||||
@@ -140,7 +145,27 @@ bool HOT DHT::read_sensor_(float *temperature, float *humidity, bool report_erro
 | 
			
		||||
      } else
 | 
			
		||||
        bit--;
 | 
			
		||||
    }
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  }
 | 
			
		||||
  if (!report_errors && error_code != 0)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  switch (error_code) {
 | 
			
		||||
    case 1:
 | 
			
		||||
      ESP_LOGW(TAG, "Waiting for DHT communication to clear failed!");
 | 
			
		||||
      return false;
 | 
			
		||||
    case 2:
 | 
			
		||||
      ESP_LOGW(TAG, "Rising edge for bit %d failed!", i);
 | 
			
		||||
      return false;
 | 
			
		||||
    case 3:
 | 
			
		||||
      ESP_LOGW(TAG, "Requesting data from DHT failed!");
 | 
			
		||||
      return false;
 | 
			
		||||
    case 4:
 | 
			
		||||
      ESP_LOGW(TAG, "Falling edge for bit %d failed!", i);
 | 
			
		||||
      return false;
 | 
			
		||||
    case 0:
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ESP_LOGVV(TAG,
 | 
			
		||||
            "Data: Hum=0b" BYTE_TO_BINARY_PATTERN BYTE_TO_BINARY_PATTERN
 | 
			
		||||
 
 | 
			
		||||
@@ -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),
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -203,10 +203,6 @@ void ESP32BLETracker::gap_scan_result(const esp_ble_gap_cb_param_t::ble_scan_res
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string hexencode_string(const std::string &raw_data) {
 | 
			
		||||
  return hexencode(reinterpret_cast<const uint8_t *>(raw_data.c_str()), raw_data.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ESPBTUUID::ESPBTUUID() : uuid_() {}
 | 
			
		||||
ESPBTUUID ESPBTUUID::from_uint16(uint16_t uuid) {
 | 
			
		||||
  ESPBTUUID ret;
 | 
			
		||||
@@ -266,13 +262,13 @@ std::string ESPBTUUID::to_string() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ESPBLEiBeacon::ESPBLEiBeacon(const uint8_t *data) { memcpy(&this->beacon_data_, data, sizeof(beacon_data_)); }
 | 
			
		||||
optional<ESPBLEiBeacon> ESPBLEiBeacon::from_manufacturer_data(const std::string &data) {
 | 
			
		||||
  if (data.size() != 25)
 | 
			
		||||
    return {};
 | 
			
		||||
  if (data[0] != 0x4C || data[1] != 0x00)
 | 
			
		||||
optional<ESPBLEiBeacon> ESPBLEiBeacon::from_manufacturer_data(const ServiceData &data) {
 | 
			
		||||
  if (!data.uuid.contains(0x4C, 0x00))
 | 
			
		||||
    return {};
 | 
			
		||||
 | 
			
		||||
  return ESPBLEiBeacon(reinterpret_cast<const uint8_t *>(data.data()));
 | 
			
		||||
  if (data.data.size() != 23)
 | 
			
		||||
    return {};
 | 
			
		||||
  return ESPBLEiBeacon(data.data.data());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) {
 | 
			
		||||
@@ -304,8 +300,8 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
 | 
			
		||||
 | 
			
		||||
  ESP_LOGVV(TAG, "  RSSI: %d", this->rssi_);
 | 
			
		||||
  ESP_LOGVV(TAG, "  Name: '%s'", this->name_.c_str());
 | 
			
		||||
  if (this->tx_power_.has_value()) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  TX Power: %d", *this->tx_power_);
 | 
			
		||||
  for (auto &it : this->tx_powers_) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  TX Power: %d", it);
 | 
			
		||||
  }
 | 
			
		||||
  if (this->appearance_.has_value()) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  Appearance: %u", *this->appearance_);
 | 
			
		||||
@@ -313,24 +309,25 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
 | 
			
		||||
  if (this->ad_flag_.has_value()) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  Ad Flag: %u", *this->ad_flag_);
 | 
			
		||||
  }
 | 
			
		||||
  for (auto uuid : this->service_uuids_) {
 | 
			
		||||
  for (auto &uuid : this->service_uuids_) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  Service UUID: %s", uuid.to_string().c_str());
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGVV(TAG, "  Manufacturer data: %s", hexencode_string(this->manufacturer_data_).c_str());
 | 
			
		||||
  ESP_LOGVV(TAG, "  Service data: %s", hexencode_string(this->service_data_).c_str());
 | 
			
		||||
 | 
			
		||||
  if (this->service_data_uuid_.has_value()) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  Service Data UUID: %s", this->service_data_uuid_->to_string().c_str());
 | 
			
		||||
  for (auto &data : this->manufacturer_datas_) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  Manufacturer data: %s", hexencode(data.data).c_str());
 | 
			
		||||
  }
 | 
			
		||||
  for (auto &data : this->service_datas_) {
 | 
			
		||||
    ESP_LOGVV(TAG, "  Service data:");
 | 
			
		||||
    ESP_LOGVV(TAG, "    UUID: %s", data.uuid.to_string().c_str());
 | 
			
		||||
    ESP_LOGVV(TAG, "    Data: %s", hexencode(data.data).c_str());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ESP_LOGVV(TAG, "Adv data: %s",
 | 
			
		||||
            hexencode_string(std::string(reinterpret_cast<const char *>(param.ble_adv), param.adv_data_len)).c_str());
 | 
			
		||||
  ESP_LOGVV(TAG, "Adv data: %s", hexencode(param.ble_adv, param.adv_data_len + param.scan_rsp_len).c_str());
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_param ¶m) {
 | 
			
		||||
  size_t offset = 0;
 | 
			
		||||
  const uint8_t *payload = param.ble_adv;
 | 
			
		||||
  uint8_t len = param.adv_data_len;
 | 
			
		||||
  uint8_t len = param.adv_data_len + param.scan_rsp_len;
 | 
			
		||||
 | 
			
		||||
  while (offset + 2 < len) {
 | 
			
		||||
    const uint8_t field_length = payload[offset++];  // First byte is length of adv record
 | 
			
		||||
@@ -343,25 +340,52 @@ void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_p
 | 
			
		||||
    const uint8_t record_length = field_length - 1;
 | 
			
		||||
    offset += record_length;
 | 
			
		||||
 | 
			
		||||
    // See also Generic Access Profile Assigned Numbers:
 | 
			
		||||
    // https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/ See also ADVERTISING AND SCAN
 | 
			
		||||
    // RESPONSE DATA FORMAT: https://www.bluetooth.com/specifications/bluetooth-core-specification/ (vol 3, part C, 11)
 | 
			
		||||
    // See also Core Specification Supplement: https://www.bluetooth.com/specifications/bluetooth-core-specification/
 | 
			
		||||
    // (called CSS here)
 | 
			
		||||
 | 
			
		||||
    switch (record_type) {
 | 
			
		||||
      case ESP_BLE_AD_TYPE_NAME_CMPL: {
 | 
			
		||||
        // CSS 1.2 LOCAL NAME
 | 
			
		||||
        // "The Local Name data type shall be the same as, or a shortened version of, the local name assigned to the
 | 
			
		||||
        // device." CSS 1: Optional in this context; shall not appear more than once in a block.
 | 
			
		||||
        this->name_ = std::string(reinterpret_cast<const char *>(record), record_length);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_TX_PWR: {
 | 
			
		||||
        this->tx_power_ = *payload;
 | 
			
		||||
        // CSS 1.5 TX POWER LEVEL
 | 
			
		||||
        // "The TX Power Level data type indicates the transmitted power level of the packet containing the data type."
 | 
			
		||||
        // CSS 1: Optional in this context (may appear more than once in a block).
 | 
			
		||||
        this->tx_powers_.push_back(*payload);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_APPEARANCE: {
 | 
			
		||||
        // CSS 1.12 APPEARANCE
 | 
			
		||||
        // "The Appearance data type defines the external appearance of the device."
 | 
			
		||||
        // See also https://www.bluetooth.com/specifications/gatt/characteristics/
 | 
			
		||||
        // CSS 1: Optional in this context; shall not appear more than once in a block and shall not appear in both
 | 
			
		||||
        // the AD and SRD of the same extended advertising interval.
 | 
			
		||||
        this->appearance_ = *reinterpret_cast<const uint16_t *>(record);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_FLAG: {
 | 
			
		||||
        // CSS 1.3 FLAGS
 | 
			
		||||
        // "The Flags data type contains one bit Boolean flags. The Flags data type shall be included when any of the
 | 
			
		||||
        // Flag bits are non-zero and the advertising packet is connectable, otherwise the Flags data type may be
 | 
			
		||||
        // omitted."
 | 
			
		||||
        // CSS 1: Optional in this context; shall not appear more than once in a block.
 | 
			
		||||
        this->ad_flag_ = *record;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      // CSS 1.1 SERVICE UUID
 | 
			
		||||
      // The Service UUID data type is used to include a list of Service or Service Class UUIDs.
 | 
			
		||||
      // There are six data types defined for the three sizes of Service UUIDs that may be returned:
 | 
			
		||||
      // CSS 1: Optional in this context (may appear more than once in a block).
 | 
			
		||||
      case ESP_BLE_AD_TYPE_16SRV_CMPL:
 | 
			
		||||
      case ESP_BLE_AD_TYPE_16SRV_PART: {
 | 
			
		||||
        // • 16-bit Bluetooth Service UUIDs
 | 
			
		||||
        for (uint8_t i = 0; i < record_length / 2; i++) {
 | 
			
		||||
          this->service_uuids_.push_back(ESPBTUUID::from_uint16(*reinterpret_cast<const uint16_t *>(record + 2 * i)));
 | 
			
		||||
        }
 | 
			
		||||
@@ -369,6 +393,7 @@ void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_p
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_32SRV_CMPL:
 | 
			
		||||
      case ESP_BLE_AD_TYPE_32SRV_PART: {
 | 
			
		||||
        // • 32-bit Bluetooth Service UUIDs
 | 
			
		||||
        for (uint8_t i = 0; i < record_length / 4; i++) {
 | 
			
		||||
          this->service_uuids_.push_back(ESPBTUUID::from_uint32(*reinterpret_cast<const uint32_t *>(record + 4 * i)));
 | 
			
		||||
        }
 | 
			
		||||
@@ -376,41 +401,70 @@ void ESPBTDevice::parse_adv_(const esp_ble_gap_cb_param_t::ble_scan_result_evt_p
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_128SRV_CMPL:
 | 
			
		||||
      case ESP_BLE_AD_TYPE_128SRV_PART: {
 | 
			
		||||
        // • Global 128-bit Service UUIDs
 | 
			
		||||
        this->service_uuids_.push_back(ESPBTUUID::from_raw(record));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE: {
 | 
			
		||||
        this->manufacturer_data_ = std::string(reinterpret_cast<const char *>(record), record_length);
 | 
			
		||||
        // CSS 1.4 MANUFACTURER SPECIFIC DATA
 | 
			
		||||
        // "The Manufacturer Specific data type is used for manufacturer specific data. The first two data octets shall
 | 
			
		||||
        // contain a company identifier from Assigned Numbers. The interpretation of any other octets within the data
 | 
			
		||||
        // shall be defined by the manufacturer specified by the company identifier."
 | 
			
		||||
        // CSS 1: Optional in this context (may appear more than once in a block).
 | 
			
		||||
        if (record_length < 2) {
 | 
			
		||||
          ESP_LOGV(TAG, "Record length too small for ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE");
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        ServiceData data{};
 | 
			
		||||
        data.uuid = ESPBTUUID::from_uint16(*reinterpret_cast<const uint16_t *>(record));
 | 
			
		||||
        data.data.assign(record + 2UL, record + record_length);
 | 
			
		||||
        this->manufacturer_datas_.push_back(data);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // CSS 1.11 SERVICE DATA
 | 
			
		||||
      // "The Service Data data type consists of a service UUID with the data associated with that service."
 | 
			
		||||
      // CSS 1: Optional in this context (may appear more than once in a block).
 | 
			
		||||
      case ESP_BLE_AD_TYPE_SERVICE_DATA: {
 | 
			
		||||
        // «Service Data - 16 bit UUID»
 | 
			
		||||
        // Size: 2 or more octets
 | 
			
		||||
        // The first 2 octets contain the 16 bit Service UUID fol- lowed by additional service data
 | 
			
		||||
        if (record_length < 2) {
 | 
			
		||||
          ESP_LOGV(TAG, "Record length too small for ESP_BLE_AD_TYPE_SERVICE_DATA");
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        this->service_data_uuid_ = ESPBTUUID::from_uint16(*reinterpret_cast<const uint16_t *>(record));
 | 
			
		||||
        if (record_length > 2)
 | 
			
		||||
          this->service_data_ = std::string(reinterpret_cast<const char *>(record + 2), record_length - 2UL);
 | 
			
		||||
        ServiceData data{};
 | 
			
		||||
        data.uuid = ESPBTUUID::from_uint16(*reinterpret_cast<const uint16_t *>(record));
 | 
			
		||||
        data.data.assign(record + 2UL, record + record_length);
 | 
			
		||||
        this->service_datas_.push_back(data);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_32SERVICE_DATA: {
 | 
			
		||||
        // «Service Data - 32 bit UUID»
 | 
			
		||||
        // Size: 4 or more octets
 | 
			
		||||
        // The first 4 octets contain the 32 bit Service UUID fol- lowed by additional service data
 | 
			
		||||
        if (record_length < 4) {
 | 
			
		||||
          ESP_LOGV(TAG, "Record length too small for ESP_BLE_AD_TYPE_32SERVICE_DATA");
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        this->service_data_uuid_ = ESPBTUUID::from_uint32(*reinterpret_cast<const uint32_t *>(record));
 | 
			
		||||
        if (record_length > 4)
 | 
			
		||||
          this->service_data_ = std::string(reinterpret_cast<const char *>(record + 4), record_length - 4UL);
 | 
			
		||||
        ServiceData data{};
 | 
			
		||||
        data.uuid = ESPBTUUID::from_uint32(*reinterpret_cast<const uint32_t *>(record));
 | 
			
		||||
        data.data.assign(record + 4UL, record + record_length);
 | 
			
		||||
        this->service_datas_.push_back(data);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ESP_BLE_AD_TYPE_128SERVICE_DATA: {
 | 
			
		||||
        // «Service Data - 128 bit UUID»
 | 
			
		||||
        // Size: 16 or more octets
 | 
			
		||||
        // The first 16 octets contain the 128 bit Service UUID followed by additional service data
 | 
			
		||||
        if (record_length < 16) {
 | 
			
		||||
          ESP_LOGV(TAG, "Record length too small for ESP_BLE_AD_TYPE_128SERVICE_DATA");
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        this->service_data_uuid_ = ESPBTUUID::from_raw(record);
 | 
			
		||||
        if (record_length > 16)
 | 
			
		||||
          this->service_data_ = std::string(reinterpret_cast<const char *>(record + 16), record_length - 16UL);
 | 
			
		||||
        ServiceData data{};
 | 
			
		||||
        data.uuid = ESPBTUUID::from_raw(record);
 | 
			
		||||
        data.data.assign(record + 16UL, record + record_length);
 | 
			
		||||
        this->service_datas_.push_back(data);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      default: {
 | 
			
		||||
@@ -427,22 +481,12 @@ std::string ESPBTDevice::address_str() const {
 | 
			
		||||
  return mac;
 | 
			
		||||
}
 | 
			
		||||
uint64_t ESPBTDevice::address_uint64() const { return ble_addr_to_uint64(this->address_); }
 | 
			
		||||
esp_ble_addr_type_t ESPBTDevice::get_address_type() const { return this->address_type_; }
 | 
			
		||||
int ESPBTDevice::get_rssi() const { return this->rssi_; }
 | 
			
		||||
const std::string &ESPBTDevice::get_name() const { return this->name_; }
 | 
			
		||||
const optional<int8_t> &ESPBTDevice::get_tx_power() const { return this->tx_power_; }
 | 
			
		||||
const optional<uint16_t> &ESPBTDevice::get_appearance() const { return this->appearance_; }
 | 
			
		||||
const optional<uint8_t> &ESPBTDevice::get_ad_flag() const { return this->ad_flag_; }
 | 
			
		||||
const std::vector<ESPBTUUID> &ESPBTDevice::get_service_uuids() const { return this->service_uuids_; }
 | 
			
		||||
const std::string &ESPBTDevice::get_manufacturer_data() const { return this->manufacturer_data_; }
 | 
			
		||||
const std::string &ESPBTDevice::get_service_data() const { return this->service_data_; }
 | 
			
		||||
const optional<ESPBTUUID> &ESPBTDevice::get_service_data_uuid() const { return this->service_data_uuid_; }
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
@@ -477,8 +521,8 @@ void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) {
 | 
			
		||||
  ESP_LOGD(TAG, "  Address Type: %s", address_type_s);
 | 
			
		||||
  if (!device.get_name().empty())
 | 
			
		||||
    ESP_LOGD(TAG, "  Name: '%s'", device.get_name().c_str());
 | 
			
		||||
  if (device.get_tx_power().has_value()) {
 | 
			
		||||
    ESP_LOGD(TAG, "  TX Power: %d", *device.get_tx_power());
 | 
			
		||||
  for (auto &tx_power : device.get_tx_powers()) {
 | 
			
		||||
    ESP_LOGD(TAG, "  TX Power: %d", tx_power);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,11 +31,18 @@ class ESPBTUUID {
 | 
			
		||||
  esp_bt_uuid_t uuid_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using adv_data_t = std::vector<uint8_t>;
 | 
			
		||||
 | 
			
		||||
struct ServiceData {
 | 
			
		||||
  ESPBTUUID uuid;
 | 
			
		||||
  adv_data_t data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ESPBLEiBeacon {
 | 
			
		||||
 public:
 | 
			
		||||
  ESPBLEiBeacon() { memset(&this->beacon_data_, 0, sizeof(this->beacon_data_)); }
 | 
			
		||||
  ESPBLEiBeacon(const uint8_t *data);
 | 
			
		||||
  static optional<ESPBLEiBeacon> from_manufacturer_data(const std::string &data);
 | 
			
		||||
  static optional<ESPBLEiBeacon> from_manufacturer_data(const ServiceData &data);
 | 
			
		||||
 | 
			
		||||
  uint16_t get_major() { return reverse_bits_16(this->beacon_data_.major); }
 | 
			
		||||
  uint16_t get_minor() { return reverse_bits_16(this->beacon_data_.minor); }
 | 
			
		||||
@@ -44,7 +51,6 @@ class ESPBLEiBeacon {
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  struct {
 | 
			
		||||
    uint16_t manufacturer_id;
 | 
			
		||||
    uint8_t sub_type;
 | 
			
		||||
    uint8_t proximity_uuid[16];
 | 
			
		||||
    uint16_t major;
 | 
			
		||||
@@ -61,18 +67,33 @@ class ESPBTDevice {
 | 
			
		||||
 | 
			
		||||
  uint64_t address_uint64() const;
 | 
			
		||||
 | 
			
		||||
  esp_ble_addr_type_t get_address_type() const;
 | 
			
		||||
  int get_rssi() const;
 | 
			
		||||
  const std::string &get_name() const;
 | 
			
		||||
  const optional<int8_t> &get_tx_power() const;
 | 
			
		||||
  const optional<uint16_t> &get_appearance() const;
 | 
			
		||||
  const optional<uint8_t> &get_ad_flag() const;
 | 
			
		||||
  const std::vector<ESPBTUUID> &get_service_uuids() const;
 | 
			
		||||
  const std::string &get_manufacturer_data() const;
 | 
			
		||||
  const std::string &get_service_data() const;
 | 
			
		||||
  const optional<ESPBTUUID> &get_service_data_uuid() const;
 | 
			
		||||
  const optional<ESPBLEiBeacon> get_ibeacon() const {
 | 
			
		||||
    return ESPBLEiBeacon::from_manufacturer_data(this->manufacturer_data_);
 | 
			
		||||
  esp_ble_addr_type_t get_address_type() const { return this->address_type_; }
 | 
			
		||||
  int get_rssi() const { return rssi_; }
 | 
			
		||||
  const std::string &get_name() const { return this->name_; }
 | 
			
		||||
 | 
			
		||||
  ESPDEPRECATED("Use get_tx_powers() instead")
 | 
			
		||||
  optional<int8_t> get_tx_power() const {
 | 
			
		||||
    if (this->tx_powers_.empty())
 | 
			
		||||
      return {};
 | 
			
		||||
    return this->tx_powers_[0];
 | 
			
		||||
  }
 | 
			
		||||
  const std::vector<int8_t> &get_tx_powers() const { return tx_powers_; }
 | 
			
		||||
 | 
			
		||||
  const optional<uint16_t> &get_appearance() const { return appearance_; }
 | 
			
		||||
  const optional<uint8_t> &get_ad_flag() const { return ad_flag_; }
 | 
			
		||||
  const std::vector<ESPBTUUID> &get_service_uuids() const { return service_uuids_; }
 | 
			
		||||
 | 
			
		||||
  const std::vector<ServiceData> &get_manufacturer_datas() const { return manufacturer_datas_; }
 | 
			
		||||
 | 
			
		||||
  const std::vector<ServiceData> &get_service_datas() const { return service_datas_; }
 | 
			
		||||
 | 
			
		||||
  optional<ESPBLEiBeacon> get_ibeacon() const {
 | 
			
		||||
    for (auto &it : this->manufacturer_datas_) {
 | 
			
		||||
      auto res = ESPBLEiBeacon::from_manufacturer_data(it);
 | 
			
		||||
      if (res.has_value())
 | 
			
		||||
        return *res;
 | 
			
		||||
    }
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
@@ -84,13 +105,12 @@ class ESPBTDevice {
 | 
			
		||||
  esp_ble_addr_type_t address_type_{BLE_ADDR_TYPE_PUBLIC};
 | 
			
		||||
  int rssi_{0};
 | 
			
		||||
  std::string name_{};
 | 
			
		||||
  optional<int8_t> tx_power_{};
 | 
			
		||||
  std::vector<int8_t> tx_powers_{};
 | 
			
		||||
  optional<uint16_t> appearance_{};
 | 
			
		||||
  optional<uint8_t> ad_flag_{};
 | 
			
		||||
  std::vector<ESPBTUUID> service_uuids_;
 | 
			
		||||
  std::string manufacturer_data_{};
 | 
			
		||||
  std::string service_data_{};
 | 
			
		||||
  optional<ESPBTUUID> service_data_uuid_{};
 | 
			
		||||
  std::vector<ServiceData> manufacturer_datas_{};
 | 
			
		||||
  std::vector<ServiceData> service_datas_{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ESP32BLETracker;
 | 
			
		||||
 
 | 
			
		||||
@@ -85,6 +85,8 @@ void ESP32Camera::dump_config() {
 | 
			
		||||
    case FRAMESIZE_UXGA:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 1600x1200 (UXGA)");
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (this->is_failed()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,8 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
 | 
			
		||||
  this->status_clear_warning();
 | 
			
		||||
  uint32_t data = 0;
 | 
			
		||||
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    for (uint8_t i = 0; i < 24; i++) {
 | 
			
		||||
      this->sck_pin_->digital_write(true);
 | 
			
		||||
      delayMicroseconds(1);
 | 
			
		||||
@@ -58,7 +59,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
 | 
			
		||||
      this->sck_pin_->digital_write(false);
 | 
			
		||||
      delayMicroseconds(1);
 | 
			
		||||
    }
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (data & 0x800000ULL) {
 | 
			
		||||
    data |= 0xFF000000ULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@ class Logger : public Component {
 | 
			
		||||
  /// Manually set the baud rate for serial, set to 0 to disable.
 | 
			
		||||
  void set_baud_rate(uint32_t baud_rate);
 | 
			
		||||
  uint32_t get_baud_rate() const { return baud_rate_; }
 | 
			
		||||
  HardwareSerial *get_hw_serial() const { return hw_serial_; }
 | 
			
		||||
 | 
			
		||||
  /// Get the UART used by the logger.
 | 
			
		||||
  UARTSelection get_uart() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,7 @@ def to_code(config):
 | 
			
		||||
    yield cg.register_component(var, config)
 | 
			
		||||
 | 
			
		||||
    # https://github.com/OttoWinter/async-mqtt-client/blob/master/library.json
 | 
			
		||||
    cg.add_library('AsyncMqttClient-esphome', '0.8.3')
 | 
			
		||||
    cg.add_library('AsyncMqttClient-esphome', '0.8.4')
 | 
			
		||||
    cg.add_define('USE_MQTT')
 | 
			
		||||
    cg.add_global(mqtt_ns.using)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,11 @@ def validate_method_pin(value):
 | 
			
		||||
        method_pins['BIT_BANG'] = list(range(0, 16))
 | 
			
		||||
    elif CORE.is_esp32:
 | 
			
		||||
        method_pins['BIT_BANG'] = list(range(0, 32))
 | 
			
		||||
    pins_ = method_pins[method]
 | 
			
		||||
    pins_ = method_pins.get(method)
 | 
			
		||||
    if pins_ is None:
 | 
			
		||||
        # all pins allowed for this method
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
    for opt in (CONF_PIN, CONF_CLOCK_PIN, CONF_DATA_PIN):
 | 
			
		||||
        if opt in value and value[opt] not in pins_:
 | 
			
		||||
            raise cv.Invalid("Method {} only supports pin(s) {}".format(
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,8 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
 | 
			
		||||
  uint32_t on_time, off_time;
 | 
			
		||||
  this->calculate_on_off_time_(this->temp_.get_carrier_frequency(), &on_time, &off_time);
 | 
			
		||||
  for (uint32_t i = 0; i < send_times; i++) {
 | 
			
		||||
    disable_interrupts();
 | 
			
		||||
    {
 | 
			
		||||
      InterruptLock lock;
 | 
			
		||||
      for (int32_t item : this->temp_.get_data()) {
 | 
			
		||||
        if (item > 0) {
 | 
			
		||||
          const auto length = uint32_t(item);
 | 
			
		||||
@@ -78,11 +79,10 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen
 | 
			
		||||
        }
 | 
			
		||||
        App.feed_wdt();
 | 
			
		||||
      }
 | 
			
		||||
    enable_interrupts();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (i + 1 < send_times) {
 | 
			
		||||
      delay(send_wait / 1000UL);
 | 
			
		||||
      delayMicroseconds(send_wait % 1000UL);
 | 
			
		||||
      delay_microseconds_accurate(send_wait);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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); }
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,14 @@ double Sun::azimuth() {
 | 
			
		||||
    return NAN;
 | 
			
		||||
  return this->azimuth_(time);
 | 
			
		||||
}
 | 
			
		||||
// like clamp, but with doubles
 | 
			
		||||
double clampd(double val, double min, double max) {
 | 
			
		||||
  if (val < min)
 | 
			
		||||
    return min;
 | 
			
		||||
  if (val > max)
 | 
			
		||||
    return max;
 | 
			
		||||
  return val;
 | 
			
		||||
}
 | 
			
		||||
double Sun::sun_declination_(double sun_time) {
 | 
			
		||||
  double n = sun_time - 1.0;
 | 
			
		||||
  // maximum declination
 | 
			
		||||
@@ -67,7 +75,7 @@ double Sun::sun_declination_(double sun_time) {
 | 
			
		||||
  const double c = TAU / 365.24;
 | 
			
		||||
  double v = cos(c * days_since_december_solstice + 2 * eccentricity * sin(c * days_since_perihelion));
 | 
			
		||||
  // Make sure value is in range (double error may lead to results slightly larger than 1)
 | 
			
		||||
  double x = clamp(tot * v, 0, 1);
 | 
			
		||||
  double x = clampd(tot * v, -1.0, 1.0);
 | 
			
		||||
  return asin(x);
 | 
			
		||||
}
 | 
			
		||||
double Sun::elevation_ratio_(double sun_time) {
 | 
			
		||||
@@ -75,7 +83,7 @@ double Sun::elevation_ratio_(double sun_time) {
 | 
			
		||||
  double hangle = this->hour_angle_(sun_time);
 | 
			
		||||
  double a = sin(this->latitude_rad_()) * sin(decl);
 | 
			
		||||
  double b = cos(this->latitude_rad_()) * cos(decl) * cos(hangle);
 | 
			
		||||
  double val = clamp(a + b, -1.0, 1.0);
 | 
			
		||||
  double val = clampd(a + b, -1.0, 1.0);
 | 
			
		||||
  return val;
 | 
			
		||||
}
 | 
			
		||||
double Sun::latitude_rad_() { return this->latitude_ * TO_RADIANS; }
 | 
			
		||||
@@ -92,7 +100,7 @@ double Sun::azimuth_rad_(double sun_time) {
 | 
			
		||||
  double zen = this->zenith_rad_(sun_time);
 | 
			
		||||
  double nom = cos(zen) * sin(this->latitude_rad_()) - sin(decl);
 | 
			
		||||
  double denom = sin(zen) * cos(this->latitude_rad_());
 | 
			
		||||
  double v = clamp(nom / denom, -1.0, 1.0);
 | 
			
		||||
  double v = clampd(nom / denom, -1.0, 1.0);
 | 
			
		||||
  double az = PI - acos(v);
 | 
			
		||||
  if (hangle > 0)
 | 
			
		||||
    az = -az;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,14 @@ RESTORE_MODES = {
 | 
			
		||||
    'RESTORE_AND_CALL': TemplateCoverRestoreMode.COVER_RESTORE_AND_CALL,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CONF_HAS_POSITION = 'has_position'
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cover.COVER_SCHEMA.extend({
 | 
			
		||||
    cv.GenerateID(): cv.declare_id(TemplateCover),
 | 
			
		||||
    cv.Optional(CONF_LAMBDA): cv.returning_lambda,
 | 
			
		||||
    cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
 | 
			
		||||
    cv.Optional(CONF_ASSUMED_STATE, default=False): cv.boolean,
 | 
			
		||||
    cv.Optional(CONF_HAS_POSITION, default=False): cv.boolean,
 | 
			
		||||
    cv.Optional(CONF_OPEN_ACTION): automation.validate_automation(single=True),
 | 
			
		||||
    cv.Optional(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
 | 
			
		||||
    cv.Optional(CONF_STOP_ACTION): automation.validate_automation(single=True),
 | 
			
		||||
@@ -56,6 +59,7 @@ def to_code(config):
 | 
			
		||||
    cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
 | 
			
		||||
    cg.add(var.set_assumed_state(config[CONF_ASSUMED_STATE]))
 | 
			
		||||
    cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE]))
 | 
			
		||||
    cg.add(var.set_has_position(config[CONF_HAS_POSITION]))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@automation.register_action('cover.template.publish', cover.CoverPublishAction, cv.Schema({
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ namespace tuya {
 | 
			
		||||
static const char *TAG = "tuya";
 | 
			
		||||
 | 
			
		||||
void Tuya::setup() {
 | 
			
		||||
  this->send_empty_command_(TuyaCommandType::MCU_CONF);
 | 
			
		||||
  this->set_interval("heartbeat", 1000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -22,8 +21,12 @@ void Tuya::loop() {
 | 
			
		||||
 | 
			
		||||
void Tuya::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Tuya:");
 | 
			
		||||
  if ((gpio_status_ != -1) || (gpio_reset_ != -1))
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  GPIO MCU configuration not supported!");
 | 
			
		||||
  if (this->init_state_ != TuyaInitState::INIT_DONE) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Configuration will be reported when setup is complete. Current init_state: %u",  // NOLINT
 | 
			
		||||
                  this->init_state_);
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  If no further output is received, confirm that this is a supported Tuya device.");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  for (auto &info : this->datapoints_) {
 | 
			
		||||
    if (info.type == TuyaDatapointType::BOOLEAN)
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Datapoint %d: switch (value: %s)", info.id, ONOFF(info.value_bool));
 | 
			
		||||
@@ -36,9 +39,11 @@ void Tuya::dump_config() {
 | 
			
		||||
    else
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Datapoint %d: unknown", info.id);
 | 
			
		||||
  }
 | 
			
		||||
  if (this->datapoints_.empty()) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Received no datapoints! Please make sure this is a supported Tuya device.");
 | 
			
		||||
  if ((this->gpio_status_ != -1) || (this->gpio_reset_ != -1)) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  GPIO Configuration: status: pin %d, reset: pin %d (not supported)", this->gpio_status_,
 | 
			
		||||
                  this->gpio_reset_);
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Product: '%s'", this->product_.c_str());
 | 
			
		||||
  this->check_uart_settings(9600);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -89,8 +94,8 @@ bool Tuya::validate_message_() {
 | 
			
		||||
 | 
			
		||||
  // valid message
 | 
			
		||||
  const uint8_t *message_data = data + 6;
 | 
			
		||||
  ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s]", command, version,
 | 
			
		||||
           hexencode(message_data, length).c_str());
 | 
			
		||||
  ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version,  // NOLINT
 | 
			
		||||
           hexencode(message_data, length).c_str(), this->init_state_);
 | 
			
		||||
  this->handle_command_(command, version, message_data, length);
 | 
			
		||||
 | 
			
		||||
  // return false to reset rx buffer
 | 
			
		||||
@@ -105,41 +110,58 @@ void Tuya::handle_char_(uint8_t c) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buffer, size_t len) {
 | 
			
		||||
  uint8_t c;
 | 
			
		||||
  switch ((TuyaCommandType) command) {
 | 
			
		||||
    case TuyaCommandType::HEARTBEAT:
 | 
			
		||||
      ESP_LOGV(TAG, "MCU Heartbeat (0x%02X)", buffer[0]);
 | 
			
		||||
      if (buffer[0] == 0) {
 | 
			
		||||
        ESP_LOGI(TAG, "MCU restarted");
 | 
			
		||||
        this->send_empty_command_(TuyaCommandType::QUERY_STATE);
 | 
			
		||||
        this->init_state_ = TuyaInitState::INIT_HEARTBEAT;
 | 
			
		||||
      }
 | 
			
		||||
      if (this->init_state_ == TuyaInitState::INIT_HEARTBEAT) {
 | 
			
		||||
        this->init_state_ = TuyaInitState::INIT_PRODUCT;
 | 
			
		||||
        this->send_empty_command_(TuyaCommandType::PRODUCT_QUERY);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::QUERY_PRODUCT: {
 | 
			
		||||
      // check it is a valid string
 | 
			
		||||
      bool valid = false;
 | 
			
		||||
    case TuyaCommandType::PRODUCT_QUERY: {
 | 
			
		||||
      // check it is a valid string made up of printable characters
 | 
			
		||||
      bool valid = true;
 | 
			
		||||
      for (int i = 0; i < len; i++) {
 | 
			
		||||
        if (buffer[i] == 0x00) {
 | 
			
		||||
          valid = true;
 | 
			
		||||
        if (!std::isprint(buffer[i])) {
 | 
			
		||||
          valid = false;
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (valid) {
 | 
			
		||||
        ESP_LOGD(TAG, "Tuya Product Code: %s", reinterpret_cast<const char *>(buffer));
 | 
			
		||||
        this->product_ = std::string(reinterpret_cast<const char *>(buffer), len);
 | 
			
		||||
      } else {
 | 
			
		||||
        this->product_ = R"({"p":"INVALID"})";
 | 
			
		||||
      }
 | 
			
		||||
      if (this->init_state_ == TuyaInitState::INIT_PRODUCT) {
 | 
			
		||||
        this->init_state_ = TuyaInitState::INIT_CONF;
 | 
			
		||||
        this->send_empty_command_(TuyaCommandType::CONF_QUERY);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case TuyaCommandType::MCU_CONF:
 | 
			
		||||
    case TuyaCommandType::CONF_QUERY: {
 | 
			
		||||
      if (len >= 2) {
 | 
			
		||||
        gpio_status_ = buffer[0];
 | 
			
		||||
        gpio_reset_ = buffer[1];
 | 
			
		||||
      }
 | 
			
		||||
      // set wifi state LED to off or on depending on the MCU firmware
 | 
			
		||||
      // but it shouldn't be blinking
 | 
			
		||||
      c = 0x3;
 | 
			
		||||
      this->send_command_(TuyaCommandType::WIFI_STATE, &c, 1);
 | 
			
		||||
      this->send_empty_command_(TuyaCommandType::QUERY_STATE);
 | 
			
		||||
      if (this->init_state_ == TuyaInitState::INIT_CONF) {
 | 
			
		||||
        // If we were following the spec to the letter we would send
 | 
			
		||||
        // state updates until connected to both WiFi and API/MQTT.
 | 
			
		||||
        // Instead we just claim to be connected immediately and move on.
 | 
			
		||||
        uint8_t c[] = {0x04};
 | 
			
		||||
        this->init_state_ = TuyaInitState::INIT_WIFI;
 | 
			
		||||
        this->send_command_(TuyaCommandType::WIFI_STATE, c, 1);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case TuyaCommandType::WIFI_STATE:
 | 
			
		||||
      if (this->init_state_ == TuyaInitState::INIT_WIFI) {
 | 
			
		||||
        this->init_state_ = TuyaInitState::INIT_DATAPOINT;
 | 
			
		||||
        this->send_empty_command_(TuyaCommandType::DATAPOINT_QUERY);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::WIFI_RESET:
 | 
			
		||||
      ESP_LOGE(TAG, "TUYA_CMD_WIFI_RESET is not handled");
 | 
			
		||||
@@ -147,14 +169,22 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
 | 
			
		||||
    case TuyaCommandType::WIFI_SELECT:
 | 
			
		||||
      ESP_LOGE(TAG, "TUYA_CMD_WIFI_SELECT is not handled");
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::SET_DATAPOINT:
 | 
			
		||||
    case TuyaCommandType::DATAPOINT_DELIVER:
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::STATE: {
 | 
			
		||||
    case TuyaCommandType::DATAPOINT_REPORT:
 | 
			
		||||
      if (this->init_state_ == TuyaInitState::INIT_DATAPOINT) {
 | 
			
		||||
        this->init_state_ = TuyaInitState::INIT_DONE;
 | 
			
		||||
        this->set_timeout("datapoint_dump", 1000, [this] { this->dump_config(); });
 | 
			
		||||
      }
 | 
			
		||||
      this->handle_datapoint_(buffer, len);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case TuyaCommandType::QUERY_STATE:
 | 
			
		||||
    case TuyaCommandType::DATAPOINT_QUERY:
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::WIFI_TEST: {
 | 
			
		||||
      uint8_t c[] = {0x00, 0x00};
 | 
			
		||||
      this->send_command_(TuyaCommandType::WIFI_TEST, c, 2);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      ESP_LOGE(TAG, "invalid command (%02x) received", command);
 | 
			
		||||
  }
 | 
			
		||||
@@ -214,8 +244,6 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) {
 | 
			
		||||
  }
 | 
			
		||||
  if (!found) {
 | 
			
		||||
    this->datapoints_.push_back(datapoint);
 | 
			
		||||
    // New datapoint found, reprint dump_config after a delay.
 | 
			
		||||
    this->set_timeout("datapoint_dump", 100, [this] { this->dump_config(); });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Run through listeners
 | 
			
		||||
@@ -227,9 +255,12 @@ void Tuya::handle_datapoint_(const uint8_t *buffer, size_t len) {
 | 
			
		||||
void Tuya::send_command_(TuyaCommandType command, const uint8_t *buffer, uint16_t len) {
 | 
			
		||||
  uint8_t len_hi = len >> 8;
 | 
			
		||||
  uint8_t len_lo = len >> 0;
 | 
			
		||||
  this->write_array({0x55, 0xAA,
 | 
			
		||||
                     0x00,  // version
 | 
			
		||||
                     (uint8_t) command, len_hi, len_lo});
 | 
			
		||||
  uint8_t version = 0;
 | 
			
		||||
 | 
			
		||||
  ESP_LOGV(TAG, "Sending Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version,  // NOLINT
 | 
			
		||||
           hexencode(buffer, len).c_str(), this->init_state_);
 | 
			
		||||
 | 
			
		||||
  this->write_array({0x55, 0xAA, version, (uint8_t) command, len_hi, len_lo});
 | 
			
		||||
  if (len != 0)
 | 
			
		||||
    this->write_array(buffer, len);
 | 
			
		||||
 | 
			
		||||
@@ -278,7 +309,7 @@ void Tuya::set_datapoint_value(TuyaDatapoint datapoint) {
 | 
			
		||||
  buffer.push_back(data.size() >> 8);
 | 
			
		||||
  buffer.push_back(data.size() >> 0);
 | 
			
		||||
  buffer.insert(buffer.end(), data.begin(), data.end());
 | 
			
		||||
  this->send_command_(TuyaCommandType::SET_DATAPOINT, buffer.data(), buffer.size());
 | 
			
		||||
  this->send_command_(TuyaCommandType::DATAPOINT_DELIVER, buffer.data(), buffer.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tuya::register_listener(uint8_t datapoint_id, const std::function<void(TuyaDatapoint)> &func) {
 | 
			
		||||
 
 | 
			
		||||
@@ -34,19 +34,29 @@ struct TuyaDatapointListener {
 | 
			
		||||
 | 
			
		||||
enum class TuyaCommandType : uint8_t {
 | 
			
		||||
  HEARTBEAT = 0x00,
 | 
			
		||||
  QUERY_PRODUCT = 0x01,
 | 
			
		||||
  MCU_CONF = 0x02,
 | 
			
		||||
  PRODUCT_QUERY = 0x01,
 | 
			
		||||
  CONF_QUERY = 0x02,
 | 
			
		||||
  WIFI_STATE = 0x03,
 | 
			
		||||
  WIFI_RESET = 0x04,
 | 
			
		||||
  WIFI_SELECT = 0x05,
 | 
			
		||||
  SET_DATAPOINT = 0x06,
 | 
			
		||||
  STATE = 0x07,
 | 
			
		||||
  QUERY_STATE = 0x08,
 | 
			
		||||
  DATAPOINT_DELIVER = 0x06,
 | 
			
		||||
  DATAPOINT_REPORT = 0x07,
 | 
			
		||||
  DATAPOINT_QUERY = 0x08,
 | 
			
		||||
  WIFI_TEST = 0x0E,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class TuyaInitState : uint8_t {
 | 
			
		||||
  INIT_HEARTBEAT = 0x00,
 | 
			
		||||
  INIT_PRODUCT,
 | 
			
		||||
  INIT_CONF,
 | 
			
		||||
  INIT_WIFI,
 | 
			
		||||
  INIT_DATAPOINT,
 | 
			
		||||
  INIT_DONE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Tuya : public Component, public uart::UARTDevice {
 | 
			
		||||
 public:
 | 
			
		||||
  float get_setup_priority() const override { return setup_priority::HARDWARE; }
 | 
			
		||||
  float get_setup_priority() const override { return setup_priority::LATE; }
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void loop() override;
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
@@ -62,8 +72,10 @@ class Tuya : public Component, public uart::UARTDevice {
 | 
			
		||||
  void send_command_(TuyaCommandType command, const uint8_t *buffer, uint16_t len);
 | 
			
		||||
  void send_empty_command_(TuyaCommandType command) { this->send_command_(command, nullptr, 0); }
 | 
			
		||||
 | 
			
		||||
  TuyaInitState init_state_ = TuyaInitState::INIT_HEARTBEAT;
 | 
			
		||||
  int gpio_status_ = -1;
 | 
			
		||||
  int gpio_reset_ = -1;
 | 
			
		||||
  std::string product_ = "";
 | 
			
		||||
  std::vector<TuyaDatapointListener> listeners_;
 | 
			
		||||
  std::vector<TuyaDatapoint> datapoints_;
 | 
			
		||||
  std::vector<uint8_t> rx_message_;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ from esphome import pins
 | 
			
		||||
from esphome.components import sensor
 | 
			
		||||
from esphome.const import CONF_ID, CONF_WIND_SPEED, CONF_PIN, \
 | 
			
		||||
    CONF_WIND_DIRECTION_DEGREES, UNIT_KILOMETER_PER_HOUR, \
 | 
			
		||||
    UNIT_EMPTY, ICON_WEATHER_WINDY, ICON_SIGN_DIRECTION
 | 
			
		||||
    ICON_WEATHER_WINDY, ICON_SIGN_DIRECTION, UNIT_DEGREES
 | 
			
		||||
 | 
			
		||||
tx20_ns = cg.esphome_ns.namespace('tx20')
 | 
			
		||||
Tx20Component = tx20_ns.class_('Tx20Component', cg.Component)
 | 
			
		||||
@@ -14,7 +14,7 @@ CONFIG_SCHEMA = cv.Schema({
 | 
			
		||||
    cv.Optional(CONF_WIND_SPEED):
 | 
			
		||||
        sensor.sensor_schema(UNIT_KILOMETER_PER_HOUR, ICON_WEATHER_WINDY, 1),
 | 
			
		||||
    cv.Optional(CONF_WIND_DIRECTION_DEGREES):
 | 
			
		||||
        sensor.sensor_schema(UNIT_EMPTY, ICON_SIGN_DIRECTION, 1),
 | 
			
		||||
        sensor.sensor_schema(UNIT_DEGREES, ICON_SIGN_DIRECTION, 1),
 | 
			
		||||
    cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema,
 | 
			
		||||
                                  pins.validate_has_interrupt),
 | 
			
		||||
}).extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
 
 | 
			
		||||
@@ -46,12 +46,7 @@ void UARTComponent::dump_config() {
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Baud Rate: %u baud", this->baud_rate_);
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Stop bits: %u", this->stop_bits_);
 | 
			
		||||
#ifdef USE_LOGGER
 | 
			
		||||
  if (this->hw_serial_ == &Serial && logger::global_logger->get_baud_rate() != 0) {
 | 
			
		||||
    ESP_LOGW(TAG, "  You're using the same serial port for logging and the UART component. Please "
 | 
			
		||||
                  "disable logging over the serial port by setting logger->baud_rate to 0.");
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
  this->check_logger_conflict_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UARTComponent::write_byte(uint8_t data) {
 | 
			
		||||
@@ -156,13 +151,7 @@ void UARTComponent::dump_config() {
 | 
			
		||||
  } else {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  Using software serial");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#ifdef USE_LOGGER
 | 
			
		||||
  if (this->hw_serial_ == &Serial && logger::global_logger->get_baud_rate() != 0) {
 | 
			
		||||
    ESP_LOGW(TAG, "  You're using the same serial port for logging and the UART component. Please "
 | 
			
		||||
                  "disable logging over the serial port by setting logger->baud_rate to 0.");
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
  this->check_logger_conflict_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UARTComponent::write_byte(uint8_t data) {
 | 
			
		||||
@@ -306,7 +295,8 @@ void ICACHE_RAM_ATTR HOT ESP8266SoftwareSerial::write_byte(uint8_t data) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    uint32_t wait = this->bit_time_;
 | 
			
		||||
    const uint32_t start = ESP.getCycleCount();
 | 
			
		||||
    // Start bit
 | 
			
		||||
@@ -323,7 +313,7 @@ void ICACHE_RAM_ATTR HOT ESP8266SoftwareSerial::write_byte(uint8_t data) {
 | 
			
		||||
    this->write_bit_(true, &wait, start);
 | 
			
		||||
    if (this->stop_bits_ == 2)
 | 
			
		||||
      this->wait_(&wait, start);
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void ICACHE_RAM_ATTR ESP8266SoftwareSerial::wait_(uint32_t *wait, const uint32_t &start) {
 | 
			
		||||
  while (ESP.getCycleCount() - start < *wait)
 | 
			
		||||
@@ -334,7 +324,7 @@ bool ICACHE_RAM_ATTR ESP8266SoftwareSerial::read_bit_(uint32_t *wait, const uint
 | 
			
		||||
  this->wait_(wait, start);
 | 
			
		||||
  return this->rx_pin_->digital_read();
 | 
			
		||||
}
 | 
			
		||||
void ESP8266SoftwareSerial::write_bit_(bool bit, uint32_t *wait, const uint32_t &start) {
 | 
			
		||||
void ICACHE_RAM_ATTR ESP8266SoftwareSerial::write_bit_(bool bit, uint32_t *wait, const uint32_t &start) {
 | 
			
		||||
  this->tx_pin_->digital_write(bit);
 | 
			
		||||
  this->wait_(wait, start);
 | 
			
		||||
}
 | 
			
		||||
@@ -378,6 +368,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=\"");
 | 
			
		||||
@@ -62,6 +64,7 @@ void WebServer::set_js_url(const char *js_url) { this->js_url_ = js_url; }
 | 
			
		||||
 | 
			
		||||
void WebServer::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up web server...");
 | 
			
		||||
  this->setup_controller();
 | 
			
		||||
  this->base_->init();
 | 
			
		||||
 | 
			
		||||
  this->events_.onConnect([this](AsyncEventSourceClient *client) {
 | 
			
		||||
@@ -135,40 +138,36 @@ 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", "");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SWITCH
 | 
			
		||||
  for (auto *obj : App.get_switches())
 | 
			
		||||
    if (!obj->is_internal())
 | 
			
		||||
    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", "");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_FAN
 | 
			
		||||
  for (auto *obj : App.get_fans())
 | 
			
		||||
    if (!obj->is_internal())
 | 
			
		||||
    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>");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_TEXT_SENSOR
 | 
			
		||||
  for (auto *obj : App.get_text_sensors())
 | 
			
		||||
    if (!obj->is_internal())
 | 
			
		||||
    write_row(stream, obj, "text_sensor", "");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
      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: {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,16 @@
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
#include "lwip/err.h"
 | 
			
		||||
#include "lwip/dns.h"
 | 
			
		||||
#include "lwip/dhcp.h"
 | 
			
		||||
#include "lwip/init.h"  // LWIP_VERSION_
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
#include "lwip/netif.h"  // struct netif
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
@@ -74,6 +82,19 @@ bool WiFiComponent::wifi_apply_power_save_() {
 | 
			
		||||
  }
 | 
			
		||||
  return wifi_set_sleep_type(power_save);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if LWIP_VERSION_MAJOR != 1
 | 
			
		||||
/*
 | 
			
		||||
  lwip v2 needs to be notified of IP changes, see also
 | 
			
		||||
  https://github.com/d-a-v/Arduino/blob/0e7d21e17144cfc5f53c016191daca8723e89ee8/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp#L251
 | 
			
		||||
 */
 | 
			
		||||
#undef netif_set_addr  // need to call lwIP-v1.4 netif_set_addr()
 | 
			
		||||
extern "C" {
 | 
			
		||||
struct netif *eagle_lwip_getif(int netif_index);
 | 
			
		||||
void netif_set_addr(struct netif *netif, const ip4_addr_t *ip, const ip4_addr_t *netmask, const ip4_addr_t *gw);
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
 | 
			
		||||
  // enable STA
 | 
			
		||||
  if (!this->wifi_mode_(true, {}))
 | 
			
		||||
@@ -94,6 +115,13 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
 | 
			
		||||
 | 
			
		||||
  bool ret = true;
 | 
			
		||||
 | 
			
		||||
#if LWIP_VERSION_MAJOR != 1
 | 
			
		||||
  // get current->previous IP address
 | 
			
		||||
  // (check below)
 | 
			
		||||
  ip_info previp{};
 | 
			
		||||
  wifi_get_ip_info(STATION_IF, &previp);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  struct ip_info info {};
 | 
			
		||||
  info.ip.addr = static_cast<uint32_t>(manual_ip->static_ip);
 | 
			
		||||
  info.gw.addr = static_cast<uint32_t>(manual_ip->gateway);
 | 
			
		||||
@@ -122,6 +150,14 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
 | 
			
		||||
    dns_setserver(1, &dns);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#if LWIP_VERSION_MAJOR != 1
 | 
			
		||||
  // trigger address change by calling lwIP-v1.4 api
 | 
			
		||||
  // only when ip is already set by other mean (generally dhcp)
 | 
			
		||||
  if (previp.ip.addr != 0 && previp.ip.addr != info.ip.addr) {
 | 
			
		||||
    netif_set_addr(eagle_lwip_getif(STATION_IF), reinterpret_cast<const ip4_addr_t *>(&info.ip),
 | 
			
		||||
                   reinterpret_cast<const ip4_addr_t *>(&info.netmask), reinterpret_cast<const ip4_addr_t *>(&info.gw));
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -133,10 +169,31 @@ IPAddress WiFiComponent::wifi_sta_ip_() {
 | 
			
		||||
  return {ip.ip.addr};
 | 
			
		||||
}
 | 
			
		||||
bool WiFiComponent::wifi_apply_hostname_() {
 | 
			
		||||
  bool ret = wifi_station_set_hostname(const_cast<char *>(App.get_name().c_str()));
 | 
			
		||||
  const std::string &hostname = App.get_name();
 | 
			
		||||
  bool ret = wifi_station_set_hostname(const_cast<char *>(hostname.c_str()));
 | 
			
		||||
  if (!ret) {
 | 
			
		||||
    ESP_LOGV(TAG, "Setting WiFi Hostname failed!");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // inform dhcp server of hostname change using dhcp_renew()
 | 
			
		||||
  for (netif *intf = netif_list; intf; intf = intf->next) {
 | 
			
		||||
    // unconditionally update all known interfaces
 | 
			
		||||
#if LWIP_VERSION_MAJOR == 1
 | 
			
		||||
    intf->hostname = (char *) wifi_station_get_hostname();
 | 
			
		||||
#else
 | 
			
		||||
    intf->hostname = wifi_station_get_hostname();
 | 
			
		||||
#endif
 | 
			
		||||
    if (netif_dhcp_data(intf) != nullptr) {
 | 
			
		||||
      // renew already started DHCP leases
 | 
			
		||||
      err_t lwipret = dhcp_renew(intf);
 | 
			
		||||
      if (lwipret != ERR_OK) {
 | 
			
		||||
        ESP_LOGW(TAG, "wifi_apply_hostname_(%s): lwIP error %d on interface %c%c (index %d)", intf->hostname,
 | 
			
		||||
                 (int) lwipret, intf->name[0], intf->name[1], intf->num);
 | 
			
		||||
        ret = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -330,8 +387,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 +451,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 +476,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 +531,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 +632,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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -63,22 +63,17 @@ bool parse_xiaomi_data_byte(uint8_t data_type, const uint8_t *data, uint8_t data
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &device) {
 | 
			
		||||
  if (!device.get_service_data_uuid().has_value()) {
 | 
			
		||||
    // ESP_LOGVV(TAG, "Xiaomi no service data");
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!device.get_service_data_uuid()->contains(0x95, 0xFE)) {
 | 
			
		||||
bool parse_xiaomi_service_data(XiaomiParseResult &result, const esp32_ble_tracker::ServiceData &service_data) {
 | 
			
		||||
  if (!service_data.uuid.contains(0x95, 0xFE)) {
 | 
			
		||||
    // ESP_LOGVV(TAG, "Xiaomi no service data UUID magic bytes");
 | 
			
		||||
    return {};
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const auto *raw = reinterpret_cast<const uint8_t *>(device.get_service_data().data());
 | 
			
		||||
  const auto raw = service_data.data;
 | 
			
		||||
 | 
			
		||||
  if (device.get_service_data().size() < 14) {
 | 
			
		||||
  if (raw.size() < 14) {
 | 
			
		||||
    // ESP_LOGVV(TAG, "Xiaomi service data too short!");
 | 
			
		||||
    return {};
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool is_lywsdcgq = (raw[1] & 0x20) == 0x20 && raw[2] == 0xAA && raw[3] == 0x01;
 | 
			
		||||
@@ -88,21 +83,9 @@ optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d
 | 
			
		||||
 | 
			
		||||
  if (!is_lywsdcgq && !is_hhccjcy01 && !is_lywsd02 && !is_cgg1) {
 | 
			
		||||
    // ESP_LOGVV(TAG, "Xiaomi no magic bytes");
 | 
			
		||||
    return {};
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    result.type = XiaomiParseResult::TYPE_LYWSDCGQ;
 | 
			
		||||
@@ -111,7 +94,51 @@ 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 = raw.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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return success;
 | 
			
		||||
}
 | 
			
		||||
optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &device) {
 | 
			
		||||
  XiaomiParseResult result;
 | 
			
		||||
  bool success = false;
 | 
			
		||||
  for (auto &service_data : device.get_service_datas()) {
 | 
			
		||||
    if (parse_xiaomi_service_data(result, service_data))
 | 
			
		||||
      success = true;
 | 
			
		||||
  }
 | 
			
		||||
  if (!success)
 | 
			
		||||
    return {};
 | 
			
		||||
  return result;
 | 
			
		||||
 
 | 
			
		||||
@@ -616,6 +616,7 @@ angle = float_with_unit("angle", u"(°|deg)", optional_unit=True)
 | 
			
		||||
_temperature_c = float_with_unit("temperature", u"(°C|° C|°|C)?")
 | 
			
		||||
_temperature_k = float_with_unit("temperature", u"(° K|° K|K)?")
 | 
			
		||||
_temperature_f = float_with_unit("temperature", u"(°F|° F|F)?")
 | 
			
		||||
decibel = float_with_unit("decibel", u"(dB|dBm|db|dbm)", optional_unit=True)
 | 
			
		||||
 | 
			
		||||
if IS_PY2:
 | 
			
		||||
    # Override voluptuous invalid to unicode for py2
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
MAJOR_VERSION = 1
 | 
			
		||||
MINOR_VERSION = 14
 | 
			
		||||
PATCH_VERSION = '0b5'
 | 
			
		||||
PATCH_VERSION = '5'
 | 
			
		||||
__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'
 | 
			
		||||
 
 | 
			
		||||
@@ -567,10 +567,12 @@ class EsphomeCore(object):
 | 
			
		||||
        return os.path.basename(self.config_path)
 | 
			
		||||
 | 
			
		||||
    def relative_config_path(self, *path):
 | 
			
		||||
        # pylint: disable=no-value-for-parameter
 | 
			
		||||
        path_ = os.path.expanduser(os.path.join(*path))
 | 
			
		||||
        return os.path.join(self.config_dir, path_)
 | 
			
		||||
 | 
			
		||||
    def relative_build_path(self, *path):
 | 
			
		||||
        # pylint: disable=no-value-for-parameter
 | 
			
		||||
        path_ = os.path.expanduser(os.path.join(*path))
 | 
			
		||||
        return os.path.join(self.build_path, path_)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -156,21 +156,6 @@ ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) {
 | 
			
		||||
 | 
			
		||||
const char *HOSTNAME_CHARACTER_WHITELIST = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
 | 
			
		||||
 | 
			
		||||
void disable_interrupts() {
 | 
			
		||||
#ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
  portDISABLE_INTERRUPTS();
 | 
			
		||||
#else
 | 
			
		||||
  noInterrupts();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
void enable_interrupts() {
 | 
			
		||||
#ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
  portENABLE_INTERRUPTS();
 | 
			
		||||
#else
 | 
			
		||||
  interrupts();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t crc8(uint8_t *data, uint8_t len) {
 | 
			
		||||
  uint8_t crc = 0;
 | 
			
		||||
 | 
			
		||||
@@ -193,8 +178,8 @@ void delay_microseconds_accurate(uint32_t usec) {
 | 
			
		||||
  if (usec <= 16383UL) {
 | 
			
		||||
    delayMicroseconds(usec);
 | 
			
		||||
  } else {
 | 
			
		||||
    delay(usec / 1000UL);
 | 
			
		||||
    delayMicroseconds(usec % 1000UL);
 | 
			
		||||
    delay(usec / 16383UL);
 | 
			
		||||
    delayMicroseconds(usec % 16383UL);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -330,4 +315,13 @@ std::string hexencode(const uint8_t *data, uint32_t len) {
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef ARDUINO_ARCH_ESP8266
 | 
			
		||||
ICACHE_RAM_ATTR InterruptLock::InterruptLock() { xt_state_ = xt_rsil(15); }
 | 
			
		||||
ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { xt_wsr_ps(xt_state_); }
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef ARDUINO_ARCH_ESP32
 | 
			
		||||
ICACHE_RAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); }
 | 
			
		||||
ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -133,16 +133,38 @@ uint16_t encode_uint16(uint8_t msb, uint8_t lsb);
 | 
			
		||||
/// Decode a 16-bit unsigned integer into an array of two values: most significant byte, least significant byte.
 | 
			
		||||
std::array<uint8_t, 2> decode_uint16(uint16_t value);
 | 
			
		||||
 | 
			
		||||
/** Cross-platform method to disable interrupts.
 | 
			
		||||
/***
 | 
			
		||||
 * An interrupt helper class.
 | 
			
		||||
 *
 | 
			
		||||
 * Useful when you need to do some timing-dependent communication.
 | 
			
		||||
 * This behaves like std::lock_guard. As long as the value is visible in the current stack, all interrupts
 | 
			
		||||
 * (including flash reads) will be disabled.
 | 
			
		||||
 *
 | 
			
		||||
 * @see Do not forget to call `enable_interrupts()` again or otherwise things will go very wrong.
 | 
			
		||||
 * Please note all functions called when the interrupt lock must be marked ICACHE_RAM_ATTR (loading code into
 | 
			
		||||
 * instruction cache is done via interrupts; disabling interrupts prevents data not already in cache from being
 | 
			
		||||
 * pulled from flash).
 | 
			
		||||
 *
 | 
			
		||||
 * Example:
 | 
			
		||||
 *
 | 
			
		||||
 * ```cpp
 | 
			
		||||
 * // interrupts are enabled
 | 
			
		||||
 * {
 | 
			
		||||
 *   InterruptLock lock;
 | 
			
		||||
 *   // do something
 | 
			
		||||
 *   // interrupts are disabled
 | 
			
		||||
 * }
 | 
			
		||||
 * // interrupts are enabled
 | 
			
		||||
 * ```
 | 
			
		||||
 */
 | 
			
		||||
void disable_interrupts();
 | 
			
		||||
class InterruptLock {
 | 
			
		||||
 public:
 | 
			
		||||
  InterruptLock();
 | 
			
		||||
  ~InterruptLock();
 | 
			
		||||
 | 
			
		||||
/// Cross-platform method to enable interrupts after they have been disabled.
 | 
			
		||||
void enable_interrupts();
 | 
			
		||||
 protected:
 | 
			
		||||
#ifdef ARDUINO_ARCH_ESP8266
 | 
			
		||||
  uint32_t xt_state_;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Calculate a crc8 of data with the provided data length.
 | 
			
		||||
uint8_t crc8(uint8_t *data, uint8_t len);
 | 
			
		||||
@@ -158,6 +180,7 @@ ParseOnOffState parse_on_off(const char *str, const char *on = nullptr, const ch
 | 
			
		||||
 | 
			
		||||
// Encode raw data to a human-readable string (for debugging)
 | 
			
		||||
std::string hexencode(const uint8_t *data, uint32_t len);
 | 
			
		||||
template<typename T> std::string hexencode(const T &data) { return hexencode(data.data(), data.size()); }
 | 
			
		||||
 | 
			
		||||
// https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971
 | 
			
		||||
template<int...> struct seq {};                                       // NOLINT
 | 
			
		||||
 
 | 
			
		||||
@@ -105,16 +105,18 @@ void ESPPreferences::save_esp8266_flash_() {
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  ESP_LOGVV(TAG, "Saving preferences to flash...");
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
  auto erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
 | 
			
		||||
  SpiFlashOpResult erase_res, write_res = SPI_FLASH_RESULT_OK;
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    erase_res = spi_flash_erase_sector(get_esp8266_flash_sector());
 | 
			
		||||
    if (erase_res == SPI_FLASH_RESULT_OK) {
 | 
			
		||||
      write_res = spi_flash_write(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (erase_res != SPI_FLASH_RESULT_OK) {
 | 
			
		||||
    enable_interrupts();
 | 
			
		||||
    ESP_LOGV(TAG, "Erase ESP8266 flash failed!");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto write_res = spi_flash_write(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4);
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  if (write_res != SPI_FLASH_RESULT_OK) {
 | 
			
		||||
    ESP_LOGV(TAG, "Write ESP8266 flash failed!");
 | 
			
		||||
    return;
 | 
			
		||||
@@ -173,9 +175,11 @@ ESPPreferences::ESPPreferences()
 | 
			
		||||
void ESPPreferences::begin() {
 | 
			
		||||
  this->flash_storage_ = new uint32_t[ESP8266_FLASH_STORAGE_SIZE];
 | 
			
		||||
  ESP_LOGVV(TAG, "Loading preferences from flash...");
 | 
			
		||||
  disable_interrupts();
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    InterruptLock lock;
 | 
			
		||||
    spi_flash_read(get_esp8266_flash_address(), this->flash_storage_, ESP8266_FLASH_STORAGE_SIZE * 4);
 | 
			
		||||
  enable_interrupts();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ESPPreferenceObject ESPPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {
 | 
			
		||||
 
 | 
			
		||||
@@ -211,6 +211,7 @@ uint32_t Scheduler::millis_() {
 | 
			
		||||
    ESP_LOGD(TAG, "Incrementing scheduler major");
 | 
			
		||||
    this->millis_major_++;
 | 
			
		||||
  }
 | 
			
		||||
  this->last_millis_ = now;
 | 
			
		||||
  return now;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,9 @@ def validate_board(value):
 | 
			
		||||
validate_platform = cv.one_of('ESP32', 'ESP8266', upper=True)
 | 
			
		||||
 | 
			
		||||
PLATFORMIO_ESP8266_LUT = {
 | 
			
		||||
    '2.6.3': 'espressif8266@2.4.0',
 | 
			
		||||
    '2.6.2': 'espressif8266@2.3.1',
 | 
			
		||||
    '2.6.1': 'espressif8266@2.3.0',
 | 
			
		||||
    '2.5.2': 'espressif8266@2.2.3',
 | 
			
		||||
    '2.5.1': 'espressif8266@2.1.0',
 | 
			
		||||
    '2.5.0': 'espressif8266@2.0.1',
 | 
			
		||||
@@ -62,8 +65,8 @@ PLATFORMIO_ESP32_LUT = {
 | 
			
		||||
    '1.0.1': 'espressif32@1.6.0',
 | 
			
		||||
    '1.0.2': 'espressif32@1.9.0',
 | 
			
		||||
    '1.0.3': 'espressif32@1.10.0',
 | 
			
		||||
    '1.0.4': 'espressif32@1.11.0',
 | 
			
		||||
    'RECOMMENDED': 'espressif32@1.11.0',
 | 
			
		||||
    '1.0.4': 'espressif32@1.12.1',
 | 
			
		||||
    'RECOMMENDED': 'espressif32@1.12.1',
 | 
			
		||||
    'LATEST': 'espressif32',
 | 
			
		||||
    'DEV': ARDUINO_VERSION_ESP32_DEV,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,9 @@ 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])
 | 
			
		||||
        host = str(config[CONF_MQTT][CONF_BROKER])
 | 
			
		||||
        port = int(config[CONF_MQTT][CONF_PORT])
 | 
			
		||||
        client.connect(host, port)
 | 
			
		||||
    except socket.error as err:
 | 
			
		||||
        raise EsphomeError("Cannot connect to MQTT broker: {}".format(err))
 | 
			
		||||
 | 
			
		||||
@@ -127,7 +129,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]), int(config[CONF_MQTT][CONF_PORT])
 | 
			
		||||
    _LOGGER.info("Getting fingerprint from %s:%s", addr[0], addr[1])
 | 
			
		||||
    try:
 | 
			
		||||
        cert_pem = ssl.get_server_certificate(addr)
 | 
			
		||||
 
 | 
			
		||||
@@ -60,6 +60,7 @@ FILTER_PLATFORMIO_LINES = [
 | 
			
		||||
    r"Using cache: .*",
 | 
			
		||||
    r'Installing dependencies',
 | 
			
		||||
    r'.* @ .* is already installed',
 | 
			
		||||
    r'Building in .* mode',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -101,12 +102,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 +168,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
 | 
			
		||||
 
 | 
			
		||||
@@ -179,7 +179,7 @@ class _Schema(vol.Schema):
 | 
			
		||||
        self._extra_schemas.append(validator)
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    # pylint: disable=arguments-differ
 | 
			
		||||
    # pylint: disable=signature-differs,arguments-differ
 | 
			
		||||
    def extend(self, *schemas, **kwargs):
 | 
			
		||||
        extra = kwargs.pop('extra', None)
 | 
			
		||||
        if kwargs:
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -42,7 +42,7 @@ build_flags = ${common.build_flags}
 | 
			
		||||
src_filter = ${common.src_filter} +<tests/livingroom8266.cpp>
 | 
			
		||||
 | 
			
		||||
[env:livingroom32]
 | 
			
		||||
platform = espressif32@1.11.0
 | 
			
		||||
platform = espressif32@1.12.1
 | 
			
		||||
board = nodemcu-32s
 | 
			
		||||
framework = arduino
 | 
			
		||||
lib_deps = ${common.lib_deps}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
voluptuous==0.11.7
 | 
			
		||||
PyYAML==5.1.2
 | 
			
		||||
paho-mqtt==1.4.0
 | 
			
		||||
colorlog==4.0.2
 | 
			
		||||
PyYAML==5.3.1
 | 
			
		||||
paho-mqtt==1.5.0
 | 
			
		||||
colorlog==4.1.0
 | 
			
		||||
tornado==5.1.1
 | 
			
		||||
typing>=3.6.6;python_version<"3.5"
 | 
			
		||||
protobuf==3.10.0
 | 
			
		||||
protobuf==3.11.3
 | 
			
		||||
tzlocal==2.0.0
 | 
			
		||||
pytz==2019.3
 | 
			
		||||
pytz==2020.1
 | 
			
		||||
pyserial==3.4
 | 
			
		||||
ifaddr==0.1.6
 | 
			
		||||
platformio==4.0.3
 | 
			
		||||
esptool==2.7
 | 
			
		||||
platformio==4.3.4
 | 
			
		||||
esptool==2.8
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,16 @@
 | 
			
		||||
voluptuous==0.11.7
 | 
			
		||||
PyYAML==5.1.2
 | 
			
		||||
paho-mqtt==1.4.0
 | 
			
		||||
colorlog==4.0.2
 | 
			
		||||
PyYAML==5.3.1
 | 
			
		||||
paho-mqtt==1.5.0
 | 
			
		||||
colorlog==4.1.0
 | 
			
		||||
tornado==5.1.1
 | 
			
		||||
typing>=3.6.6;python_version<"3.5"
 | 
			
		||||
protobuf==3.10.0
 | 
			
		||||
protobuf==3.11.3
 | 
			
		||||
tzlocal==2.0.0
 | 
			
		||||
pytz==2019.3
 | 
			
		||||
pytz==2020.1
 | 
			
		||||
pyserial==3.4
 | 
			
		||||
ifaddr==0.1.6
 | 
			
		||||
platformio==4.0.3
 | 
			
		||||
esptool==2.7
 | 
			
		||||
platformio==4.3.4
 | 
			
		||||
esptool==2.8
 | 
			
		||||
 | 
			
		||||
pylint==1.9.4 ; python_version<"3"
 | 
			
		||||
pylint==2.3.0 ; python_version>"3"
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								setup.py
									
									
									
									
									
								
							@@ -24,14 +24,14 @@ DOWNLOAD_URL = '{}/archive/v{}.zip'.format(GITHUB_URL, const.__version__)
 | 
			
		||||
 | 
			
		||||
REQUIRES = [
 | 
			
		||||
    'voluptuous==0.11.7',
 | 
			
		||||
    'PyYAML==5.1.2',
 | 
			
		||||
    'paho-mqtt==1.4.0',
 | 
			
		||||
    'colorlog==4.0.2',
 | 
			
		||||
    'PyYAML==5.3.1',
 | 
			
		||||
    'paho-mqtt==1.5.0',
 | 
			
		||||
    'colorlog==4.1.0',
 | 
			
		||||
    'tornado==5.1.1',
 | 
			
		||||
    'typing>=3.6.6;python_version<"3.5"',
 | 
			
		||||
    'protobuf==3.10.0',
 | 
			
		||||
    'typing>=3.6.6;python_version<"3.6"',
 | 
			
		||||
    'protobuf==3.11.3',
 | 
			
		||||
    'tzlocal==2.0.0',
 | 
			
		||||
    'pytz==2019.3',
 | 
			
		||||
    'pytz==2020.1',
 | 
			
		||||
    'pyserial==3.4',
 | 
			
		||||
    'ifaddr==0.1.6',
 | 
			
		||||
]
 | 
			
		||||
@@ -41,8 +41,8 @@ REQUIRES = [
 | 
			
		||||
# This means they have to be in your $PATH.
 | 
			
		||||
if os.environ.get('ESPHOME_USE_SUBPROCESS') is None:
 | 
			
		||||
    REQUIRES.extend([
 | 
			
		||||
        'platformio==4.0.3',
 | 
			
		||||
        'esptool==2.7',
 | 
			
		||||
        'platformio==4.3.4',
 | 
			
		||||
        'esptool==2.8',
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
CLASSIFIERS = [
 | 
			
		||||
 
 | 
			
		||||
@@ -1105,6 +1105,11 @@ climate:
 | 
			
		||||
    sensor: my_sensor
 | 
			
		||||
  - platform: coolix
 | 
			
		||||
    name: Coolix Climate
 | 
			
		||||
  - platform: fujitsu_general
 | 
			
		||||
    name: Fujitsu General Climate
 | 
			
		||||
  - platform: yashima
 | 
			
		||||
    name: Yashima Climate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
switch:
 | 
			
		||||
  - platform: gpio
 | 
			
		||||
 
 | 
			
		||||
@@ -620,6 +620,7 @@ light:
 | 
			
		||||
servo:
 | 
			
		||||
  id: my_servo
 | 
			
		||||
  output: out
 | 
			
		||||
  restore: true
 | 
			
		||||
 | 
			
		||||
ttp229_lsf:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user