mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			25 Commits
		
	
	
		
			2023.9.0b3
			...
			2023.9.3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					0d800958aa | ||
| 
						 | 
					471533d041 | ||
| 
						 | 
					7dfc4c74da | ||
| 
						 | 
					f709350b04 | ||
| 
						 | 
					85c5928baa | ||
| 
						 | 
					f5dfbaff4b | ||
| 
						 | 
					689c2f11a3 | ||
| 
						 | 
					f73fd97525 | ||
| 
						 | 
					40523e6823 | ||
| 
						 | 
					5e1472185c | ||
| 
						 | 
					af005a6554 | ||
| 
						 | 
					efd31be21c | ||
| 
						 | 
					e9bda2810f | ||
| 
						 | 
					ec4777b8d0 | ||
| 
						 | 
					9b75121337 | ||
| 
						 | 
					d262548d2e | ||
| 
						 | 
					b5b654e054 | ||
| 
						 | 
					dae8ab563c | ||
| 
						 | 
					5751e9ec59 | ||
| 
						 | 
					cc1b7a7a56 | ||
| 
						 | 
					29249cdc1b | ||
| 
						 | 
					e5bae8187f | ||
| 
						 | 
					69adebfefa | ||
| 
						 | 
					7dabbb65d0 | ||
| 
						 | 
					b30bab8c1b | 
