mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	Compare commits
	
		
			14 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					60e6366521 | ||
| 
						 | 
					072b2c445c | ||
| 
						 | 
					219fe41831 | ||
| 
						 | 
					dcc8bb83af | ||
| 
						 | 
					a8e3521f3c | ||
| 
						 | 
					706dc6d116 | ||
| 
						 | 
					84accb6df6 | ||
| 
						 | 
					8421570b18 | ||
| 
						 | 
					d355543ac9 | ||
| 
						 | 
					3a597c5aa6 | ||
| 
						 | 
					c7dddaded4 | ||
| 
						 | 
					aae4b2ea5d | ||
| 
						 | 
					310e2a0b20 | ||
| 
						 | 
					0b04d143ac | 
							
								
								
									
										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,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 \
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -71,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);
 | 
			
		||||
@@ -92,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;
 | 
			
		||||
@@ -120,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;
 | 
			
		||||
@@ -144,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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,16 +481,6 @@ 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:");
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -295,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
 | 
			
		||||
@@ -312,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)
 | 
			
		||||
@@ -323,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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -64,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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,10 +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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  XiaomiParseResult result;
 | 
			
		||||
  result.type = XiaomiParseResult::TYPE_HHCCJCY01;
 | 
			
		||||
  if (is_lywsdcgq) {
 | 
			
		||||
    result.type = XiaomiParseResult::TYPE_LYWSDCGQ;
 | 
			
		||||
@@ -111,7 +105,7 @@ optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d
 | 
			
		||||
 | 
			
		||||
  const uint8_t *raw_data = &raw[raw_offset];
 | 
			
		||||
  uint8_t data_offset = 0;
 | 
			
		||||
  uint8_t data_length = device.get_service_data().size() - raw_offset;
 | 
			
		||||
  uint8_t data_length = raw.size() - raw_offset;
 | 
			
		||||
  bool success = false;
 | 
			
		||||
 | 
			
		||||
  while (true) {
 | 
			
		||||
@@ -136,6 +130,15 @@ optional<XiaomiParseResult> parse_xiaomi(const esp32_ble_tracker::ESPBTDevice &d
 | 
			
		||||
    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;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
MAJOR_VERSION = 1
 | 
			
		||||
MINOR_VERSION = 14
 | 
			
		||||
PATCH_VERSION = '3'
 | 
			
		||||
PATCH_VERSION = '4'
 | 
			
		||||
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
 | 
			
		||||
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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() { portENABLE_INTERRUPTS(); }
 | 
			
		||||
ICACHE_RAM_ATTR InterruptLock::~InterruptLock() { portDISABLE_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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,9 @@ def initialize(config, subscriptions, on_message, username, password, client_id)
 | 
			
		||||
                       tls_version=tls_version, ciphers=None)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        client.connect(str(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 = str(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',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								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.6"',
 | 
			
		||||
    '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',
 | 
			
		||||
]
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user