mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			41 Commits
		
	
	
		
			2023.3.0b1
			...
			jesserockz
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b6e765daaa | ||
| 
						 | 
					cd57469e06 | ||
| 
						 | 
					d98d6ff45f | ||
| 
						 | 
					14e38f0469 | ||
| 
						 | 
					f0f6d3f1cd | ||
| 
						 | 
					0b383542da | ||
| 
						 | 
					b2cec10601 | ||
| 
						 | 
					48658d5a55 | ||
| 
						 | 
					5207ca1d52 | ||
| 
						 | 
					7196fb8e82 | ||
| 
						 | 
					48ada2eebb | ||
| 
						 | 
					0de5808ed2 | ||
| 
						 | 
					ebc544e4b4 | ||
| 
						 | 
					a31fb3c987 | ||
| 
						 | 
					dfc7cd7f5d | ||
| 
						 | 
					a8bb2a42a1 | ||
| 
						 | 
					3d4c0e6667 | ||
| 
						 | 
					25fb288016 | ||
| 
						 | 
					1b8b8cdd11 | ||
| 
						 | 
					2f50e18eb5 | ||
| 
						 | 
					215107e8ea | ||
| 
						 | 
					d3f2b93c42 | ||
| 
						 | 
					ee7102fcd1 | ||
| 
						 | 
					a44e38300b | ||
| 
						 | 
					b00e20c29f | ||
| 
						 | 
					d642aeba0f | ||
| 
						 | 
					6a6aee510d | ||
| 
						 | 
					ea17a92dbc | ||
| 
						 | 
					32a0a60480 | ||
| 
						 | 
					5a56644702 | ||
| 
						 | 
					29113808ee | ||
| 
						 | 
					6471361715 | ||
| 
						 | 
					01687a9d57 | ||
| 
						 | 
					801fbf44c5 | ||
| 
						 | 
					ba1416cc0e | ||
| 
						 | 
					afc1c83af4 | ||
| 
						 | 
					da056866ff | ||
| 
						 | 
					336c2d34e6 | ||
| 
						 | 
					f3a969d35c | ||
| 
						 | 
					c12dd77c64 | ||
| 
						 | 
					4f138c600b | 
@@ -51,6 +51,6 @@
 | 
			
		||||
    "files.associations": {
 | 
			
		||||
      "**/.vscode/*.json": "jsonc"
 | 
			
		||||
    },
 | 
			
		||||
    "C_Cpp.clang_format_path": "/usr/bin/clang-format-11",
 | 
			
		||||
    "C_Cpp.clang_format_path": "/usr/bin/clang-format-13",
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -41,6 +41,10 @@ jobs:
 | 
			
		||||
            file: tests/test3.yaml
 | 
			
		||||
            name: Test tests/test3.yaml
 | 
			
		||||
            pio_cache_key: test3
 | 
			
		||||
          - id: test
 | 
			
		||||
            file: tests/test3.1.yaml
 | 
			
		||||
            name: Test tests/test3.1.yaml
 | 
			
		||||
            pio_cache_key: test3.1
 | 
			
		||||
          - id: test
 | 
			
		||||
            file: tests/test4.yaml
 | 
			
		||||
            name: Test tests/test4.yaml
 | 
			
		||||
@@ -129,7 +133,7 @@ jobs:
 | 
			
		||||
      - name: Install clang tools
 | 
			
		||||
        run: |
 | 
			
		||||
          sudo apt-get install \
 | 
			
		||||
              clang-format-11 \
 | 
			
		||||
              clang-format-13 \
 | 
			
		||||
              clang-tidy-11
 | 
			
		||||
        if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format'
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,6 +111,7 @@ esphome/components/hte501/* @Stock-M
 | 
			
		||||
esphome/components/hydreon_rgxx/* @functionpointer
 | 
			
		||||
esphome/components/i2c/* @esphome/core
 | 
			
		||||
esphome/components/i2s_audio/* @jesserockz
 | 
			
		||||
esphome/components/ili9xxx/* @nielsnl68
 | 
			
		||||
esphome/components/improv_base/* @esphome/core
 | 
			
		||||
esphome/components/improv_serial/* @esphome/core
 | 
			
		||||
esphome/components/ina260/* @MrEditor97
 | 
			
		||||
 
 | 
			
		||||
@@ -135,7 +135,7 @@ RUN \
 | 
			
		||||
    apt-get update \
 | 
			
		||||
    # Use pinned versions so that we get updates with build caching
 | 
			
		||||
    && apt-get install -y --no-install-recommends \
 | 
			
		||||
        clang-format-11=1:11.0.1-2 \
 | 
			
		||||
        clang-format-13=1:13.0.1-6~deb11u1 \
 | 
			
		||||
        clang-tidy-11=1:11.0.1-2 \
 | 
			
		||||
        patch=2.7.6-7 \
 | 
			
		||||
        software-properties-common=0.96.20.2-2.1 \
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ void Am43Component::control(const CoverCall &call) {
 | 
			
		||||
 | 
			
		||||
    if (this->invert_position_)
 | 
			
		||||
      pos = 1 - pos;
 | 
			
		||||
    auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100));
 | 
			
		||||
    auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t) (pos * 100));
 | 
			
		||||
    auto status =
 | 
			
		||||
        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
			
		||||
                                 packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
			
		||||
 
 | 
			
		||||
@@ -295,7 +295,7 @@ APIError APINoiseFrameHelper::state_action_() {
 | 
			
		||||
    if (aerr != APIError::OK)
 | 
			
		||||
      return aerr;
 | 
			
		||||
    // ignore contents, may be used in future for flags
 | 
			
		||||
    prologue_.push_back((uint8_t)(frame.msg.size() >> 8));
 | 
			
		||||
    prologue_.push_back((uint8_t) (frame.msg.size() >> 8));
 | 
			
		||||
    prologue_.push_back((uint8_t) frame.msg.size());
 | 
			
		||||
    prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end());
 | 
			
		||||
 | 
			
		||||
@@ -492,9 +492,9 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload
 | 
			
		||||
  // tmpbuf[1], tmpbuf[2] to be set later
 | 
			
		||||
  const uint8_t msg_offset = 3;
 | 
			
		||||
  const uint8_t payload_offset = msg_offset + 4;
 | 
			
		||||
  tmpbuf[msg_offset + 0] = (uint8_t)(type >> 8);  // type
 | 
			
		||||
  tmpbuf[msg_offset + 0] = (uint8_t) (type >> 8);  // type
 | 
			
		||||
  tmpbuf[msg_offset + 1] = (uint8_t) type;
 | 
			
		||||
  tmpbuf[msg_offset + 2] = (uint8_t)(payload_len >> 8);  // data_len
 | 
			
		||||
  tmpbuf[msg_offset + 2] = (uint8_t) (payload_len >> 8);  // data_len
 | 
			
		||||
  tmpbuf[msg_offset + 3] = (uint8_t) payload_len;
 | 
			
		||||
  // copy data
 | 
			
		||||
  std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]);
 | 
			
		||||
@@ -512,7 +512,7 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  size_t total_len = 3 + mbuf.size;
 | 
			
		||||
  tmpbuf[1] = (uint8_t)(mbuf.size >> 8);
 | 
			
		||||
  tmpbuf[1] = (uint8_t) (mbuf.size >> 8);
 | 
			
		||||
  tmpbuf[2] = (uint8_t) mbuf.size;
 | 
			
		||||
 | 
			
		||||
  struct iovec iov;
 | 
			
		||||
@@ -610,7 +610,7 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) {
 | 
			
		||||
APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
 | 
			
		||||
  uint8_t header[3];
 | 
			
		||||
  header[0] = 0x01;  // indicator
 | 
			
		||||
  header[1] = (uint8_t)(len >> 8);
 | 
			
		||||
  header[1] = (uint8_t) (len >> 8);
 | 
			
		||||
  header[2] = (uint8_t) len;
 | 
			
		||||
 | 
			
		||||
  struct iovec iov[2];
 | 
			
		||||
 
 | 
			
		||||
@@ -41,16 +41,13 @@ void BinarySensor::send_state_internal(bool state, bool is_initial) {
 | 
			
		||||
    this->state_callback_.call(state);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
std::string BinarySensor::device_class() { return ""; }
 | 
			
		||||
 | 
			
		||||
BinarySensor::BinarySensor() : state(false) {}
 | 
			
		||||
void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
 | 
			
		||||
std::string BinarySensor::get_device_class() {
 | 
			
		||||
  if (this->device_class_.has_value())
 | 
			
		||||
    return *this->device_class_;
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 | 
			
		||||
  return this->device_class();
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
void BinarySensor::add_filter(Filter *filter) {
 | 
			
		||||
  filter->parent_ = this;
 | 
			
		||||
 
 | 
			
		||||
@@ -80,14 +80,6 @@ class BinarySensor : public EntityBase {
 | 
			
		||||
 | 
			
		||||
  virtual bool is_status_binary_sensor() const;
 | 
			
		||||
 | 
			
		||||
  // ========== OVERRIDE METHODS ==========
 | 
			
		||||
  // (You'll only need this when creating your own custom binary sensor)
 | 
			
		||||
  /** Override this to set the default device class.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string device_class();
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  CallbackManager<void(bool)> state_callback_{};
 | 
			
		||||
  optional<std::string> device_class_{};  ///< Stores the override of the device class
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#include "bme680.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace bme680 {
 | 
			
		||||
@@ -117,18 +117,24 @@ void BME680Component::setup() {
 | 
			
		||||
  this->calibration_.gh2 = cal2[12] << 8 | cal2[13];
 | 
			
		||||
  this->calibration_.gh3 = cal2[15];
 | 
			
		||||
 | 
			
		||||
  if (!this->read_byte(0x02, &this->calibration_.res_heat_range)) {
 | 
			
		||||
  uint8_t temp_var = 0;
 | 
			
		||||
  if (!this->read_byte(0x02, &temp_var)) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (!this->read_byte(0x00, &this->calibration_.res_heat_val)) {
 | 
			
		||||
  this->calibration_.res_heat_range = ((temp_var & 0x30) / 16);
 | 
			
		||||
 | 
			
		||||
  if (!this->read_byte(0x00, &temp_var)) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (!this->read_byte(0x04, &this->calibration_.range_sw_err)) {
 | 
			
		||||
  this->calibration_.res_heat_val = (int8_t) temp_var;
 | 
			
		||||
 | 
			
		||||
  if (!this->read_byte(0x04, &temp_var)) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  this->calibration_.range_sw_err = ((int8_t) temp_var & (int8_t) 0xf0) / 16;
 | 
			
		||||
 | 
			
		||||
  this->calibration_.ambient_temperature = 25;  // prime ambient temperature
 | 
			
		||||
 | 
			
		||||
@@ -181,7 +187,7 @@ void BME680Component::setup() {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  gas0_control &= ~0b00001000;
 | 
			
		||||
  gas0_control |= heat_off ? 0b100 : 0b000;
 | 
			
		||||
  gas0_control |= heat_off << 3;
 | 
			
		||||
  if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
@@ -249,12 +255,12 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
 | 
			
		||||
  if (temperature > 400)
 | 
			
		||||
    temperature = 400;
 | 
			
		||||
 | 
			
		||||
  const uint8_t ambient_temperature = this->calibration_.ambient_temperature;
 | 
			
		||||
  const int8_t ambient_temperature = this->calibration_.ambient_temperature;
 | 
			
		||||
  const int8_t gh1 = this->calibration_.gh1;
 | 
			
		||||
  const int16_t gh2 = this->calibration_.gh2;
 | 
			
		||||
  const int8_t gh3 = this->calibration_.gh3;
 | 
			
		||||
  const uint8_t res_heat_range = this->calibration_.res_heat_range;
 | 
			
		||||
  const uint8_t res_heat_val = this->calibration_.res_heat_val;
 | 
			
		||||
  const int8_t res_heat_val = this->calibration_.res_heat_val;
 | 
			
		||||
 | 
			
		||||
  uint8_t heatr_res;
 | 
			
		||||
  int32_t var1;
 | 
			
		||||
@@ -269,8 +275,8 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) {
 | 
			
		||||
  var3 = var1 + (var2 / 2);
 | 
			
		||||
  var4 = (var3 / (res_heat_range + 4));
 | 
			
		||||
  var5 = (131 * res_heat_val) + 65536;
 | 
			
		||||
  heatr_res_x100 = (int32_t)(((var4 / var5) - 250) * 34);
 | 
			
		||||
  heatr_res = (uint8_t)((heatr_res_x100 + 50) / 100);
 | 
			
		||||
  heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34);
 | 
			
		||||
  heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100);
 | 
			
		||||
 | 
			
		||||
  return heatr_res;
 | 
			
		||||
}
 | 
			
		||||
@@ -293,35 +299,57 @@ uint8_t BME680Component::calc_heater_duration_(uint16_t duration) {
 | 
			
		||||
void BME680Component::read_data_() {
 | 
			
		||||
  uint8_t data[15];
 | 
			
		||||
  if (!this->read_bytes(BME680_REGISTER_FIELD0, data, 15)) {
 | 
			
		||||
    if (this->temperature_sensor_ != nullptr)
 | 
			
		||||
      this->temperature_sensor_->publish_state(NAN);
 | 
			
		||||
    if (this->pressure_sensor_ != nullptr)
 | 
			
		||||
      this->pressure_sensor_->publish_state(NAN);
 | 
			
		||||
    if (this->humidity_sensor_ != nullptr)
 | 
			
		||||
      this->humidity_sensor_->publish_state(NAN);
 | 
			
		||||
    if (this->gas_resistance_sensor_ != nullptr)
 | 
			
		||||
      this->gas_resistance_sensor_->publish_state(NAN);
 | 
			
		||||
    ESP_LOGW(TAG, "Communication with BME680 failed!");
 | 
			
		||||
    this->status_set_warning();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  this->status_clear_warning();
 | 
			
		||||
 | 
			
		||||
  uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4);
 | 
			
		||||
  uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4);
 | 
			
		||||
  uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]);
 | 
			
		||||
  uint16_t raw_gas = (uint16_t(data[13]) << 2) | (uint16_t(14) >> 6);
 | 
			
		||||
  uint16_t raw_gas = (uint16_t) ((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64));
 | 
			
		||||
  uint8_t gas_range = data[14] & 0x0F;
 | 
			
		||||
 | 
			
		||||
  float temperature = this->calc_temperature_(raw_temperature);
 | 
			
		||||
  float pressure = this->calc_pressure_(raw_pressure);
 | 
			
		||||
  float humidity = this->calc_humidity_(raw_humidity);
 | 
			
		||||
  float gas_resistance = NAN;
 | 
			
		||||
  if (data[14] & 0x20) {
 | 
			
		||||
    gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
 | 
			
		||||
  }
 | 
			
		||||
  float gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range);
 | 
			
		||||
 | 
			
		||||
  bool gas_valid = (data[14] >> 5) & 1;
 | 
			
		||||
  bool heat_stable = (data[14] >> 4) & 1;
 | 
			
		||||
  if (this->heater_temperature_ == 0 || this->heater_duration_ == 0)
 | 
			
		||||
    heat_stable = true;  // Allow reporting gas resistance when heater is disabled
 | 
			
		||||
 | 
			
		||||
  ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%% gas_resistance=%.1fΩ", temperature, pressure,
 | 
			
		||||
           humidity, gas_resistance);
 | 
			
		||||
  if (!gas_valid)
 | 
			
		||||
    ESP_LOGW(TAG, "Gas measurement unsuccessful, reading invalid!");
 | 
			
		||||
  if (!heat_stable)
 | 
			
		||||
    ESP_LOGW(TAG, "Heater unstable, reading invalid! (Normal for a few readings after a power cycle)");
 | 
			
		||||
 | 
			
		||||
  if (this->temperature_sensor_ != nullptr)
 | 
			
		||||
    this->temperature_sensor_->publish_state(temperature);
 | 
			
		||||
  if (this->pressure_sensor_ != nullptr)
 | 
			
		||||
    this->pressure_sensor_->publish_state(pressure);
 | 
			
		||||
  if (this->humidity_sensor_ != nullptr)
 | 
			
		||||
    this->humidity_sensor_->publish_state(humidity);
 | 
			
		||||
  if (this->gas_resistance_sensor_ != nullptr)
 | 
			
		||||
    this->gas_resistance_sensor_->publish_state(gas_resistance);
 | 
			
		||||
  this->status_clear_warning();
 | 
			
		||||
  if (this->gas_resistance_sensor_ != nullptr) {
 | 
			
		||||
    if (gas_valid && heat_stable) {
 | 
			
		||||
      this->gas_resistance_sensor_->publish_state(gas_resistance);
 | 
			
		||||
    } else {
 | 
			
		||||
      this->status_set_warning();
 | 
			
		||||
      this->gas_resistance_sensor_->publish_state(NAN);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float BME680Component::calc_temperature_(uint32_t raw_temperature) {
 | 
			
		||||
@@ -428,20 +456,22 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) {
 | 
			
		||||
 | 
			
		||||
  return calc_hum;
 | 
			
		||||
}
 | 
			
		||||
uint32_t BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) {
 | 
			
		||||
float BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) {
 | 
			
		||||
  float calc_gas_res;
 | 
			
		||||
  float var1 = 0;
 | 
			
		||||
  float var2 = 0;
 | 
			
		||||
  float var3 = 0;
 | 
			
		||||
  float raw_gas_f = raw_gas;
 | 
			
		||||
  float range_f = 1U << range;
 | 
			
		||||
  const float range_sw_err = this->calibration_.range_sw_err;
 | 
			
		||||
 | 
			
		||||
  var1 = 1340.0f + (5.0f * range_sw_err);
 | 
			
		||||
  var2 = var1 * (1.0f + BME680_GAS_LOOKUP_TABLE_1[range] / 100.0f);
 | 
			
		||||
  var3 = 1.0f + (BME680_GAS_LOOKUP_TABLE_2[range] / 100.0f);
 | 
			
		||||
 | 
			
		||||
  calc_gas_res = 1.0f / (var3 * 0.000000125f * float(1 << range) * (((float(raw_gas) - 512.0f) / var2) + 1.0f));
 | 
			
		||||
  calc_gas_res = 1.0f / (var3 * 0.000000125f * range_f * (((raw_gas_f - 512.0f) / var2) + 1.0f));
 | 
			
		||||
 | 
			
		||||
  return static_cast<uint32_t>(calc_gas_res);
 | 
			
		||||
  return calc_gas_res;
 | 
			
		||||
}
 | 
			
		||||
uint32_t BME680Component::calc_meas_duration_() {
 | 
			
		||||
  uint32_t tph_dur;  // Calculate in us
 | 
			
		||||
 
 | 
			
		||||
@@ -59,11 +59,11 @@ struct BME680CalibrationData {
 | 
			
		||||
  int8_t gh3;
 | 
			
		||||
 | 
			
		||||
  uint8_t res_heat_range;
 | 
			
		||||
  uint8_t res_heat_val;
 | 
			
		||||
  uint8_t range_sw_err;
 | 
			
		||||
  int8_t res_heat_val;
 | 
			
		||||
  int8_t range_sw_err;
 | 
			
		||||
 | 
			
		||||
  float tfine;
 | 
			
		||||
  uint8_t ambient_temperature;
 | 
			
		||||
  int8_t ambient_temperature;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class BME680Component : public PollingComponent, public i2c::I2CDevice {
 | 
			
		||||
@@ -117,7 +117,7 @@ class BME680Component : public PollingComponent, public i2c::I2CDevice {
 | 
			
		||||
  /// Calculate the relative humidity in % using the provided raw ADC value.
 | 
			
		||||
  float calc_humidity_(uint16_t raw_humidity);
 | 
			
		||||
  /// Calculate the gas resistance in Ω using the provided raw ADC value.
 | 
			
		||||
  uint32_t calc_gas_resistance_(uint16_t raw_gas, uint8_t range);
 | 
			
		||||
  float calc_gas_resistance_(uint16_t raw_gas, uint8_t range);
 | 
			
		||||
  /// Calculate how long the sensor will take until we can retrieve data.
 | 
			
		||||
  uint32_t calc_meas_duration_();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -145,8 +145,8 @@ void CCS811Component::send_env_data_() {
 | 
			
		||||
  // https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142
 | 
			
		||||
  uint16_t hum_conv = static_cast<uint16_t>(lroundf(humidity * 512.0f + 0.5f));
 | 
			
		||||
  uint16_t temp_conv = static_cast<uint16_t>(lroundf(temperature * 512.0f + 0.5f));
 | 
			
		||||
  this->write_bytes(0x05, {(uint8_t)((hum_conv >> 8) & 0xff), (uint8_t)((hum_conv & 0xff)),
 | 
			
		||||
                           (uint8_t)((temp_conv >> 8) & 0xff), (uint8_t)((temp_conv & 0xff))});
 | 
			
		||||
  this->write_bytes(0x05, {(uint8_t) ((hum_conv >> 8) & 0xff), (uint8_t) ((hum_conv & 0xff)),
 | 
			
		||||
                           (uint8_t) ((temp_conv >> 8) & 0xff), (uint8_t) ((temp_conv & 0xff))});
 | 
			
		||||
}
 | 
			
		||||
void CCS811Component::dump_config() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "CCS811");
 | 
			
		||||
 
 | 
			
		||||
@@ -324,6 +324,10 @@ async def setup_climate_core_(var, config):
 | 
			
		||||
        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
			
		||||
        await automation.build_automation(trigger, [], conf)
 | 
			
		||||
 | 
			
		||||
    for conf in config.get(CONF_ON_CONTROL, []):
 | 
			
		||||
        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
			
		||||
        await automation.build_automation(trigger, [], conf)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def register_climate(var, config):
 | 
			
		||||
    if not CORE.has_id(config[CONF_ID]):
 | 
			
		||||
 
 | 
			
		||||
@@ -10,23 +10,42 @@ CONF_RED_INT = "red_int"
 | 
			
		||||
CONF_GREEN_INT = "green_int"
 | 
			
		||||
CONF_BLUE_INT = "blue_int"
 | 
			
		||||
CONF_WHITE_INT = "white_int"
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.Required(CONF_ID): cv.declare_id(ColorStruct),
 | 
			
		||||
        cv.Exclusive(CONF_RED, "red"): cv.percentage,
 | 
			
		||||
        cv.Exclusive(CONF_RED_INT, "red"): cv.uint8_t,
 | 
			
		||||
        cv.Exclusive(CONF_GREEN, "green"): cv.percentage,
 | 
			
		||||
        cv.Exclusive(CONF_GREEN_INT, "green"): cv.uint8_t,
 | 
			
		||||
        cv.Exclusive(CONF_BLUE, "blue"): cv.percentage,
 | 
			
		||||
        cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t,
 | 
			
		||||
        cv.Exclusive(CONF_WHITE, "white"): cv.percentage,
 | 
			
		||||
        cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t,
 | 
			
		||||
    }
 | 
			
		||||
).extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
CONF_HEX = "hex"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
def hex_color(value):
 | 
			
		||||
    if len(value) != 6:
 | 
			
		||||
        raise cv.Invalid("Color must have six digits")
 | 
			
		||||
    try:
 | 
			
		||||
        return (int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16))
 | 
			
		||||
    except ValueError as exc:
 | 
			
		||||
        raise cv.Invalid("Color must be hexadecimal") from exc
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.Any(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.Required(CONF_ID): cv.declare_id(ColorStruct),
 | 
			
		||||
            cv.Exclusive(CONF_RED, "red"): cv.percentage,
 | 
			
		||||
            cv.Exclusive(CONF_RED_INT, "red"): cv.uint8_t,
 | 
			
		||||
            cv.Exclusive(CONF_GREEN, "green"): cv.percentage,
 | 
			
		||||
            cv.Exclusive(CONF_GREEN_INT, "green"): cv.uint8_t,
 | 
			
		||||
            cv.Exclusive(CONF_BLUE, "blue"): cv.percentage,
 | 
			
		||||
            cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t,
 | 
			
		||||
            cv.Exclusive(CONF_WHITE, "white"): cv.percentage,
 | 
			
		||||
            cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t,
 | 
			
		||||
        }
 | 
			
		||||
    ).extend(cv.COMPONENT_SCHEMA),
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.Required(CONF_ID): cv.declare_id(ColorStruct),
 | 
			
		||||
            cv.Required(CONF_HEX): hex_color,
 | 
			
		||||
        }
 | 
			
		||||
    ).extend(cv.COMPONENT_SCHEMA),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def from_rgbw(config):
 | 
			
		||||
    r = 0
 | 
			
		||||
    if CONF_RED in config:
 | 
			
		||||
        r = int(config[CONF_RED] * 255)
 | 
			
		||||
@@ -51,6 +70,16 @@ async def to_code(config):
 | 
			
		||||
    elif CONF_WHITE_INT in config:
 | 
			
		||||
        w = config[CONF_WHITE_INT]
 | 
			
		||||
 | 
			
		||||
    return (r, g, b, w)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    if CONF_HEX in config:
 | 
			
		||||
        r, g, b = config[CONF_HEX]
 | 
			
		||||
        w = 0
 | 
			
		||||
    else:
 | 
			
		||||
        r, g, b, w = from_rgbw(config)
 | 
			
		||||
 | 
			
		||||
    cg.new_variable(
 | 
			
		||||
        config[CONF_ID],
 | 
			
		||||
        cg.StructInitializer(ColorStruct, ("r", r), ("g", g), ("b", b), ("w", w)),
 | 
			
		||||
 
 | 
			
		||||
@@ -208,14 +208,10 @@ Cover::Cover() : Cover("") {}
 | 
			
		||||
std::string Cover::get_device_class() {
 | 
			
		||||
  if (this->device_class_override_.has_value())
 | 
			
		||||
    return *this->device_class_override_;
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 | 
			
		||||
  return this->device_class();
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
bool Cover::is_fully_open() const { return this->position == COVER_OPEN; }
 | 
			
		||||
bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; }
 | 
			
		||||
std::string Cover::device_class() { return ""; }
 | 
			
		||||
 | 
			
		||||
CoverCall CoverRestoreState::to_call(Cover *cover) {
 | 
			
		||||
  auto call = cover->make_call();
 | 
			
		||||
 
 | 
			
		||||
@@ -170,12 +170,6 @@ class Cover : public EntityBase {
 | 
			
		||||
 | 
			
		||||
  virtual void control(const CoverCall &call) = 0;
 | 
			
		||||
 | 
			
		||||
  /** Override this to set the default device class.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string device_class();
 | 
			
		||||
 | 
			
		||||
  optional<CoverRestoreState> restore_state_();
 | 
			
		||||
 | 
			
		||||
  CallbackManager<void()> state_callback_{};
 | 
			
		||||
 
 | 
			
		||||
@@ -305,7 +305,7 @@ bool CS5460AComponent::check_status_() {
 | 
			
		||||
      voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_);
 | 
			
		||||
 | 
			
		||||
    if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) {
 | 
			
		||||
      int32_t raw = (int32_t)(raw_energy << 8) >> 8; /* Sign-extend */
 | 
			
		||||
      int32_t raw = (int32_t) (raw_energy << 8) >> 8; /* Sign-extend */
 | 
			
		||||
      power_sensor_->publish_state(raw * power_multiplier_);
 | 
			
		||||
      prev_raw_energy_ = raw_energy;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,10 @@ void CTClampSensor::update() {
 | 
			
		||||
 | 
			
		||||
    const float rms_ac_dc_squared = this->sample_squared_sum_ / this->num_samples_;
 | 
			
		||||
    const float rms_dc = this->sample_sum_ / this->num_samples_;
 | 
			
		||||
    const float rms_ac = std::sqrt(rms_ac_dc_squared - rms_dc * rms_dc);
 | 
			
		||||
    const float rms_ac_squared = rms_ac_dc_squared - rms_dc * rms_dc;
 | 
			
		||||
    float rms_ac = 0;
 | 
			
		||||
    if (rms_ac_squared > 0)
 | 
			
		||||
      rms_ac = std::sqrt(rms_ac_squared);
 | 
			
		||||
    ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac,
 | 
			
		||||
             this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_);
 | 
			
		||||
    this->publish_state(rms_ac);
 | 
			
		||||
 
 | 
			
		||||
