mirror of
https://github.com/esphome/esphome.git
synced 2026-09-16 17:48:40 +00:00
Merge branch 'dev' into api/peel-first-write-iteration
This commit is contained in:
@@ -459,6 +459,7 @@ esphome/components/sonoff_d1/* @anatoly-savchenkov
|
||||
esphome/components/sound_level/* @kahrendt
|
||||
esphome/components/spa06_base/* @danielkent-net
|
||||
esphome/components/spa06_i2c/* @danielkent-net
|
||||
esphome/components/spa06_spi/* @danielkent-net
|
||||
esphome/components/speaker/* @jesserockz @kahrendt
|
||||
esphome/components/speaker/media_player/* @kahrendt @synesthesiam
|
||||
esphome/components/speaker_source/* @kahrendt
|
||||
|
||||
@@ -119,6 +119,7 @@ ETHERNET_TYPES = {
|
||||
"OPENETH": EthernetType.ETHERNET_TYPE_OPENETH,
|
||||
"DM9051": EthernetType.ETHERNET_TYPE_DM9051,
|
||||
"LAN8670": EthernetType.ETHERNET_TYPE_LAN8670,
|
||||
"ENC28J60": EthernetType.ETHERNET_TYPE_ENC28J60,
|
||||
}
|
||||
|
||||
# PHY types that need compile-time defines for conditional compilation
|
||||
@@ -134,6 +135,7 @@ _PHY_TYPE_TO_DEFINE = {
|
||||
"W5500": "USE_ETHERNET_W5500",
|
||||
"DM9051": "USE_ETHERNET_DM9051",
|
||||
"LAN8670": "USE_ETHERNET_LAN8670",
|
||||
"ENC28J60": "USE_ETHERNET_ENC28J60",
|
||||
}
|
||||
|
||||
|
||||
@@ -155,11 +157,16 @@ _IDF6_ETHERNET_COMPONENTS: dict[str, IDFRegistryComponent] = {
|
||||
"KSZ8081RNA": IDFRegistryComponent("espressif/ksz80xx", "1.0.0"),
|
||||
"W5500": IDFRegistryComponent("espressif/w5500", "1.0.1"),
|
||||
"DM9051": IDFRegistryComponent("espressif/dm9051", "1.0.0"),
|
||||
"ENC28J60": IDFRegistryComponent("espressif/enc28j60", "1.0.1"),
|
||||
"LAN8670": IDFRegistryComponent("espressif/lan867x", "2.0.0"),
|
||||
}
|
||||
|
||||
SPI_ETHERNET_TYPES = ["W5500", "DM9051"]
|
||||
# These types are always external IDF components (never built-in to ESP-IDF)
|
||||
_ALWAYS_EXTERNAL_IDF_COMPONENTS = {"LAN8670", "ENC28J60"}
|
||||
|
||||
SPI_ETHERNET_TYPES = ["W5500", "DM9051", "ENC28J60"]
|
||||
# RP2040-supported SPI ethernet types
|
||||
RP2040_SPI_ETHERNET_TYPES = ["W5500"]
|
||||
RP2040_SPI_ETHERNET_TYPES = ["W5500", "ENC28J60"]
|
||||
SPI_ETHERNET_DEFAULT_POLLING_INTERVAL = TimePeriodMilliseconds(milliseconds=10)
|
||||
|
||||
emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t")
|
||||
@@ -220,7 +227,18 @@ def _validate(config):
|
||||
|
||||
if CORE.is_esp32:
|
||||
if config[CONF_TYPE] in SPI_ETHERNET_TYPES:
|
||||
if _is_framework_spi_polling_mode_supported():
|
||||
# ENC28J60 driver does not support polling mode - interrupt is required
|
||||
if config[CONF_TYPE] == "ENC28J60":
|
||||
if CONF_POLLING_INTERVAL in config:
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_POLLING_INTERVAL}' is not supported for ENC28J60. "
|
||||
f"'{CONF_INTERRUPT_PIN}' is required."
|
||||
)
|
||||
if CONF_INTERRUPT_PIN not in config:
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_INTERRUPT_PIN}' is a required option for ENC28J60."
|
||||
)
|
||||
elif _is_framework_spi_polling_mode_supported():
|
||||
if CONF_POLLING_INTERVAL in config and CONF_INTERRUPT_PIN in config:
|
||||
raise cv.Invalid(
|
||||
f"Cannot specify more than one of {CONF_INTERRUPT_PIN}, {CONF_POLLING_INTERVAL}"
|
||||
@@ -367,6 +385,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
"W5500": SPI_SCHEMA,
|
||||
"OPENETH": cv.All(BASE_SCHEMA, cv.only_on([Platform.ESP32])),
|
||||
"DM9051": SPI_SCHEMA,
|
||||
"ENC28J60": SPI_SCHEMA,
|
||||
"LAN8670": RMII_SCHEMA,
|
||||
},
|
||||
upper=True,
|
||||
@@ -502,7 +521,8 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
cg.add_define("USE_ETHERNET_SPI")
|
||||
add_idf_sdkconfig_option("CONFIG_ETH_USE_SPI_ETHERNET", True)
|
||||
# CONFIG_ETH_SPI_ETHERNET_{TYPE} Kconfig options were removed in IDF 6.0
|
||||
if idf_version() < cv.Version(6, 0, 0):
|
||||
# ENC28J60 was never built-in to IDF, so it has no Kconfig option
|
||||
if idf_version() < cv.Version(6, 0, 0) and config[CONF_TYPE] != "ENC28J60":
|
||||
add_idf_sdkconfig_option(
|
||||
f"CONFIG_ETH_SPI_ETHERNET_{config[CONF_TYPE]}", True
|
||||
)
|
||||
@@ -533,12 +553,11 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
# Re-enable ESP-IDF's Ethernet driver (excluded by default to save compile time)
|
||||
include_builtin_idf_component("esp_eth")
|
||||
|
||||
if config[CONF_TYPE] == "LAN8670":
|
||||
# Add LAN867x 10BASE-T1S PHY support component
|
||||
add_idf_component(name="espressif/lan867x", ref="2.0.0")
|
||||
|
||||
# IDF 6.0 moved per-chip PHY/MAC drivers to the Espressif Component Registry
|
||||
if idf_version() >= cv.Version(6, 0, 0) and (
|
||||
if config[CONF_TYPE] in _ALWAYS_EXTERNAL_IDF_COMPONENTS:
|
||||
component = _IDF6_ETHERNET_COMPONENTS[config[CONF_TYPE]]
|
||||
add_idf_component(name=component.name, ref=component.version)
|
||||
elif idf_version() >= cv.Version(6, 0, 0) and (
|
||||
# IDF 6.0 moved per-chip PHY/MAC drivers to the Espressif Component Registry
|
||||
component := _IDF6_ETHERNET_COMPONENTS.get(config[CONF_TYPE])
|
||||
):
|
||||
add_idf_component(name=component.name, ref=component.version)
|
||||
@@ -555,7 +574,10 @@ async def _to_code_rp2040(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
cg.add(var.set_reset_pin(config[CONF_RESET_PIN]))
|
||||
|
||||
cg.add_define("USE_ETHERNET_SPI")
|
||||
cg.add_library("lwIP_w5500", None)
|
||||
if config[CONF_TYPE] == "ENC28J60":
|
||||
cg.add_library("lwIP_enc28j60", None)
|
||||
else:
|
||||
cg.add_library("lwIP_w5500", None)
|
||||
|
||||
|
||||
def _final_validate_rmii_pins(config: ConfigType) -> None:
|
||||
|
||||
@@ -23,7 +23,13 @@ extern "C" eth_esp32_emac_config_t eth_esp32_emac_default_config(void);
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
#include <W5500lwIP.h>
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
#include <ENC28J60lwIP.h>
|
||||
#else
|
||||
#error "Unsupported RP2040 SPI Ethernet type"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace esphome::ethernet {
|
||||
@@ -57,6 +63,7 @@ enum EthernetType : uint8_t {
|
||||
ETHERNET_TYPE_OPENETH,
|
||||
ETHERNET_TYPE_DM9051,
|
||||
ETHERNET_TYPE_LAN8670,
|
||||
ETHERNET_TYPE_ENC28J60,
|
||||
};
|
||||
|
||||
struct ManualIP {
|
||||
@@ -215,7 +222,13 @@ class EthernetComponent final : public Component {
|
||||
|
||||
#ifdef USE_RP2040
|
||||
static constexpr uint32_t LINK_CHECK_INTERVAL = 500; // ms between link/IP polls
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
Wiznet5500lwIP *eth_{nullptr};
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
ENC28J60lwIP *eth_{nullptr};
|
||||
#else
|
||||
#error "Unsupported RP2040 SPI Ethernet type"
|
||||
#endif
|
||||
uint32_t last_link_check_{0};
|
||||
uint8_t clk_pin_;
|
||||
uint8_t miso_pin_;
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
#include "esp_eth_phy_lan867x.h"
|
||||
#endif
|
||||
|
||||
// ENC28J60 header exists on all IDF versions (always an external component)
|
||||
#ifdef USE_ETHERNET_ENC28J60
|
||||
#include "esp_eth_enc28j60.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_master.h>
|
||||
@@ -194,25 +199,27 @@ void EthernetComponent::setup() {
|
||||
.post_cb = nullptr,
|
||||
};
|
||||
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg);
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(host, &devcfg);
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
eth_enc28j60_config_t enc28j60_config = ETH_ENC28J60_DEFAULT_CONFIG(host, &devcfg);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
w5500_config.int_gpio_num = this->interrupt_pin_;
|
||||
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
|
||||
w5500_config.poll_period_ms = this->polling_interval_;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
dm9051_config.int_gpio_num = this->interrupt_pin_;
|
||||
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
|
||||
dm9051_config.poll_period_ms = this->polling_interval_;
|
||||
#endif
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
enc28j60_config.int_gpio_num = this->interrupt_pin_;
|
||||
// ENC28J60 does not support poll_period_ms
|
||||
#endif
|
||||
|
||||
phy_config.phy_addr = this->phy_addr_spi_;
|
||||
@@ -300,19 +307,24 @@ void EthernetComponent::setup() {
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
case ETHERNET_TYPE_W5500: {
|
||||
mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
this->phy_ = esp_eth_phy_new_w5500(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
case ETHERNET_TYPE_DM9051: {
|
||||
mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
this->phy_ = esp_eth_phy_new_dm9051(&phy_config);
|
||||
break;
|
||||
}
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
case ETHERNET_TYPE_ENC28J60: {
|
||||
mac = esp_eth_mac_new_enc28j60(&enc28j60_config, &mac_config);
|
||||
this->phy_ = esp_eth_phy_new_enc28j60(&phy_config);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
default: {
|
||||
@@ -405,15 +417,18 @@ void EthernetComponent::dump_config() {
|
||||
eth_type = "KSZ8081RNA";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_W5500
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
case ETHERNET_TYPE_W5500:
|
||||
eth_type = "W5500";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_DM9051
|
||||
#elif defined(USE_ETHERNET_DM9051)
|
||||
case ETHERNET_TYPE_DM9051:
|
||||
eth_type = "DM9051";
|
||||
break;
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
case ETHERNET_TYPE_ENC28J60:
|
||||
eth_type = "ENC28J60";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_OPENETH
|
||||
case ETHERNET_TYPE_OPENETH:
|
||||
|
||||
@@ -31,11 +31,15 @@ void EthernetComponent::setup() {
|
||||
reset_pin.digital_write(false);
|
||||
delay(1); // NOLINT
|
||||
reset_pin.digital_write(true);
|
||||
delay(10); // NOLINT - wait for W5500 to initialize after reset
|
||||
delay(10); // NOLINT - wait for chip to initialize after reset
|
||||
}
|
||||
|
||||
// Create the W5500 device instance
|
||||
// Create the SPI Ethernet device instance
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
this->eth_ = new Wiznet5500lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
this->eth_ = new ENC28J60lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT
|
||||
#endif
|
||||
|
||||
// Set hostname before begin() so the LWIP netif gets it
|
||||
this->eth_->hostname(App.get_name().c_str());
|
||||
@@ -61,7 +65,7 @@ void EthernetComponent::setup() {
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
ESP_LOGE(TAG, "Failed to initialize W5500 Ethernet");
|
||||
ESP_LOGE(TAG, "Failed to initialize Ethernet");
|
||||
delete this->eth_; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
this->eth_ = nullptr;
|
||||
this->mark_failed();
|
||||
@@ -164,9 +168,15 @@ void EthernetComponent::loop() {
|
||||
}
|
||||
|
||||
void EthernetComponent::dump_config() {
|
||||
const char *type_str = "Unknown";
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
type_str = "W5500";
|
||||
#elif defined(USE_ETHERNET_ENC28J60)
|
||||
type_str = "ENC28J60";
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Ethernet:\n"
|
||||
" Type: W5500\n"
|
||||
" Type: %s\n"
|
||||
" Connected: %s\n"
|
||||
" CLK Pin: %u\n"
|
||||
" MISO Pin: %u\n"
|
||||
@@ -174,7 +184,7 @@ void EthernetComponent::dump_config() {
|
||||
" CS Pin: %u\n"
|
||||
" IRQ Pin: %d\n"
|
||||
" Reset Pin: %d",
|
||||
YESNO(this->is_connected()), this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_,
|
||||
type_str, YESNO(this->is_connected()), this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_,
|
||||
this->interrupt_pin_, this->reset_pin_);
|
||||
this->dump_connect_params_();
|
||||
}
|
||||
@@ -216,13 +226,18 @@ const char *EthernetComponent::get_eth_mac_address_pretty_into_buffer(
|
||||
}
|
||||
|
||||
eth_duplex_t EthernetComponent::get_duplex_mode() {
|
||||
// W5500 is always full duplex
|
||||
// Both W5500 and ENC28J60 are full-duplex on RP2040
|
||||
return ETH_DUPLEX_FULL;
|
||||
}
|
||||
|
||||
eth_speed_t EthernetComponent::get_link_speed() {
|
||||
#ifdef USE_ETHERNET_ENC28J60
|
||||
// ENC28J60 is 10Mbps only
|
||||
return ETH_SPEED_10M;
|
||||
#else
|
||||
// W5500 is always 100Mbps
|
||||
return ETH_SPEED_100M;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EthernetComponent::powerdown() {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import logging
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import spi
|
||||
from esphome.components.spi import CONF_SPI_MODE
|
||||
import esphome.config_validation as cv
|
||||
|
||||
from ..spa06_base import CONFIG_SCHEMA_BASE, to_code_base
|
||||
|
||||
AUTO_LOAD = ["spa06_base"]
|
||||
CODEOWNERS = ["@danielkent-net"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
|
||||
spa06_ns = cg.esphome_ns.namespace("spa06_spi")
|
||||
SPA06SPIComponent = spa06_ns.class_(
|
||||
"SPA06SPIComponent", cg.PollingComponent, spi.SPIDevice
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
VALID_SPI_MODES = {3: "MODE3", "3": "MODE3", "MODE3": "MODE3"}
|
||||
|
||||
|
||||
def check_spi_mode(config):
|
||||
spi_mode = config.get(CONF_SPI_MODE)
|
||||
if spi_mode not in VALID_SPI_MODES:
|
||||
raise cv.Invalid("SPA06 only supports SPI mode 3")
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema(default_mode="mode3")).extend(
|
||||
{cv.GenerateID(): cv.declare_id(SPA06SPIComponent)}
|
||||
),
|
||||
check_spi_mode,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = await to_code_base(config)
|
||||
await spi.register_spi_device(var, config)
|
||||
@@ -0,0 +1,72 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include "spa06_spi.h"
|
||||
#include "esphome/components/spa06_base/spa06_base.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
// OR (|) register with SPA06_SPI_READ for read.
|
||||
inline constexpr uint8_t SPA06_SPI_READ = 0x80;
|
||||
|
||||
// AND (&) register with SPA06_SPI_WRITE for write.
|
||||
inline constexpr uint8_t SPA06_SPI_WRITE = 0x7F;
|
||||
|
||||
namespace esphome::spa06_spi {
|
||||
|
||||
static const char *const TAG = "spa06_spi";
|
||||
|
||||
void SPA06SPIComponent::dump_config() {
|
||||
SPA06Component::dump_config();
|
||||
LOG_SPI_DEVICE(this)
|
||||
}
|
||||
|
||||
void SPA06SPIComponent::setup() {
|
||||
this->spi_setup();
|
||||
SPA06Component::setup();
|
||||
}
|
||||
|
||||
void SPA06SPIComponent::protocol_reset() {
|
||||
// Forces the device into SPI mode using a dummy read
|
||||
uint8_t dummy_read = 0;
|
||||
this->spa_read_byte(spa06_base::SPA06_ID, &dummy_read);
|
||||
}
|
||||
|
||||
// In SPI mode, only 7 bits of the register addresses are used; the MSB of register address
|
||||
// is not used and replaced by a read/write bit (RW = ‘0’ for write and RW = ‘1’ for read).
|
||||
// Example: address 0xF7 is accessed by using SPI register address 0x77. For write access,
|
||||
// the byte 0x77 is transferred, for read access, the byte 0xF7 is transferred.
|
||||
// The expressions SPA06_SPI_READ (| with register) and SPA06_SPI_WRITE (& with register)
|
||||
// are defined for readability.
|
||||
|
||||
bool SPA06SPIComponent::spa_read_byte(uint8_t a_register, uint8_t *data) {
|
||||
this->enable();
|
||||
this->transfer_byte(a_register | SPA06_SPI_READ);
|
||||
*data = this->transfer_byte(0);
|
||||
this->disable();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SPA06SPIComponent::spa_write_byte(uint8_t a_register, uint8_t data) {
|
||||
this->enable();
|
||||
this->transfer_byte(a_register & SPA06_SPI_WRITE);
|
||||
this->transfer_byte(data);
|
||||
this->disable();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SPA06SPIComponent::spa_read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
|
||||
this->enable();
|
||||
this->transfer_byte(a_register | SPA06_SPI_READ);
|
||||
this->read_array(data, len);
|
||||
this->disable();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SPA06SPIComponent::spa_write_bytes(uint8_t a_register, uint8_t *data, size_t len) {
|
||||
this->enable();
|
||||
this->transfer_byte(a_register & SPA06_SPI_WRITE);
|
||||
this->write_array(data, len);
|
||||
this->disable();
|
||||
return true;
|
||||
}
|
||||
} // namespace esphome::spa06_spi
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/spa06_base/spa06_base.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
namespace esphome::spa06_spi {
|
||||
|
||||
class SPA06SPIComponent : public spa06_base::SPA06Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH,
|
||||
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_200KHZ> {
|
||||
void setup() override;
|
||||
bool spa_read_byte(uint8_t a_register, uint8_t *data) override;
|
||||
bool spa_write_byte(uint8_t a_register, uint8_t data) override;
|
||||
bool spa_read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
|
||||
bool spa_write_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
void protocol_reset() override;
|
||||
};
|
||||
|
||||
} // namespace esphome::spa06_spi
|
||||
@@ -34,6 +34,8 @@ using SPIInterface = void *; // Stub for platforms without SPI (e.g., Zephyr)
|
||||
*/
|
||||
namespace esphome::spi {
|
||||
|
||||
#define LOG_SPI_DEVICE(this) ESP_LOGCONFIG(TAG, " CS Pin: %d", esphome::spi::Utility::get_pin_no(this->cs_));
|
||||
|
||||
/// The bit-order for SPI devices. This defines how the data read from and written to the device is interpreted.
|
||||
enum SPIBitOrder {
|
||||
/// The least significant bit is transmitted/received first.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import text_sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_SOURCE_ID
|
||||
|
||||
from .. import Text, text_ns
|
||||
|
||||
TextTextSensor = text_ns.class_("TextTextSensor", text_sensor.TextSensor, cg.Component)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
text_sensor.text_sensor_schema(TextTextSensor)
|
||||
.extend(
|
||||
{
|
||||
cv.Required(CONF_SOURCE_ID): cv.use_id(Text),
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
source = await cg.get_variable(config[CONF_SOURCE_ID])
|
||||
var = await text_sensor.new_text_sensor(config, source)
|
||||
await cg.register_component(var, config)
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "text_text_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::text {
|
||||
|
||||
static const char *const TAG = "text.text_sensor";
|
||||
|
||||
void TextTextSensor::setup() {
|
||||
this->source_->add_on_state_callback([this](const std::string &value) { this->publish_state(value); });
|
||||
if (this->source_->has_state())
|
||||
this->publish_state(this->source_->state);
|
||||
}
|
||||
|
||||
void TextTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Text Text Sensor", this); }
|
||||
|
||||
} // namespace esphome::text
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "../text.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
namespace esphome::text {
|
||||
|
||||
class TextTextSensor : public text_sensor::TextSensor, public Component {
|
||||
public:
|
||||
explicit TextTextSensor(Text *source) : source_(source) {}
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
Text *source_;
|
||||
};
|
||||
|
||||
} // namespace esphome::text
|
||||
@@ -6,7 +6,7 @@ pre-commit
|
||||
|
||||
# Unit tests
|
||||
pytest==9.0.2
|
||||
pytest-cov==7.0.0
|
||||
pytest-cov==7.1.0
|
||||
pytest-mock==3.15.1
|
||||
pytest-asyncio==1.3.0
|
||||
pytest-xdist==3.8.0
|
||||
|
||||
@@ -963,6 +963,7 @@ def lint_log_multiline_continuation(fname, content):
|
||||
"esphome/components/nextion/nextion_base.h",
|
||||
"esphome/components/select/select.h",
|
||||
"esphome/components/sensor/sensor.h",
|
||||
"esphome/components/spi/spi.h",
|
||||
"esphome/components/stepper/stepper.h",
|
||||
"esphome/components/switch/switch.h",
|
||||
"esphome/components/text/text.h",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
ethernet:
|
||||
type: ENC28J60
|
||||
clk_pin: 18
|
||||
mosi_pin: 19
|
||||
miso_pin: 16
|
||||
cs_pin: 17
|
||||
interrupt_pin: 21
|
||||
reset_pin: 20
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.56
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
domain: .local
|
||||
mac_address: "02:AA:BB:CC:DD:01"
|
||||
on_connect:
|
||||
- logger.log: "Ethernet connected!"
|
||||
on_disconnect:
|
||||
- logger.log: "Ethernet disconnected!"
|
||||
@@ -0,0 +1,19 @@
|
||||
ethernet:
|
||||
type: ENC28J60
|
||||
clk_pin: 19
|
||||
mosi_pin: 21
|
||||
miso_pin: 23
|
||||
cs_pin: 18
|
||||
interrupt_pin: 36
|
||||
reset_pin: 22
|
||||
clock_speed: 10Mhz
|
||||
manual_ip:
|
||||
static_ip: 192.168.178.56
|
||||
gateway: 192.168.178.1
|
||||
subnet: 255.255.255.0
|
||||
domain: .local
|
||||
mac_address: "02:AA:BB:CC:DD:01"
|
||||
on_connect:
|
||||
- logger.log: "Ethernet connected!"
|
||||
on_disconnect:
|
||||
- logger.log: "Ethernet disconnected!"
|
||||
@@ -0,0 +1 @@
|
||||
<<: !include common-enc28j60.yaml
|
||||
@@ -0,0 +1 @@
|
||||
<<: !include common-enc28j60-rp2040.yaml
|
||||
@@ -0,0 +1,15 @@
|
||||
sensor:
|
||||
- platform: spa06_spi
|
||||
spi_id: spi_bus
|
||||
cs_pin: ${cs_pin}
|
||||
temperature:
|
||||
id: spa06_spi_temperature
|
||||
name: Outside Temperature
|
||||
sample_rate: 1
|
||||
oversampling: NONE
|
||||
pressure:
|
||||
name: Outside Pressure
|
||||
id: spa06_spi_pressure
|
||||
sample_rate: 25p4
|
||||
oversampling: 16X
|
||||
update_interval: 15s
|
||||
@@ -0,0 +1,7 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO5
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp32-idf.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -0,0 +1,7 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO15
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp8266-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -0,0 +1,7 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO17
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/rp2040-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -23,3 +23,8 @@ text:
|
||||
min_length: 8
|
||||
max_length: 32
|
||||
mode: password
|
||||
|
||||
text_sensor:
|
||||
- platform: text
|
||||
name: "Test Text State"
|
||||
source_id: test_text
|
||||
|
||||
Reference in New Issue
Block a user