@@ -131,7 +131,7 @@ esphome/components/i2s_audio/* @jesserockz
 | 
			
		||||
esphome/components/i2s_audio/media_player/* @jesserockz
 | 
			
		||||
esphome/components/i2s_audio/microphone/* @jesserockz
 | 
			
		||||
esphome/components/i2s_audio/speaker/* @jesserockz
 | 
			
		||||
esphome/components/ili9xxx/* @nielsnl68
 | 
			
		||||
esphome/components/ili9xxx/* @clydebarrow @nielsnl68
 | 
			
		||||
esphome/components/improv_base/* @esphome/core
 | 
			
		||||
esphome/components/improv_serial/* @esphome/core
 | 
			
		||||
esphome/components/ina260/* @mreditor97
 | 
			
		||||
@@ -270,7 +270,7 @@ esphome/components/sn74hc165/* @jesserockz
 | 
			
		||||
esphome/components/socket/* @esphome/core
 | 
			
		||||
esphome/components/sonoff_d1/* @anatoly-savchenkov
 | 
			
		||||
esphome/components/speaker/* @jesserockz
 | 
			
		||||
esphome/components/spi/* @esphome/core
 | 
			
		||||
esphome/components/spi/* @clydebarrow @esphome/core
 | 
			
		||||
esphome/components/spi_device/* @clydebarrow
 | 
			
		||||
esphome/components/spi_led_strip/* @clydebarrow
 | 
			
		||||
esphome/components/sprinkler/* @kbx81
 | 
			
		||||
 
 | 
			
		||||
@@ -41,8 +41,15 @@ fi
 | 
			
		||||
 | 
			
		||||
mkdir -p "${pio_cache_base}"
 | 
			
		||||
 | 
			
		||||
mkdir -p /config/esphome
 | 
			
		||||
 | 
			
		||||
if bashio::fs.directory_exists '/config/esphome/.esphome'; then
 | 
			
		||||
    bashio::log.info "Removing old .esphome directory..."
 | 
			
		||||
    bashio::log.info "Migrating old .esphome directory..."
 | 
			
		||||
    if bashio::fs.file_exists '/config/esphome/.esphome/esphome.json'; then
 | 
			
		||||
        mv /config/esphome/.esphome/esphome.json /data/esphome.json
 | 
			
		||||
    fi
 | 
			
		||||
    mkdir -p "/data/storage"
 | 
			
		||||
    mv /config/esphome/.esphome/*.json /data/storage/ || true
 | 
			
		||||
    rm -rf /config/esphome/.esphome
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,10 +39,14 @@ void BP5758D::loop() {
 | 
			
		||||
  uint8_t data[17];
 | 
			
		||||
  if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
      this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
			
		||||
    // Off / Sleep
 | 
			
		||||
    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY;
 | 
			
		||||
    for (int i = 1; i < 16; i++)
 | 
			
		||||
      data[i] = 0;
 | 
			
		||||
 | 
			
		||||
    // First turn all channels off
 | 
			
		||||
    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH;
 | 
			
		||||
    this->write_buffer_(data, 17);
 | 
			
		||||
    // Then sleep
 | 
			
		||||
    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY;
 | 
			
		||||
    this->write_buffer_(data, 17);
 | 
			
		||||
  } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
			
		||||
             (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -235,6 +235,7 @@ ESP32_BOARD_PINS = {
 | 
			
		||||
        "SDA": 5,
 | 
			
		||||
        "SS": 15,
 | 
			
		||||
    },
 | 
			
		||||
    "denky_d4": {"RX": 8, "LED": 14},
 | 
			
		||||
    "esp-wrover-kit": {},
 | 
			
		||||
    "esp32-devkitlipo": {},
 | 
			
		||||
    "esp32-evb": {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ def AUTO_LOAD():
 | 
			
		||||
    return []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@nielsnl68"]
 | 
			
		||||
CODEOWNERS = ["@nielsnl68", "@clydebarrow"]
 | 
			
		||||
 | 
			
		||||
ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx")
 | 
			
		||||
ili9XXXSPI = ili9XXX_ns.class_(
 | 
			
		||||
@@ -42,6 +42,7 @@ MODELS = {
 | 
			
		||||
    "ILI9341": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI),
 | 
			
		||||
    "ILI9342": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI),
 | 
			
		||||
    "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI),
 | 
			
		||||
    "ILI9481-18": ili9XXX_ns.class_("ILI9XXXILI948118", ili9XXXSPI),
 | 
			
		||||
    "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI),
 | 
			
		||||
    "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI),
 | 
			
		||||
    "ILI9488_A": ili9XXX_ns.class_("ILI9XXXILI9488A", ili9XXXSPI),
 | 
			
		||||
@@ -140,8 +141,6 @@ async def to_code(config):
 | 
			
		||||
        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
 | 
			
		||||
@@ -178,6 +177,4 @@ async def to_code(config):
 | 
			
		||||
    if rhs is not None:
 | 
			
		||||
        prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
 | 
			
		||||
        cg.add(var.set_palette(prog_arr))
 | 
			
		||||
 | 
			
		||||
    spi_data_rate = str(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]])
 | 
			
		||||
    cg.add_define("ILI9XXXDisplay_DATA_RATE", cg.RawExpression(spi_data_rate))
 | 
			
		||||
    cg.add(var.set_data_rate(config[CONF_DATA_RATE]))
 | 
			
		||||
 
 | 
			
		||||
@@ -59,6 +59,7 @@ void ILI9XXXDisplay::dump_config() {
 | 
			
		||||
  if (this->is_18bitdisplay_) {
 | 
			
		||||
    ESP_LOGCONFIG(TAG, "  18-Bit Mode: YES");
 | 
			
		||||
  }
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Data rate: %dMHz", (unsigned) (this->data_rate_ / 1000000));
 | 
			
		||||
 | 
			
		||||
  LOG_PIN("  Reset Pin: ", this->reset_pin_);
 | 
			
		||||
  LOG_PIN("  DC Pin: ", this->dc_pin_);
 | 
			
		||||
@@ -387,6 +388,17 @@ void ILI9XXXILI9481::initialize() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ILI9XXXILI948118::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9481_18);
 | 
			
		||||
  if (this->width_ == 0) {
 | 
			
		||||
    this->width_ = 320;
 | 
			
		||||
  }
 | 
			
		||||
  if (this->height_ == 0) {
 | 
			
		||||
    this->height_ = 480;
 | 
			
		||||
  }
 | 
			
		||||
  this->is_18bitdisplay_ = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//   35_TFT display
 | 
			
		||||
void ILI9XXXILI9486::initialize() {
 | 
			
		||||
  this->init_lcd_(INITCMD_ILI9486);
 | 
			
		||||
 
 | 
			
		||||
@@ -120,6 +120,12 @@ class ILI9XXXILI9481 : public ILI9XXXDisplay {
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9481 in 18 bit mode --------------
 | 
			
		||||
class ILI9XXXILI948118 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//-----------   ILI9XXX_35_TFT rotated display --------------
 | 
			
		||||
class ILI9XXXILI9486 : public ILI9XXXDisplay {
 | 
			
		||||
 protected:
 | 
			
		||||
 
 | 
			
		||||
@@ -94,12 +94,36 @@ static const uint8_t PROGMEM INITCMD_ILI9481[] = {
 | 
			
		||||
  ILI9XXX_IFCTR  , 1, 0x83,
 | 
			
		||||
  ILI9XXX_GMCTR  ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00,
 | 
			
		||||
  ILI9XXX_IFMODE , 1, 0x00,  // CommandAccessProtect
 | 
			
		||||
  ILI9XXX_PTLAR , 4, 0, 0, 1, 0xDF,
 | 
			
		||||
  0xE4        , 1, 0xA0,
 | 
			
		||||
  ILI9XXX_MADCTL  , 1, MADCTL_MV | MADCTL_BGR,       // Memory Access Control
 | 
			
		||||
  ILI9XXX_CSCON , 1, 0x01,
 | 
			
		||||
  ILI9XXX_PIXFMT, 1, 0x55,  // 16 bit mode
 | 
			
		||||
  ILI9XXX_INVON, 0,
 | 
			
		||||
  ILI9XXX_DISPON, 0x80,     // Set display on
 | 
			
		||||
  0x00 // end
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ILI9481_18[] = {
 | 
			
		||||
    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
 | 
			
		||||
    ILI9XXX_PTLAR , 4, 0, 0, 1, 0xDF,
 | 
			
		||||
    0xE4        , 1, 0xA0,
 | 
			
		||||
    ILI9XXX_MADCTL  , 1, MADCTL_MX| MADCTL_BGR,       // Memory Access Control
 | 
			
		||||
    ILI9XXX_CSCON , 1, 0x01,
 | 
			
		||||
    ILI9XXX_PIXFMT, 1, 0x66,  // 18 bit mode
 | 
			
		||||
    ILI9XXX_INVON, 0,
 | 
			
		||||
    ILI9XXX_DISPON, 0x80,     // Set display on
 | 
			
		||||
    0x00 // end
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const uint8_t PROGMEM INITCMD_ILI9486[] = {
 | 
			
		||||
  ILI9XXX_SLPOUT, 0x80,
 | 
			
		||||
  ILI9XXX_PIXFMT, 1, 0x55,
 | 
			
		||||
 
 | 
			
		||||
@@ -170,7 +170,7 @@ def _notify_old_style(config):
 | 
			
		||||
ARDUINO_VERSIONS = {
 | 
			
		||||
    "dev": (cv.Version(0, 0, 0), "https://github.com/libretiny-eu/libretiny.git"),
 | 
			
		||||
    "latest": (cv.Version(0, 0, 0), None),
 | 
			
		||||
    "recommended": (cv.Version(1, 4, 0), None),
 | 
			
		||||
    "recommended": (cv.Version(1, 4, 1), None),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -217,10 +217,7 @@ uint8_t MAX7219Component::printf(const char *format, ...) {
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
void MAX7219Component::set_writer(max7219_writer_t &&writer) { this->writer_ = writer; }
 | 
			
		||||
void MAX7219Component::set_intensity(uint8_t intensity) {
 | 
			
		||||
  this->intensity_ = intensity;
 | 
			
		||||
  this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_);
 | 
			
		||||
}
 | 
			
		||||
void MAX7219Component::set_intensity(uint8_t intensity) { this->intensity_ = intensity; }
 | 
			
		||||
void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; }
 | 
			
		||||
 | 
			
		||||
uint8_t MAX7219Component::strftime(uint8_t pos, const char *format, ESPTime time) {
 | 
			
		||||
 
 | 
			
		||||
@@ -250,7 +250,7 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
        }
 | 
			
		||||
    ),
 | 
			
		||||
    validate_config,
 | 
			
		||||
    cv.only_on(["esp32", "esp8266"]),
 | 
			
		||||
    cv.only_on(["esp32", "esp8266", "bk72xx"]),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -271,10 +271,10 @@ def exp_mqtt_message(config):
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    # Add required libraries for ESP8266
 | 
			
		||||
    if CORE.is_esp8266:
 | 
			
		||||
    # Add required libraries for ESP8266 and LibreTiny
 | 
			
		||||
    if CORE.is_esp8266 or CORE.is_libretiny:
 | 
			
		||||
        # https://github.com/heman/async-mqtt-client/blob/master/library.json
 | 
			
		||||
        cg.add_library("heman/AsyncMqttClient-esphome", "1.0.0")
 | 
			
		||||
        cg.add_library("heman/AsyncMqttClient-esphome", "2.0.0")
 | 
			
		||||
 | 
			
		||||
    cg.add_define("USE_MQTT")
 | 
			
		||||
    cg.add_global(mqtt_ns.using)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										74
									
								
								esphome/components/mqtt/mqtt_backend_libretiny.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								esphome/components/mqtt/mqtt_backend_libretiny.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#ifdef USE_LIBRETINY
 | 
			
		||||
 | 
			
		||||
#include "mqtt_backend.h"
 | 
			
		||||
#include <AsyncMqttClient.h>
 | 
			
		||||
 | 
			
		||||
namespace esphome {
 | 
			
		||||
namespace mqtt {
 | 
			
		||||
 | 
			
		||||
class MQTTBackendLibreTiny final : public MQTTBackend {
 | 
			
		||||
 public:
 | 
			
		||||
  void set_keep_alive(uint16_t keep_alive) final { mqtt_client_.setKeepAlive(keep_alive); }
 | 
			
		||||
  void set_client_id(const char *client_id) final { mqtt_client_.setClientId(client_id); }
 | 
			
		||||
  void set_clean_session(bool clean_session) final { mqtt_client_.setCleanSession(clean_session); }
 | 
			
		||||
  void set_credentials(const char *username, const char *password) final {
 | 
			
		||||
    mqtt_client_.setCredentials(username, password);
 | 
			
		||||
  }
 | 
			
		||||
  void set_will(const char *topic, uint8_t qos, bool retain, const char *payload) final {
 | 
			
		||||
    mqtt_client_.setWill(topic, qos, retain, payload);
 | 
			
		||||
  }
 | 
			
		||||
  void set_server(network::IPAddress ip, uint16_t port) final {
 | 
			
		||||
    mqtt_client_.setServer(IPAddress(static_cast<uint32_t>(ip)), port);
 | 
			
		||||
  }
 | 
			
		||||
  void set_server(const char *host, uint16_t port) final { mqtt_client_.setServer(host, port); }
 | 
			
		||||
#if ASYNC_TCP_SSL_ENABLED
 | 
			
		||||
  void set_secure(bool secure) { mqtt_client.setSecure(secure); }
 | 
			
		||||
  void add_server_fingerprint(const uint8_t *fingerprint) { mqtt_client.addServerFingerprint(fingerprint); }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  void set_on_connect(std::function<on_connect_callback_t> &&callback) final {
 | 
			
		||||
    this->mqtt_client_.onConnect(std::move(callback));
 | 
			
		||||
  }
 | 
			
		||||
  void set_on_disconnect(std::function<on_disconnect_callback_t> &&callback) final {
 | 
			
		||||
    auto async_callback = [callback](AsyncMqttClientDisconnectReason reason) {
 | 
			
		||||
      // int based enum so casting isn't a problem
 | 
			
		||||
      callback(static_cast<MQTTClientDisconnectReason>(reason));
 | 
			
		||||
    };
 | 
			
		||||
    this->mqtt_client_.onDisconnect(std::move(async_callback));
 | 
			
		||||
  }
 | 
			
		||||
  void set_on_subscribe(std::function<on_subscribe_callback_t> &&callback) final {
 | 
			
		||||
    this->mqtt_client_.onSubscribe(std::move(callback));
 | 
			
		||||
  }
 | 
			
		||||
  void set_on_unsubscribe(std::function<on_unsubscribe_callback_t> &&callback) final {
 | 
			
		||||
    this->mqtt_client_.onUnsubscribe(std::move(callback));
 | 
			
		||||
  }
 | 
			
		||||
  void set_on_message(std::function<on_message_callback_t> &&callback) final {
 | 
			
		||||
    auto async_callback = [callback](const char *topic, const char *payload,
 | 
			
		||||
                                     AsyncMqttClientMessageProperties async_properties, size_t len, size_t index,
 | 
			
		||||
                                     size_t total) { callback(topic, payload, len, index, total); };
 | 
			
		||||
    mqtt_client_.onMessage(std::move(async_callback));
 | 
			
		||||
  }
 | 
			
		||||
  void set_on_publish(std::function<on_publish_user_callback_t> &&callback) final {
 | 
			
		||||
    this->mqtt_client_.onPublish(std::move(callback));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool connected() const final { return mqtt_client_.connected(); }
 | 
			
		||||
  void connect() final { mqtt_client_.connect(); }
 | 
			
		||||
  void disconnect() final { mqtt_client_.disconnect(true); }
 | 
			
		||||
  bool subscribe(const char *topic, uint8_t qos) final { return mqtt_client_.subscribe(topic, qos) != 0; }
 | 
			
		||||
  bool unsubscribe(const char *topic) final { return mqtt_client_.unsubscribe(topic) != 0; }
 | 
			
		||||
  bool publish(const char *topic, const char *payload, size_t length, uint8_t qos, bool retain) final {
 | 
			
		||||
    return mqtt_client_.publish(topic, qos, retain, payload, length, false, 0) != 0;
 | 
			
		||||
  }
 | 
			
		||||
  using MQTTBackend::publish;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  AsyncMqttClient mqtt_client_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace mqtt
 | 
			
		||||
}  // namespace esphome
 | 
			
		||||
 | 
			
		||||
#endif  // defined(USE_LIBRETINY)
 | 
			
		||||
@@ -106,6 +106,9 @@ void MQTTClientComponent::send_device_info_() {
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
        root["platform"] = "ESP32";
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_LIBRETINY
 | 
			
		||||
        root["platform"] = lt_cpu_get_model_name();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        root["board"] = ESPHOME_BOARD;
 | 
			
		||||
#if defined(USE_WIFI)
 | 
			
		||||
@@ -156,7 +159,7 @@ void MQTTClientComponent::start_dnslookup_() {
 | 
			
		||||
  this->dns_resolve_error_ = false;
 | 
			
		||||
  this->dns_resolved_ = false;
 | 
			
		||||
  ip_addr_t addr;
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
 | 
			
		||||
  err_t err = dns_gethostbyname_addrtype(this->credentials_.address.c_str(), &addr,
 | 
			
		||||
                                         MQTTClientComponent::dns_found_callback, this, LWIP_DNS_ADDRTYPE_IPV4);
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,8 @@
 | 
			
		||||
#include "mqtt_backend_esp32.h"
 | 
			
		||||
#elif defined(USE_ESP8266)
 | 
			
		||||
#include "mqtt_backend_esp8266.h"
 | 
			
		||||
#elif defined(USE_LIBRETINY)
 | 
			
		||||
#include "mqtt_backend_libretiny.h"
 | 
			
		||||
#endif
 | 
			
		||||
#include "lwip/ip_addr.h"
 | 
			
		||||
 | 
			
		||||
@@ -300,6 +302,8 @@ class MQTTClientComponent : public Component {
 | 
			
		||||
  MQTTBackendESP32 mqtt_backend_;
 | 
			
		||||
#elif defined(USE_ESP8266)
 | 
			
		||||
  MQTTBackendESP8266 mqtt_backend_;
 | 
			
		||||
#elif defined(USE_LIBRETINY)
 | 
			
		||||
  MQTTBackendLibreTiny mqtt_backend_;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  MQTTClientState state_{MQTT_CLIENT_DISCONNECTED};
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ from esphome.const import (
 | 
			
		||||
)
 | 
			
		||||
from esphome.core import coroutine_with_priority, CORE
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@esphome/core"]
 | 
			
		||||
CODEOWNERS = ["@esphome/core", "@clydebarrow"]
 | 
			
		||||
spi_ns = cg.esphome_ns.namespace("spi")
 | 
			
		||||
SPIComponent = spi_ns.class_("SPIComponent", cg.Component)
 | 
			
		||||
SPIDevice = spi_ns.class_("SPIDevice")
 | 
			
		||||
@@ -54,6 +54,21 @@ CONF_FORCE_SW = "force_sw"
 | 
			
		||||
CONF_INTERFACE = "interface"
 | 
			
		||||
CONF_INTERFACE_INDEX = "interface_index"
 | 
			
		||||
 | 
			
		||||
# RP2040 SPI pin assignments are complicated. Refer to https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
 | 
			
		||||
 | 
			
		||||
RP_SPI_PINSETS = [
 | 
			
		||||
    {
 | 
			
		||||
        CONF_MISO_PIN: [0, 4, 16, 20, -1],
 | 
			
		||||
        CONF_CLK_PIN: [2, 6, 18, 22],
 | 
			
		||||
        CONF_MOSI_PIN: [3, 7, 19, 23, -1],
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        CONF_MISO_PIN: [8, 12, 24, 28, -1],
 | 
			
		||||
        CONF_CLK_PIN: [10, 14, 26],
 | 
			
		||||
        CONF_MOSI_PIN: [11, 23, 27, -1],
 | 
			
		||||
    },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_target_platform():
 | 
			
		||||
    return (
 | 
			
		||||
@@ -85,7 +100,7 @@ def get_hw_interface_list():
 | 
			
		||||
            return [["spi", "spi2"]]
 | 
			
		||||
        return [["spi", "spi2"], ["spi3"]]
 | 
			
		||||
    if target_platform == "rp2040":
 | 
			
		||||
        return [["spi"]]
 | 
			
		||||
        return [["spi"], ["spi1"]]
 | 
			
		||||
    return []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -99,8 +114,10 @@ def get_spi_index(name):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Check that pins are suitable for HW spi
 | 
			
		||||
# \param spi the config data for the spi instance
 | 
			
		||||
# \param index the selected hw interface number, -1 if not yet known
 | 
			
		||||
# TODO verify that the pins are internal
 | 
			
		||||
def validate_hw_pins(spi):
 | 
			
		||||
def validate_hw_pins(spi, index=-1):
 | 
			
		||||
    clk_pin = spi[CONF_CLK_PIN]
 | 
			
		||||
    if clk_pin[CONF_INVERTED]:
 | 
			
		||||
        return False
 | 
			
		||||
@@ -129,9 +146,30 @@ def validate_hw_pins(spi):
 | 
			
		||||
    if target_platform == "esp32":
 | 
			
		||||
        return clk_pin_no >= 0
 | 
			
		||||
 | 
			
		||||
    if target_platform == "rp2040":
 | 
			
		||||
        pin_set = (
 | 
			
		||||
            list(filter(lambda s: clk_pin_no in s[CONF_CLK_PIN], RP_SPI_PINSETS))[0]
 | 
			
		||||
            if index == -1
 | 
			
		||||
            else RP_SPI_PINSETS[index]
 | 
			
		||||
        )
 | 
			
		||||
        if pin_set is None:
 | 
			
		||||
            return False
 | 
			
		||||
        if sdo_pin_no not in pin_set[CONF_MOSI_PIN]:
 | 
			
		||||
            return False
 | 
			
		||||
        if sdi_pin_no not in pin_set[CONF_MISO_PIN]:
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_hw_spi(config, available):
 | 
			
		||||
    """Get an available hardware spi interface suitable for this config"""
 | 
			
		||||
    matching = list(filter(lambda idx: validate_hw_pins(config, idx), available))
 | 
			
		||||
    if len(matching) != 0:
 | 
			
		||||
        return matching[0]
 | 
			
		||||
    return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def validate_spi_config(config):
 | 
			
		||||
    available = list(range(len(get_hw_interface_list())))
 | 
			
		||||
    for spi in config:
 | 
			
		||||
@@ -147,9 +185,10 @@ def validate_spi_config(config):
 | 
			
		||||
            if not validate_hw_pins(spi):
 | 
			
		||||
                spi[CONF_INTERFACE] = "software"
 | 
			
		||||
        elif interface == "hardware":
 | 
			
		||||
            if len(available) == 0:
 | 
			
		||||
                raise cv.Invalid("No hardware interface available")
 | 
			
		||||
            index = spi[CONF_INTERFACE_INDEX] = available[0]
 | 
			
		||||
            index = get_hw_spi(spi, available)
 | 
			
		||||
            if index is None:
 | 
			
		||||
                raise cv.Invalid("No suitable hardware interface available")
 | 
			
		||||
            spi[CONF_INTERFACE_INDEX] = index
 | 
			
		||||
            available.remove(index)
 | 
			
		||||
        else:
 | 
			
		||||
            # Must be a specific name
 | 
			
		||||
@@ -164,11 +203,14 @@ def validate_spi_config(config):
 | 
			
		||||
    # Any specific names and any 'hardware' requests will have already been filled,
 | 
			
		||||
    # so just need to assign remaining hardware to 'any' requests.
 | 
			
		||||
    for spi in config:
 | 
			
		||||
        if spi[CONF_INTERFACE] == "any" and len(available) != 0:
 | 
			
		||||
            index = available[0]
 | 
			
		||||
            spi[CONF_INTERFACE_INDEX] = index
 | 
			
		||||
            available.remove(index)
 | 
			
		||||
        if CONF_INTERFACE_INDEX in spi and not validate_hw_pins(spi):
 | 
			
		||||
        if spi[CONF_INTERFACE] == "any":
 | 
			
		||||
            index = get_hw_spi(spi, available)
 | 
			
		||||
            if index is not None:
 | 
			
		||||
                spi[CONF_INTERFACE_INDEX] = index
 | 
			
		||||
                available.remove(index)
 | 
			
		||||
        if CONF_INTERFACE_INDEX in spi and not validate_hw_pins(
 | 
			
		||||
            spi, spi[CONF_INTERFACE_INDEX]
 | 
			
		||||
        ):
 | 
			
		||||
            raise cv.Invalid("Invalid pin selections for hardware SPI interface")
 | 
			
		||||
 | 
			
		||||
    return config
 | 
			
		||||
@@ -181,13 +223,13 @@ def get_spi_interface(index):
 | 
			
		||||
    # Arduino code follows
 | 
			
		||||
    platform = get_target_platform()
 | 
			
		||||
    if platform == "rp2040":
 | 
			
		||||
        return "&spi1"
 | 
			
		||||
        return ["&SPI", "&SPI1"][index]
 | 
			
		||||
    if index == 0:
 | 
			
		||||
        return "&SPI"
 | 
			
		||||
    # Following code can't apply to C2, H2 or 8266 since they have only one SPI
 | 
			
		||||
    if get_target_variant() in (VARIANT_ESP32S3, VARIANT_ESP32S2):
 | 
			
		||||
        return "new SPIClass(FSPI)"
 | 
			
		||||
    return "return new SPIClass(HSPI)"
 | 
			
		||||
    return "new SPIClass(HSPI)"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SPI_SCHEMA = cv.All(
 | 
			
		||||
 
 | 
			
		||||
@@ -248,6 +248,7 @@ class SPIDelegateDummy : public SPIDelegate {
 | 
			
		||||
  SPIDelegateDummy() = default;
 | 
			
		||||
 | 
			
		||||
  uint8_t transfer(uint8_t data) override { return 0; }
 | 
			
		||||
  void end_transaction() override{};
 | 
			
		||||
 | 
			
		||||
  void begin_transaction() override;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ from esphome.const import (
 | 
			
		||||
    CONF_NUMBER_DATAPOINT,
 | 
			
		||||
    CONF_MAX_VALUE,
 | 
			
		||||
    CONF_MIN_VALUE,
 | 
			
		||||
    CONF_MULTIPLY,
 | 
			
		||||
    CONF_STEP,
 | 
			
		||||
)
 | 
			
		||||
from .. import tuya_ns, CONF_TUYA_ID, Tuya
 | 
			
		||||
@@ -31,6 +32,7 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
            cv.Required(CONF_MAX_VALUE): cv.float_,
 | 
			
		||||
            cv.Required(CONF_MIN_VALUE): cv.float_,
 | 
			
		||||
            cv.Required(CONF_STEP): cv.positive_float,
 | 
			
		||||
            cv.Optional(CONF_MULTIPLY, default=1.0): cv.float_,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.COMPONENT_SCHEMA),
 | 
			
		||||
@@ -49,7 +51,8 @@ async def to_code(config):
 | 
			
		||||
        step=config[CONF_STEP],
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    paren = await cg.get_variable(config[CONF_TUYA_ID])
 | 
			
		||||
    cg.add(var.set_tuya_parent(paren))
 | 
			
		||||
    cg.add(var.set_write_multiply(config[CONF_MULTIPLY]))
 | 
			
		||||
    parent = await cg.get_variable(config[CONF_TUYA_ID])
 | 
			
		||||
    cg.add(var.set_tuya_parent(parent))
 | 
			
		||||
 | 
			
		||||
    cg.add(var.set_number_id(config[CONF_NUMBER_DATAPOINT]))
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ void TuyaNumber::setup() {
 | 
			
		||||
  this->parent_->register_listener(this->number_id_, [this](const TuyaDatapoint &datapoint) {
 | 
			
		||||
    if (datapoint.type == TuyaDatapointType::INTEGER) {
 | 
			
		||||
      ESP_LOGV(TAG, "MCU reported number %u is: %d", datapoint.id, datapoint.value_int);
 | 
			
		||||
      this->publish_state(datapoint.value_int);
 | 
			
		||||
      this->publish_state(datapoint.value_int / multiply_by_);
 | 
			
		||||
    } else if (datapoint.type == TuyaDatapointType::ENUM) {
 | 
			
		||||
      ESP_LOGV(TAG, "MCU reported number %u is: %u", datapoint.id, datapoint.value_enum);
 | 
			
		||||
      this->publish_state(datapoint.value_enum);
 | 
			
		||||
@@ -22,7 +22,8 @@ void TuyaNumber::setup() {
 | 
			
		||||
void TuyaNumber::control(float value) {
 | 
			
		||||
  ESP_LOGV(TAG, "Setting number %u: %f", this->number_id_, value);
 | 
			
		||||
  if (this->type_ == TuyaDatapointType::INTEGER) {
 | 
			
		||||
    this->parent_->set_integer_datapoint_value(this->number_id_, value);
 | 
			
		||||
    int integer_value = lround(value * multiply_by_);
 | 
			
		||||
    this->parent_->set_integer_datapoint_value(this->number_id_, integer_value);
 | 
			
		||||
  } else if (this->type_ == TuyaDatapointType::ENUM) {
 | 
			
		||||
    this->parent_->set_enum_datapoint_value(this->number_id_, value);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ class TuyaNumber : public number::Number, public Component {
 | 
			
		||||
  void setup() override;
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  void set_number_id(uint8_t number_id) { this->number_id_ = number_id; }
 | 
			
		||||
  void set_write_multiply(float factor) { multiply_by_ = factor; }
 | 
			
		||||
 | 
			
		||||
  void set_tuya_parent(Tuya *parent) { this->parent_ = parent; }
 | 
			
		||||
 | 
			
		||||
@@ -20,6 +21,7 @@ class TuyaNumber : public number::Number, public Component {
 | 
			
		||||
 | 
			
		||||
  Tuya *parent_;
 | 
			
		||||
  uint8_t number_id_{0};
 | 
			
		||||
  float multiply_by_{1.0};
 | 
			
		||||
  TuyaDatapointType type_{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ const uint8_t WHIRLPOOL_SWING_MASK = 128;
 | 
			
		||||
const uint8_t WHIRLPOOL_POWER = 0x04;
 | 
			
		||||
 | 
			
		||||
void WhirlpoolClimate::transmit_state() {
 | 
			
		||||
  this->last_transmit_time_ = millis();  // setting the time of the last transmission.
 | 
			
		||||
  uint8_t remote_state[WHIRLPOOL_STATE_LENGTH] = {0};
 | 
			
		||||
  remote_state[0] = 0x83;
 | 
			
		||||
  remote_state[1] = 0x06;
 | 
			
		||||
@@ -149,6 +150,12 @@ void WhirlpoolClimate::transmit_state() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WhirlpoolClimate::on_receive(remote_base::RemoteReceiveData data) {
 | 
			
		||||
  // Check if the esp isn't currently transmitting.
 | 
			
		||||
  if (millis() - this->last_transmit_time_ < 500) {
 | 
			
		||||
    ESP_LOGV(TAG, "Blocked receive because of current trasmittion");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Validate header
 | 
			
		||||
  if (!data.expect_item(WHIRLPOOL_HEADER_MARK, WHIRLPOOL_HEADER_SPACE)) {
 | 
			
		||||
    ESP_LOGV(TAG, "Header fail");
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,8 @@ class WhirlpoolClimate : public climate_ir::ClimateIR {
 | 
			
		||||
  void transmit_state() override;
 | 
			
		||||
  /// Handle received IR Buffer
 | 
			
		||||
  bool on_receive(remote_base::RemoteReceiveData data) override;
 | 
			
		||||
  /// Set the time of the last transmission.
 | 
			
		||||
  int32_t last_transmit_time_{};
 | 
			
		||||
 | 
			
		||||
  bool send_swing_cmd_{false};
 | 
			
		||||
  Model model_;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ from esphome.const import (
 | 
			
		||||
    CONF_REBOOT_TIMEOUT,
 | 
			
		||||
)
 | 
			
		||||
from esphome.components import time
 | 
			
		||||
from esphome.core import TimePeriod
 | 
			
		||||
 | 
			
		||||
CONF_NETMASK = "netmask"
 | 
			
		||||
CONF_PRIVATE_KEY = "private_key"
 | 
			
		||||
@@ -59,9 +60,9 @@ CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
        cv.Optional(CONF_PEER_ALLOWED_IPS, default=["0.0.0.0/0"]): cv.ensure_list(
 | 
			
		||||
            _cidr_network
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default=0): cv.Any(
 | 
			
		||||
        cv.Optional(CONF_PEER_PERSISTENT_KEEPALIVE, default="0s"): cv.All(
 | 
			
		||||
            cv.positive_time_period_seconds,
 | 
			
		||||
            cv.uint16_t,
 | 
			
		||||
            cv.Range(max=TimePeriod(seconds=65535)),
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(
 | 
			
		||||
            CONF_REBOOT_TIMEOUT, default="15min"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2023.9.0b3"
 | 
			
		||||
__version__ = "2023.9.3"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
VALID_SUBSTITUTIONS_CHARACTERS = (
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ esptool==4.6.2
 | 
			
		||||
click==8.1.7
 | 
			
		||||
esphome-dashboard==20230904.0
 | 
			
		||||
aioesphomeapi==15.0.0
 | 
			
		||||
zeroconf==0.112.0
 | 
			
		||||
zeroconf==0.115.1
 | 
			
		||||
 | 
			
		||||
# esp-idf requires this, but doesn't bundle it by default
 | 
			
		||||
# https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24
 | 
			
		||||
 
 | 
			
		||||
@@ -2972,6 +2972,7 @@ display:
 | 
			
		||||
    model: TFT 2.4
 | 
			
		||||
    cs_pin: GPIO5
 | 
			
		||||
    dc_pin: GPIO4
 | 
			
		||||
    color_palette: GRAYSCALE
 | 
			
		||||
    reset_pin: GPIO22
 | 
			
		||||
    lambda: |-
 | 
			
		||||
      it.rectangle(0, 0, it.get_width(), it.get_height());
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,14 @@ switch:
 | 
			
		||||
    output: pin_4
 | 
			
		||||
    id: pin_4_switch
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
spi:  # Pins are for SPI1 on the RP2040 Pico-W
 | 
			
		||||
  miso_pin: 8
 | 
			
		||||
  clk_pin: 10
 | 
			
		||||
  mosi_pin: 11
 | 
			
		||||
  id: spi_0
 | 
			
		||||
  interface: hardware
 | 
			
		||||
 | 
			
		||||
#light:
 | 
			
		||||
#  - platform: rp2040_pio_led_strip
 | 
			
		||||
#    id: led_strip
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user