@@ -61,8 +61,8 @@ void DalyBmsComponent::request_data_(uint8_t data_id) {
 | 
			
		||||
  request_message[9] = 0x00;     //     |
 | 
			
		||||
  request_message[10] = 0x00;    //     |
 | 
			
		||||
  request_message[11] = 0x00;    // Empty Data
 | 
			
		||||
  request_message[12] = (uint8_t)(request_message[0] + request_message[1] + request_message[2] +
 | 
			
		||||
                                  request_message[3]);  // Checksum (Lower byte of the other bytes sum)
 | 
			
		||||
  request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] +
 | 
			
		||||
                                   request_message[3]);  // Checksum (Lower byte of the other bytes sum)
 | 
			
		||||
 | 
			
		||||
  this->write_array(request_message, sizeof(request_message));
 | 
			
		||||
  this->flush();
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ void DFPlayer::play_folder(uint16_t folder, uint16_t file) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) {
 | 
			
		||||
  uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t)(argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef};
 | 
			
		||||
  uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t) (argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef};
 | 
			
		||||
  uint16_t checksum = 0;
 | 
			
		||||
  for (uint8_t i = 1; i < 7; i++)
 | 
			
		||||
    checksum += buffer[i];
 | 
			
		||||
 
 | 
			
		||||
@@ -32,9 +32,11 @@ void Rect::extend(Rect rect) {
 | 
			
		||||
    this->h = rect.h;
 | 
			
		||||
  } else {
 | 
			
		||||
    if (this->x > rect.x) {
 | 
			
		||||
      this->w = this->w + (this->x - rect.x);
 | 
			
		||||
      this->x = rect.x;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->y > rect.y) {
 | 
			
		||||
      this->h = this->h + (this->y - rect.y);
 | 
			
		||||
      this->y = rect.y;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->x2() < rect.x2()) {
 | 
			
		||||
@@ -49,29 +51,35 @@ void Rect::shrink(Rect rect) {
 | 
			
		||||
  if (!this->inside(rect)) {
 | 
			
		||||
    (*this) = Rect();
 | 
			
		||||
  } else {
 | 
			
		||||
    if (this->x < rect.x) {
 | 
			
		||||
      this->x = rect.x;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->y < rect.y) {
 | 
			
		||||
      this->y = rect.y;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->x2() > rect.x2()) {
 | 
			
		||||
      this->w = rect.x2() - this->x;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->x < rect.x) {
 | 
			
		||||
      this->w = this->w + (this->x - rect.x);
 | 
			
		||||
      this->x = rect.x;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->y2() > rect.y2()) {
 | 
			
		||||
      this->h = rect.y2() - this->y;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->y < rect.y) {
 | 
			
		||||
      this->h = this->h + (this->y - rect.y);
 | 
			
		||||
      this->y = rect.y;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Rect::inside(int16_t x, int16_t y, bool absolute) {  // NOLINT
 | 
			
		||||
bool Rect::equal(Rect rect) {
 | 
			
		||||
  return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) {  // NOLINT
 | 
			
		||||
  if (!this->is_set()) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  if (absolute) {
 | 
			
		||||
    return ((x >= 0) && (x <= this->w) && (y >= 0) && (y <= this->h));
 | 
			
		||||
    return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2()));
 | 
			
		||||
  } else {
 | 
			
		||||
    return ((x >= this->x) && (x <= this->x2()) && (y >= this->y) && (y <= this->y2()));
 | 
			
		||||
    return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -80,15 +88,16 @@ bool Rect::inside(Rect rect, bool absolute) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  if (absolute) {
 | 
			
		||||
    return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0));
 | 
			
		||||
  } else {
 | 
			
		||||
    return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y));
 | 
			
		||||
  } else {
 | 
			
		||||
    return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Rect::info(const std::string &prefix) {
 | 
			
		||||
  if (this->is_set()) {
 | 
			
		||||
    ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d]", prefix.c_str(), this->x, this->y, this->w, this->h);
 | 
			
		||||
    ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(),
 | 
			
		||||
             this->y2());
 | 
			
		||||
  } else
 | 
			
		||||
    ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str());
 | 
			
		||||
}
 | 
			
		||||
@@ -256,7 +265,7 @@ void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align
 | 
			
		||||
    if (glyph_n < 0) {
 | 
			
		||||
      // Unknown char, skip
 | 
			
		||||
      ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]);
 | 
			
		||||
      if (font->get_glyphs_size() > 0) {
 | 
			
		||||
      if (!font->get_glyphs().empty()) {
 | 
			
		||||
        uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width;
 | 
			
		||||
        for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) {
 | 
			
		||||
          for (int glyph_y = 0; glyph_y < height; glyph_y++)
 | 
			
		||||
@@ -557,7 +566,7 @@ void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const {
 | 
			
		||||
}
 | 
			
		||||
int Font::match_next_glyph(const char *str, int *match_length) {
 | 
			
		||||
  int lo = 0;
 | 
			
		||||
  int hi = this->glyphs_size_ - 1;
 | 
			
		||||
  int hi = this->glyphs_.size() - 1;
 | 
			
		||||
  while (lo != hi) {
 | 
			
		||||
    int mid = (lo + hi + 1) / 2;
 | 
			
		||||
    if (this->glyphs_[mid].compare_to(str)) {
 | 
			
		||||
@@ -583,7 +592,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in
 | 
			
		||||
    int glyph_n = this->match_next_glyph(str + i, &match_length);
 | 
			
		||||
    if (glyph_n < 0) {
 | 
			
		||||
      // Unknown char, skip
 | 
			
		||||
      if (this->glyphs_size_ > 0)
 | 
			
		||||
      if (!this->get_glyphs().empty())
 | 
			
		||||
        x += this->get_glyphs()[0].glyph_data_->width;
 | 
			
		||||
      i++;
 | 
			
		||||
      continue;
 | 
			
		||||
@@ -604,16 +613,9 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in
 | 
			
		||||
  *width = x - min_x;
 | 
			
		||||
}
 | 
			
		||||
Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) {
 | 
			
		||||
  ExternalRAMAllocator<Glyph> allocator(ExternalRAMAllocator<Glyph>::ALLOW_FAILURE);
 | 
			
		||||
  this->glyphs_ = allocator.allocate(data_nr);
 | 
			
		||||
  if (this->glyphs_ == nullptr) {
 | 
			
		||||
    ESP_LOGE(TAG, "Could not allocate buffer for Glyphs!");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  for (int i = 0; i < data_nr; ++i) {
 | 
			
		||||
    this->glyphs_[i] = Glyph(data + i);
 | 
			
		||||
  }
 | 
			
		||||
  this->glyphs_size_ = data_nr;
 | 
			
		||||
  glyphs_.reserve(data_nr);
 | 
			
		||||
  for (int i = 0; i < data_nr; ++i)
 | 
			
		||||
    glyphs_.emplace_back(&data[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Image::get_pixel(int x, int y) const {
 | 
			
		||||
@@ -662,7 +664,7 @@ bool Animation::get_pixel(int x, int y) const {
 | 
			
		||||
    return false;
 | 
			
		||||
  const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
 | 
			
		||||
  const uint32_t frame_index = this->height_ * width_8 * this->current_frame_;
 | 
			
		||||
  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
  if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
    return false;
 | 
			
		||||
  const uint32_t pos = x + y * width_8 + frame_index;
 | 
			
		||||
  return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
 | 
			
		||||
@@ -671,7 +673,7 @@ Color Animation::get_color_pixel(int x, int y) const {
 | 
			
		||||
  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
 | 
			
		||||
    return Color::BLACK;
 | 
			
		||||
  const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
 | 
			
		||||
  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
  if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
    return Color::BLACK;
 | 
			
		||||
  const uint32_t pos = (x + y * this->width_ + frame_index) * 3;
 | 
			
		||||
  const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) |
 | 
			
		||||
@@ -683,7 +685,7 @@ Color Animation::get_rgb565_pixel(int x, int y) const {
 | 
			
		||||
  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
 | 
			
		||||
    return Color::BLACK;
 | 
			
		||||
  const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
 | 
			
		||||
  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
  if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
    return Color::BLACK;
 | 
			
		||||
  const uint32_t pos = (x + y * this->width_ + frame_index) * 2;
 | 
			
		||||
  uint16_t rgb565 =
 | 
			
		||||
@@ -697,7 +699,7 @@ Color Animation::get_grayscale_pixel(int x, int y) const {
 | 
			
		||||
  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
 | 
			
		||||
    return Color::BLACK;
 | 
			
		||||
  const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
 | 
			
		||||
  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
  if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_))
 | 
			
		||||
    return Color::BLACK;
 | 
			
		||||
  const uint32_t pos = (x + y * this->width_ + frame_index);
 | 
			
		||||
  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
 | 
			
		||||
 
 | 
			
		||||
@@ -120,8 +120,9 @@ class Rect {
 | 
			
		||||
  void extend(Rect rect);
 | 
			
		||||
  void shrink(Rect rect);
 | 
			
		||||
 | 
			
		||||
  bool inside(Rect rect, bool absolute = false);
 | 
			
		||||
  bool inside(int16_t x, int16_t y, bool absolute = false);
 | 
			
		||||
  bool inside(Rect rect, bool absolute = true);
 | 
			
		||||
  bool inside(int16_t test_x, int16_t test_y, bool absolute = true);
 | 
			
		||||
  bool equal(Rect rect);
 | 
			
		||||
  void info(const std::string &prefix = "rect info:");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -526,12 +527,10 @@ class Font {
 | 
			
		||||
  inline int get_baseline() { return this->baseline_; }
 | 
			
		||||
  inline int get_height() { return this->height_; }
 | 
			
		||||
 | 
			
		||||
  Glyph *&get_glyphs() { return this->glyphs_; }
 | 
			
		||||
  const u_int16_t &get_glyphs_size() const { return this->glyphs_size_; }
 | 
			
		||||
  const std::vector<Glyph, ExternalRAMAllocator<Glyph>> &get_glyphs() const { return glyphs_; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  Glyph *glyphs_{nullptr};
 | 
			
		||||
  u_int16_t glyphs_size_;
 | 
			
		||||
  std::vector<Glyph, ExternalRAMAllocator<Glyph>> glyphs_;
 | 
			
		||||
  int baseline_;
 | 
			
		||||
  int height_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -168,7 +168,7 @@ void ENS210Component::update() {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    // Pack bytes for humidity
 | 
			
		||||
    h_val_data = (uint32_t)((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]);
 | 
			
		||||
    h_val_data = (uint32_t) ((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]);
 | 
			
		||||
    // Extract humidity data and update the status
 | 
			
		||||
    extract_measurement_(h_val_data, &humidity_data, &humidity_status);
 | 
			
		||||
 | 
			
		||||
@@ -183,7 +183,7 @@ void ENS210Component::update() {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    // Pack bytes for temperature
 | 
			
		||||
    t_val_data = (uint32_t)((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]);
 | 
			
		||||
    t_val_data = (uint32_t) ((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]);
 | 
			
		||||
    // Extract temperature data and update the status
 | 
			
		||||
    extract_measurement_(t_val_data, &temperature_data, &temperature_status);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ void loop();
 | 
			
		||||
namespace esphome {
 | 
			
		||||
 | 
			
		||||
void IRAM_ATTR HOT yield() { vPortYield(); }
 | 
			
		||||
uint32_t IRAM_ATTR HOT millis() { return (uint32_t)(esp_timer_get_time() / 1000ULL); }
 | 
			
		||||
uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); }
 | 
			
		||||
void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
 | 
			
		||||
uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); }
 | 
			
		||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
 | 
			
		||||
 
 | 
			
		||||
@@ -316,18 +316,18 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
 | 
			
		||||
    case 0xD:  // int12.
 | 
			
		||||
    case 0xE:  // int16.
 | 
			
		||||
      if (length > 2) {
 | 
			
		||||
        return (float) ((int16_t)(value[1] << 8) + (int16_t) value[2]);
 | 
			
		||||
        return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]);
 | 
			
		||||
      }
 | 
			
		||||
      // fall through
 | 
			
		||||
    case 0xF:  // int24.
 | 
			
		||||
      if (length > 3) {
 | 
			
		||||
        return (float) ((int32_t)(value[1] << 16) + (int32_t)(value[2] << 8) + (int32_t)(value[3]));
 | 
			
		||||
        return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3]));
 | 
			
		||||
      }
 | 
			
		||||
      // fall through
 | 
			
		||||
    case 0x10:  // int32.
 | 
			
		||||
      if (length > 4) {
 | 
			
		||||
        return (float) ((int32_t)(value[1] << 24) + (int32_t)(value[2] << 16) + (int32_t)(value[3] << 8) +
 | 
			
		||||
                        (int32_t)(value[4]));
 | 
			
		||||
        return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) +
 | 
			
		||||
                        (int32_t) (value[4]));
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_,
 | 
			
		||||
 
 | 
			
		||||
@@ -45,10 +45,11 @@ class BLEClientBase : public espbt::ESPBTClient, public Component {
 | 
			
		||||
      memset(this->remote_bda_, 0, sizeof(this->remote_bda_));
 | 
			
		||||
      this->address_str_ = "";
 | 
			
		||||
    } else {
 | 
			
		||||
      this->address_str_ = str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t)(this->address_ >> 40) & 0xff,
 | 
			
		||||
                                        (uint8_t)(this->address_ >> 32) & 0xff, (uint8_t)(this->address_ >> 24) & 0xff,
 | 
			
		||||
                                        (uint8_t)(this->address_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff,
 | 
			
		||||
                                        (uint8_t)(this->address_ >> 0) & 0xff);
 | 
			
		||||
      this->address_str_ =
 | 
			
		||||
          str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t) (this->address_ >> 40) & 0xff,
 | 
			
		||||
                       (uint8_t) (this->address_ >> 32) & 0xff, (uint8_t) (this->address_ >> 24) & 0xff,
 | 
			
		||||
                       (uint8_t) (this->address_ >> 16) & 0xff, (uint8_t) (this->address_ >> 8) & 0xff,
 | 
			
		||||
                       (uint8_t) (this->address_ >> 0) & 0xff);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  std::string address_str() const { return this->address_str_; }
 | 
			
		||||
 
 | 
			
		||||
@@ -148,44 +148,44 @@ bool BLECharacteristic::is_failed() {
 | 
			
		||||
 | 
			
		||||
void BLECharacteristic::set_broadcast_property(bool value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void BLECharacteristic::set_indicate_property(bool value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void BLECharacteristic::set_notify_property(bool value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void BLECharacteristic::set_read_property(bool value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void BLECharacteristic::set_write_property(bool value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void BLECharacteristic::set_write_no_response_property(bool value) {
 | 
			
		||||
  if (value) {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
 | 
			
		||||
    this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,6 +55,22 @@ FRAME_SIZES = {
 | 
			
		||||
    "SXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024,
 | 
			
		||||
    "1600X1200": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
 | 
			
		||||
    "UXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200,
 | 
			
		||||
    "1920X1080": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1920X1080,
 | 
			
		||||
    "FHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1920X1080,
 | 
			
		||||
    "720X1280": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_720X1280,
 | 
			
		||||
    "PHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_720X1280,
 | 
			
		||||
    "864X1536": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_864X1536,
 | 
			
		||||
    "P3MP": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_864X1536,
 | 
			
		||||
    "2048X1536": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2048X1536,
 | 
			
		||||
    "QXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2048X1536,
 | 
			
		||||
    "2560X1440": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1440,
 | 
			
		||||
    "QHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1440,
 | 
			
		||||
    "2560X1600": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1600,
 | 
			
		||||
    "WQXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1600,
 | 
			
		||||
    "1080X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1080X1920,
 | 
			
		||||
    "PFHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1080X1920,
 | 
			
		||||
    "2560X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920,
 | 
			
		||||
    "QSXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920,
 | 
			
		||||
}
 | 
			
		||||
ESP32GainControlMode = esp32_camera_ns.enum("ESP32GainControlMode")
 | 
			
		||||
ENUM_GAIN_CONTROL_MODE = {
 | 
			
		||||
@@ -140,7 +156,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
 | 
			
		||||
            {
 | 
			
		||||
                cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number,
 | 
			
		||||
                cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All(
 | 
			
		||||
                    cv.frequency, cv.one_of(20e6, 10e6)
 | 
			
		||||
                    cv.frequency, cv.Range(min=10e6, max=20e6)
 | 
			
		||||
                ),
 | 
			
		||||
            }
 | 
			
		||||
        ),
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,30 @@ void ESP32Camera::dump_config() {
 | 
			
		||||
    case FRAMESIZE_UXGA:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 1600x1200 (UXGA)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_FHD:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 1920x1080 (FHD)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_P_HD:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 720x1280 (P_HD)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_P_3MP:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 864x1536 (P_3MP)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_QXGA:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 2048x1536 (QXGA)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_QHD:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 2560x1440 (QHD)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_WQXGA:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 2560x1600 (WQXGA)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_P_FHD:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 1080x1920 (P_FHD)");
 | 
			
		||||
      break;
 | 
			
		||||
    case FRAMESIZE_QSXGA:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Resolution: 2560x1920 (QSXGA)");
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
@@ -257,6 +281,30 @@ void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) {
 | 
			
		||||
    case ESP32_CAMERA_SIZE_1600X1200:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_UXGA;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_1920X1080:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_FHD;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_720X1280:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_P_HD;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_864X1536:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_P_3MP;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_2048X1536:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_QXGA;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_2560X1440:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_QHD;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_2560X1600:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_WQXGA;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_1080X1920:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_P_FHD;
 | 
			
		||||
      break;
 | 
			
		||||
    case ESP32_CAMERA_SIZE_2560X1920:
 | 
			
		||||
      this->config_.frame_size = FRAMESIZE_QSXGA;
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; }
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,14 @@ enum ESP32CameraFrameSize {
 | 
			
		||||
  ESP32_CAMERA_SIZE_1024X768,   // XGA
 | 
			
		||||
  ESP32_CAMERA_SIZE_1280X1024,  // SXGA
 | 
			
		||||
  ESP32_CAMERA_SIZE_1600X1200,  // UXGA
 | 
			
		||||
  ESP32_CAMERA_SIZE_1920X1080,  // FHD
 | 
			
		||||
  ESP32_CAMERA_SIZE_720X1280,   // PHD
 | 
			
		||||
  ESP32_CAMERA_SIZE_864X1536,   // P3MP
 | 
			
		||||
  ESP32_CAMERA_SIZE_2048X1536,  // QXGA
 | 
			
		||||
  ESP32_CAMERA_SIZE_2560X1440,  // QHD
 | 
			
		||||
  ESP32_CAMERA_SIZE_2560X1600,  // WQXGA
 | 
			
		||||
  ESP32_CAMERA_SIZE_1080X1920,  // PFHD
 | 
			
		||||
  ESP32_CAMERA_SIZE_2560X1920,  // QSXGA
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ESP32AgcGainCeiling {
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ from esphome.const import (
 | 
			
		||||
    CONF_VOLTAGE_ATTENUATION,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import TimePeriod
 | 
			
		||||
from esphome.components import esp32
 | 
			
		||||
 | 
			
		||||
AUTO_LOAD = ["binary_sensor"]
 | 
			
		||||
DEPENDENCIES = ["esp32"]
 | 
			
		||||
@@ -50,30 +51,37 @@ VOLTAGE_ATTENUATION = {
 | 
			
		||||
    "0V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(): cv.declare_id(ESP32TouchComponent),
 | 
			
		||||
        cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean,
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            CONF_IIR_FILTER, default="0ms"
 | 
			
		||||
        ): cv.positive_time_period_milliseconds,
 | 
			
		||||
        cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All(
 | 
			
		||||
            cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906))
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_MEASUREMENT_DURATION, default="8192us"): cv.All(
 | 
			
		||||
            cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=8192))
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_LOW_VOLTAGE_REFERENCE, default="0.5V"): validate_voltage(
 | 
			
		||||
            LOW_VOLTAGE_REFERENCE
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_HIGH_VOLTAGE_REFERENCE, default="2.7V"): validate_voltage(
 | 
			
		||||
            HIGH_VOLTAGE_REFERENCE
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_VOLTAGE_ATTENUATION, default="0V"): validate_voltage(
 | 
			
		||||
            VOLTAGE_ATTENUATION
 | 
			
		||||
        ),
 | 
			
		||||
    }
 | 
			
		||||
).extend(cv.COMPONENT_SCHEMA)
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(): cv.declare_id(ESP32TouchComponent),
 | 
			
		||||
            cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean,
 | 
			
		||||
            cv.Optional(
 | 
			
		||||
                CONF_IIR_FILTER, default="0ms"
 | 
			
		||||
            ): cv.positive_time_period_milliseconds,
 | 
			
		||||
            cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All(
 | 
			
		||||
                cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906))
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_MEASUREMENT_DURATION, default="8192us"): cv.All(
 | 
			
		||||
                cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=8192))
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_LOW_VOLTAGE_REFERENCE, default="0.5V"): validate_voltage(
 | 
			
		||||
                LOW_VOLTAGE_REFERENCE
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_HIGH_VOLTAGE_REFERENCE, default="2.7V"): validate_voltage(
 | 
			
		||||
                HIGH_VOLTAGE_REFERENCE
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_VOLTAGE_ATTENUATION, default="0V"): validate_voltage(
 | 
			
		||||
                VOLTAGE_ATTENUATION
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    ).extend(cv.COMPONENT_SCHEMA),
 | 
			
		||||
    esp32.only_on_variant(
 | 
			
		||||
        supported=[
 | 
			
		||||
            esp32.const.VARIANT_ESP32,
 | 
			
		||||
        ]
 | 
			
		||||
    ),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
from esphome.components import binary_sensor
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_PIN,
 | 
			
		||||
@@ -7,6 +8,13 @@ from esphome.const import (
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
)
 | 
			
		||||
from esphome.components.esp32 import gpio
 | 
			
		||||
from esphome.components.esp32.const import (
 | 
			
		||||
    KEY_ESP32,
 | 
			
		||||
    KEY_VARIANT,
 | 
			
		||||
    VARIANT_ESP32,
 | 
			
		||||
    VARIANT_ESP32S2,
 | 
			
		||||
    VARIANT_ESP32S3,
 | 
			
		||||
)
 | 
			
		||||
from . import esp32_touch_ns, ESP32TouchComponent
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["esp32_touch", "esp32"]
 | 
			
		||||
@@ -15,24 +23,63 @@ CONF_ESP32_TOUCH_ID = "esp32_touch_id"
 | 
			
		||||
CONF_WAKEUP_THRESHOLD = "wakeup_threshold"
 | 
			
		||||
 | 
			
		||||
TOUCH_PADS = {
 | 
			
		||||
    4: cg.global_ns.TOUCH_PAD_NUM0,
 | 
			
		||||
    0: cg.global_ns.TOUCH_PAD_NUM1,
 | 
			
		||||
    2: cg.global_ns.TOUCH_PAD_NUM2,
 | 
			
		||||
    15: cg.global_ns.TOUCH_PAD_NUM3,
 | 
			
		||||
    13: cg.global_ns.TOUCH_PAD_NUM4,
 | 
			
		||||
    12: cg.global_ns.TOUCH_PAD_NUM5,
 | 
			
		||||
    14: cg.global_ns.TOUCH_PAD_NUM6,
 | 
			
		||||
    27: cg.global_ns.TOUCH_PAD_NUM7,
 | 
			
		||||
    33: cg.global_ns.TOUCH_PAD_NUM8,
 | 
			
		||||
    32: cg.global_ns.TOUCH_PAD_NUM9,
 | 
			
		||||
    VARIANT_ESP32: {
 | 
			
		||||
        4: cg.global_ns.TOUCH_PAD_NUM0,
 | 
			
		||||
        0: cg.global_ns.TOUCH_PAD_NUM1,
 | 
			
		||||
        2: cg.global_ns.TOUCH_PAD_NUM2,
 | 
			
		||||
        15: cg.global_ns.TOUCH_PAD_NUM3,
 | 
			
		||||
        13: cg.global_ns.TOUCH_PAD_NUM4,
 | 
			
		||||
        12: cg.global_ns.TOUCH_PAD_NUM5,
 | 
			
		||||
        14: cg.global_ns.TOUCH_PAD_NUM6,
 | 
			
		||||
        27: cg.global_ns.TOUCH_PAD_NUM7,
 | 
			
		||||
        33: cg.global_ns.TOUCH_PAD_NUM8,
 | 
			
		||||
        32: cg.global_ns.TOUCH_PAD_NUM9,
 | 
			
		||||
    },
 | 
			
		||||
    VARIANT_ESP32S2: {
 | 
			
		||||
        1: cg.global_ns.TOUCH_PAD_NUM1,
 | 
			
		||||
        2: cg.global_ns.TOUCH_PAD_NUM2,
 | 
			
		||||
        3: cg.global_ns.TOUCH_PAD_NUM3,
 | 
			
		||||
        4: cg.global_ns.TOUCH_PAD_NUM4,
 | 
			
		||||
        5: cg.global_ns.TOUCH_PAD_NUM5,
 | 
			
		||||
        6: cg.global_ns.TOUCH_PAD_NUM6,
 | 
			
		||||
        7: cg.global_ns.TOUCH_PAD_NUM7,
 | 
			
		||||
        8: cg.global_ns.TOUCH_PAD_NUM8,
 | 
			
		||||
        9: cg.global_ns.TOUCH_PAD_NUM9,
 | 
			
		||||
        10: cg.global_ns.TOUCH_PAD_NUM10,
 | 
			
		||||
        11: cg.global_ns.TOUCH_PAD_NUM11,
 | 
			
		||||
        12: cg.global_ns.TOUCH_PAD_NUM12,
 | 
			
		||||
        13: cg.global_ns.TOUCH_PAD_NUM13,
 | 
			
		||||
        14: cg.global_ns.TOUCH_PAD_NUM14,
 | 
			
		||||
    },
 | 
			
		||||
    VARIANT_ESP32S3: {
 | 
			
		||||
        1: cg.global_ns.TOUCH_PAD_NUM1,
 | 
			
		||||
        2: cg.global_ns.TOUCH_PAD_NUM2,
 | 
			
		||||
        3: cg.global_ns.TOUCH_PAD_NUM3,
 | 
			
		||||
        4: cg.global_ns.TOUCH_PAD_NUM4,
 | 
			
		||||
        5: cg.global_ns.TOUCH_PAD_NUM5,
 | 
			
		||||
        6: cg.global_ns.TOUCH_PAD_NUM6,
 | 
			
		||||
        7: cg.global_ns.TOUCH_PAD_NUM7,
 | 
			
		||||
        8: cg.global_ns.TOUCH_PAD_NUM8,
 | 
			
		||||
        9: cg.global_ns.TOUCH_PAD_NUM9,
 | 
			
		||||
        10: cg.global_ns.TOUCH_PAD_NUM10,
 | 
			
		||||
        11: cg.global_ns.TOUCH_PAD_NUM11,
 | 
			
		||||
        12: cg.global_ns.TOUCH_PAD_NUM12,
 | 
			
		||||
        13: cg.global_ns.TOUCH_PAD_NUM13,
 | 
			
		||||
        14: cg.global_ns.TOUCH_PAD_NUM14,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_touch_pad(value):
 | 
			
		||||
    value = gpio.validate_gpio_pin(value)
 | 
			
		||||
    if value not in TOUCH_PADS:
 | 
			
		||||
    variant = CORE.data[KEY_ESP32][KEY_VARIANT]
 | 
			
		||||
    if variant not in TOUCH_PADS:
 | 
			
		||||
        raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.")
 | 
			
		||||
 | 
			
		||||
    pads = TOUCH_PADS[variant]
 | 
			
		||||
    if value not in pads:
 | 
			
		||||
        raise cv.Invalid(f"Pin {value} does not support touch pads.")
 | 
			
		||||
    return value
 | 
			
		||||
    return cv.enum(pads)(value)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ESP32TouchBinarySensor = esp32_touch_ns.class_(
 | 
			
		||||
@@ -53,7 +100,7 @@ async def to_code(config):
 | 
			
		||||
    hub = await cg.get_variable(config[CONF_ESP32_TOUCH_ID])
 | 
			
		||||
    var = cg.new_Pvariable(
 | 
			
		||||
        config[CONF_ID],
 | 
			
		||||
        TOUCH_PADS[config[CONF_PIN]],
 | 
			
		||||
        config[CONF_PIN],
 | 
			
		||||
        config[CONF_THRESHOLD],
 | 
			
		||||
        config[CONF_WAKEUP_THRESHOLD],
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -36,12 +36,25 @@ ETHERNET_TYPES = {
 | 
			
		||||
    "JL1101": EthernetType.ETHERNET_TYPE_JL1101,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t")
 | 
			
		||||
emac_rmii_clock_gpio_t = cg.global_ns.enum("emac_rmii_clock_gpio_t")
 | 
			
		||||
CLK_MODES = {
 | 
			
		||||
    "GPIO0_IN": emac_rmii_clock_gpio_t.EMAC_CLK_IN_GPIO,
 | 
			
		||||
    "GPIO0_OUT": emac_rmii_clock_gpio_t.EMAC_APPL_CLK_OUT_GPIO,
 | 
			
		||||
    "GPIO16_OUT": emac_rmii_clock_gpio_t.EMAC_CLK_OUT_GPIO,
 | 
			
		||||
    "GPIO17_OUT": emac_rmii_clock_gpio_t.EMAC_CLK_OUT_180_GPIO,
 | 
			
		||||
    "GPIO0_IN": (
 | 
			
		||||
        emac_rmii_clock_mode_t.EMAC_CLK_EXT_IN,
 | 
			
		||||
        emac_rmii_clock_gpio_t.EMAC_CLK_IN_GPIO,
 | 
			
		||||
    ),
 | 
			
		||||
    "GPIO0_OUT": (
 | 
			
		||||
        emac_rmii_clock_mode_t.EMAC_CLK_OUT,
 | 
			
		||||
        emac_rmii_clock_gpio_t.EMAC_APPL_CLK_OUT_GPIO,
 | 
			
		||||
    ),
 | 
			
		||||
    "GPIO16_OUT": (
 | 
			
		||||
        emac_rmii_clock_mode_t.EMAC_CLK_OUT,
 | 
			
		||||
        emac_rmii_clock_gpio_t.EMAC_CLK_OUT_GPIO,
 | 
			
		||||
    ),
 | 
			
		||||
    "GPIO17_OUT": (
 | 
			
		||||
        emac_rmii_clock_mode_t.EMAC_CLK_OUT,
 | 
			
		||||
        emac_rmii_clock_gpio_t.EMAC_CLK_OUT_180_GPIO,
 | 
			
		||||
    ),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -114,7 +127,7 @@ async def to_code(config):
 | 
			
		||||
    cg.add(var.set_mdc_pin(config[CONF_MDC_PIN]))
 | 
			
		||||
    cg.add(var.set_mdio_pin(config[CONF_MDIO_PIN]))
 | 
			
		||||
    cg.add(var.set_type(config[CONF_TYPE]))
 | 
			
		||||
    cg.add(var.set_clk_mode(CLK_MODES[config[CONF_CLK_MODE]]))
 | 
			
		||||
    cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]]))
 | 
			
		||||
    cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
 | 
			
		||||
 | 
			
		||||
    if CONF_POWER_PIN in config:
 | 
			
		||||
 
 | 
			
		||||
@@ -47,8 +47,8 @@ void EthernetComponent::setup() {
 | 
			
		||||
 | 
			
		||||
  mac_config.smi_mdc_gpio_num = this->mdc_pin_;
 | 
			
		||||
  mac_config.smi_mdio_gpio_num = this->mdio_pin_;
 | 
			
		||||
  mac_config.clock_config.rmii.clock_mode = this->clk_mode_ == EMAC_CLK_IN_GPIO ? EMAC_CLK_EXT_IN : EMAC_CLK_OUT;
 | 
			
		||||
  mac_config.clock_config.rmii.clock_gpio = this->clk_mode_;
 | 
			
		||||
  mac_config.clock_config.rmii.clock_mode = this->clk_mode_;
 | 
			
		||||
  mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_;
 | 
			
		||||
 | 
			
		||||
  esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config);
 | 
			
		||||
 | 
			
		||||
@@ -315,7 +315,10 @@ void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_
 | 
			
		||||
void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; }
 | 
			
		||||
void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; }
 | 
			
		||||
void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
 | 
			
		||||
void EthernetComponent::set_clk_mode(emac_rmii_clock_gpio_t clk_mode) { this->clk_mode_ = clk_mode; }
 | 
			
		||||
void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio) {
 | 
			
		||||
  this->clk_mode_ = clk_mode;
 | 
			
		||||
  this->clk_gpio_ = clk_gpio;
 | 
			
		||||
}
 | 
			
		||||
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
 | 
			
		||||
 | 
			
		||||
std::string EthernetComponent::get_use_address() const {
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ class EthernetComponent : public Component {
 | 
			
		||||
  void set_mdc_pin(uint8_t mdc_pin);
 | 
			
		||||
  void set_mdio_pin(uint8_t mdio_pin);
 | 
			
		||||
  void set_type(EthernetType type);
 | 
			
		||||
  void set_clk_mode(emac_rmii_clock_gpio_t clk_mode);
 | 
			
		||||
  void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio);
 | 
			
		||||
  void set_manual_ip(const ManualIP &manual_ip);
 | 
			
		||||
 | 
			
		||||
  network::IPAddress get_ip_address();
 | 
			
		||||
@@ -70,7 +70,8 @@ class EthernetComponent : public Component {
 | 
			
		||||
  uint8_t mdc_pin_{23};
 | 
			
		||||
  uint8_t mdio_pin_{18};
 | 
			
		||||
  EthernetType type_{ETHERNET_TYPE_LAN8720};
 | 
			
		||||
  emac_rmii_clock_gpio_t clk_mode_{EMAC_CLK_IN_GPIO};
 | 
			
		||||
  emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
 | 
			
		||||
  emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
 | 
			
		||||
  optional<ManualIP> manual_ip_{};
 | 
			
		||||
 | 
			
		||||
  bool started_{false};
 | 
			
		||||
 
 | 
			
		||||
@@ -95,7 +95,7 @@ void FingerprintGrowComponent::scan_and_match_() {
 | 
			
		||||
  }
 | 
			
		||||
  if (this->scan_image_(1) == OK) {
 | 
			
		||||
    this->waiting_removal_ = true;
 | 
			
		||||
    this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t)(this->capacity_ >> 8), (uint8_t)(this->capacity_ & 0xFF)};
 | 
			
		||||
    this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t) (this->capacity_ >> 8), (uint8_t) (this->capacity_ & 0xFF)};
 | 
			
		||||
    switch (this->send_command_()) {
 | 
			
		||||
      case OK: {
 | 
			
		||||
        ESP_LOGD(TAG, "Fingerprint matched");
 | 
			
		||||
@@ -171,7 +171,7 @@ uint8_t FingerprintGrowComponent::save_fingerprint_() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ESP_LOGI(TAG, "Storing model");
 | 
			
		||||
  this->data_ = {STORE, 0x01, (uint8_t)(this->enrollment_slot_ >> 8), (uint8_t)(this->enrollment_slot_ & 0xFF)};
 | 
			
		||||
  this->data_ = {STORE, 0x01, (uint8_t) (this->enrollment_slot_ >> 8), (uint8_t) (this->enrollment_slot_ & 0xFF)};
 | 
			
		||||
  switch (this->send_command_()) {
 | 
			
		||||
    case OK:
 | 
			
		||||
      ESP_LOGI(TAG, "Stored model");
 | 
			
		||||
@@ -188,8 +188,8 @@ uint8_t FingerprintGrowComponent::save_fingerprint_() {
 | 
			
		||||
 | 
			
		||||
bool FingerprintGrowComponent::check_password_() {
 | 
			
		||||
  ESP_LOGD(TAG, "Checking password");
 | 
			
		||||
  this->data_ = {VERIFY_PASSWORD, (uint8_t)(this->password_ >> 24), (uint8_t)(this->password_ >> 16),
 | 
			
		||||
                 (uint8_t)(this->password_ >> 8), (uint8_t)(this->password_ & 0xFF)};
 | 
			
		||||
  this->data_ = {VERIFY_PASSWORD, (uint8_t) (this->password_ >> 24), (uint8_t) (this->password_ >> 16),
 | 
			
		||||
                 (uint8_t) (this->password_ >> 8), (uint8_t) (this->password_ & 0xFF)};
 | 
			
		||||
  switch (this->send_command_()) {
 | 
			
		||||
    case OK:
 | 
			
		||||
      ESP_LOGD(TAG, "Password verified");
 | 
			
		||||
@@ -203,8 +203,8 @@ bool FingerprintGrowComponent::check_password_() {
 | 
			
		||||
 | 
			
		||||
bool FingerprintGrowComponent::set_password_() {
 | 
			
		||||
  ESP_LOGI(TAG, "Setting new password: %d", this->new_password_);
 | 
			
		||||
  this->data_ = {SET_PASSWORD, (uint8_t)(this->new_password_ >> 24), (uint8_t)(this->new_password_ >> 16),
 | 
			
		||||
                 (uint8_t)(this->new_password_ >> 8), (uint8_t)(this->new_password_ & 0xFF)};
 | 
			
		||||
  this->data_ = {SET_PASSWORD, (uint8_t) (this->new_password_ >> 24), (uint8_t) (this->new_password_ >> 16),
 | 
			
		||||
                 (uint8_t) (this->new_password_ >> 8), (uint8_t) (this->new_password_ & 0xFF)};
 | 
			
		||||
  if (this->send_command_() == OK) {
 | 
			
		||||
    ESP_LOGI(TAG, "New password successfully set");
 | 
			
		||||
    ESP_LOGI(TAG, "Define the new password in your configuration and reflash now");
 | 
			
		||||
@@ -250,7 +250,7 @@ void FingerprintGrowComponent::get_fingerprint_count_() {
 | 
			
		||||
 | 
			
		||||
void FingerprintGrowComponent::delete_fingerprint(uint16_t finger_id) {
 | 
			
		||||
  ESP_LOGI(TAG, "Deleting fingerprint in slot %d", finger_id);
 | 
			
		||||
  this->data_ = {DELETE, (uint8_t)(finger_id >> 8), (uint8_t)(finger_id & 0xFF), 0x00, 0x01};
 | 
			
		||||
  this->data_ = {DELETE, (uint8_t) (finger_id >> 8), (uint8_t) (finger_id & 0xFF), 0x00, 0x01};
 | 
			
		||||
  switch (this->send_command_()) {
 | 
			
		||||
    case OK:
 | 
			
		||||
      ESP_LOGI(TAG, "Deleted fingerprint");
 | 
			
		||||
@@ -320,8 +320,8 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t FingerprintGrowComponent::send_command_() {
 | 
			
		||||
  this->write((uint8_t)(START_CODE >> 8));
 | 
			
		||||
  this->write((uint8_t)(START_CODE & 0xFF));
 | 
			
		||||
  this->write((uint8_t) (START_CODE >> 8));
 | 
			
		||||
  this->write((uint8_t) (START_CODE & 0xFF));
 | 
			
		||||
  this->write(this->address_[0]);
 | 
			
		||||
  this->write(this->address_[1]);
 | 
			
		||||
  this->write(this->address_[2]);
 | 
			
		||||
@@ -329,8 +329,8 @@ uint8_t FingerprintGrowComponent::send_command_() {
 | 
			
		||||
  this->write(COMMAND);
 | 
			
		||||
 | 
			
		||||
  uint16_t wire_length = this->data_.size() + 2;
 | 
			
		||||
  this->write((uint8_t)(wire_length >> 8));
 | 
			
		||||
  this->write((uint8_t)(wire_length & 0xFF));
 | 
			
		||||
  this->write((uint8_t) (wire_length >> 8));
 | 
			
		||||
  this->write((uint8_t) (wire_length & 0xFF));
 | 
			
		||||
 | 
			
		||||
  uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND;
 | 
			
		||||
  for (auto data : this->data_) {
 | 
			
		||||
@@ -338,8 +338,8 @@ uint8_t FingerprintGrowComponent::send_command_() {
 | 
			
		||||
    sum += data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->write((uint8_t)(sum >> 8));
 | 
			
		||||
  this->write((uint8_t)(sum & 0xFF));
 | 
			
		||||
  this->write((uint8_t) (sum >> 8));
 | 
			
		||||
  this->write((uint8_t) (sum & 0xFF));
 | 
			
		||||
 | 
			
		||||
  this->data_.clear();
 | 
			
		||||
 | 
			
		||||
@@ -354,11 +354,11 @@ uint8_t FingerprintGrowComponent::send_command_() {
 | 
			
		||||
    byte = this->read();
 | 
			
		||||
    switch (idx) {
 | 
			
		||||
      case 0:
 | 
			
		||||
        if (byte != (uint8_t)(START_CODE >> 8))
 | 
			
		||||
        if (byte != (uint8_t) (START_CODE >> 8))
 | 
			
		||||
          continue;
 | 
			
		||||
        break;
 | 
			
		||||
      case 1:
 | 
			
		||||
        if (byte != (uint8_t)(START_CODE & 0xFF)) {
 | 
			
		||||
        if (byte != (uint8_t) (START_CODE & 0xFF)) {
 | 
			
		||||
          idx = 0;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -91,10 +91,10 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
 | 
			
		||||
  void set_address(uint32_t address) {
 | 
			
		||||
    this->address_[0] = (uint8_t)(address >> 24);
 | 
			
		||||
    this->address_[1] = (uint8_t)(address >> 16);
 | 
			
		||||
    this->address_[2] = (uint8_t)(address >> 8);
 | 
			
		||||
    this->address_[3] = (uint8_t)(address & 0xFF);
 | 
			
		||||
    this->address_[0] = (uint8_t) (address >> 24);
 | 
			
		||||
    this->address_[1] = (uint8_t) (address >> 16);
 | 
			
		||||
    this->address_[2] = (uint8_t) (address >> 8);
 | 
			
		||||
    this->address_[3] = (uint8_t) (address & 0xFF);
 | 
			
		||||
  }
 | 
			
		||||
  void set_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_pin; }
 | 
			
		||||
  void set_password(uint32_t password) { this->password_ = password; }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, con
 | 
			
		||||
  uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits));
 | 
			
		||||
  // Calculate the mask & clear the space for the data.
 | 
			
		||||
  // Clear the destination bits.
 | 
			
		||||
  *dst &= ~(uint8_t)(mask << offset);
 | 
			
		||||
  *dst &= ~(uint8_t) (mask << offset);
 | 
			
		||||
  // Merge in the data.
 | 
			
		||||
  *dst |= ((data & mask) << offset);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, con
 | 
			
		||||
  uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits));
 | 
			
		||||
  // Calculate the mask & clear the space for the data.
 | 
			
		||||
  // Clear the destination bits.
 | 
			
		||||
  *dst &= ~(uint8_t)(mask << offset);
 | 
			
		||||
  *dst &= ~(uint8_t) (mask << offset);
 | 
			
		||||
  // Merge in the data.
 | 
			
		||||
  *dst |= ((data & mask) << offset);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,9 +35,9 @@ uint8_t HONEYWELLABPSensor::readsensor_() {
 | 
			
		||||
  // if device is normal and there is new data, bitmask and save the raw data
 | 
			
		||||
  if (status_ == 0) {
 | 
			
		||||
    // 14 - bit pressure is the last 6 bits of byte 0 (high bits) & all of byte 1 (lowest 8 bits)
 | 
			
		||||
    pressure_count_ = ((uint16_t)(buf_[0]) << 8 & 0x3F00) | ((uint16_t)(buf_[1]) & 0xFF);
 | 
			
		||||
    pressure_count_ = ((uint16_t) (buf_[0]) << 8 & 0x3F00) | ((uint16_t) (buf_[1]) & 0xFF);
 | 
			
		||||
    // 11 - bit temperature is all of byte 2 (lowest 8 bits) and the first three bits of byte 3
 | 
			
		||||
    temperature_count_ = (((uint16_t)(buf_[2]) << 3) & 0x7F8) | (((uint16_t)(buf_[3]) >> 5) & 0x7);
 | 
			
		||||
    temperature_count_ = (((uint16_t) (buf_[2]) << 3) & 0x7F8) | (((uint16_t) (buf_[3]) >> 5) & 0x7);
 | 
			
		||||
    ESP_LOGV(TAG, "Sensor pressure_count_ %d", pressure_count_);
 | 
			
		||||
    ESP_LOGV(TAG, "Sensor temperature_count_ %d", temperature_count_);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,153 +1,5 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome import core, pins
 | 
			
		||||
from esphome.components import display, spi
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_COLOR_PALETTE,
 | 
			
		||||
    CONF_DC_PIN,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_LAMBDA,
 | 
			
		||||
    CONF_MODEL,
 | 
			
		||||
    CONF_PAGES,
 | 
			
		||||
    CONF_RAW_DATA_ID,
 | 
			
		||||
    CONF_RESET_PIN,
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.invalid(
 | 
			
		||||
    "The ili9341 platform component has been renamed to ili9xxx."
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE, HexInt
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["spi"]
 | 
			
		||||
 | 
			
		||||
CONF_COLOR_PALETTE_IMAGES = "color_palette_images"
 | 
			
		||||
CONF_LED_PIN = "led_pin"
 | 
			
		||||
 | 
			
		||||
ili9341_ns = cg.esphome_ns.namespace("ili9341")
 | 
			
		||||
ili9341 = ili9341_ns.class_(
 | 
			
		||||
    "ILI9341Display", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer
 | 
			
		||||
)
 | 
			
		||||
ILI9341M5Stack = ili9341_ns.class_("ILI9341M5Stack", ili9341)
 | 
			
		||||
ILI9341TFT24 = ili9341_ns.class_("ILI9341TFT24", ili9341)
 | 
			
		||||
ILI9341TFT24R = ili9341_ns.class_("ILI9341TFT24R", ili9341)
 | 
			
		||||
 | 
			
		||||
ILI9341Model = ili9341_ns.enum("ILI9341Model")
 | 
			
		||||
ILI9341ColorMode = ili9341_ns.enum("ILI9341ColorMode")
 | 
			
		||||
 | 
			
		||||
MODELS = {
 | 
			
		||||
    "M5STACK": ILI9341Model.M5STACK,
 | 
			
		||||
    "TFT_2.4": ILI9341Model.TFT_24,
 | 
			
		||||
    "TFT_2.4R": ILI9341Model.TFT_24R,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ILI9341_MODEL = cv.enum(MODELS, upper=True, space="_")
 | 
			
		||||
 | 
			
		||||
COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate(config):
 | 
			
		||||
    if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get(
 | 
			
		||||
        CONF_COLOR_PALETTE_IMAGES
 | 
			
		||||
    ):
 | 
			
		||||
        raise cv.Invalid(
 | 
			
		||||
            "Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette"
 | 
			
		||||
        )
 | 
			
		||||
    if (
 | 
			
		||||
        config.get(CONF_COLOR_PALETTE_IMAGES)
 | 
			
		||||
        and config.get(CONF_COLOR_PALETTE) != "IMAGE_ADAPTIVE"
 | 
			
		||||
    ):
 | 
			
		||||
        raise cv.Invalid(
 | 
			
		||||
            "Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'"
 | 
			
		||||
        )
 | 
			
		||||
    return config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    display.FULL_DISPLAY_SCHEMA.extend(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(): cv.declare_id(ili9341),
 | 
			
		||||
            cv.Required(CONF_MODEL): ILI9341_MODEL,
 | 
			
		||||
            cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_LED_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE,
 | 
			
		||||
            cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list(
 | 
			
		||||
                cv.file_
 | 
			
		||||
            ),
 | 
			
		||||
            cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.polling_component_schema("1s"))
 | 
			
		||||
    .extend(spi.spi_device_schema(False)),
 | 
			
		||||
    cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
 | 
			
		||||
    _validate,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    if config[CONF_MODEL] == "M5STACK":
 | 
			
		||||
        lcd_type = ILI9341M5Stack
 | 
			
		||||
    if config[CONF_MODEL] == "TFT_2.4":
 | 
			
		||||
        lcd_type = ILI9341TFT24
 | 
			
		||||
    if config[CONF_MODEL] == "TFT_2.4R":
 | 
			
		||||
        lcd_type = ILI9341TFT24R
 | 
			
		||||
    rhs = lcd_type.new()
 | 
			
		||||
    var = cg.Pvariable(config[CONF_ID], rhs)
 | 
			
		||||
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    await display.register_display(var, config)
 | 
			
		||||
    await spi.register_spi_device(var, config)
 | 
			
		||||
    cg.add(var.set_model(config[CONF_MODEL]))
 | 
			
		||||
    dc = await cg.gpio_pin_expression(config[CONF_DC_PIN])
 | 
			
		||||
    cg.add(var.set_dc_pin(dc))
 | 
			
		||||
 | 
			
		||||
    if CONF_LAMBDA in config:
 | 
			
		||||
        lambda_ = await cg.process_lambda(
 | 
			
		||||
            config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
 | 
			
		||||
        )
 | 
			
		||||
        cg.add(var.set_writer(lambda_))
 | 
			
		||||
    if CONF_RESET_PIN in config:
 | 
			
		||||
        reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
 | 
			
		||||
        cg.add(var.set_reset_pin(reset))
 | 
			
		||||
    if CONF_LED_PIN in config:
 | 
			
		||||
        led_pin = await cg.gpio_pin_expression(config[CONF_LED_PIN])
 | 
			
		||||
        cg.add(var.set_led_pin(led_pin))
 | 
			
		||||
 | 
			
		||||
    rhs = None
 | 
			
		||||
    if config[CONF_COLOR_PALETTE] == "GRAYSCALE":
 | 
			
		||||
        cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED))
 | 
			
		||||
        rhs = []
 | 
			
		||||
        for x in range(256):
 | 
			
		||||
            rhs.extend([HexInt(x), HexInt(x), HexInt(x)])
 | 
			
		||||
    elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE":
 | 
			
		||||
        cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED))
 | 
			
		||||
        from PIL import Image
 | 
			
		||||
 | 
			
		||||
        def load_image(filename):
 | 
			
		||||
            path = CORE.relative_config_path(filename)
 | 
			
		||||
            try:
 | 
			
		||||
                return Image.open(path)
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                raise core.EsphomeError(f"Could not load image file {path}: {e}")
 | 
			
		||||
 | 
			
		||||
        # make a wide horizontal combined image.
 | 
			
		||||
        images = [load_image(x) for x in config[CONF_COLOR_PALETTE_IMAGES]]
 | 
			
		||||
        total_width = sum(i.width for i in images)
 | 
			
		||||
        max_height = max(i.height for i in images)
 | 
			
		||||
 | 
			
		||||
        ref_image = Image.new("RGB", (total_width, max_height))
 | 
			
		||||
        x = 0
 | 
			
		||||
        for i in images:
 | 
			
		||||
            ref_image.paste(i, (x, 0))
 | 
			
		||||
            x = x + i.width
 | 
			
		||||
 | 
			
		||||
        # reduce the colors on combined image to 256.
 | 
			
		||||
        converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256)
 | 
			
		||||
        # if you want to verify how the images look use
 | 
			
		||||
        # ref_image.save("ref_in.png")
 | 
			
		||||
        # converted.save("ref_out.png")
 | 
			
		||||
        palette = converted.getpalette()
 | 
			
		||||
        assert len(palette) == 256 * 3
 | 
			
		||||
        rhs = palette
 | 
			
		||||
    else:
 | 
			
		||||
        cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8))
 | 
			
		||||
 | 
			
		||||
    if rhs is not None:
 | 
			
		||||
        prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
 | 
			
		||||
        cg.add(var.set_palette(prog_arr))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,83 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9341 {
 | 
			
		||||
 | 
			
		||||
// Color definitions
 | 
			
		||||
// clang-format off
 | 
			
		||||
static const uint8_t MADCTL_MY    = 0x80;   ///< Bit 7 Bottom to top
 | 
			
		||||
static const uint8_t MADCTL_MX    = 0x40;   ///< Bit 6 Right to left
 | 
			
		||||
static const uint8_t MADCTL_MV    = 0x20;   ///< Bit 5 Reverse Mode
 | 
			
		||||
static const uint8_t MADCTL_ML    = 0x10;   ///< Bit 4 LCD refresh Bottom to top
 | 
			
		||||
static const uint8_t MADCTL_RGB   = 0x00;  ///< Bit 3 Red-Green-Blue pixel order
 | 
			
		||||
static const uint8_t MADCTL_BGR   = 0x08;  ///< Bit 3 Blue-Green-Red pixel order
 | 
			
		||||
static const uint8_t MADCTL_MH    = 0x04;   ///< Bit 2 LCD refresh right to left
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
static const uint16_t ILI9341_TFTWIDTH = 320;   ///< ILI9341 max TFT width
 | 
			
		||||
static const uint16_t ILI9341_TFTHEIGHT = 240;  ///< ILI9341 max TFT height
 | 
			
		||||
 | 
			
		||||
// All ILI9341 specific commands some are used by init()
 | 
			
		||||
static const uint8_t ILI9341_NOP = 0x00;
 | 
			
		||||
static const uint8_t ILI9341_SWRESET = 0x01;
 | 
			
		||||
static const uint8_t ILI9341_RDDID = 0x04;
 | 
			
		||||
static const uint8_t ILI9341_RDDST = 0x09;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_SLPIN = 0x10;
 | 
			
		||||
static const uint8_t ILI9341_SLPOUT = 0x11;
 | 
			
		||||
static const uint8_t ILI9341_PTLON = 0x12;
 | 
			
		||||
static const uint8_t ILI9341_NORON = 0x13;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_RDMODE = 0x0A;
 | 
			
		||||
static const uint8_t ILI9341_RDMADCTL = 0x0B;
 | 
			
		||||
static const uint8_t ILI9341_RDPIXFMT = 0x0C;
 | 
			
		||||
static const uint8_t ILI9341_RDIMGFMT = 0x0A;
 | 
			
		||||
static const uint8_t ILI9341_RDSELFDIAG = 0x0F;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_INVOFF = 0x20;
 | 
			
		||||
static const uint8_t ILI9341_INVON = 0x21;
 | 
			
		||||
static const uint8_t ILI9341_GAMMASET = 0x26;
 | 
			
		||||
static const uint8_t ILI9341_DISPOFF = 0x28;
 | 
			
		||||
static const uint8_t ILI9341_DISPON = 0x29;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_CASET = 0x2A;
 | 
			
		||||
static const uint8_t ILI9341_PASET = 0x2B;
 | 
			
		||||
static const uint8_t ILI9341_RAMWR = 0x2C;
 | 
			
		||||
static const uint8_t ILI9341_RAMRD = 0x2E;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_PTLAR = 0x30;
 | 
			
		||||
static const uint8_t ILI9341_VSCRDEF = 0x33;
 | 
			
		||||
static const uint8_t ILI9341_MADCTL = 0x36;
 | 
			
		||||
static const uint8_t ILI9341_VSCRSADD = 0x37;
 | 
			
		||||
static const uint8_t ILI9341_PIXFMT = 0x3A;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_WRDISBV = 0x51;
 | 
			
		||||
static const uint8_t ILI9341_RDDISBV = 0x52;
 | 
			
		||||
static const uint8_t ILI9341_WRCTRLD = 0x53;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_FRMCTR1 = 0xB1;
 | 
			
		||||
static const uint8_t ILI9341_FRMCTR2 = 0xB2;
 | 
			
		||||
static const uint8_t ILI9341_FRMCTR3 = 0xB3;
 | 
			
		||||
static const uint8_t ILI9341_INVCTR = 0xB4;
 | 
			
		||||
static const uint8_t ILI9341_DFUNCTR = 0xB6;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_PWCTR1 = 0xC0;
 | 
			
		||||
static const uint8_t ILI9341_PWCTR2 = 0xC1;
 | 
			
		||||
static const uint8_t ILI9341_PWCTR3 = 0xC2;
 | 
			
		||||
static const uint8_t ILI9341_PWCTR4 = 0xC3;
 | 
			
		||||
static const uint8_t ILI9341_PWCTR5 = 0xC4;
 | 
			
		||||
static const uint8_t ILI9341_VMCTR1 = 0xC5;
 | 
			
		||||
static const uint8_t ILI9341_VMCTR2 = 0xC7;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_RDID4 = 0xD3;
 | 
			
		||||
static const uint8_t ILI9341_RDINDEX = 0xD9;
 | 
			
		||||
static const uint8_t ILI9341_RDID1 = 0xDA;
 | 
			
		||||
static const uint8_t ILI9341_RDID2 = 0xDB;
 | 
			
		||||
static const uint8_t ILI9341_RDID3 = 0xDC;
 | 
			
		||||
static const uint8_t ILI9341_RDIDX = 0xDD;  // TBC
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9341_GMCTRP1 = 0xE0;
 | 
			
		||||
static const uint8_t ILI9341_GMCTRN1 = 0xE1;
 | 
			
		||||
 | 
			
		||||
}  // namespace ili9341
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -1,308 +0,0 @@
 | 
			
		||||
#include "ili9341_display.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9341 {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "ili9341";
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::setup_pins_() {
 | 
			
		||||
  this->dc_pin_->setup();  // OUTPUT
 | 
			
		||||
  this->dc_pin_->digital_write(false);
 | 
			
		||||
  if (this->reset_pin_ != nullptr) {
 | 
			
		||||
    this->reset_pin_->setup();  // OUTPUT
 | 
			
		||||
    this->reset_pin_->digital_write(true);
 | 
			
		||||
  }
 | 
			
		||||
  if (this->led_pin_ != nullptr) {
 | 
			
		||||
    this->led_pin_->setup();
 | 
			
		||||
    this->led_pin_->digital_write(true);
 | 
			
		||||
  }
 | 
			
		||||
  this->spi_setup();
 | 
			
		||||
 | 
			
		||||
  this->reset_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::dump_config() {
 | 
			
		||||
  LOG_DISPLAY("", "ili9341", this);
 | 
			
		||||
  LOG_PIN("  Reset Pin: ", this->reset_pin_);
 | 
			
		||||
  LOG_PIN("  DC Pin: ", this->dc_pin_);
 | 
			
		||||
  LOG_PIN("  Busy Pin: ", this->busy_pin_);
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ILI9341Display::get_setup_priority() const { return setup_priority::HARDWARE; }
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::command(uint8_t value) {
 | 
			
		||||
  this->start_command_();
 | 
			
		||||
  this->write_byte(value);
 | 
			
		||||
  this->end_command_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::reset_() {
 | 
			
		||||
  if (this->reset_pin_ != nullptr) {
 | 
			
		||||
    this->reset_pin_->digital_write(false);
 | 
			
		||||
    delay(10);
 | 
			
		||||
    this->reset_pin_->digital_write(true);
 | 
			
		||||
    delay(10);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::data(uint8_t value) {
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_byte(value);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) {
 | 
			
		||||
  this->command(command_byte);  // Send the command byte
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_array(data_bytes, num_data_bytes);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ILI9341Display::read_command(uint8_t command_byte, uint8_t index) {
 | 
			
		||||
  uint8_t data = 0x10 + index;
 | 
			
		||||
  this->send_command(0xD9, &data, 1);  // Set Index Register
 | 
			
		||||
  uint8_t result;
 | 
			
		||||
  this->start_command_();
 | 
			
		||||
  this->write_byte(command_byte);
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  do {
 | 
			
		||||
    result = this->read_byte();
 | 
			
		||||
  } while (index--);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::update() {
 | 
			
		||||
  this->do_update_();
 | 
			
		||||
  this->display_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::display_() {
 | 
			
		||||
  // we will only update the changed window to the display
 | 
			
		||||
  uint16_t w = this->x_high_ - this->x_low_ + 1;
 | 
			
		||||
  uint16_t h = this->y_high_ - this->y_low_ + 1;
 | 
			
		||||
  uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_);
 | 
			
		||||
 | 
			
		||||
  // check if something was displayed
 | 
			
		||||
  if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set_addr_window_(this->x_low_, this->y_low_, w, h);
 | 
			
		||||
 | 
			
		||||
  ESP_LOGVV("ILI9341", "Start ILI9341Display::display_(xl:%d, xh:%d, yl:%d, yh:%d, w:%d, h:%d, start_pos:%d)",
 | 
			
		||||
            this->x_low_, this->x_high_, this->y_low_, this->y_high_, w, h, start_pos);
 | 
			
		||||
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  for (uint16_t row = 0; row < h; row++) {
 | 
			
		||||
    uint32_t pos = start_pos + (row * width_);
 | 
			
		||||
    uint32_t rem = w;
 | 
			
		||||
 | 
			
		||||
    while (rem > 0) {
 | 
			
		||||
      uint32_t sz = buffer_to_transfer_(pos, rem);
 | 
			
		||||
      this->write_array(transfer_buffer_, 2 * sz);
 | 
			
		||||
      pos += sz;
 | 
			
		||||
      rem -= sz;
 | 
			
		||||
      App.feed_wdt();
 | 
			
		||||
    }
 | 
			
		||||
    App.feed_wdt();
 | 
			
		||||
  }
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
 | 
			
		||||
  // invalidate watermarks
 | 
			
		||||
  this->x_low_ = this->width_;
 | 
			
		||||
  this->y_low_ = this->height_;
 | 
			
		||||
  this->x_high_ = 0;
 | 
			
		||||
  this->y_high_ = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::fill(Color color) {
 | 
			
		||||
  uint8_t color332 = 0;
 | 
			
		||||
  if (this->buffer_color_mode_ == BITS_8) {
 | 
			
		||||
    color332 = display::ColorUtil::color_to_332(color);
 | 
			
		||||
  } else {  // if (this->buffer_color_mode_ == BITS_8_INDEXED)
 | 
			
		||||
    color332 = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
 | 
			
		||||
  }
 | 
			
		||||
  memset(this->buffer_, color332, this->get_buffer_length_());
 | 
			
		||||
  this->x_low_ = 0;
 | 
			
		||||
  this->y_low_ = 0;
 | 
			
		||||
  this->x_high_ = this->get_width_internal() - 1;
 | 
			
		||||
  this->y_high_ = this->get_height_internal() - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::fill_internal_(uint8_t color) {
 | 
			
		||||
  memset(transfer_buffer_, color, sizeof(transfer_buffer_));
 | 
			
		||||
 | 
			
		||||
  uint32_t rem = (this->get_buffer_length_() * 2);
 | 
			
		||||
 | 
			
		||||
  this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal());
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
 | 
			
		||||
  while (rem > 0) {
 | 
			
		||||
    size_t sz = rem <= sizeof(transfer_buffer_) ? rem : sizeof(transfer_buffer_);
 | 
			
		||||
    this->write_array(transfer_buffer_, sz);
 | 
			
		||||
    rem -= sz;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
 | 
			
		||||
  memset(buffer_, color, this->get_buffer_length_());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::rotate_my_(uint8_t m) {
 | 
			
		||||
  uint8_t rotation = m & 3;  // can't be higher than 3
 | 
			
		||||
  switch (rotation) {
 | 
			
		||||
    case 0:
 | 
			
		||||
      m = (MADCTL_MX | MADCTL_BGR);
 | 
			
		||||
      // _width = ILI9341_TFTWIDTH;
 | 
			
		||||
      // _height = ILI9341_TFTHEIGHT;
 | 
			
		||||
      break;
 | 
			
		||||
    case 1:
 | 
			
		||||
      m = (MADCTL_MV | MADCTL_BGR);
 | 
			
		||||
      // _width = ILI9341_TFTHEIGHT;
 | 
			
		||||
      // _height = ILI9341_TFTWIDTH;
 | 
			
		||||
      break;
 | 
			
		||||
    case 2:
 | 
			
		||||
      m = (MADCTL_MY | MADCTL_BGR);
 | 
			
		||||
      // _width = ILI9341_TFTWIDTH;
 | 
			
		||||
      // _height = ILI9341_TFTHEIGHT;
 | 
			
		||||
      break;
 | 
			
		||||
    case 3:
 | 
			
		||||
      m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
 | 
			
		||||
      // _width = ILI9341_TFTHEIGHT;
 | 
			
		||||
      // _height = ILI9341_TFTWIDTH;
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->command(ILI9341_MADCTL);
 | 
			
		||||
  this->data(m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HOT ILI9341Display::draw_absolute_pixel_internal(int x, int y, Color color) {
 | 
			
		||||
  if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  uint32_t pos = (y * width_) + x;
 | 
			
		||||
  uint8_t new_color;
 | 
			
		||||
 | 
			
		||||
  if (this->buffer_color_mode_ == BITS_8) {
 | 
			
		||||
    new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
 | 
			
		||||
  } else {  // if (this->buffer_color_mode_ == BITS_8_INDEXED) {
 | 
			
		||||
    new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (buffer_[pos] != new_color) {
 | 
			
		||||
    buffer_[pos] = new_color;
 | 
			
		||||
    // low and high watermark may speed up drawing from buffer
 | 
			
		||||
    this->x_low_ = (x < this->x_low_) ? x : this->x_low_;
 | 
			
		||||
    this->y_low_ = (y < this->y_low_) ? y : this->y_low_;
 | 
			
		||||
    this->x_high_ = (x > this->x_high_) ? x : this->x_high_;
 | 
			
		||||
    this->y_high_ = (y > this->y_high_) ? y : this->y_high_;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
 | 
			
		||||
// values per bit is huge
 | 
			
		||||
uint32_t ILI9341Display::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); }
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::start_command_() {
 | 
			
		||||
  this->dc_pin_->digital_write(false);
 | 
			
		||||
  this->enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::end_command_() { this->disable(); }
 | 
			
		||||
void ILI9341Display::start_data_() {
 | 
			
		||||
  this->dc_pin_->digital_write(true);
 | 
			
		||||
  this->enable();
 | 
			
		||||
}
 | 
			
		||||
void ILI9341Display::end_data_() { this->disable(); }
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::init_lcd_(const uint8_t *init_cmd) {
 | 
			
		||||
  uint8_t cmd, x, num_args;
 | 
			
		||||
  const uint8_t *addr = init_cmd;
 | 
			
		||||
  while ((cmd = progmem_read_byte(addr++)) > 0) {
 | 
			
		||||
    x = progmem_read_byte(addr++);
 | 
			
		||||
    num_args = x & 0x7F;
 | 
			
		||||
    send_command(cmd, addr, num_args);
 | 
			
		||||
    addr += num_args;
 | 
			
		||||
    if (x & 0x80)
 | 
			
		||||
      delay(150);  // NOLINT
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) {
 | 
			
		||||
  uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1);
 | 
			
		||||
  this->command(ILI9341_CASET);  // Column address set
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_byte(x1 >> 8);
 | 
			
		||||
  this->write_byte(x1);
 | 
			
		||||
  this->write_byte(x2 >> 8);
 | 
			
		||||
  this->write_byte(x2);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
  this->command(ILI9341_PASET);  // Row address set
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_byte(y1 >> 8);
 | 
			
		||||
  this->write_byte(y1);
 | 
			
		||||
  this->write_byte(y2 >> 8);
 | 
			
		||||
  this->write_byte(y2);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
  this->command(ILI9341_RAMWR);  // Write to RAM
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9341Display::invert_display_(bool invert) { this->command(invert ? ILI9341_INVON : ILI9341_INVOFF); }
 | 
			
		||||
 | 
			
		||||
int ILI9341Display::get_width_internal() { return this->width_; }
 | 
			
		||||
int ILI9341Display::get_height_internal() { return this->height_; }
 | 
			
		||||
 | 
			
		||||
uint32_t ILI9341Display::buffer_to_transfer_(uint32_t pos, uint32_t sz) {
 | 
			
		||||
  uint8_t *src = buffer_ + pos;
 | 
			
		||||
  uint8_t *dst = transfer_buffer_;
 | 
			
		||||
 | 
			
		||||
  if (sz > sizeof(transfer_buffer_) / 2) {
 | 
			
		||||
    sz = sizeof(transfer_buffer_) / 2;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (uint32_t i = 0; i < sz; ++i) {
 | 
			
		||||
    uint16_t color;
 | 
			
		||||
    if (this->buffer_color_mode_ == BITS_8) {
 | 
			
		||||
      color = display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(*src++));
 | 
			
		||||
    } else {  //  if (this->buffer_color_mode == BITS_8_INDEXED) {
 | 
			
		||||
      Color col = display::ColorUtil::index8_to_color_palette888(*src++, this->palette_);
 | 
			
		||||
      color = display::ColorUtil::color_to_565(col);
 | 
			
		||||
    }
 | 
			
		||||
    *dst++ = (uint8_t)(color >> 8);
 | 
			
		||||
    *dst++ = (uint8_t) color;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return sz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   M5Stack display
 | 
			
		||||
void ILI9341M5Stack::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_M5STACK);
 | 
			
		||||
  this->width_ = 320;
 | 
			
		||||
  this->height_ = 240;
 | 
			
		||||
  this->invert_display_(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   24_TFT display
 | 
			
		||||
void ILI9341TFT24::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_TFT);
 | 
			
		||||
  this->width_ = 240;
 | 
			
		||||
  this->height_ = 320;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   24_TFT rotated display
 | 
			
		||||
void ILI9341TFT24R::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_TFT);
 | 
			
		||||
  this->width_ = 320;
 | 
			
		||||
  this->height_ = 240;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace ili9341
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -1,70 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9341 {
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_M5STACK[] = {
 | 
			
		||||
  0xEF, 3, 0x03, 0x80, 0x02,
 | 
			
		||||
  0xCF, 3, 0x00, 0xC1, 0x30,
 | 
			
		||||
  0xED, 4, 0x64, 0x03, 0x12, 0x81,
 | 
			
		||||
  0xE8, 3, 0x85, 0x00, 0x78,
 | 
			
		||||
  0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
 | 
			
		||||
  0xF7, 1, 0x20,
 | 
			
		||||
  0xEA, 2, 0x00, 0x00,
 | 
			
		||||
  ILI9341_PWCTR1  , 1, 0x23,             // Power control VRH[5:0]
 | 
			
		||||
  ILI9341_PWCTR2  , 1, 0x10,             // Power control SAP[2:0];BT[3:0]
 | 
			
		||||
  ILI9341_VMCTR1  , 2, 0x3e, 0x28,       // VCM control
 | 
			
		||||
  ILI9341_VMCTR2  , 1, 0x86,             // VCM control2
 | 
			
		||||
  ILI9341_MADCTL  , 1, MADCTL_BGR,       // Memory Access Control
 | 
			
		||||
  ILI9341_VSCRSADD, 1, 0x00,             // Vertical scroll zero
 | 
			
		||||
  ILI9341_PIXFMT  , 1, 0x55,
 | 
			
		||||
  ILI9341_FRMCTR1 , 2, 0x00, 0x13,
 | 
			
		||||
  ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
 | 
			
		||||
  0xF2, 1, 0x00,                         // 3Gamma Function Disable
 | 
			
		||||
  ILI9341_GAMMASET , 1, 0x01,             // Gamma curve selected
 | 
			
		||||
  ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
 | 
			
		||||
                        0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
 | 
			
		||||
                        0x0E, 0x09, 0x00,
 | 
			
		||||
  ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
 | 
			
		||||
                        0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
 | 
			
		||||
                        0x31, 0x36, 0x0F,
 | 
			
		||||
  ILI9341_SLPOUT  , 0x80,                // Exit Sleep
 | 
			
		||||
  ILI9341_DISPON  , 0x80,                // Display on
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_TFT[] = {
 | 
			
		||||
  0xEF, 3, 0x03, 0x80, 0x02,
 | 
			
		||||
  0xCF, 3, 0x00, 0xC1, 0x30,
 | 
			
		||||
  0xED, 4, 0x64, 0x03, 0x12, 0x81,
 | 
			
		||||
  0xE8, 3, 0x85, 0x00, 0x78,
 | 
			
		||||
  0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
 | 
			
		||||
  0xF7, 1, 0x20,
 | 
			
		||||
  0xEA, 2, 0x00, 0x00,
 | 
			
		||||
  ILI9341_PWCTR1  , 1, 0x23,             // Power control VRH[5:0]
 | 
			
		||||
  ILI9341_PWCTR2  , 1, 0x10,             // Power control SAP[2:0];BT[3:0]
 | 
			
		||||
  ILI9341_VMCTR1  , 2, 0x3e, 0x28,       // VCM control
 | 
			
		||||
  ILI9341_VMCTR2  , 1, 0x86,             // VCM control2
 | 
			
		||||
  ILI9341_MADCTL  , 1, 0x48,             // Memory Access Control
 | 
			
		||||
  ILI9341_VSCRSADD, 1, 0x00,             // Vertical scroll zero
 | 
			
		||||
  ILI9341_PIXFMT  , 1, 0x55,
 | 
			
		||||
  ILI9341_FRMCTR1 , 2, 0x00, 0x18,
 | 
			
		||||
  ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
 | 
			
		||||
  0xF2, 1, 0x00,                         // 3Gamma Function Disable
 | 
			
		||||
  ILI9341_GAMMASET , 1, 0x01,             // Gamma curve selected
 | 
			
		||||
  ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
 | 
			
		||||
                        0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
 | 
			
		||||
                        0x0E, 0x09, 0x00,
 | 
			
		||||
  ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
 | 
			
		||||
                        0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
 | 
			
		||||
                        0x31, 0x36, 0x0F,
 | 
			
		||||
  ILI9341_SLPOUT  , 0x80,                // Exit Sleep
 | 
			
		||||
  ILI9341_DISPON  , 0x80,                // Display on
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// clang-format on
 | 
			
		||||
}  // namespace ili9341
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										0
									
								
								esphome/components/ili9xxx/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/ili9xxx/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										175
									
								
								esphome/components/ili9xxx/display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								esphome/components/ili9xxx/display.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome import core, pins
 | 
			
		||||
from esphome.components import display, spi
 | 
			
		||||
from esphome.core import CORE, HexInt
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    CONF_COLOR_PALETTE,
 | 
			
		||||
    CONF_DC_PIN,
 | 
			
		||||
    CONF_ID,
 | 
			
		||||
    CONF_LAMBDA,
 | 
			
		||||
    CONF_MODEL,
 | 
			
		||||
    CONF_RAW_DATA_ID,
 | 
			
		||||
    CONF_PAGES,
 | 
			
		||||
    CONF_RESET_PIN,
 | 
			
		||||
    CONF_DIMENSIONS,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["spi"]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def AUTO_LOAD():
 | 
			
		||||
    if CORE.is_esp32:
 | 
			
		||||
        return ["psram"]
 | 
			
		||||
    return []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@nielsnl68"]
 | 
			
		||||
 | 
			
		||||
ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx")
 | 
			
		||||
ili9XXXSPI = ili9XXX_ns.class_(
 | 
			
		||||
    "ILI9XXXDisplay", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
ILI9XXXColorMode = ili9XXX_ns.enum("ILI9XXXColorMode")
 | 
			
		||||
 | 
			
		||||
MODELS = {
 | 
			
		||||
    "M5STACK": ili9XXX_ns.class_("ILI9XXXM5Stack", ili9XXXSPI),
 | 
			
		||||
    "M5CORE": ili9XXX_ns.class_("ILI9XXXM5CORE", ili9XXXSPI),
 | 
			
		||||
    "TFT_2.4": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI),
 | 
			
		||||
    "TFT_2.4R": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI),
 | 
			
		||||
    "ILI9341": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI),
 | 
			
		||||
    "ILI9342": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI),
 | 
			
		||||
    "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI),
 | 
			
		||||
    "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI),
 | 
			
		||||
    "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI),
 | 
			
		||||
    "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE")
 | 
			
		||||
 | 
			
		||||
CONF_LED_PIN = "led_pin"
 | 
			
		||||
CONF_COLOR_PALETTE_IMAGES = "color_palette_images"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate(config):
 | 
			
		||||
    if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get(
 | 
			
		||||
        CONF_COLOR_PALETTE_IMAGES
 | 
			
		||||
    ):
 | 
			
		||||
        raise cv.Invalid(
 | 
			
		||||
            "Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette"
 | 
			
		||||
        )
 | 
			
		||||
    if (
 | 
			
		||||
        config.get(CONF_COLOR_PALETTE_IMAGES)
 | 
			
		||||
        and config.get(CONF_COLOR_PALETTE) != "IMAGE_ADAPTIVE"
 | 
			
		||||
    ):
 | 
			
		||||
        raise cv.Invalid(
 | 
			
		||||
            "Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'"
 | 
			
		||||
        )
 | 
			
		||||
    if CORE.is_esp8266 and config.get(CONF_MODEL) not in [
 | 
			
		||||
        "M5STACK",
 | 
			
		||||
        "TFT_2.4",
 | 
			
		||||
        "TFT_2.4R",
 | 
			
		||||
        "ILI9341",
 | 
			
		||||
        "ILI9342",
 | 
			
		||||
    ]:
 | 
			
		||||
        raise cv.Invalid(
 | 
			
		||||
            "Provided model can't run on ESP8266. Use an ESP32 with PSRAM onboard"
 | 
			
		||||
        )
 | 
			
		||||
    return config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    display.FULL_DISPLAY_SCHEMA.extend(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(): cv.declare_id(ili9XXXSPI),
 | 
			
		||||
            cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True, space="_"),
 | 
			
		||||
            cv.Optional(CONF_DIMENSIONS): cv.dimensions,
 | 
			
		||||
            cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_LED_PIN): cv.invalid(
 | 
			
		||||
                "This property is removed. To use the backlight use proper light component."
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE,
 | 
			
		||||
            cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
 | 
			
		||||
            cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list(
 | 
			
		||||
                cv.file_
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.polling_component_schema("1s"))
 | 
			
		||||
    .extend(spi.spi_device_schema(False)),
 | 
			
		||||
    cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
 | 
			
		||||
    _validate,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    rhs = MODELS[config[CONF_MODEL]].new()
 | 
			
		||||
    var = cg.Pvariable(config[CONF_ID], rhs)
 | 
			
		||||
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    await display.register_display(var, config)
 | 
			
		||||
    await spi.register_spi_device(var, config)
 | 
			
		||||
    dc = await cg.gpio_pin_expression(config[CONF_DC_PIN])
 | 
			
		||||
    cg.add(var.set_dc_pin(dc))
 | 
			
		||||
 | 
			
		||||
    if CONF_LAMBDA in config:
 | 
			
		||||
        lambda_ = await cg.process_lambda(
 | 
			
		||||
            config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
 | 
			
		||||
        )
 | 
			
		||||
        cg.add(var.set_writer(lambda_))
 | 
			
		||||
 | 
			
		||||
    if CONF_RESET_PIN in config:
 | 
			
		||||
        reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN])
 | 
			
		||||
        cg.add(var.set_reset_pin(reset))
 | 
			
		||||
 | 
			
		||||
    if CONF_DIMENSIONS in config:
 | 
			
		||||
        cg.add(
 | 
			
		||||
            var.set_dimentions(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1])
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    rhs = None
 | 
			
		||||
    if config[CONF_COLOR_PALETTE] == "GRAYSCALE":
 | 
			
		||||
        cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED))
 | 
			
		||||
        rhs = []
 | 
			
		||||
        for x in range(256):
 | 
			
		||||
            rhs.extend([HexInt(x), HexInt(x), HexInt(x)])
 | 
			
		||||
        prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
 | 
			
		||||
        cg.add(var.set_palette(prog_arr))
 | 
			
		||||
    elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE":
 | 
			
		||||
        cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED))
 | 
			
		||||
        from PIL import Image
 | 
			
		||||
 | 
			
		||||
        def load_image(filename):
 | 
			
		||||
            path = CORE.relative_config_path(filename)
 | 
			
		||||
            try:
 | 
			
		||||
                return Image.open(path)
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                raise core.EsphomeError(f"Could not load image file {path}: {e}")
 | 
			
		||||
 | 
			
		||||
        # make a wide horizontal combined image.
 | 
			
		||||
        images = [load_image(x) for x in config[CONF_COLOR_PALETTE_IMAGES]]
 | 
			
		||||
        total_width = sum(i.width for i in images)
 | 
			
		||||
        max_height = max(i.height for i in images)
 | 
			
		||||
 | 
			
		||||
        ref_image = Image.new("RGB", (total_width, max_height))
 | 
			
		||||
        x = 0
 | 
			
		||||
        for i in images:
 | 
			
		||||
            ref_image.paste(i, (x, 0))
 | 
			
		||||
            x = x + i.width
 | 
			
		||||
 | 
			
		||||
        # reduce the colors on combined image to 256.
 | 
			
		||||
        converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256)
 | 
			
		||||
        # if you want to verify how the images look use
 | 
			
		||||
        # ref_image.save("ref_in.png")
 | 
			
		||||
        # converted.save("ref_out.png")
 | 
			
		||||
        palette = converted.getpalette()
 | 
			
		||||
        assert len(palette) == 256 * 3
 | 
			
		||||
        rhs = palette
 | 
			
		||||
    else:
 | 
			
		||||
        cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_16))
 | 
			
		||||
 | 
			
		||||
    if rhs is not None:
 | 
			
		||||
        prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
 | 
			
		||||
        cg.add(var.set_palette(prog_arr))
 | 
			
		||||
							
								
								
									
										96
									
								
								esphome/components/ili9xxx/ili9xxx_defines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								esphome/components/ili9xxx/ili9xxx_defines.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9xxx {
 | 
			
		||||
 | 
			
		||||
// Color definitions
 | 
			
		||||
// clang-format off
 | 
			
		||||
static const uint8_t MADCTL_MY    = 0x80;   ///< Bit 7 Bottom to top
 | 
			
		||||
static const uint8_t MADCTL_MX    = 0x40;   ///< Bit 6 Right to left
 | 
			
		||||
static const uint8_t MADCTL_MV    = 0x20;   ///< Bit 5 Reverse Mode
 | 
			
		||||
static const uint8_t MADCTL_ML    = 0x10;   ///< Bit 4 LCD refresh Bottom to top
 | 
			
		||||
static const uint8_t MADCTL_RGB   = 0x00;  ///< Bit 3 Red-Green-Blue pixel order
 | 
			
		||||
static const uint8_t MADCTL_BGR   = 0x08;  ///< Bit 3 Blue-Green-Red pixel order
 | 
			
		||||
static const uint8_t MADCTL_MH    = 0x04;   ///< Bit 2 LCD refresh right to left
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
// All ILI9XXX specific commands some are used by init()
 | 
			
		||||
static const uint8_t ILI9XXX_NOP = 0x00;
 | 
			
		||||
static const uint8_t ILI9XXX_SWRESET = 0x01;
 | 
			
		||||
static const uint8_t ILI9XXX_RDDID = 0x04;
 | 
			
		||||
static const uint8_t ILI9XXX_RDDST = 0x09;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_SLPIN = 0x10;
 | 
			
		||||
static const uint8_t ILI9XXX_SLPOUT = 0x11;
 | 
			
		||||
static const uint8_t ILI9XXX_PTLON = 0x12;
 | 
			
		||||
static const uint8_t ILI9XXX_NORON = 0x13;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_RDMODE = 0x0A;
 | 
			
		||||
static const uint8_t ILI9XXX_RDMADCTL = 0x0B;
 | 
			
		||||
static const uint8_t ILI9XXX_RDPIXFMT = 0x0C;
 | 
			
		||||
static const uint8_t ILI9XXX_RDIMGFMT = 0x0D;
 | 
			
		||||
static const uint8_t ILI9XXX_RDSELFDIAG = 0x0F;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_INVOFF = 0x20;
 | 
			
		||||
static const uint8_t ILI9XXX_INVON = 0x21;
 | 
			
		||||
static const uint8_t ILI9XXX_GAMMASET = 0x26;
 | 
			
		||||
static const uint8_t ILI9XXX_DISPOFF = 0x28;
 | 
			
		||||
static const uint8_t ILI9XXX_DISPON = 0x29;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_CASET = 0x2A;
 | 
			
		||||
static const uint8_t ILI9XXX_PASET = 0x2B;
 | 
			
		||||
static const uint8_t ILI9XXX_RAMWR = 0x2C;
 | 
			
		||||
static const uint8_t ILI9XXX_RAMRD = 0x2E;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_PTLAR = 0x30;
 | 
			
		||||
static const uint8_t ILI9XXX_VSCRDEF = 0x33;
 | 
			
		||||
static const uint8_t ILI9XXX_MADCTL = 0x36;
 | 
			
		||||
static const uint8_t ILI9XXX_VSCRSADD = 0x37;
 | 
			
		||||
static const uint8_t ILI9XXX_IDMOFF = 0x38;
 | 
			
		||||
static const uint8_t ILI9XXX_IDMON = 0x39;
 | 
			
		||||
static const uint8_t ILI9XXX_PIXFMT = 0x3A;
 | 
			
		||||
static const uint8_t ILI9XXX_COLMOD = 0x3A;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_GETSCANLINE = 0x45;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_WRDISBV = 0x51;
 | 
			
		||||
static const uint8_t ILI9XXX_RDDISBV = 0x52;
 | 
			
		||||
static const uint8_t ILI9XXX_WRCTRLD = 0x53;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_IFMODE = 0xB0;
 | 
			
		||||
static const uint8_t ILI9XXX_FRMCTR1 = 0xB1;
 | 
			
		||||
static const uint8_t ILI9XXX_FRMCTR2 = 0xB2;
 | 
			
		||||
static const uint8_t ILI9XXX_FRMCTR3 = 0xB3;
 | 
			
		||||
static const uint8_t ILI9XXX_INVCTR = 0xB4;
 | 
			
		||||
static const uint8_t ILI9XXX_DFUNCTR = 0xB6;
 | 
			
		||||
static const uint8_t ILI9XXX_ETMOD = 0xB7;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_PWCTR1 = 0xC0;
 | 
			
		||||
static const uint8_t ILI9XXX_PWCTR2 = 0xC1;
 | 
			
		||||
static const uint8_t ILI9XXX_PWCTR3 = 0xC2;
 | 
			
		||||
static const uint8_t ILI9XXX_PWCTR4 = 0xC3;
 | 
			
		||||
static const uint8_t ILI9XXX_PWCTR5 = 0xC4;
 | 
			
		||||
static const uint8_t ILI9XXX_VMCTR1 = 0xC5;
 | 
			
		||||
static const uint8_t ILI9XXX_IFCTR = 0xC6;
 | 
			
		||||
static const uint8_t ILI9XXX_VMCTR2 = 0xC7;
 | 
			
		||||
static const uint8_t ILI9XXX_GMCTR = 0xC8;
 | 
			
		||||
static const uint8_t ILI9XXX_SETEXTC = 0xC8;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_PWSET = 0xD0;
 | 
			
		||||
static const uint8_t ILI9XXX_VMCTR = 0xD1;
 | 
			
		||||
static const uint8_t ILI9XXX_PWSETN = 0xD2;
 | 
			
		||||
static const uint8_t ILI9XXX_RDID4 = 0xD3;
 | 
			
		||||
static const uint8_t ILI9XXX_RDINDEX = 0xD9;
 | 
			
		||||
static const uint8_t ILI9XXX_RDID1 = 0xDA;
 | 
			
		||||
static const uint8_t ILI9XXX_RDID2 = 0xDB;
 | 
			
		||||
static const uint8_t ILI9XXX_RDID3 = 0xDC;
 | 
			
		||||
static const uint8_t ILI9XXX_RDIDX = 0xDD;  // TBC
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_GMCTRP1 = 0xE0;
 | 
			
		||||
static const uint8_t ILI9XXX_GMCTRN1 = 0xE1;
 | 
			
		||||
 | 
			
		||||
static const uint8_t ILI9XXX_CSCON = 0xF0;
 | 
			
		||||
static const uint8_t ILI9XXX_ADJCTL3 = 0xF7;
 | 
			
		||||
 | 
			
		||||
}  // namespace ili9xxx
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										416
									
								
								esphome/components/ili9xxx/ili9xxx_display.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										416
									
								
								esphome/components/ili9xxx/ili9xxx_display.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,416 @@
 | 
			
		||||
#include "ili9xxx_display.h"
 | 
			
		||||
#include "esphome/core/application.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9xxx {
 | 
			
		||||
 | 
			
		||||
static const char *const TAG = "ili9xxx";
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::setup() {
 | 
			
		||||
  this->setup_pins_();
 | 
			
		||||
  this->initialize();
 | 
			
		||||
 | 
			
		||||
  this->x_low_ = this->width_;
 | 
			
		||||
  this->y_low_ = this->height_;
 | 
			
		||||
  this->x_high_ = 0;
 | 
			
		||||
  this->y_high_ = 0;
 | 
			
		||||
  if (this->buffer_color_mode_ == BITS_16) {
 | 
			
		||||
    this->init_internal_(this->get_buffer_length_() * 2);
 | 
			
		||||
    if (this->buffer_ != nullptr) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this->buffer_color_mode_ = BITS_8;
 | 
			
		||||
  }
 | 
			
		||||
  this->init_internal_(this->get_buffer_length_());
 | 
			
		||||
  if (this->buffer_ == nullptr) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::setup_pins_() {
 | 
			
		||||
  this->dc_pin_->setup();  // OUTPUT
 | 
			
		||||
  this->dc_pin_->digital_write(false);
 | 
			
		||||
  if (this->reset_pin_ != nullptr) {
 | 
			
		||||
    this->reset_pin_->setup();  // OUTPUT
 | 
			
		||||
    this->reset_pin_->digital_write(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->spi_setup();
 | 
			
		||||
 | 
			
		||||
  this->reset_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::dump_config() {
 | 
			
		||||
  LOG_DISPLAY("", "ili9xxx", this);
 | 
			
		||||
  switch (this->buffer_color_mode_) {
 | 
			
		||||
    case BITS_8_INDEXED:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Color mode: 8bit Indexed");
 | 
			
		||||
      break;
 | 
			
		||||
    case BITS_16:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Color mode: 16bit");
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      ESP_LOGCONFIG(TAG, "  Color mode: 8bit 332 mode");
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->is_18bitdisplay_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  18-Bit Mode: YES");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  LOG_PIN("  Reset Pin: ", this->reset_pin_);
 | 
			
		||||
  LOG_PIN("  DC Pin: ", this->dc_pin_);
 | 
			
		||||
  LOG_PIN("  Busy Pin: ", this->busy_pin_);
 | 
			
		||||
 | 
			
		||||
  if (this->is_failed()) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  => Failed to init Memory: YES!");
 | 
			
		||||
  }
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ILI9XXXDisplay::get_setup_priority() const { return setup_priority::HARDWARE; }
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::fill(Color color) {
 | 
			
		||||
  uint16_t new_color = 0;
 | 
			
		||||
  this->x_low_ = 0;
 | 
			
		||||
  this->y_low_ = 0;
 | 
			
		||||
  this->x_high_ = this->get_width_internal() - 1;
 | 
			
		||||
  this->y_high_ = this->get_height_internal() - 1;
 | 
			
		||||
  switch (this->buffer_color_mode_) {
 | 
			
		||||
    case BITS_8_INDEXED:
 | 
			
		||||
      new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
 | 
			
		||||
      break;
 | 
			
		||||
    case BITS_16:
 | 
			
		||||
      new_color = display::ColorUtil::color_to_565(color);
 | 
			
		||||
      for (uint32_t i = 0; i < this->get_buffer_length_() * 2; i = i + 2) {
 | 
			
		||||
        this->buffer_[i] = (uint8_t) (new_color >> 8);
 | 
			
		||||
        this->buffer_[i + 1] = (uint8_t) new_color;
 | 
			
		||||
      }
 | 
			
		||||
      return;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  memset(this->buffer_, (uint8_t) new_color, this->get_buffer_length_());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HOT ILI9XXXDisplay::draw_absolute_pixel_internal(int x, int y, Color color) {
 | 
			
		||||
  if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  uint32_t pos = (y * width_) + x;
 | 
			
		||||
  uint16_t new_color;
 | 
			
		||||
  bool updated = false;
 | 
			
		||||
  switch (this->buffer_color_mode_) {
 | 
			
		||||
    case BITS_8_INDEXED:
 | 
			
		||||
      new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_);
 | 
			
		||||
      break;
 | 
			
		||||
    case BITS_16:
 | 
			
		||||
      pos = pos * 2;
 | 
			
		||||
      new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB);
 | 
			
		||||
      if (this->buffer_[pos] != (uint8_t) (new_color >> 8)) {
 | 
			
		||||
        this->buffer_[pos] = (uint8_t) (new_color >> 8);
 | 
			
		||||
        updated = true;
 | 
			
		||||
      }
 | 
			
		||||
      pos = pos + 1;
 | 
			
		||||
      new_color = new_color & 0xFF;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB);
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (this->buffer_[pos] != new_color) {
 | 
			
		||||
    this->buffer_[pos] = new_color;
 | 
			
		||||
    updated = true;
 | 
			
		||||
  }
 | 
			
		||||
  if (updated) {
 | 
			
		||||
    // low and high watermark may speed up drawing from buffer
 | 
			
		||||
    this->x_low_ = (x < this->x_low_) ? x : this->x_low_;
 | 
			
		||||
    this->y_low_ = (y < this->y_low_) ? y : this->y_low_;
 | 
			
		||||
    this->x_high_ = (x > this->x_high_) ? x : this->x_high_;
 | 
			
		||||
    this->y_high_ = (y > this->y_high_) ? y : this->y_high_;
 | 
			
		||||
    // ESP_LOGVV(TAG, "=>>> pixel (x:%d, y:%d) (xl:%d, xh:%d, yl:%d, yh:%d", x, y, this->x_low_, this->x_high_,
 | 
			
		||||
    //           this->y_low_, this->y_high_);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::update() {
 | 
			
		||||
  if (this->prossing_update_) {
 | 
			
		||||
    this->need_update_ = true;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  do {
 | 
			
		||||
    this->prossing_update_ = true;
 | 
			
		||||
    this->need_update_ = false;
 | 
			
		||||
    if (!this->need_update_) {
 | 
			
		||||
      this->do_update_();
 | 
			
		||||
    }
 | 
			
		||||
  } while (this->need_update_);
 | 
			
		||||
  this->prossing_update_ = false;
 | 
			
		||||
  this->display_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::display_() {
 | 
			
		||||
  // we will only update the changed window to the display
 | 
			
		||||
  uint16_t w = this->x_high_ - this->x_low_ + 1;  // NOLINT
 | 
			
		||||
  uint16_t h = this->y_high_ - this->y_low_ + 1;  // NOLINT
 | 
			
		||||
  uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_);
 | 
			
		||||
 | 
			
		||||
  // check if something was displayed
 | 
			
		||||
  if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) {
 | 
			
		||||
    ESP_LOGV(TAG, "Nothing to display");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set_addr_window_(this->x_low_, this->y_low_, w, h);
 | 
			
		||||
 | 
			
		||||
  ESP_LOGV(TAG,
 | 
			
		||||
           "Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, "
 | 
			
		||||
           "heigth:%d, start_pos:%d)",
 | 
			
		||||
           this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, start_pos);
 | 
			
		||||
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  for (uint16_t row = 0; row < h; row++) {
 | 
			
		||||
    uint32_t pos = start_pos + (row * width_);
 | 
			
		||||
    uint32_t rem = w;
 | 
			
		||||
 | 
			
		||||
    while (rem > 0) {
 | 
			
		||||
      uint32_t sz = std::min(rem, ILI9XXX_TRANSFER_BUFFER_SIZE);
 | 
			
		||||
      // ESP_LOGVV(TAG, "Send to display(pos:%d, rem:%d, zs:%d)", pos, rem, sz);
 | 
			
		||||
      buffer_to_transfer_(pos, sz);
 | 
			
		||||
      if (this->is_18bitdisplay_) {
 | 
			
		||||
        for (uint32_t i = 0; i < sz; ++i) {
 | 
			
		||||
          uint16_t color_val = transfer_buffer_[i];
 | 
			
		||||
 | 
			
		||||
          uint8_t red = color_val & 0x1F;
 | 
			
		||||
          uint8_t green = (color_val & 0x7E0) >> 5;
 | 
			
		||||
          uint8_t blue = (color_val & 0xF800) >> 11;
 | 
			
		||||
 | 
			
		||||
          uint8_t pass_buff[3];
 | 
			
		||||
 | 
			
		||||
          pass_buff[2] = (uint8_t) ((red / 32.0) * 64) << 2;
 | 
			
		||||
          pass_buff[1] = (uint8_t) green << 2;
 | 
			
		||||
          pass_buff[0] = (uint8_t) ((blue / 32.0) * 64) << 2;
 | 
			
		||||
 | 
			
		||||
          this->write_array(pass_buff, sizeof(pass_buff));
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        this->write_array16(transfer_buffer_, sz);
 | 
			
		||||
      }
 | 
			
		||||
      pos += sz;
 | 
			
		||||
      rem -= sz;
 | 
			
		||||
    }
 | 
			
		||||
    App.feed_wdt();
 | 
			
		||||
  }
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
 | 
			
		||||
  // invalidate watermarks
 | 
			
		||||
  this->x_low_ = this->width_;
 | 
			
		||||
  this->y_low_ = this->height_;
 | 
			
		||||
  this->x_high_ = 0;
 | 
			
		||||
  this->y_high_ = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t ILI9XXXDisplay::buffer_to_transfer_(uint32_t pos, uint32_t sz) {
 | 
			
		||||
  for (uint32_t i = 0; i < sz; ++i) {
 | 
			
		||||
    switch (this->buffer_color_mode_) {
 | 
			
		||||
      case BITS_8_INDEXED:
 | 
			
		||||
        transfer_buffer_[i] = display::ColorUtil::color_to_565(
 | 
			
		||||
            display::ColorUtil::index8_to_color_palette888(this->buffer_[pos + i], this->palette_));
 | 
			
		||||
        break;
 | 
			
		||||
      case BITS_16:
 | 
			
		||||
        transfer_buffer_[i] = ((uint16_t) this->buffer_[(pos + i) * 2] << 8) | this->buffer_[((pos + i) * 2) + 1];
 | 
			
		||||
        continue;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        transfer_buffer_[i] =
 | 
			
		||||
            display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(this->buffer_[pos + i]));
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return sz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color
 | 
			
		||||
// values per bit is huge
 | 
			
		||||
uint32_t ILI9XXXDisplay::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); }
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::command(uint8_t value) {
 | 
			
		||||
  this->start_command_();
 | 
			
		||||
  this->write_byte(value);
 | 
			
		||||
  this->end_command_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::data(uint8_t value) {
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_byte(value);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) {
 | 
			
		||||
  this->command(command_byte);  // Send the command byte
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_array(data_bytes, num_data_bytes);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ILI9XXXDisplay::read_command(uint8_t command_byte, uint8_t index) {
 | 
			
		||||
  uint8_t data = 0x10 + index;
 | 
			
		||||
  this->send_command(0xD9, &data, 1);  // Set Index Register
 | 
			
		||||
  uint8_t result;
 | 
			
		||||
  this->start_command_();
 | 
			
		||||
  this->write_byte(command_byte);
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  do {
 | 
			
		||||
    result = this->read_byte();
 | 
			
		||||
  } while (index--);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::start_command_() {
 | 
			
		||||
  this->dc_pin_->digital_write(false);
 | 
			
		||||
  this->enable();
 | 
			
		||||
}
 | 
			
		||||
void ILI9XXXDisplay::start_data_() {
 | 
			
		||||
  this->dc_pin_->digital_write(true);
 | 
			
		||||
  this->enable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::end_command_() { this->disable(); }
 | 
			
		||||
void ILI9XXXDisplay::end_data_() { this->disable(); }
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::reset_() {
 | 
			
		||||
  if (this->reset_pin_ != nullptr) {
 | 
			
		||||
    this->reset_pin_->digital_write(false);
 | 
			
		||||
    delay(10);
 | 
			
		||||
    this->reset_pin_->digital_write(true);
 | 
			
		||||
    delay(10);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::init_lcd_(const uint8_t *init_cmd) {
 | 
			
		||||
  uint8_t cmd, x, num_args;
 | 
			
		||||
  const uint8_t *addr = init_cmd;
 | 
			
		||||
  while ((cmd = progmem_read_byte(addr++)) > 0) {
 | 
			
		||||
    x = progmem_read_byte(addr++);
 | 
			
		||||
    num_args = x & 0x7F;
 | 
			
		||||
    send_command(cmd, addr, num_args);
 | 
			
		||||
    addr += num_args;
 | 
			
		||||
    if (x & 0x80)
 | 
			
		||||
      delay(150);  // NOLINT
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) {
 | 
			
		||||
  uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1);
 | 
			
		||||
  this->command(ILI9XXX_CASET);  // Column address set
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_byte(x1 >> 8);
 | 
			
		||||
  this->write_byte(x1);
 | 
			
		||||
  this->write_byte(x2 >> 8);
 | 
			
		||||
  this->write_byte(x2);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
  this->command(ILI9XXX_PASET);  // Row address set
 | 
			
		||||
  this->start_data_();
 | 
			
		||||
  this->write_byte(y1 >> 8);
 | 
			
		||||
  this->write_byte(y1);
 | 
			
		||||
  this->write_byte(y2 >> 8);
 | 
			
		||||
  this->write_byte(y2);
 | 
			
		||||
  this->end_data_();
 | 
			
		||||
  this->command(ILI9XXX_RAMWR);  // Write to RAM
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXDisplay::invert_display_(bool invert) { this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); }
 | 
			
		||||
 | 
			
		||||
int ILI9XXXDisplay::get_width_internal() { return this->width_; }
 | 
			
		||||
int ILI9XXXDisplay::get_height_internal() { return this->height_; }
 | 
			
		||||
 | 
			
		||||
//   M5Stack display
 | 
			
		||||
void ILI9XXXM5Stack::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_M5STACK);
 | 
			
		||||
  if (this->width_ == 0)
 | 
			
		||||
    this->width_ = 320;
 | 
			
		||||
  if (this->height_ == 0)
 | 
			
		||||
    this->height_ = 240;
 | 
			
		||||
  this->invert_display_(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   M5CORE display // Based on the configuration settings of M5stact's M5GFX code.
 | 
			
		||||
void ILI9XXXM5CORE::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_M5CORE);
 | 
			
		||||
  if (this->width_ == 0)
 | 
			
		||||
    this->width_ = 320;
 | 
			
		||||
  if (this->height_ == 0)
 | 
			
		||||
    this->height_ = 240;
 | 
			
		||||
  this->invert_display_(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   24_TFT display
 | 
			
		||||
void ILI9XXXILI9341::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9341);
 | 
			
		||||
  if (this->width_ == 0)
 | 
			
		||||
    this->width_ = 240;
 | 
			
		||||
  if (this->height_ == 0)
 | 
			
		||||
    this->height_ = 320;
 | 
			
		||||
}
 | 
			
		||||
//   24_TFT rotated display
 | 
			
		||||
void ILI9XXXILI9342::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9341);
 | 
			
		||||
  if (this->width_ == 0) {
 | 
			
		||||
    this->width_ = 320;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->height_ == 0) {
 | 
			
		||||
    this->height_ = 240;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   35_TFT display
 | 
			
		||||
void ILI9XXXILI9481::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9481);
 | 
			
		||||
  if (this->width_ == 0) {
 | 
			
		||||
    this->width_ = 480;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->height_ == 0) {
 | 
			
		||||
    this->height_ = 320;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   35_TFT display
 | 
			
		||||
void ILI9XXXILI9486::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9486);
 | 
			
		||||
  if (this->width_ == 0) {
 | 
			
		||||
    this->width_ = 480;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->height_ == 0) {
 | 
			
		||||
    this->height_ = 320;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
//    40_TFT display
 | 
			
		||||
void ILI9XXXILI9488::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9488);
 | 
			
		||||
  if (this->width_ == 0) {
 | 
			
		||||
    this->width_ = 480;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->height_ == 0) {
 | 
			
		||||
    this->height_ = 320;
 | 
			
		||||
  }
 | 
			
		||||
  this->is_18bitdisplay_ = true;
 | 
			
		||||
}
 | 
			
		||||
//    40_TFT display
 | 
			
		||||
void ILI9XXXST7796::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ST7796);
 | 
			
		||||
  if (this->width_ == 0) {
 | 
			
		||||
    this->width_ = 320;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->height_ == 0) {
 | 
			
		||||
    this->height_ = 480;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace ili9xxx
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -1,27 +1,21 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/components/spi/spi.h"
 | 
			
		||||
#include "esphome/components/display/display_buffer.h"
 | 
			
		||||
#include "ili9341_defines.h"
 | 
			
		||||
#include "ili9341_init.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "ili9xxx_defines.h"
 | 
			
		||||
#include "ili9xxx_init.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9341 {
 | 
			
		||||
namespace ili9xxx {
 | 
			
		||||
 | 
			
		||||
enum ILI9341Model {
 | 
			
		||||
  M5STACK = 0,
 | 
			
		||||
  TFT_24,
 | 
			
		||||
  TFT_24R,
 | 
			
		||||
const uint32_t ILI9XXX_TRANSFER_BUFFER_SIZE = 64;
 | 
			
		||||
 | 
			
		||||
enum ILI9XXXColorMode {
 | 
			
		||||
  BITS_8 = 0x08,
 | 
			
		||||
  BITS_8_INDEXED = 0x09,
 | 
			
		||||
  BITS_16 = 0x10,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ILI9341ColorMode {
 | 
			
		||||
  BITS_8,
 | 
			
		||||
  BITS_8_INDEXED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ILI9341Display : public PollingComponent,
 | 
			
		||||
class ILI9XXXDisplay : public PollingComponent,
 | 
			
		||||
                       public display::DisplayBuffer,
 | 
			
		||||
                       public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
 | 
			
		||||
                                             spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_40MHZ> {
 | 
			
		||||
@@ -29,59 +23,46 @@ class ILI9341Display : public PollingComponent,
 | 
			
		||||
  void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; }
 | 
			
		||||
  float get_setup_priority() const override;
 | 
			
		||||
  void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; }
 | 
			
		||||
  void set_led_pin(GPIOPin *led) { this->led_pin_ = led; }
 | 
			
		||||
  void set_model(ILI9341Model model) { this->model_ = model; }
 | 
			
		||||
  void set_palette(const uint8_t *palette) { this->palette_ = palette; }
 | 
			
		||||
  void set_buffer_color_mode(ILI9341ColorMode color_mode) { this->buffer_color_mode_ = color_mode; }
 | 
			
		||||
 | 
			
		||||
  void set_buffer_color_mode(ILI9XXXColorMode color_mode) { this->buffer_color_mode_ = color_mode; }
 | 
			
		||||
  void set_dimentions(int16_t width, int16_t height) {
 | 
			
		||||
    this->height_ = height;
 | 
			
		||||
    this->width_ = width;
 | 
			
		||||
  }
 | 
			
		||||
  void command(uint8_t value);
 | 
			
		||||
  void data(uint8_t value);
 | 
			
		||||
  void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes);
 | 
			
		||||
  uint8_t read_command(uint8_t command_byte, uint8_t index);
 | 
			
		||||
  virtual void initialize() = 0;
 | 
			
		||||
 | 
			
		||||
  void update() override;
 | 
			
		||||
 | 
			
		||||
  void fill(Color color) override;
 | 
			
		||||
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  void setup() override {
 | 
			
		||||
    this->setup_pins_();
 | 
			
		||||
    this->initialize();
 | 
			
		||||
 | 
			
		||||
    this->x_low_ = this->width_;
 | 
			
		||||
    this->y_low_ = this->height_;
 | 
			
		||||
    this->x_high_ = 0;
 | 
			
		||||
    this->y_high_ = 0;
 | 
			
		||||
 | 
			
		||||
    this->init_internal_(this->get_buffer_length_());
 | 
			
		||||
    this->fill_internal_(0x00);
 | 
			
		||||
  }
 | 
			
		||||
  void setup() override;
 | 
			
		||||
 | 
			
		||||
  display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  void draw_absolute_pixel_internal(int x, int y, Color color) override;
 | 
			
		||||
  void setup_pins_();
 | 
			
		||||
  virtual void initialize() = 0;
 | 
			
		||||
 | 
			
		||||
  void display_();
 | 
			
		||||
  void init_lcd_(const uint8_t *init_cmd);
 | 
			
		||||
  void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
 | 
			
		||||
  void invert_display_(bool invert);
 | 
			
		||||
  void reset_();
 | 
			
		||||
  void fill_internal_(uint8_t color);
 | 
			
		||||
  void display_();
 | 
			
		||||
  void rotate_my_(uint8_t m);
 | 
			
		||||
 | 
			
		||||
  ILI9341Model model_;
 | 
			
		||||
  int16_t width_{320};   ///< Display width as modified by current rotation
 | 
			
		||||
  int16_t height_{240};  ///< Display height as modified by current rotation
 | 
			
		||||
  int16_t width_{0};   ///< Display width as modified by current rotation
 | 
			
		||||
  int16_t height_{0};  ///< Display height as modified by current rotation
 | 
			
		||||
  uint16_t x_low_{0};
 | 
			
		||||
  uint16_t y_low_{0};
 | 
			
		||||
  uint16_t x_high_{0};
 | 
			
		||||
  uint16_t y_high_{0};
 | 
			
		||||
  const uint8_t *palette_;
 | 
			
		||||
 | 
			
		||||
  ILI9341ColorMode buffer_color_mode_{BITS_8};
 | 
			
		||||
  ILI9XXXColorMode buffer_color_mode_{BITS_16};
 | 
			
		||||
 | 
			
		||||
  uint32_t get_buffer_length_();
 | 
			
		||||
  int get_width_internal() override;
 | 
			
		||||
@@ -92,33 +73,66 @@ class ILI9341Display : public PollingComponent,
 | 
			
		||||
  void start_data_();
 | 
			
		||||
  void end_data_();
 | 
			
		||||
 | 
			
		||||
  uint8_t transfer_buffer_[64];
 | 
			
		||||
  uint16_t transfer_buffer_[ILI9XXX_TRANSFER_BUFFER_SIZE];
 | 
			
		||||
 | 
			
		||||
  uint32_t buffer_to_transfer_(uint32_t pos, uint32_t sz);
 | 
			
		||||
 | 
			
		||||
  GPIOPin *reset_pin_{nullptr};
 | 
			
		||||
  GPIOPin *led_pin_{nullptr};
 | 
			
		||||
  GPIOPin *dc_pin_;
 | 
			
		||||
  GPIOPin *dc_pin_{nullptr};
 | 
			
		||||
  GPIOPin *busy_pin_{nullptr};
 | 
			
		||||
 | 
			
		||||
  bool prossing_update_ = false;
 | 
			
		||||
  bool need_update_ = false;
 | 
			
		||||
  bool is_18bitdisplay_ = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   M5Stack display --------------
 | 
			
		||||
class ILI9341M5Stack : public ILI9341Display {
 | 
			
		||||
 public:
 | 
			
		||||
class ILI9XXXM5Stack : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9341_24_TFT display --------------
 | 
			
		||||
class ILI9341TFT24 : public ILI9341Display {
 | 
			
		||||
 public:
 | 
			
		||||
//-----------   M5Stack display --------------
 | 
			
		||||
class ILI9XXXM5CORE : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9341_24_TFT rotated display --------------
 | 
			
		||||
class ILI9341TFT24R : public ILI9341Display {
 | 
			
		||||
 public:
 | 
			
		||||
//-----------   ILI9XXX_24_TFT display --------------
 | 
			
		||||
class ILI9XXXILI9341 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace ili9341
 | 
			
		||||
//-----------   ILI9XXX_24_TFT rotated display --------------
 | 
			
		||||
class ILI9XXXILI9342 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9XXX_??_TFT rotated display --------------
 | 
			
		||||
class ILI9XXXILI9481 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9XXX_35_TFT rotated display --------------
 | 
			
		||||
class ILI9XXXILI9486 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9XXX_35_TFT rotated display --------------
 | 
			
		||||
class ILI9XXXILI9488 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9XXX_35_TFT rotated display --------------
 | 
			
		||||
class ILI9XXXST7796 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace ili9xxx
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
							
								
								
									
										174
									
								
								esphome/components/ili9xxx/ili9xxx_init.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								esphome/components/ili9xxx/ili9xxx_init.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace ili9xxx {
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_M5STACK[] = {
 | 
			
		||||
  0xEF, 3, 0x03, 0x80, 0x02,
 | 
			
		||||
  0xCF, 3, 0x00, 0xC1, 0x30,
 | 
			
		||||
  0xED, 4, 0x64, 0x03, 0x12, 0x81,
 | 
			
		||||
  0xE8, 3, 0x85, 0x00, 0x78,
 | 
			
		||||
  0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
 | 
			
		||||
  0xF7, 1, 0x20,
 | 
			
		||||
  0xEA, 2, 0x00, 0x00,
 | 
			
		||||
  ILI9XXX_PWCTR1  , 1, 0x23,             // Power control VRH[5:0]
 | 
			
		||||
  ILI9XXX_PWCTR2  , 1, 0x10,             // Power control SAP[2:0];BT[3:0]
 | 
			
		||||
  ILI9XXX_VMCTR1  , 2, 0x3e, 0x28,       // VCM control
 | 
			
		||||
  ILI9XXX_VMCTR2  , 1, 0x86,             // VCM control2
 | 
			
		||||
  ILI9XXX_MADCTL  , 1, MADCTL_BGR,       // Memory Access Control
 | 
			
		||||
  ILI9XXX_VSCRSADD, 1, 0x00,             // Vertical scroll zero
 | 
			
		||||
  ILI9XXX_PIXFMT  , 1, 0x55,
 | 
			
		||||
  ILI9XXX_FRMCTR1 , 2, 0x00, 0x13,
 | 
			
		||||
  ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
 | 
			
		||||
  0xF2, 1, 0x00,                         // 3Gamma Function Disable
 | 
			
		||||
  ILI9XXX_GAMMASET , 1, 0x01,             // Gamma curve selected
 | 
			
		||||
  ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
 | 
			
		||||
                        0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
 | 
			
		||||
                        0x0E, 0x09, 0x00,
 | 
			
		||||
  ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
 | 
			
		||||
                        0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
 | 
			
		||||
                        0x31, 0x36, 0x0F,
 | 
			
		||||
  ILI9XXX_SLPOUT  , 0x80,                // Exit Sleep
 | 
			
		||||
  ILI9XXX_DISPON  , 0x80,                // Display on
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_M5CORE[] = {
 | 
			
		||||
  ILI9XXX_SETEXTC, 3, 0xFF,0x93,0x42,   // Turn on the external command
 | 
			
		||||
  ILI9XXX_PWCTR1 , 2, 0x12, 0x12,
 | 
			
		||||
  ILI9XXX_PWCTR2 , 1, 0x03,
 | 
			
		||||
  ILI9XXX_VMCTR1 , 1, 0xF2,
 | 
			
		||||
  ILI9XXX_IFMODE , 1, 0xE0,
 | 
			
		||||
  0xF6           , 3, 0x01, 0x00, 0x00,
 | 
			
		||||
  ILI9XXX_GMCTRP1,15, 0x00,0x0C,0x11,0x04,0x11,0x08,0x37,0x89,0x4C,0x06,0x0C,0x0A,0x2E,0x34,0x0F,
 | 
			
		||||
  ILI9XXX_GMCTRN1,15, 0x00,0x0B,0x11,0x05,0x13,0x09,0x33,0x67,0x48,0x07,0x0E,0x0B,0x2E,0x33,0x0F,
 | 
			
		||||
  ILI9XXX_DFUNCTR, 4, 0x08,0x82,0x1D,0x04,
 | 
			
		||||
  ILI9XXX_IDMOFF , 0,
 | 
			
		||||
  ILI9XXX_DISPON , 0x80,                // Display on
 | 
			
		||||
  ILI9XXX_SLPOUT , 0x80,                // Exit Sleep
 | 
			
		||||
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ILI9341[] = {
 | 
			
		||||
  0xEF, 3, 0x03, 0x80, 0x02,
 | 
			
		||||
  0xCF, 3, 0x00, 0xC1, 0x30,
 | 
			
		||||
  0xED, 4, 0x64, 0x03, 0x12, 0x81,
 | 
			
		||||
  0xE8, 3, 0x85, 0x00, 0x78,
 | 
			
		||||
  0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
 | 
			
		||||
  0xF7, 1, 0x20,
 | 
			
		||||
  0xEA, 2, 0x00, 0x00,
 | 
			
		||||
  ILI9XXX_PWCTR1  , 1, 0x23,             // Power control VRH[5:0]
 | 
			
		||||
  ILI9XXX_PWCTR2  , 1, 0x10,             // Power control SAP[2:0];BT[3:0]
 | 
			
		||||
  ILI9XXX_VMCTR1  , 2, 0x3e, 0x28,       // VCM control
 | 
			
		||||
  ILI9XXX_VMCTR2  , 1, 0x86,             // VCM control2
 | 
			
		||||
  ILI9XXX_MADCTL  , 1, 0x48,             // Memory Access Control
 | 
			
		||||
  ILI9XXX_VSCRSADD, 1, 0x00,             // Vertical scroll zero
 | 
			
		||||
  ILI9XXX_PIXFMT  , 1, 0x55,
 | 
			
		||||
  ILI9XXX_FRMCTR1 , 2, 0x00, 0x18,
 | 
			
		||||
  ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
 | 
			
		||||
  0xF2, 1, 0x00,                         // 3Gamma Function Disable
 | 
			
		||||
  ILI9XXX_GAMMASET , 1, 0x01,             // Gamma curve selected
 | 
			
		||||
  ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
 | 
			
		||||
                        0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03,
 | 
			
		||||
                        0x0E, 0x09, 0x00,
 | 
			
		||||
  ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
 | 
			
		||||
                        0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C,
 | 
			
		||||
                        0x31, 0x36, 0x0F,
 | 
			
		||||
  ILI9XXX_SLPOUT  , 0x80,                // Exit Sleep
 | 
			
		||||
  ILI9XXX_DISPON  , 0x80,                // Display on
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ILI9481[] = {
 | 
			
		||||
  ILI9XXX_SLPOUT ,  0x80,    // Exit sleep mode
 | 
			
		||||
  ILI9XXX_PWSET  , 3, 0x07, 0x41, 0x1D,
 | 
			
		||||
  ILI9XXX_VMCTR  , 3, 0x00, 0x1C, 0x1F,
 | 
			
		||||
  ILI9XXX_PWSETN , 2, 0x01, 0x11,
 | 
			
		||||
  ILI9XXX_PWCTR1 , 5, 0x10, 0x3B, 0x00, 0x02, 0x11,
 | 
			
		||||
  ILI9XXX_VMCTR1 , 1, 0x03,
 | 
			
		||||
  ILI9XXX_IFCTR  , 1, 0x83,
 | 
			
		||||
  ILI9XXX_GMCTR  ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00,
 | 
			
		||||
  ILI9XXX_IFMODE , 1, 0x00,  // CommandAccessProtect
 | 
			
		||||
  0xE4        , 1, 0xA0,
 | 
			
		||||
  ILI9XXX_CSCON , 1, 0x01,
 | 
			
		||||
  ILI9XXX_DISPON, 0x80,     // Set display on
 | 
			
		||||
  0x00 // end
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ILI9486[] = {
 | 
			
		||||
  ILI9XXX_SLPOUT, 0x80,
 | 
			
		||||
  ILI9XXX_PIXFMT, 1, 0x55,
 | 
			
		||||
  ILI9XXX_PWCTR3, 1, 0x44,
 | 
			
		||||
  ILI9XXX_VMCTR1, 4, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
  ILI9XXX_GMCTRP1, 15, 0x0f,0x1f,0x1c,0x0c,0x0f,0x08,0x48,0x98,0x37,0x0a,0x13,0x04,0x11,0x0d,0x00,
 | 
			
		||||
  ILI9XXX_GMCTRN1, 15, 0x0f,0x32,0x2e,0x0b,0x0d,0x05,0x47,0x75,0x37,0x06,0x10,0x03,0x24,0x20,0x00,
 | 
			
		||||
  ILI9XXX_INVOFF, 0x80,
 | 
			
		||||
  ILI9XXX_MADCTL, 1, 0x48,
 | 
			
		||||
  ILI9XXX_DISPON, 0x80,
 | 
			
		||||
 | 
			
		||||
  // ILI9XXX_MADCTL, 1, MADCTL_BGR | MADCTL_MV, //hardware rotation
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ILI9488[] = {
 | 
			
		||||
  ILI9XXX_GMCTRP1,15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F,
 | 
			
		||||
  ILI9XXX_GMCTRN1,15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F,
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_PWCTR1,  2, 0x17, 0x15,  // VRH1 VRH2
 | 
			
		||||
  ILI9XXX_PWCTR2,  1, 0x41,  // VGH, VGL
 | 
			
		||||
  ILI9XXX_VMCTR1,  3, 0x00, 0x12, 0x80,    // nVM VCM_REG VCM_REG_EN
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_IFMODE,  1, 0x00,
 | 
			
		||||
  ILI9XXX_FRMCTR1, 1, 0xA0,  // Frame rate = 60Hz
 | 
			
		||||
  ILI9XXX_INVCTR,  1, 0x02,  // Display Inversion Control = 2dot
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_DFUNCTR, 2, 0x02, 0x02, // Nomal scan
 | 
			
		||||
 | 
			
		||||
  0xE9, 1, 0x00,   // Set Image Functio. Disable 24 bit data
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_ADJCTL3, 4, 0xA9, 0x51, 0x2C, 0x82,  // Adjust Control 3
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_MADCTL,  1, 0x28,
 | 
			
		||||
  //ILI9XXX_PIXFMT,  1, 0x55,  // Interface Pixel Format = 16bit
 | 
			
		||||
  ILI9XXX_PIXFMT, 1, 0x66,   //ILI9488 only supports 18-bit pixel format in 4/3 wire SPI mode
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // 5 frames
 | 
			
		||||
  //ILI9XXX_ETMOD,   1, 0xC6,  //
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_SLPOUT,  0x80,    // Exit sleep mode
 | 
			
		||||
  //ILI9XXX_INVON  , 0,
 | 
			
		||||
  ILI9XXX_DISPON,  0x80,    // Set display on
 | 
			
		||||
  0x00 // end
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ST7796[] = {
 | 
			
		||||
  // This ST7796S initilization routine was copied from https://github.com/prenticedavid/Adafruit_ST7796S_kbv/blob/master/Adafruit_ST7796S_kbv.cpp
 | 
			
		||||
  ILI9XXX_SWRESET, 0x80,         // Soft reset, then delay 150 ms
 | 
			
		||||
  ILI9XXX_CSCON, 1, 0xC3,              // ?? Unlock Manufacturer
 | 
			
		||||
  ILI9XXX_CSCON, 1, 0x96,
 | 
			
		||||
  ILI9XXX_VMCTR1, 1, 0x1C,              //VCOM  Control 1 [1C]
 | 
			
		||||
  ILI9XXX_MADCTL, 1, 0x48,              //Memory Access [00]
 | 
			
		||||
  ILI9XXX_PIXFMT, 1, 0x55,              //565
 | 
			
		||||
  ILI9XXX_IFMODE, 1, 0x80,              //Interface     [00]
 | 
			
		||||
  ILI9XXX_INVCTR, 1, 0x01,              //Inversion Control [01]
 | 
			
		||||
  ILI9XXX_DFUNCTR, 3, 0x80, 0x02, 0x3B,  // Display Function Control [80 02 3B] .kbv SS=1, NL=480
 | 
			
		||||
  ILI9XXX_ETMOD, 1, 0xC6,              //Entry Mode      [06]
 | 
			
		||||
 | 
			
		||||
  ILI9XXX_CSCON, 1, 0x69,              //?? lock manufacturer commands
 | 
			
		||||
  ILI9XXX_CSCON, 1, 0x3C,              //
 | 
			
		||||
  ILI9XXX_SLPOUT, 0x80, // Exit Sleep, then delay 150 ms
 | 
			
		||||
  ILI9XXX_DISPON, 0x80, // Main screen turn on, delay 150 ms
 | 
			
		||||
  0x00                                   // End of list
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// clang-format on
 | 
			
		||||
}  // namespace ili9xxx
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
@@ -73,7 +73,7 @@ void parse_json(const std::string &data, const json_parse_t &f) {
 | 
			
		||||
  const size_t free_heap = rp2040.getFreeHeap();
 | 
			
		||||
#endif
 | 
			
		||||
  bool pass = false;
 | 
			
		||||
  size_t request_size = std::min(free_heap, (size_t)(data.size() * 1.5));
 | 
			
		||||
  size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5));
 | 
			
		||||
  do {
 | 
			
		||||
    DynamicJsonDocument json_document(request_size);
 | 
			
		||||
    if (json_document.capacity() == 0) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ void GPIOLCDDisplay::setup() {
 | 
			
		||||
  this->enable_pin_->setup();  // OUTPUT
 | 
			
		||||
  this->enable_pin_->digital_write(false);
 | 
			
		||||
 | 
			
		||||
  for (uint8_t i = 0; i < (uint8_t)(this->is_four_bit_mode() ? 4u : 8u); i++) {
 | 
			
		||||
  for (uint8_t i = 0; i < (uint8_t) (this->is_four_bit_mode() ? 4u : 8u); i++) {
 | 
			
		||||
    this->data_pins_[i]->setup();  // OUTPUT
 | 
			
		||||
    this->data_pins_[i]->digital_write(false);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,7 @@ class LD2410Component : public Component, public uart::UARTDevice {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  std::vector<uint8_t> rx_buffer_;
 | 
			
		||||
  int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t)(secondbyte << 8) + firstbyte; }
 | 
			
		||||
  int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; }
 | 
			
		||||
  void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len);
 | 
			
		||||
 | 
			
		||||
  void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range,
 | 
			
		||||
 
 | 
			
		||||
@@ -52,25 +52,26 @@ enum class ColorMode : uint8_t {
 | 
			
		||||
  /// Only on/off control.
 | 
			
		||||
  ON_OFF = (uint8_t) ColorCapability::ON_OFF,
 | 
			
		||||
  /// Dimmable light.
 | 
			
		||||
  BRIGHTNESS = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS),
 | 
			
		||||
  BRIGHTNESS = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS),
 | 
			
		||||
  /// White output only (use only if the light also has another color mode such as RGB).
 | 
			
		||||
  WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::WHITE),
 | 
			
		||||
  WHITE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::WHITE),
 | 
			
		||||
  /// Controllable color temperature output.
 | 
			
		||||
  COLOR_TEMPERATURE =
 | 
			
		||||
      (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLOR_TEMPERATURE),
 | 
			
		||||
      (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLOR_TEMPERATURE),
 | 
			
		||||
  /// Cold and warm white output with individually controllable brightness.
 | 
			
		||||
  COLD_WARM_WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLD_WARM_WHITE),
 | 
			
		||||
  COLD_WARM_WHITE =
 | 
			
		||||
      (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLD_WARM_WHITE),
 | 
			
		||||
  /// RGB color output.
 | 
			
		||||
  RGB = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB),
 | 
			
		||||
  RGB = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB),
 | 
			
		||||
  /// RGB color output and a separate white output.
 | 
			
		||||
  RGB_WHITE =
 | 
			
		||||
      (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | ColorCapability::WHITE),
 | 
			
		||||
      (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | ColorCapability::WHITE),
 | 
			
		||||
  /// RGB color output and a separate white output with controllable color temperature.
 | 
			
		||||
  RGB_COLOR_TEMPERATURE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB |
 | 
			
		||||
                                    ColorCapability::WHITE | ColorCapability::COLOR_TEMPERATURE),
 | 
			
		||||
  RGB_COLOR_TEMPERATURE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB |
 | 
			
		||||
                                     ColorCapability::WHITE | ColorCapability::COLOR_TEMPERATURE),
 | 
			
		||||
  /// RGB color output, and separate cold and warm white outputs.
 | 
			
		||||
  RGB_COLD_WARM_WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB |
 | 
			
		||||
                                  ColorCapability::COLD_WARM_WHITE),
 | 
			
		||||
  RGB_COLD_WARM_WHITE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB |
 | 
			
		||||
                                   ColorCapability::COLD_WARM_WHITE),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Helper class to allow bitwise operations on ColorMode with ColorCapability
 | 
			
		||||
 
 | 
			
		||||
@@ -113,8 +113,8 @@ void LilygoT547Touchscreen::loop() {
 | 
			
		||||
      if (tp.state == 0x06)
 | 
			
		||||
        tp.state = 0x07;
 | 
			
		||||
 | 
			
		||||
      uint16_t y = (uint16_t)((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F));
 | 
			
		||||
      uint16_t x = (uint16_t)((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F));
 | 
			
		||||
      uint16_t y = (uint16_t) ((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F));
 | 
			
		||||
      uint16_t x = (uint16_t) ((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F));
 | 
			
		||||
 | 
			
		||||
      switch (this->rotation_) {
 | 
			
		||||
        case ROTATE_0_DEGREES:
 | 
			
		||||
@@ -142,8 +142,8 @@ void LilygoT547Touchscreen::loop() {
 | 
			
		||||
    tp.id = (buffer[0] >> 4) & 0x0F;
 | 
			
		||||
    tp.state = 0x06;
 | 
			
		||||
 | 
			
		||||
    uint16_t y = (uint16_t)((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F));
 | 
			
		||||
    uint16_t x = (uint16_t)((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F));
 | 
			
		||||
    uint16_t y = (uint16_t) ((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F));
 | 
			
		||||
    uint16_t x = (uint16_t) ((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F));
 | 
			
		||||
 | 
			
		||||
    switch (this->rotation_) {
 | 
			
		||||
      case ROTATE_0_DEGREES:
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ CODEOWNERS = ["@rspaargaren"]
 | 
			
		||||
DEPENDENCIES = ["spi"]
 | 
			
		||||
 | 
			
		||||
CONF_ROTATE_CHIP = "rotate_chip"
 | 
			
		||||
CONF_FLIP_X = "flip_x"
 | 
			
		||||
CONF_SCROLL_SPEED = "scroll_speed"
 | 
			
		||||
CONF_SCROLL_DWELL = "scroll_dwell"
 | 
			
		||||
CONF_SCROLL_DELAY = "scroll_delay"
 | 
			
		||||
@@ -67,6 +68,7 @@ CONFIG_SCHEMA = (
 | 
			
		||||
                CONF_SCROLL_DWELL, default="1000ms"
 | 
			
		||||
            ): cv.positive_time_period_milliseconds,
 | 
			
		||||
            cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean,
 | 
			
		||||
            cv.Optional(CONF_FLIP_X, default=False): cv.boolean,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.polling_component_schema("500ms"))
 | 
			
		||||
@@ -91,6 +93,7 @@ async def to_code(config):
 | 
			
		||||
    cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE]))
 | 
			
		||||
    cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE]))
 | 
			
		||||
    cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE]))
 | 
			
		||||
    cg.add(var.set_flip_x([CONF_FLIP_X]))
 | 
			
		||||
 | 
			
		||||
    if CONF_LAMBDA in config:
 | 
			
		||||
        lambda_ = await cg.process_lambda(
 | 
			
		||||
 
 | 
			
		||||
@@ -261,13 +261,21 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) {
 | 
			
		||||
    if (this->orientation_ == 0) {
 | 
			
		||||
      for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
        // run this loop 8 times for all the pixels[8] received
 | 
			
		||||
        b |= ((pixels[i] >> col) & 1) << (7 - i);  // change the column bits into row bits
 | 
			
		||||
        if (this->flip_x_) {
 | 
			
		||||
          b |= ((pixels[i] >> col) & 1) << i;  // change the column bits into row bits
 | 
			
		||||
        } else {
 | 
			
		||||
          b |= ((pixels[i] >> col) & 1) << (7 - i);  // change the column bits into row bits
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else if (this->orientation_ == 1) {
 | 
			
		||||
      b = pixels[col];
 | 
			
		||||
    } else if (this->orientation_ == 2) {
 | 
			
		||||
      for (uint8_t i = 0; i < 8; i++) {
 | 
			
		||||
        b |= ((pixels[i] >> (7 - col)) & 1) << i;
 | 
			
		||||
        if (this->flip_x_) {
 | 
			
		||||
          b |= ((pixels[i] >> (7 - col)) & 1) << (7 - i);
 | 
			
		||||
        } else {
 | 
			
		||||
          b |= ((pixels[i] >> (7 - col)) & 1) << i;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      b = pixels[7 - col];
 | 
			
		||||
 
 | 
			
		||||
@@ -67,6 +67,7 @@ class MAX7219Component : public PollingComponent,
 | 
			
		||||
  void set_scroll(bool on_off) { this->scroll_ = on_off; };
 | 
			
		||||
  void set_scroll_mode(ScrollMode mode) { this->scroll_mode_ = mode; };
 | 
			
		||||
  void set_reverse(bool on_off) { this->reverse_ = on_off; };
 | 
			
		||||
  void set_flip_x(bool flip_x) { this->flip_x_ = flip_x; };
 | 
			
		||||
 | 
			
		||||
  void send_char(uint8_t chip, uint8_t data);
 | 
			
		||||
  void send64pixels(uint8_t chip, const uint8_t pixels[8]);
 | 
			
		||||
@@ -108,6 +109,7 @@ class MAX7219Component : public PollingComponent,
 | 
			
		||||
  ChipLinesStyle chip_lines_style_;
 | 
			
		||||
  bool scroll_;
 | 
			
		||||
  bool reverse_;
 | 
			
		||||
  bool flip_x_;
 | 
			
		||||
  bool update_{false};
 | 
			
		||||
  uint16_t scroll_speed_;
 | 
			
		||||
  uint16_t scroll_delay_;
 | 
			
		||||
 
 | 
			
		||||
@@ -148,19 +148,19 @@ canbus::Error MCP2515::set_clk_out_(const CanClkOut divisor) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MCP2515::prepare_id_(uint8_t *buffer, const bool extended, const uint32_t id) {
 | 
			
		||||
  uint16_t canid = (uint16_t)(id & 0x0FFFF);
 | 
			
		||||
  uint16_t canid = (uint16_t) (id & 0x0FFFF);
 | 
			
		||||
 | 
			
		||||
  if (extended) {
 | 
			
		||||
    buffer[MCP_EID0] = (uint8_t)(canid & 0xFF);
 | 
			
		||||
    buffer[MCP_EID8] = (uint8_t)(canid >> 8);
 | 
			
		||||
    canid = (uint16_t)(id >> 16);
 | 
			
		||||
    buffer[MCP_SIDL] = (uint8_t)(canid & 0x03);
 | 
			
		||||
    buffer[MCP_SIDL] += (uint8_t)((canid & 0x1C) << 3);
 | 
			
		||||
    buffer[MCP_EID0] = (uint8_t) (canid & 0xFF);
 | 
			
		||||
    buffer[MCP_EID8] = (uint8_t) (canid >> 8);
 | 
			
		||||
    canid = (uint16_t) (id >> 16);
 | 
			
		||||
    buffer[MCP_SIDL] = (uint8_t) (canid & 0x03);
 | 
			
		||||
    buffer[MCP_SIDL] += (uint8_t) ((canid & 0x1C) << 3);
 | 
			
		||||
    buffer[MCP_SIDL] |= TXB_EXIDE_MASK;
 | 
			
		||||
    buffer[MCP_SIDH] = (uint8_t)(canid >> 5);
 | 
			
		||||
    buffer[MCP_SIDH] = (uint8_t) (canid >> 5);
 | 
			
		||||
  } else {
 | 
			
		||||
    buffer[MCP_SIDH] = (uint8_t)(canid >> 3);
 | 
			
		||||
    buffer[MCP_SIDL] = (uint8_t)((canid & 0x07) << 5);
 | 
			
		||||
    buffer[MCP_SIDH] = (uint8_t) (canid >> 3);
 | 
			
		||||
    buffer[MCP_SIDL] = (uint8_t) ((canid & 0x07) << 5);
 | 
			
		||||
    buffer[MCP_EID0] = 0;
 | 
			
		||||
    buffer[MCP_EID8] = 0;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@ void MCP9600Component::setup() {
 | 
			
		||||
 | 
			
		||||
  uint16_t dev_id = 0;
 | 
			
		||||
  this->read_byte_16(MCP9600_REGISTER_DEVICE_ID, &dev_id);
 | 
			
		||||
  this->device_id_ = (uint8_t)(dev_id >> 8);
 | 
			
		||||
  this->device_id_ = (uint8_t) (dev_id >> 8);
 | 
			
		||||
 | 
			
		||||
  // Allows both MCP9600's and MCP9601's to be connected.
 | 
			
		||||
  if (this->device_id_ != (uint8_t) 0x40 && this->device_id_ != (uint8_t) 0x41) {
 | 
			
		||||
 
 | 
			
		||||
@@ -54,16 +54,16 @@ void MCP9808Sensor::update() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  float temp = NAN;
 | 
			
		||||
  uint8_t msb = (uint8_t)((raw_temp & 0xff00) >> 8);
 | 
			
		||||
  uint8_t msb = (uint8_t) ((raw_temp & 0xff00) >> 8);
 | 
			
		||||
  uint8_t lsb = raw_temp & 0x00ff;
 | 
			
		||||
 | 
			
		||||
  msb = msb & MCP9808_AMBIENT_CLEAR_FLAGS;
 | 
			
		||||
 | 
			
		||||
  if ((msb & MCP9808_AMBIENT_TEMP_NEGATIVE) == MCP9808_AMBIENT_TEMP_NEGATIVE) {
 | 
			
		||||
    msb = msb & MCP9808_AMBIENT_CLEAR_SIGN;
 | 
			
		||||
    temp = (256 - ((uint16_t)(msb) *16 + lsb / 16.0f)) * -1;
 | 
			
		||||
    temp = (256 - ((uint16_t) (msb) *16 + lsb / 16.0f)) * -1;
 | 
			
		||||
  } else {
 | 
			
		||||
    temp = (uint16_t)(msb) *16 + lsb / 16.0f;
 | 
			
		||||
    temp = (uint16_t) (msb) *16 + lsb / 16.0f;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (std::isnan(temp)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -123,7 +123,8 @@ uint32_t MopekaProCheck::parse_distance_(const std::vector<uint8_t> &message) {
 | 
			
		||||
  double raw_level = raw & 0x3FFF;
 | 
			
		||||
  double raw_t = (message[2] & 0x7F);
 | 
			
		||||
 | 
			
		||||
  return (uint32_t)(raw_level * (MOPEKA_LPG_COEF[0] + MOPEKA_LPG_COEF[1] * raw_t + MOPEKA_LPG_COEF[2] * raw_t * raw_t));
 | 
			
		||||
  return (uint32_t) (raw_level *
 | 
			
		||||
                     (MOPEKA_LPG_COEF[0] + MOPEKA_LPG_COEF[1] * raw_t + MOPEKA_LPG_COEF[2] * raw_t * raw_t));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t MopekaProCheck::parse_temperature_(const std::vector<uint8_t> &message) { return (message[2] & 0x7F) - 40; }
 | 
			
		||||
 
 | 
			
		||||
@@ -216,7 +216,7 @@ uint8_t MopekaStdCheck::parse_temperature_(const mopeka_std_package *message) {
 | 
			
		||||
  if (tmp == 0x0) {
 | 
			
		||||
    return -40;
 | 
			
		||||
  } else {
 | 
			
		||||
    return (uint8_t)((tmp - 25.0f) * 1.776964f);
 | 
			
		||||
    return (uint8_t) ((tmp - 25.0f) * 1.776964f);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,8 @@ const float GRAVITY_EARTH = 9.80665f;
 | 
			
		||||
void MPU6050Component::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up MPU6050...");
 | 
			
		||||
  uint8_t who_am_i;
 | 
			
		||||
  if (!this->read_byte(MPU6050_REGISTER_WHO_AM_I, &who_am_i) || (who_am_i != 0x68 && who_am_i != 0x98)) {
 | 
			
		||||
  if (!this->read_byte(MPU6050_REGISTER_WHO_AM_I, &who_am_i) ||
 | 
			
		||||
      (who_am_i != 0x68 && who_am_i != 0x70 && who_am_i != 0x98)) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,8 @@ from esphome.const import (
 | 
			
		||||
from esphome.components.esp32 import get_esp32_variant
 | 
			
		||||
from esphome.components.esp32.const import (
 | 
			
		||||
    VARIANT_ESP32,
 | 
			
		||||
    VARIANT_ESP32S2,
 | 
			
		||||
    VARIANT_ESP32C3,
 | 
			
		||||
    VARIANT_ESP32S2,
 | 
			
		||||
    VARIANT_ESP32S3,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
@@ -58,9 +58,9 @@ SPI_SPEEDS = [40e6, 20e6, 10e6, 5e6, 2e6, 1e6, 500e3]
 | 
			
		||||
 | 
			
		||||
def _esp32_rmt_default_channel():
 | 
			
		||||
    return {
 | 
			
		||||
        VARIANT_ESP32C3: 1,
 | 
			
		||||
        VARIANT_ESP32S2: 1,
 | 
			
		||||
        VARIANT_ESP32S3: 1,
 | 
			
		||||
        VARIANT_ESP32C3: 1,
 | 
			
		||||
    }.get(get_esp32_variant(), 6)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -71,9 +71,9 @@ def _validate_esp32_rmt_channel(value):
 | 
			
		||||
        value = cv.int_(value)
 | 
			
		||||
    variant_channels = {
 | 
			
		||||
        VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7, CHANNEL_DYNAMIC],
 | 
			
		||||
        VARIANT_ESP32C3: [0, 1, CHANNEL_DYNAMIC],
 | 
			
		||||
        VARIANT_ESP32S2: [0, 1, 2, 3, CHANNEL_DYNAMIC],
 | 
			
		||||
        VARIANT_ESP32S3: [0, 1, 2, 3, CHANNEL_DYNAMIC],
 | 
			
		||||
        VARIANT_ESP32C3: [0, 1, CHANNEL_DYNAMIC],
 | 
			
		||||
    }
 | 
			
		||||
    variant = get_esp32_variant()
 | 
			
		||||
    if variant not in variant_channels:
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ from esphome.const import (
 | 
			
		||||
from esphome.components.esp32 import get_esp32_variant
 | 
			
		||||
from esphome.components.esp32.const import (
 | 
			
		||||
    VARIANT_ESP32C3,
 | 
			
		||||
    VARIANT_ESP32S3,
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
from ._methods import (
 | 
			
		||||
@@ -96,7 +97,7 @@ def _choose_default_method(config):
 | 
			
		||||
            config[CONF_METHOD] = _validate_method(METHOD_BIT_BANG)
 | 
			
		||||
 | 
			
		||||
    if CORE.is_esp32:
 | 
			
		||||
        if get_esp32_variant() == VARIANT_ESP32C3:
 | 
			
		||||
        if get_esp32_variant() in (VARIANT_ESP32C3, VARIANT_ESP32S3):
 | 
			
		||||
            config[CONF_METHOD] = _validate_method(METHOD_ESP32_RMT)
 | 
			
		||||
        else:
 | 
			
		||||
            config[CONF_METHOD] = _validate_method(METHOD_ESP32_I2S)
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,10 @@ struct IPAddress {
 | 
			
		||||
  IPAddress() : addr_({0, 0, 0, 0}) {}
 | 
			
		||||
  IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) : addr_({first, second, third, fourth}) {}
 | 
			
		||||
  IPAddress(uint32_t raw) {
 | 
			
		||||
    addr_[0] = (uint8_t)(raw >> 0);
 | 
			
		||||
    addr_[1] = (uint8_t)(raw >> 8);
 | 
			
		||||
    addr_[2] = (uint8_t)(raw >> 16);
 | 
			
		||||
    addr_[3] = (uint8_t)(raw >> 24);
 | 
			
		||||
    addr_[0] = (uint8_t) (raw >> 0);
 | 
			
		||||
    addr_[1] = (uint8_t) (raw >> 8);
 | 
			
		||||
    addr_[2] = (uint8_t) (raw >> 16);
 | 
			
		||||
    addr_[3] = (uint8_t) (raw >> 24);
 | 
			
		||||
  }
 | 
			
		||||
  operator uint32_t() const {
 | 
			
		||||
    uint32_t res = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -448,7 +448,7 @@ void Pipsolar::loop() {
 | 
			
		||||
        ESP_LOGD(TAG, "Decode QPIGS");
 | 
			
		||||
        sscanf(                                                                                              // NOLINT
 | 
			
		||||
            tmp,                                                                                             // NOLINT
 | 
			
		||||
            "(%f %f %f %f %d %d %d %d %f %d %d %d %d %f %f %d %1d%1d%1d%1d%1d%1d%1d%1d %d %d %d %1d%1d%1d",  // NOLINT
 | 
			
		||||
            "(%f %f %f %f %d %d %d %d %f %d %d %d %f %f %f %d %1d%1d%1d%1d%1d%1d%1d%1d %d %d %d %1d%1d%1d",  // NOLINT
 | 
			
		||||
            &value_grid_voltage_, &value_grid_frequency_, &value_ac_output_voltage_,                         // NOLINT
 | 
			
		||||
            &value_ac_output_frequency_,                                                                     // NOLINT
 | 
			
		||||
            &value_ac_output_apparent_power_, &value_ac_output_active_power_, &value_output_load_percent_,   // NOLINT
 | 
			
		||||
@@ -770,15 +770,15 @@ uint8_t Pipsolar::check_incoming_crc_() {
 | 
			
		||||
  uint16_t crc16;
 | 
			
		||||
  crc16 = cal_crc_half_(read_buffer_, read_pos_ - 3);
 | 
			
		||||
  ESP_LOGD(TAG, "checking crc on incoming message");
 | 
			
		||||
  if (((uint8_t)((crc16) >> 8)) == read_buffer_[read_pos_ - 3] &&
 | 
			
		||||
      ((uint8_t)((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) {
 | 
			
		||||
  if (((uint8_t) ((crc16) >> 8)) == read_buffer_[read_pos_ - 3] &&
 | 
			
		||||
      ((uint8_t) ((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) {
 | 
			
		||||
    ESP_LOGD(TAG, "CRC OK");
 | 
			
		||||
    read_buffer_[read_pos_ - 1] = 0;
 | 
			
		||||
    read_buffer_[read_pos_ - 2] = 0;
 | 
			
		||||
    read_buffer_[read_pos_ - 3] = 0;
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGD(TAG, "CRC NOK expected: %X %X but got: %X %X", ((uint8_t)((crc16) >> 8)), ((uint8_t)((crc16) &0xff)),
 | 
			
		||||
  ESP_LOGD(TAG, "CRC NOK expected: %X %X but got: %X %X", ((uint8_t) ((crc16) >> 8)), ((uint8_t) ((crc16) &0xff)),
 | 
			
		||||
           read_buffer_[read_pos_ - 3], read_buffer_[read_pos_ - 2]);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -800,8 +800,8 @@ uint8_t Pipsolar::send_next_command_() {
 | 
			
		||||
    crc16 = cal_crc_half_(byte_command, length);
 | 
			
		||||
    this->write_str(command);
 | 
			
		||||
    // checksum
 | 
			
		||||
    this->write(((uint8_t)((crc16) >> 8)));   // highbyte
 | 
			
		||||
    this->write(((uint8_t)((crc16) &0xff)));  // lowbyte
 | 
			
		||||
    this->write(((uint8_t) ((crc16) >> 8)));   // highbyte
 | 
			
		||||
    this->write(((uint8_t) ((crc16) &0xff)));  // lowbyte
 | 
			
		||||
    // end Byte
 | 
			
		||||
    this->write(0x0D);
 | 
			
		||||
    ESP_LOGD(TAG, "Sending command from queue: %s with length %d", command, length);
 | 
			
		||||
@@ -829,8 +829,8 @@ void Pipsolar::send_next_poll_() {
 | 
			
		||||
  this->write_array(this->used_polling_commands_[this->last_polling_command_].command,
 | 
			
		||||
                    this->used_polling_commands_[this->last_polling_command_].length);
 | 
			
		||||
  // checksum
 | 
			
		||||
  this->write(((uint8_t)((crc16) >> 8)));   // highbyte
 | 
			
		||||
  this->write(((uint8_t)((crc16) &0xff)));  // lowbyte
 | 
			
		||||
  this->write(((uint8_t) ((crc16) >> 8)));   // highbyte
 | 
			
		||||
  this->write(((uint8_t) ((crc16) &0xff)));  // lowbyte
 | 
			
		||||
  // end Byte
 | 
			
		||||
  this->write(0x0D);
 | 
			
		||||
  ESP_LOGD(TAG, "Sending polling command : %s with length %d",
 | 
			
		||||
@@ -882,7 +882,7 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll
 | 
			
		||||
      used_polling_command.command = new uint8_t[length];  // NOLINT(cppcoreguidelines-owning-memory)
 | 
			
		||||
      size_t i = 0;
 | 
			
		||||
      for (; beg != end; ++beg, ++i) {
 | 
			
		||||
        used_polling_command.command[i] = (uint8_t)(*beg);
 | 
			
		||||
        used_polling_command.command[i] = (uint8_t) (*beg);
 | 
			
		||||
      }
 | 
			
		||||
      used_polling_command.errors = 0;
 | 
			
		||||
      used_polling_command.identifier = polling_command;
 | 
			
		||||
@@ -907,17 +907,17 @@ uint16_t Pipsolar::cal_crc_half_(uint8_t *msg, uint8_t len) {
 | 
			
		||||
  crc = 0;
 | 
			
		||||
 | 
			
		||||
  while (len-- != 0) {
 | 
			
		||||
    da = ((uint8_t)(crc >> 8)) >> 4;
 | 
			
		||||
    da = ((uint8_t) (crc >> 8)) >> 4;
 | 
			
		||||
    crc <<= 4;
 | 
			
		||||
    crc ^= crc_ta[da ^ (*ptr >> 4)];
 | 
			
		||||
    da = ((uint8_t)(crc >> 8)) >> 4;
 | 
			
		||||
    da = ((uint8_t) (crc >> 8)) >> 4;
 | 
			
		||||
    crc <<= 4;
 | 
			
		||||
    crc ^= crc_ta[da ^ (*ptr & 0x0f)];
 | 
			
		||||
    ptr++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  b_crc_low = crc;
 | 
			
		||||
  b_crc_hign = (uint8_t)(crc >> 8);
 | 
			
		||||
  b_crc_hign = (uint8_t) (crc >> 8);
 | 
			
		||||
 | 
			
		||||
  if (b_crc_low == 0x28 || b_crc_low == 0x0d || b_crc_low == 0x0a)
 | 
			
		||||
    b_crc_low++;
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent {
 | 
			
		||||
  PIPSOLAR_SENSOR(battery_charging_current, QPIGS, int)
 | 
			
		||||
  PIPSOLAR_SENSOR(battery_capacity_percent, QPIGS, int)
 | 
			
		||||
  PIPSOLAR_SENSOR(inverter_heat_sink_temperature, QPIGS, int)
 | 
			
		||||
  PIPSOLAR_SENSOR(pv_input_current_for_battery, QPIGS, int)
 | 
			
		||||
  PIPSOLAR_SENSOR(pv_input_current_for_battery, QPIGS, float)
 | 
			
		||||
  PIPSOLAR_SENSOR(pv_input_voltage, QPIGS, float)
 | 
			
		||||
  PIPSOLAR_SENSOR(battery_voltage_scc, QPIGS, float)
 | 
			
		||||
  PIPSOLAR_SENSOR(battery_discharge_current, QPIGS, int)
 | 
			
		||||
 
 | 
			
		||||
@@ -264,13 +264,52 @@ void PMSX003Component::parse_data_() {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case PMSX003_TYPE_5003T: {
 | 
			
		||||
      uint16_t pm_1_0_std_concentration = this->get_16_bit_uint_(4);
 | 
			
		||||
      uint16_t pm_2_5_std_concentration = this->get_16_bit_uint_(6);
 | 
			
		||||
      uint16_t pm_10_0_std_concentration = this->get_16_bit_uint_(8);
 | 
			
		||||
 | 
			
		||||
      uint16_t pm_1_0_concentration = this->get_16_bit_uint_(10);
 | 
			
		||||
      uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12);
 | 
			
		||||
      uint16_t pm_10_0_concentration = this->get_16_bit_uint_(14);
 | 
			
		||||
 | 
			
		||||
      uint16_t pm_particles_03um = this->get_16_bit_uint_(16);
 | 
			
		||||
      uint16_t pm_particles_05um = this->get_16_bit_uint_(18);
 | 
			
		||||
      uint16_t pm_particles_10um = this->get_16_bit_uint_(20);
 | 
			
		||||
      uint16_t pm_particles_25um = this->get_16_bit_uint_(22);
 | 
			
		||||
      // Note the pm particles 50um & 100um are not returned,
 | 
			
		||||
      // as PMS5003T uses those data values for temperature and humidity.
 | 
			
		||||
 | 
			
		||||
      float temperature = this->get_16_bit_uint_(24) / 10.0f;
 | 
			
		||||
      float humidity = this->get_16_bit_uint_(26) / 10.0f;
 | 
			
		||||
      ESP_LOGD(TAG, "Got PM2.5 Concentration: %u µg/m^3, Temperature: %.1f°C, Humidity: %.1f%%", pm_2_5_concentration,
 | 
			
		||||
               temperature, humidity);
 | 
			
		||||
 | 
			
		||||
      ESP_LOGD(TAG,
 | 
			
		||||
               "Got PM1.0 Concentration: %u µg/m^3, PM2.5 Concentration %u µg/m^3, PM10.0 Concentration: %u µg/m^3, "
 | 
			
		||||
               "Temperature: %.1f°C, Humidity: %.1f%%",
 | 
			
		||||
               pm_1_0_concentration, pm_2_5_concentration, pm_10_0_concentration, temperature, humidity);
 | 
			
		||||
 | 
			
		||||
      if (this->pm_1_0_std_sensor_ != nullptr)
 | 
			
		||||
        this->pm_1_0_std_sensor_->publish_state(pm_1_0_std_concentration);
 | 
			
		||||
      if (this->pm_2_5_std_sensor_ != nullptr)
 | 
			
		||||
        this->pm_2_5_std_sensor_->publish_state(pm_2_5_std_concentration);
 | 
			
		||||
      if (this->pm_10_0_std_sensor_ != nullptr)
 | 
			
		||||
        this->pm_10_0_std_sensor_->publish_state(pm_10_0_std_concentration);
 | 
			
		||||
 | 
			
		||||
      if (this->pm_1_0_sensor_ != nullptr)
 | 
			
		||||
        this->pm_1_0_sensor_->publish_state(pm_1_0_concentration);
 | 
			
		||||
      if (this->pm_2_5_sensor_ != nullptr)
 | 
			
		||||
        this->pm_2_5_sensor_->publish_state(pm_2_5_concentration);
 | 
			
		||||
      if (this->pm_10_0_sensor_ != nullptr)
 | 
			
		||||
        this->pm_10_0_sensor_->publish_state(pm_10_0_concentration);
 | 
			
		||||
 | 
			
		||||
      if (this->pm_particles_03um_sensor_ != nullptr)
 | 
			
		||||
        this->pm_particles_03um_sensor_->publish_state(pm_particles_03um);
 | 
			
		||||
      if (this->pm_particles_05um_sensor_ != nullptr)
 | 
			
		||||
        this->pm_particles_05um_sensor_->publish_state(pm_particles_05um);
 | 
			
		||||
      if (this->pm_particles_10um_sensor_ != nullptr)
 | 
			
		||||
        this->pm_particles_10um_sensor_->publish_state(pm_particles_10um);
 | 
			
		||||
      if (this->pm_particles_25um_sensor_ != nullptr)
 | 
			
		||||
        this->pm_particles_25um_sensor_->publish_state(pm_particles_25um);
 | 
			
		||||
 | 
			
		||||
      if (this->temperature_sensor_ != nullptr)
 | 
			
		||||
        this->temperature_sensor_->publish_state(temperature);
 | 
			
		||||
      if (this->humidity_sensor_ != nullptr)
 | 
			
		||||
 
 | 
			
		||||
@@ -55,9 +55,9 @@ PMSX003_TYPES = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SENSORS_TO_TYPE = {
 | 
			
		||||
    CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S],
 | 
			
		||||
    CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
 | 
			
		||||
    CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
 | 
			
		||||
    CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S],
 | 
			
		||||
    CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S],
 | 
			
		||||
    CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST],
 | 
			
		||||
    CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST],
 | 
			
		||||
    CONF_FORMALDEHYDE: [TYPE_PMS5003ST, TYPE_PMS5003S],
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "esphome/core/automation.h"
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/components/sensor/sensor.h"
 | 
			
		||||
#include "esphome/components/modbus/modbus.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -121,38 +121,38 @@ bool QMP6988Component::get_calibration_data_() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_a0 =
 | 
			
		||||
      (QMP6988_S32_t)(((a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) |
 | 
			
		||||
                       (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f))
 | 
			
		||||
                      << 12);
 | 
			
		||||
      (QMP6988_S32_t) (((a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) |
 | 
			
		||||
                        (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f))
 | 
			
		||||
                       << 12);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_a0 = qmp6988_data_.qmp6988_cali.COE_a0 >> 12;
 | 
			
		||||
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_a1 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[20]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[20]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_a2 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[22]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[22]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]);
 | 
			
		||||
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_b00 =
 | 
			
		||||
      (QMP6988_S32_t)(((a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) |
 | 
			
		||||
                       ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION))
 | 
			
		||||
                      << 12);
 | 
			
		||||
      (QMP6988_S32_t) (((a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) |
 | 
			
		||||
                        ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION))
 | 
			
		||||
                       << 12);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_b00 = qmp6988_data_.qmp6988_cali.COE_b00 >> 12;
 | 
			
		||||
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_bt1 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[2]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[2]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_bt2 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[4]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[4]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_bp1 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[6]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[6]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_b11 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[8]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[8]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_bp2 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[10]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[10]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_b12 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[12]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[12]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_b21 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[14]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[14]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]);
 | 
			
		||||
  qmp6988_data_.qmp6988_cali.COE_bp3 =
 | 
			
		||||
      (QMP6988_S16_t)(((a_data_uint8_tr[16]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]);
 | 
			
		||||
      (QMP6988_S16_t) (((a_data_uint8_tr[16]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]);
 | 
			
		||||
 | 
			
		||||
  ESP_LOGV(TAG, "<-----------calibration data-------------->\r\n");
 | 
			
		||||
  ESP_LOGV(TAG, "COE_a0[%d] COE_a1[%d] COE_a2[%d] COE_b00[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_a0,
 | 
			
		||||
@@ -197,7 +197,7 @@ QMP6988_S16_t QMP6988Component::get_compensated_temperature_(qmp6988_ik_data_t *
 | 
			
		||||
  wk2 = ((QMP6988_S64_t) ik->a2 * (QMP6988_S64_t) dt) >> 14;  // 30Q47+24-1=53 (39Q33)
 | 
			
		||||
  wk2 = (wk2 * (QMP6988_S64_t) dt) >> 10;                     // 39Q33+24-1=62 (52Q23)
 | 
			
		||||
  wk2 = ((wk1 + wk2) / 32767) >> 19;                          // 54,52->55Q23 (20Q04)
 | 
			
		||||
  ret = (QMP6988_S16_t)((ik->a0 + wk2) >> 4);                 // 21Q4 -> 17Q0
 | 
			
		||||
  ret = (QMP6988_S16_t) ((ik->a0 + wk2) >> 4);                // 21Q4 -> 17Q0
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -332,13 +332,13 @@ void QMP6988Component::calculate_pressure_() {
 | 
			
		||||
    ESP_LOGE(TAG, "Error reading raw pressure/temp values");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  p_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) |
 | 
			
		||||
                           (((QMP6988_U16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2]));
 | 
			
		||||
  p_raw = (QMP6988_S32_t)(p_read - SUBTRACTOR);
 | 
			
		||||
  p_read = (QMP6988_U32_t) ((((QMP6988_U32_t) (a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) |
 | 
			
		||||
                            (((QMP6988_U16_t) (a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2]));
 | 
			
		||||
  p_raw = (QMP6988_S32_t) (p_read - SUBTRACTOR);
 | 
			
		||||
 | 
			
		||||
  t_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) |
 | 
			
		||||
                           (((QMP6988_U16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5]));
 | 
			
		||||
  t_raw = (QMP6988_S32_t)(t_read - SUBTRACTOR);
 | 
			
		||||
  t_read = (QMP6988_U32_t) ((((QMP6988_U32_t) (a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) |
 | 
			
		||||
                            (((QMP6988_U16_t) (a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5]));
 | 
			
		||||
  t_raw = (QMP6988_S32_t) (t_read - SUBTRACTOR);
 | 
			
		||||
 | 
			
		||||
  t_int = this->get_compensated_temperature_(&(qmp6988_data_.ik), t_raw);
 | 
			
		||||
  p_int = this->get_compensated_pressure_(&(qmp6988_data_.ik), p_raw, t_int);
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ optional<RC5Data> RC5Protocol::decode(RemoteReceiveData src) {
 | 
			
		||||
    out_data |= 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  out.command = (uint8_t)(out_data & 0x3F) + (1 - field_bit) * 64u;
 | 
			
		||||
  out.command = (uint8_t) (out_data & 0x3F) + (1 - field_bit) * 64u;
 | 
			
		||||
  out.address = (out_data >> 6) & 0x1F;
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ void SCD30Component::setup() {
 | 
			
		||||
           uint16_t(raw_firmware_version[0] & 0xFF));
 | 
			
		||||
 | 
			
		||||
  if (this->temperature_offset_ != 0) {
 | 
			
		||||
    if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t)(temperature_offset_ * 100.0))) {
 | 
			
		||||
    if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t) (temperature_offset_ * 100.0))) {
 | 
			
		||||
      ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset.");
 | 
			
		||||
      this->error_code_ = MEASUREMENT_INIT_FAILED;
 | 
			
		||||
      this->mark_failed();
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ class SCD30Component : public Component, public sensirion_common::SensirionI2CDe
 | 
			
		||||
  void set_automatic_self_calibration(bool asc) { enable_asc_ = asc; }
 | 
			
		||||
  void set_altitude_compensation(uint16_t altitude) { altitude_compensation_ = altitude; }
 | 
			
		||||
  void set_ambient_pressure_compensation(float pressure) {
 | 
			
		||||
    ambient_pressure_compensation_ = (uint16_t)(pressure * 1000);
 | 
			
		||||
    ambient_pressure_compensation_ = (uint16_t) (pressure * 1000);
 | 
			
		||||
  }
 | 
			
		||||
  void set_temperature_offset(float offset) { temperature_offset_ = offset; }
 | 
			
		||||
  void set_update_interval(uint16_t interval) { update_interval_ = interval; }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ from esphome.const import (
 | 
			
		||||
    CONF_CO2,
 | 
			
		||||
    CONF_UPDATE_INTERVAL,
 | 
			
		||||
    CONF_VALUE,
 | 
			
		||||
    DEVICE_CLASS_CARBON_DIOXIDE,
 | 
			
		||||
    DEVICE_CLASS_HUMIDITY,
 | 
			
		||||
    DEVICE_CLASS_TEMPERATURE,
 | 
			
		||||
    STATE_CLASS_MEASUREMENT,
 | 
			
		||||
@@ -46,6 +47,7 @@ CONFIG_SCHEMA = (
 | 
			
		||||
                unit_of_measurement=UNIT_PARTS_PER_MILLION,
 | 
			
		||||
                icon=ICON_MOLECULE_CO2,
 | 
			
		||||
                accuracy_decimals=0,
 | 
			
		||||
                device_class=DEVICE_CLASS_CARBON_DIOXIDE,
 | 
			
		||||
                state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
            ),
 | 
			
		||||
            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ void SCD4XComponent::setup() {
 | 
			
		||||
               uint16_t(raw_serial_number[0] & 0xFF), (uint16_t(raw_serial_number[1]) >> 8));
 | 
			
		||||
 | 
			
		||||
      if (!this->write_command(SCD4X_CMD_TEMPERATURE_OFFSET,
 | 
			
		||||
                               (uint16_t)(temperature_offset_ * SCD4X_TEMPERATURE_OFFSET_MULTIPLIER))) {
 | 
			
		||||
                               (uint16_t) (temperature_offset_ * SCD4X_TEMPERATURE_OFFSET_MULTIPLIER))) {
 | 
			
		||||
        ESP_LOGE(TAG, "Error setting temperature offset.");
 | 
			
		||||
        this->error_code_ = MEASUREMENT_INIT_FAILED;
 | 
			
		||||
        this->mark_failed();
 | 
			
		||||
 
 | 
			
		||||
@@ -194,6 +194,7 @@ SensorPublishAction = sensor_ns.class_("SensorPublishAction", automation.Action)
 | 
			
		||||
Filter = sensor_ns.class_("Filter")
 | 
			
		||||
QuantileFilter = sensor_ns.class_("QuantileFilter", Filter)
 | 
			
		||||
MedianFilter = sensor_ns.class_("MedianFilter", Filter)
 | 
			
		||||
SkipInitialFilter = sensor_ns.class_("SkipInitialFilter", Filter)
 | 
			
		||||
MinFilter = sensor_ns.class_("MinFilter", Filter)
 | 
			
		||||
MaxFilter = sensor_ns.class_("MaxFilter", Filter)
 | 
			
		||||
SlidingWindowMovingAverageFilter = sensor_ns.class_(
 | 
			
		||||
@@ -365,6 +366,11 @@ MIN_SCHEMA = cv.All(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("skip_initial", SkipInitialFilter, cv.positive_not_null_int)
 | 
			
		||||
async def skip_initial_filter_to_code(config, filter_id):
 | 
			
		||||
    return cg.new_Pvariable(filter_id, config)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("min", MinFilter, MIN_SCHEMA)
 | 
			
		||||
async def min_filter_to_code(config, filter_id):
 | 
			
		||||
    return cg.new_Pvariable(
 | 
			
		||||
@@ -466,9 +472,21 @@ async def lambda_filter_to_code(config, filter_id):
 | 
			
		||||
    return cg.new_Pvariable(filter_id, lambda_)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_)
 | 
			
		||||
def validate_delta(config):
 | 
			
		||||
    try:
 | 
			
		||||
        return (cv.positive_float(config), False)
 | 
			
		||||
    except cv.Invalid:
 | 
			
		||||
        pass
 | 
			
		||||
    try:
 | 
			
		||||
        return (cv.percentage(config), True)
 | 
			
		||||
    except cv.Invalid:
 | 
			
		||||
        pass
 | 
			
		||||
    raise cv.Invalid("Delta filter requires a positive number or percentage value.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta)
 | 
			
		||||
async def delta_filter_to_code(config, filter_id):
 | 
			
		||||
    return cg.new_Pvariable(filter_id, config)
 | 
			
		||||
    return cg.new_Pvariable(filter_id, *config)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@FILTER_REGISTRY.register("or", OrFilter, validate_filters)
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,19 @@ optional<float> MedianFilter::new_value(float value) {
 | 
			
		||||
  return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SkipInitialFilter
 | 
			
		||||
SkipInitialFilter::SkipInitialFilter(size_t num_to_ignore) : num_to_ignore_(num_to_ignore) {}
 | 
			
		||||
optional<float> SkipInitialFilter::new_value(float value) {
 | 
			
		||||
  if (num_to_ignore_ > 0) {
 | 
			
		||||
    num_to_ignore_--;
 | 
			
		||||
    ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %u left", this, value, num_to_ignore_);
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SENDING", this, value);
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QuantileFilter
 | 
			
		||||
QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile)
 | 
			
		||||
    : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size), quantile_(quantile) {}
 | 
			
		||||
@@ -315,19 +328,23 @@ optional<float> ThrottleFilter::new_value(float value) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeltaFilter
 | 
			
		||||
DeltaFilter::DeltaFilter(float min_delta) : min_delta_(min_delta), last_value_(NAN) {}
 | 
			
		||||
DeltaFilter::DeltaFilter(float delta, bool percentage_mode)
 | 
			
		||||
    : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {}
 | 
			
		||||
optional<float> DeltaFilter::new_value(float value) {
 | 
			
		||||
  if (std::isnan(value)) {
 | 
			
		||||
    if (std::isnan(this->last_value_)) {
 | 
			
		||||
      return {};
 | 
			
		||||
    } else {
 | 
			
		||||
      if (this->percentage_mode_) {
 | 
			
		||||
        this->current_delta_ = fabsf(value * this->delta_);
 | 
			
		||||
      }
 | 
			
		||||
      return this->last_value_ = value;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (std::isnan(this->last_value_)) {
 | 
			
		||||
    return this->last_value_ = value;
 | 
			
		||||
  }
 | 
			
		||||
  if (fabsf(value - this->last_value_) >= this->min_delta_) {
 | 
			
		||||
  if (std::isnan(this->last_value_) || fabsf(value - this->last_value_) >= this->current_delta_) {
 | 
			
		||||
    if (this->percentage_mode_) {
 | 
			
		||||
      this->current_delta_ = fabsf(value * this->delta_);
 | 
			
		||||
    }
 | 
			
		||||
    return this->last_value_ = value;
 | 
			
		||||
  }
 | 
			
		||||
  return {};
 | 
			
		||||
 
 | 
			
		||||
@@ -102,6 +102,24 @@ class MedianFilter : public Filter {
 | 
			
		||||
  size_t window_size_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Simple skip filter.
 | 
			
		||||
 *
 | 
			
		||||
 * Skips the first N values, then passes everything else.
 | 
			
		||||
 */
 | 
			
		||||
class SkipInitialFilter : public Filter {
 | 
			
		||||
 public:
 | 
			
		||||
  /** Construct a SkipInitialFilter.
 | 
			
		||||
   *
 | 
			
		||||
   * @param num_to_ignore How many values to ignore before the filter becomes a no-op.
 | 
			
		||||
   */
 | 
			
		||||
  explicit SkipInitialFilter(size_t num_to_ignore);
 | 
			
		||||
 | 
			
		||||
  optional<float> new_value(float value) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  size_t num_to_ignore_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Simple min filter.
 | 
			
		||||
 *
 | 
			
		||||
 * Takes the min of the last <send_every> values and pushes it out every <send_every>.
 | 
			
		||||
@@ -325,12 +343,14 @@ class HeartbeatFilter : public Filter, public Component {
 | 
			
		||||
 | 
			
		||||
class DeltaFilter : public Filter {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit DeltaFilter(float min_delta);
 | 
			
		||||
  explicit DeltaFilter(float delta, bool percentage_mode);
 | 
			
		||||
 | 
			
		||||
  optional<float> new_value(float value) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  float min_delta_;
 | 
			
		||||
  float delta_;
 | 
			
		||||
  float current_delta_;
 | 
			
		||||
  bool percentage_mode_;
 | 
			
		||||
  float last_value_{NAN};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,48 +26,32 @@ Sensor::Sensor() : Sensor("") {}
 | 
			
		||||
std::string Sensor::get_unit_of_measurement() {
 | 
			
		||||
  if (this->unit_of_measurement_.has_value())
 | 
			
		||||
    return *this->unit_of_measurement_;
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 | 
			
		||||
  return this->unit_of_measurement();
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
void Sensor::set_unit_of_measurement(const std::string &unit_of_measurement) {
 | 
			
		||||
  this->unit_of_measurement_ = unit_of_measurement;
 | 
			
		||||
}
 | 
			
		||||
std::string Sensor::unit_of_measurement() { return ""; }
 | 
			
		||||
 | 
			
		||||
int8_t Sensor::get_accuracy_decimals() {
 | 
			
		||||
  if (this->accuracy_decimals_.has_value())
 | 
			
		||||
    return *this->accuracy_decimals_;
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 | 
			
		||||
  return this->accuracy_decimals();
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
void Sensor::set_accuracy_decimals(int8_t accuracy_decimals) { this->accuracy_decimals_ = accuracy_decimals; }
 | 
			
		||||
int8_t Sensor::accuracy_decimals() { return 0; }
 | 
			
		||||
 | 
			
		||||
std::string Sensor::get_device_class() {
 | 
			
		||||
  if (this->device_class_.has_value())
 | 
			
		||||
    return *this->device_class_;
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 | 
			
		||||
  return this->device_class();
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
void Sensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; }
 | 
			
		||||
std::string Sensor::device_class() { return ""; }
 | 
			
		||||
 | 
			
		||||
void Sensor::set_state_class(StateClass state_class) { this->state_class_ = state_class; }
 | 
			
		||||
StateClass Sensor::get_state_class() {
 | 
			
		||||
  if (this->state_class_.has_value())
 | 
			
		||||
    return *this->state_class_;
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 | 
			
		||||
  return this->state_class();
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
  return StateClass::STATE_CLASS_NONE;
 | 
			
		||||
}
 | 
			
		||||
StateClass Sensor::state_class() { return StateClass::STATE_CLASS_NONE; }
 | 
			
		||||
 | 
			
		||||
void Sensor::publish_state(float state) {
 | 
			
		||||
  this->raw_state = state;
 | 
			
		||||
 
 | 
			
		||||
@@ -150,40 +150,15 @@ class Sensor : public EntityBase {
 | 
			
		||||
  /// Return whether this sensor has gotten a full state (that passed through all filters) yet.
 | 
			
		||||
  bool has_state() const;
 | 
			
		||||
 | 
			
		||||
  /** A unique ID for this sensor, empty for no unique id. See unique ID requirements:
 | 
			
		||||
   * https://developers.home-assistant.io/docs/en/entity_registry_index.html#unique-id-requirements
 | 
			
		||||
  /** Override this method to set the unique ID of this sensor.
 | 
			
		||||
   *
 | 
			
		||||
   * @return The unique id as a string.
 | 
			
		||||
   * @deprecated Do not use for new sensors, a suitable unique ID is automatically generated (2023.4).
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string unique_id();
 | 
			
		||||
 | 
			
		||||
  void internal_send_state_to_frontend(float state);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /** Override this to set the default unit of measurement.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string unit_of_measurement();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  /** Override this to set the default accuracy in decimals.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
 | 
			
		||||
   */
 | 
			
		||||
  virtual int8_t accuracy_decimals();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  /** Override this to set the default device class.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string device_class();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  /** Override this to set the default state class.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated This method is deprecated, set the property during config validation instead. (2022.1)
 | 
			
		||||
   */
 | 
			
		||||
  virtual StateClass state_class();  // NOLINT
 | 
			
		||||
 | 
			
		||||
  CallbackManager<void(float)> raw_callback_;  ///< Storage for raw state callbacks.
 | 
			
		||||
  CallbackManager<void(float)> callback_;      ///< Storage for filtered state callbacks.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -234,8 +234,8 @@ bool SGP4xComponent::measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw) {
 | 
			
		||||
      response_words = 2;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  uint16_t rhticks = llround((uint16_t)((humidity * 65535) / 100));
 | 
			
		||||
  uint16_t tempticks = (uint16_t)(((temperature + 45) * 65535) / 175);
 | 
			
		||||
  uint16_t rhticks = llround((uint16_t) ((humidity * 65535) / 100));
 | 
			
		||||
  uint16_t tempticks = (uint16_t) (((temperature + 45) * 65535) / 175);
 | 
			
		||||
  // first parameter are the relative humidity ticks
 | 
			
		||||
  data[0] = rhticks;
 | 
			
		||||
  // secomd parameter are the temperature ticks
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ void SHT4XComponent::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up sht4x...");
 | 
			
		||||
 | 
			
		||||
  if (this->duty_cycle_ > 0.0) {
 | 
			
		||||
    uint32_t heater_interval = (uint32_t)(this->heater_time_ / this->duty_cycle_);
 | 
			
		||||
    uint32_t heater_interval = (uint32_t) (this->heater_time_ / this->duty_cycle_);
 | 
			
		||||
    ESP_LOGD(TAG, "Heater interval: %i", heater_interval);
 | 
			
		||||
 | 
			
		||||
    if (this->heater_power_ == SHT4X_HEATERPOWER_HIGH) {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ spi_ns = cg.esphome_ns.namespace("spi")
 | 
			
		||||
SPIComponent = spi_ns.class_("SPIComponent", cg.Component)
 | 
			
		||||
SPIDevice = spi_ns.class_("SPIDevice")
 | 
			
		||||
MULTI_CONF = True
 | 
			
		||||
CONF_FORCE_SW = "force_sw"
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    cv.Schema(
 | 
			
		||||
@@ -25,6 +26,7 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
            cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_FORCE_SW, default=False): cv.boolean,
 | 
			
		||||
        }
 | 
			
		||||
    ),
 | 
			
		||||
    cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN),
 | 
			
		||||
@@ -39,6 +41,7 @@ async def to_code(config):
 | 
			
		||||
 | 
			
		||||
    clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN])
 | 
			
		||||
    cg.add(var.set_clk(clk))
 | 
			
		||||
    cg.add(var.set_force_sw(config[CONF_FORCE_SW]))
 | 
			
		||||
    if CONF_MISO_PIN in config:
 | 
			
		||||
        miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN])
 | 
			
		||||
        cg.add(var.set_miso(miso))
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ void SPIComponent::setup() {
 | 
			
		||||
  this->clk_->digital_write(true);
 | 
			
		||||
 | 
			
		||||
#ifdef USE_SPI_ARDUINO_BACKEND
 | 
			
		||||
  bool use_hw_spi = true;
 | 
			
		||||
  bool use_hw_spi = !this->force_sw_;
 | 
			
		||||
  const bool has_miso = this->miso_ != nullptr;
 | 
			
		||||
  const bool has_mosi = this->mosi_ != nullptr;
 | 
			
		||||
  int8_t clk_pin = -1, miso_pin = -1, mosi_pin = -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,7 @@ class SPIComponent : public Component {
 | 
			
		||||
  void set_clk(GPIOPin *clk) { clk_ = clk; }
 | 
			
		||||
  void set_miso(GPIOPin *miso) { miso_ = miso; }
 | 
			
		||||
  void set_mosi(GPIOPin *mosi) { mosi_ = mosi; }
 | 
			
		||||
  void set_force_sw(bool force_sw) { force_sw_ = force_sw; }
 | 
			
		||||
 | 
			
		||||
  void setup() override;
 | 
			
		||||
 | 
			
		||||
@@ -260,6 +261,7 @@ class SPIComponent : public Component {
 | 
			
		||||
  GPIOPin *miso_{nullptr};
 | 
			
		||||
  GPIOPin *mosi_{nullptr};
 | 
			
		||||
  GPIOPin *active_cs_{nullptr};
 | 
			
		||||
  bool force_sw_{false};
 | 
			
		||||
#ifdef USE_SPI_ARDUINO_BACKEND
 | 
			
		||||
  SPIClass *hw_spi_{nullptr};
 | 
			
		||||
#endif  // USE_SPI_ARDUINO_BACKEND
 | 
			
		||||
 
 | 
			
		||||
@@ -477,7 +477,6 @@ void Sprinkler::configure_valve_switch(size_t valve_number, switch_::Switch *val
 | 
			
		||||
  if (this->is_a_valid_valve(valve_number)) {
 | 
			
		||||
    this->valve_[valve_number].valve_switch.set_on_switch(valve_switch);
 | 
			
		||||
    this->valve_[valve_number].run_duration = run_duration;
 | 
			
		||||
    valve_switch->turn_off();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -489,8 +488,6 @@ void Sprinkler::configure_valve_switch_pulsed(size_t valve_number, switch_::Swit
 | 
			
		||||
    this->valve_[valve_number].valve_switch.set_on_switch(valve_switch_on);
 | 
			
		||||
    this->valve_[valve_number].valve_switch.set_pulse_duration(pulse_duration);
 | 
			
		||||
    this->valve_[valve_number].run_duration = run_duration;
 | 
			
		||||
    valve_switch_off->turn_off();
 | 
			
		||||
    valve_switch_on->turn_off();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -505,7 +502,6 @@ void Sprinkler::configure_valve_pump_switch(size_t valve_number, switch_::Switch
 | 
			
		||||
    this->pump_.resize(this->pump_.size() + 1);
 | 
			
		||||
    this->pump_.back().set_on_switch(pump_switch);
 | 
			
		||||
    this->valve_[valve_number].pump_switch_index = this->pump_.size() - 1;  // save the index to the new pump
 | 
			
		||||
    pump_switch->turn_off();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -524,8 +520,6 @@ void Sprinkler::configure_valve_pump_switch_pulsed(size_t valve_number, switch_:
 | 
			
		||||
    this->pump_.back().set_on_switch(pump_switch_on);
 | 
			
		||||
    this->pump_.back().set_pulse_duration(pulse_duration);
 | 
			
		||||
    this->valve_[valve_number].pump_switch_index = this->pump_.size() - 1;  // save the index to the new pump
 | 
			
		||||
    pump_switch_off->turn_off();
 | 
			
		||||
    pump_switch_on->turn_off();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -103,7 +103,7 @@ class SprinklerControllerNumber : public number::Number, public Component {
 | 
			
		||||
 public:
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  float get_setup_priority() const override { return setup_priority::HARDWARE; }
 | 
			
		||||
  float get_setup_priority() const override { return setup_priority::PROCESSOR; }
 | 
			
		||||
 | 
			
		||||
  Trigger<float> *get_set_trigger() const { return set_trigger_; }
 | 
			
		||||
  void set_initial_value(float initial_value) { initial_value_ = initial_value; }
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ void ST7920::goto_xy_(uint16_t x, uint16_t y) {
 | 
			
		||||
 | 
			
		||||
void HOT ST7920::write_display_data() {
 | 
			
		||||
  uint8_t i, j, b;
 | 
			
		||||
  for (j = 0; j < (uint8_t)(this->get_height_internal() / 2); j++) {
 | 
			
		||||
  for (j = 0; j < (uint8_t) (this->get_height_internal() / 2); j++) {
 | 
			
		||||
    this->goto_xy_(0, j);
 | 
			
		||||
    this->enable();
 | 
			
		||||
    for (i = 0; i < 16; i++) {  // 16 bytes from line #0+
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +1,35 @@
 | 
			
		||||
from esphome import pins
 | 
			
		||||
import esphome.codegen as cg
 | 
			
		||||
import esphome.config_validation as cv
 | 
			
		||||
from esphome.components import light
 | 
			
		||||
from esphome.const import CONF_OUTPUT_ID, CONF_PIN
 | 
			
		||||
from esphome.components import light, output
 | 
			
		||||
from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID, CONF_PIN
 | 
			
		||||
from .. import status_led_ns
 | 
			
		||||
 | 
			
		||||
AUTO_LOAD = ["output"]
 | 
			
		||||
 | 
			
		||||
StatusLEDLightOutput = status_led_ns.class_(
 | 
			
		||||
    "StatusLEDLightOutput", light.LightOutput, cg.Component
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput),
 | 
			
		||||
        cv.Required(CONF_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
    }
 | 
			
		||||
CONFIG_SCHEMA = cv.All(
 | 
			
		||||
    light.BINARY_LIGHT_SCHEMA.extend(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput),
 | 
			
		||||
            cv.Optional(CONF_PIN): pins.gpio_output_pin_schema,
 | 
			
		||||
            cv.Optional(CONF_OUTPUT): cv.use_id(output.BinaryOutput),
 | 
			
		||||
        }
 | 
			
		||||
    ),
 | 
			
		||||
    cv.has_at_least_one_key(CONF_PIN, CONF_OUTPUT),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
 | 
			
		||||
    pin = await cg.gpio_pin_expression(config[CONF_PIN])
 | 
			
		||||
    cg.add(var.set_pin(pin))
 | 
			
		||||
    if CONF_PIN in config:
 | 
			
		||||
        pin = await cg.gpio_pin_expression(config[CONF_PIN])
 | 
			
		||||
        cg.add(var.set_pin(pin))
 | 
			
		||||
    if CONF_OUTPUT in config:
 | 
			
		||||
        out = await cg.get_variable(config[CONF_OUTPUT])
 | 
			
		||||
        cg.add(var.set_output(out))
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    # cg.add(cg.App.register_component(var))
 | 
			
		||||
    await light.register_light(var, config)
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,10 @@ void StatusLEDLightOutput::loop() {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ((new_state & STATUS_LED_ERROR) != 0u) {
 | 
			
		||||
    this->pin_->digital_write(millis() % 250u < 150u);
 | 
			
		||||
    this->output_state_(millis() % 250u < 150u);
 | 
			
		||||
    this->last_app_state_ = new_state;
 | 
			
		||||
  } else if ((new_state & STATUS_LED_WARNING) != 0u) {
 | 
			
		||||
    this->pin_->digital_write(millis() % 1500u < 250u);
 | 
			
		||||
    this->output_state_(millis() % 1500u < 250u);
 | 
			
		||||
    this->last_app_state_ = new_state;
 | 
			
		||||
  } else if (new_state != this->last_app_state_) {
 | 
			
		||||
    // if no error/warning -> restore light state or turn off
 | 
			
		||||
@@ -26,17 +26,16 @@ void StatusLEDLightOutput::loop() {
 | 
			
		||||
 | 
			
		||||
    if (lightstate_)
 | 
			
		||||
      lightstate_->current_values_as_binary(&state);
 | 
			
		||||
 | 
			
		||||
    this->pin_->digital_write(state);
 | 
			
		||||
    this->last_app_state_ = new_state;
 | 
			
		||||
 | 
			
		||||
    ESP_LOGD(TAG, "Restoring light state %s", ONOFF(state));
 | 
			
		||||
 | 
			
		||||
    this->output_state_(state);
 | 
			
		||||
    this->last_app_state_ = new_state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StatusLEDLightOutput::setup_state(light::LightState *state) {
 | 
			
		||||
  lightstate_ = state;
 | 
			
		||||
  ESP_LOGD(TAG, "'%s': Setting initital state", state->get_name().c_str());
 | 
			
		||||
  ESP_LOGD(TAG, "'%s': Setting initial state", state->get_name().c_str());
 | 
			
		||||
  this->write_state(state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -47,16 +46,18 @@ void StatusLEDLightOutput::write_state(light::LightState *state) {
 | 
			
		||||
  // if in warning/error, don't overwrite the status_led
 | 
			
		||||
  // once it is back to OK, the loop will restore the state
 | 
			
		||||
  if ((App.get_app_state() & (STATUS_LED_ERROR | STATUS_LED_WARNING)) == 0u) {
 | 
			
		||||
    this->pin_->digital_write(binary);
 | 
			
		||||
    ESP_LOGD(TAG, "'%s': Setting state %s", state->get_name().c_str(), ONOFF(binary));
 | 
			
		||||
    this->output_state_(binary);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StatusLEDLightOutput::setup() {
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "Setting up Status LED...");
 | 
			
		||||
 | 
			
		||||
  this->pin_->setup();
 | 
			
		||||
  this->pin_->digital_write(false);
 | 
			
		||||
  if (this->pin_ != nullptr) {
 | 
			
		||||
    this->pin_->setup();
 | 
			
		||||
    this->pin_->digital_write(false);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StatusLEDLightOutput::dump_config() {
 | 
			
		||||
@@ -64,5 +65,12 @@ void StatusLEDLightOutput::dump_config() {
 | 
			
		||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StatusLEDLightOutput::output_state_(bool state) {
 | 
			
		||||
  if (this->pin_ != nullptr)
 | 
			
		||||
    this->pin_->digital_write(state);
 | 
			
		||||
  if (this->output_ != nullptr)
 | 
			
		||||
    this->output_->set_state(state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace status_led
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
#include "esphome/core/component.h"
 | 
			
		||||
#include "esphome/core/hal.h"
 | 
			
		||||
#include "esphome/components/light/light_output.h"
 | 
			
		||||
#include "esphome/components/output/binary_output.h"
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace status_led {
 | 
			
		||||
@@ -10,6 +11,7 @@ namespace status_led {
 | 
			
		||||
class StatusLEDLightOutput : public light::LightOutput, public Component {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_pin(GPIOPin *pin) { pin_ = pin; }
 | 
			
		||||
  void set_output(output::BinaryOutput *output) { output_ = output; }
 | 
			
		||||
 | 
			
		||||
  light::LightTraits get_traits() override {
 | 
			
		||||
    auto traits = light::LightTraits();
 | 
			
		||||
@@ -31,9 +33,11 @@ class StatusLEDLightOutput : public light::LightOutput, public Component {
 | 
			
		||||
  float get_loop_priority() const override { return 50.0f; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  GPIOPin *pin_;
 | 
			
		||||
  GPIOPin *pin_{nullptr};
 | 
			
		||||
  output::BinaryOutput *output_{nullptr};
 | 
			
		||||
  light::LightState *lightstate_{};
 | 
			
		||||
  uint32_t last_app_state_{0xFFFF};
 | 
			
		||||
  void output_state_(bool state);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace status_led
 | 
			
		||||
 
 | 
			
		||||
@@ -269,7 +269,7 @@ struct SunAtLocation {
 | 
			
		||||
    num_t jd = julian_day(date) + added_d;
 | 
			
		||||
 | 
			
		||||
    num_t eot = SunAtTime(jd).equation_of_time() * 240;
 | 
			
		||||
    time_t new_timestamp = (time_t)(date.timestamp + added_d * 86400 - eot);
 | 
			
		||||
    time_t new_timestamp = (time_t) (date.timestamp + added_d * 86400 - eot);
 | 
			
		||||
    return time::ESPTime::from_epoch_utc(new_timestamp);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -287,7 +287,7 @@ void TCS34725Component::update() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // calculate register value from timing
 | 
			
		||||
    uint8_t regval_atime = (uint8_t)(256.f - integration_time_next / 2.4f);
 | 
			
		||||
    uint8_t regval_atime = (uint8_t) (256.f - integration_time_next / 2.4f);
 | 
			
		||||
    ESP_LOGD(TAG, "Integration time: %.1fms, ideal: %.1fms regval_new %d Gain: %.f Clear channel raw: %d  gain reg: %d",
 | 
			
		||||
             this->integration_time_, integration_time_next, regval_atime, this->gain_, raw_c, this->gain_reg_);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -61,6 +61,10 @@ class TextSensor : public EntityBase {
 | 
			
		||||
 | 
			
		||||
  // ========== INTERNAL METHODS ==========
 | 
			
		||||
  // (In most use cases you won't need these)
 | 
			
		||||
  /** Override this method to set the unique ID of this sensor.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated Do not use for new sensors, a suitable unique ID is automatically generated (2023.4).
 | 
			
		||||
   */
 | 
			
		||||
  virtual std::string unique_id();
 | 
			
		||||
 | 
			
		||||
  bool has_state();
 | 
			
		||||
 
 | 
			
		||||
@@ -168,7 +168,7 @@ uint8_t TM1637Display::get_keys() {
 | 
			
		||||
    //    Bit | 7  6  5  4  3  2  1  0
 | 
			
		||||
    //  ------+------------------------
 | 
			
		||||
    //     To | 0  0  0  0  K2 S2 S1 S0
 | 
			
		||||
    key_code = (uint8_t)((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08));
 | 
			
		||||
    key_code = (uint8_t) ((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08));
 | 
			
		||||
  }
 | 
			
		||||
  return key_code;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -140,7 +140,7 @@ void TM1638Component::set_intensity(uint8_t brightness_level) {
 | 
			
		||||
  this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
 | 
			
		||||
 | 
			
		||||
  if (brightness_level > 0) {
 | 
			
		||||
    this->send_command_((uint8_t)(TM1638_REGISTER_DISPLAYON | intensity_));
 | 
			
		||||
    this->send_command_((uint8_t) (TM1638_REGISTER_DISPLAYON | intensity_));
 | 
			
		||||
  } else {
 | 
			
		||||
    this->send_command_(TM1638_REGISTER_DISPLAYOFF);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,10 @@
 | 
			
		||||
#include "esphome/core/util.h"
 | 
			
		||||
#include "esphome/core/gpio.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_WIFI
 | 
			
		||||
#include "esphome/components/wifi/wifi_component.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef USE_CAPTIVE_PORTAL
 | 
			
		||||
#include "esphome/components/captive_portal/captive_portal.h"
 | 
			
		||||
#endif
 | 
			
		||||
@@ -234,6 +238,10 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff
 | 
			
		||||
    case TuyaCommandType::WIFI_TEST:
 | 
			
		||||
      this->send_command_(TuyaCommand{.cmd = TuyaCommandType::WIFI_TEST, .payload = std::vector<uint8_t>{0x00, 0x00}});
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::WIFI_RSSI:
 | 
			
		||||
      this->send_command_(
 | 
			
		||||
          TuyaCommand{.cmd = TuyaCommandType::WIFI_RSSI, .payload = std::vector<uint8_t>{get_wifi_rssi_()}});
 | 
			
		||||
      break;
 | 
			
		||||
    case TuyaCommandType::LOCAL_TIME_QUERY:
 | 
			
		||||
#ifdef USE_TIME
 | 
			
		||||
      if (this->time_id_.has_value()) {
 | 
			
		||||
@@ -373,8 +381,8 @@ void Tuya::handle_datapoints_(const uint8_t *buffer, size_t len) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tuya::send_raw_command_(TuyaCommand command) {
 | 
			
		||||
  uint8_t len_hi = (uint8_t)(command.payload.size() >> 8);
 | 
			
		||||
  uint8_t len_lo = (uint8_t)(command.payload.size() & 0xFF);
 | 
			
		||||
  uint8_t len_hi = (uint8_t) (command.payload.size() >> 8);
 | 
			
		||||
  uint8_t len_lo = (uint8_t) (command.payload.size() & 0xFF);
 | 
			
		||||
  uint8_t version = 0;
 | 
			
		||||
 | 
			
		||||
  this->last_command_timestamp_ = millis();
 | 
			
		||||
@@ -475,6 +483,15 @@ uint8_t Tuya::get_wifi_status_code_() {
 | 
			
		||||
  return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t Tuya::get_wifi_rssi_() {
 | 
			
		||||
#ifdef USE_WIFI
 | 
			
		||||
  if (wifi::global_wifi_component != nullptr)
 | 
			
		||||
    return wifi::global_wifi_component->wifi_rssi();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tuya::send_wifi_status_() {
 | 
			
		||||
  uint8_t status = this->get_wifi_status_code_();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,6 +55,7 @@ enum class TuyaCommandType : uint8_t {
 | 
			
		||||
  DATAPOINT_QUERY = 0x08,
 | 
			
		||||
  WIFI_TEST = 0x0E,
 | 
			
		||||
  LOCAL_TIME_QUERY = 0x1C,
 | 
			
		||||
  WIFI_RSSI = 0x24,
 | 
			
		||||
  VACUUM_MAP_UPLOAD = 0x28,
 | 
			
		||||
  GET_NETWORK_STATUS = 0x2B,
 | 
			
		||||
};
 | 
			
		||||
@@ -123,6 +124,7 @@ class Tuya : public Component, public uart::UARTDevice {
 | 
			
		||||
  void set_status_pin_();
 | 
			
		||||
  void send_wifi_status_();
 | 
			
		||||
  uint8_t get_wifi_status_code_();
 | 
			
		||||
  uint8_t get_wifi_rssi_();
 | 
			
		||||
 | 
			
		||||
#ifdef USE_TIME
 | 
			
		||||
  void send_local_time_();
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user