mirror of
https://github.com/esphome/esphome.git
synced 2026-09-19 19:18:47 +00:00
Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
+27
-17
@@ -402,35 +402,45 @@ This document provides essential context for AI models interacting with this pro
|
||||
_use_feature = True
|
||||
```
|
||||
|
||||
**Good Pattern (CORE.data with Helpers):**
|
||||
**Bad Pattern (Flat Keys):**
|
||||
```python
|
||||
# Don't do this - keys should be namespaced under component domain
|
||||
MY_FEATURE_KEY = "my_component_feature"
|
||||
CORE.data[MY_FEATURE_KEY] = True
|
||||
```
|
||||
|
||||
**Good Pattern (dataclass):**
|
||||
```python
|
||||
from dataclasses import dataclass, field
|
||||
from esphome.core import CORE
|
||||
|
||||
# Keys for CORE.data storage
|
||||
COMPONENT_STATE_KEY = "my_component_state"
|
||||
USE_FEATURE_KEY = "my_component_use_feature"
|
||||
DOMAIN = "my_component"
|
||||
|
||||
def _get_component_state() -> list:
|
||||
"""Get component state from CORE.data."""
|
||||
return CORE.data.setdefault(COMPONENT_STATE_KEY, [])
|
||||
@dataclass
|
||||
class MyComponentData:
|
||||
feature_enabled: bool = False
|
||||
item_count: int = 0
|
||||
items: list[str] = field(default_factory=list)
|
||||
|
||||
def _get_use_feature() -> bool | None:
|
||||
"""Get feature flag from CORE.data."""
|
||||
return CORE.data.get(USE_FEATURE_KEY)
|
||||
def _get_data() -> MyComponentData:
|
||||
if DOMAIN not in CORE.data:
|
||||
CORE.data[DOMAIN] = MyComponentData()
|
||||
return CORE.data[DOMAIN]
|
||||
|
||||
def _set_use_feature(value: bool) -> None:
|
||||
"""Set feature flag in CORE.data."""
|
||||
CORE.data[USE_FEATURE_KEY] = value
|
||||
def request_feature() -> None:
|
||||
_get_data().feature_enabled = True
|
||||
|
||||
def enable_feature():
|
||||
_set_use_feature(True)
|
||||
def add_item(item: str) -> None:
|
||||
_get_data().items.append(item)
|
||||
```
|
||||
|
||||
If you need a real-world example, search for components that use `@dataclass` with `CORE.data` in the codebase. Note: Some components may use `TypedDict` for dictionary-based storage; both patterns are acceptable depending on your needs.
|
||||
|
||||
**Why this matters:**
|
||||
- Module-level globals persist between compilation runs if the dashboard doesn't fork/exec
|
||||
- `CORE.data` automatically clears between runs
|
||||
- Typed helper functions provide better IDE support and maintainability
|
||||
- Encapsulation makes state management explicit and testable
|
||||
- Namespacing under `DOMAIN` prevents key collisions between components
|
||||
- `@dataclass` provides type safety and cleaner attribute access
|
||||
|
||||
* **Security:** Be mindful of security when making changes to the API, web server, or any other network-related code. Do not hardcode secrets or keys.
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3d46b63015d761c85ca9cb77ab79a389509e5776701fb22aed16e7b79d432c0c
|
||||
29270eecb86ffa07b2b1d2a4ca56dd7f84762ddc89c6248dbf3f012eca8780b6
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Stale
|
||||
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
|
||||
uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
|
||||
with:
|
||||
debug-only: ${{ github.ref != 'refs/heads/dev' }} # Dry-run when not run on dev branch
|
||||
remove-stale-when-updated: true
|
||||
|
||||
@@ -97,6 +97,7 @@ esphome/components/camera_encoder/* @DT-art1
|
||||
esphome/components/canbus/* @danielschramm @mvturnho
|
||||
esphome/components/cap1188/* @mreditor97
|
||||
esphome/components/captive_portal/* @esphome/core
|
||||
esphome/components/cc1101/* @gabest11 @lygris
|
||||
esphome/components/ccs811/* @habbie
|
||||
esphome/components/cd74hc4067/* @asoehlke
|
||||
esphome/components/ch422g/* @clydebarrow @jesterret
|
||||
@@ -190,6 +191,7 @@ esphome/components/gps/* @coogle @ximex
|
||||
esphome/components/graph/* @synco
|
||||
esphome/components/graphical_display_menu/* @MrMDavidson
|
||||
esphome/components/gree/* @orestismers
|
||||
esphome/components/gree/switch/* @nagyrobi
|
||||
esphome/components/grove_gas_mc_v2/* @YorkshireIoT
|
||||
esphome/components/grove_tb6612fng/* @max246
|
||||
esphome/components/growatt_solar/* @leeuwte
|
||||
|
||||
@@ -107,6 +107,17 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
||||
4: adc_channel_t.ADC_CHANNEL_3,
|
||||
5: adc_channel_t.ADC_CHANNEL_4,
|
||||
},
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32p4/include/soc/adc_channel.h
|
||||
VARIANT_ESP32P4: {
|
||||
16: adc_channel_t.ADC_CHANNEL_0,
|
||||
17: adc_channel_t.ADC_CHANNEL_1,
|
||||
18: adc_channel_t.ADC_CHANNEL_2,
|
||||
19: adc_channel_t.ADC_CHANNEL_3,
|
||||
20: adc_channel_t.ADC_CHANNEL_4,
|
||||
21: adc_channel_t.ADC_CHANNEL_5,
|
||||
22: adc_channel_t.ADC_CHANNEL_6,
|
||||
23: adc_channel_t.ADC_CHANNEL_7,
|
||||
},
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
|
||||
VARIANT_ESP32S2: {
|
||||
1: adc_channel_t.ADC_CHANNEL_0,
|
||||
@@ -133,16 +144,6 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
||||
9: adc_channel_t.ADC_CHANNEL_8,
|
||||
10: adc_channel_t.ADC_CHANNEL_9,
|
||||
},
|
||||
VARIANT_ESP32P4: {
|
||||
16: adc_channel_t.ADC_CHANNEL_0,
|
||||
17: adc_channel_t.ADC_CHANNEL_1,
|
||||
18: adc_channel_t.ADC_CHANNEL_2,
|
||||
19: adc_channel_t.ADC_CHANNEL_3,
|
||||
20: adc_channel_t.ADC_CHANNEL_4,
|
||||
21: adc_channel_t.ADC_CHANNEL_5,
|
||||
22: adc_channel_t.ADC_CHANNEL_6,
|
||||
23: adc_channel_t.ADC_CHANNEL_7,
|
||||
},
|
||||
}
|
||||
|
||||
# pin to adc2 channel mapping
|
||||
@@ -175,6 +176,15 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
||||
VARIANT_ESP32C6: {}, # no ADC2
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
|
||||
VARIANT_ESP32H2: {}, # no ADC2
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32p4/include/soc/adc_channel.h
|
||||
VARIANT_ESP32P4: {
|
||||
49: adc_channel_t.ADC_CHANNEL_0,
|
||||
50: adc_channel_t.ADC_CHANNEL_1,
|
||||
51: adc_channel_t.ADC_CHANNEL_2,
|
||||
52: adc_channel_t.ADC_CHANNEL_3,
|
||||
53: adc_channel_t.ADC_CHANNEL_4,
|
||||
54: adc_channel_t.ADC_CHANNEL_5,
|
||||
},
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
|
||||
VARIANT_ESP32S2: {
|
||||
11: adc_channel_t.ADC_CHANNEL_0,
|
||||
@@ -201,14 +211,6 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
||||
19: adc_channel_t.ADC_CHANNEL_8,
|
||||
20: adc_channel_t.ADC_CHANNEL_9,
|
||||
},
|
||||
VARIANT_ESP32P4: {
|
||||
49: adc_channel_t.ADC_CHANNEL_0,
|
||||
50: adc_channel_t.ADC_CHANNEL_1,
|
||||
51: adc_channel_t.ADC_CHANNEL_2,
|
||||
52: adc_channel_t.ADC_CHANNEL_3,
|
||||
53: adc_channel_t.ADC_CHANNEL_4,
|
||||
54: adc_channel_t.ADC_CHANNEL_5,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ void ADCSensor::setup() {
|
||||
adc_cali_handle_t handle = nullptr;
|
||||
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
|
||||
// RISC-V variants and S3 use curve fitting calibration
|
||||
adc_cali_curve_fitting_config_t cali_config = {}; // Zero initialize first
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
@@ -111,7 +111,7 @@ void ADCSensor::setup() {
|
||||
ESP_LOGW(TAG, "Line fitting calibration failed with error %d, will use uncalibrated readings", err);
|
||||
this->setup_flags_.calibration_complete = false;
|
||||
}
|
||||
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32S3 || ESP32H2
|
||||
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32H2 || ESP32P4 || ESP32S3
|
||||
}
|
||||
|
||||
this->setup_flags_.init_complete = true;
|
||||
@@ -186,11 +186,11 @@ float ADCSensor::sample_fixed_attenuation_() {
|
||||
ESP_LOGW(TAG, "ADC calibration conversion failed with error %d, disabling calibration", err);
|
||||
if (this->calibration_handle_ != nullptr) {
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
|
||||
adc_cali_delete_scheme_curve_fitting(this->calibration_handle_);
|
||||
#else // Other ESP32 variants use line fitting calibration
|
||||
adc_cali_delete_scheme_line_fitting(this->calibration_handle_);
|
||||
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32S3 || ESP32H2
|
||||
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32H2 || ESP32P4 || ESP32S3
|
||||
this->calibration_handle_ = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -219,7 +219,7 @@ float ADCSensor::sample_autorange_() {
|
||||
if (this->calibration_handle_ != nullptr) {
|
||||
// Delete old calibration handle
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
|
||||
adc_cali_delete_scheme_curve_fitting(this->calibration_handle_);
|
||||
#else
|
||||
adc_cali_delete_scheme_line_fitting(this->calibration_handle_);
|
||||
@@ -231,7 +231,7 @@ float ADCSensor::sample_autorange_() {
|
||||
adc_cali_handle_t handle = nullptr;
|
||||
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
|
||||
adc_cali_curve_fitting_config_t cali_config = {};
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
cali_config.chan = this->channel_;
|
||||
@@ -266,7 +266,7 @@ float ADCSensor::sample_autorange_() {
|
||||
ESP_LOGW(TAG, "ADC read failed in autorange with error %d", err);
|
||||
if (handle != nullptr) {
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
|
||||
adc_cali_delete_scheme_curve_fitting(handle);
|
||||
#else
|
||||
adc_cali_delete_scheme_line_fitting(handle);
|
||||
@@ -288,7 +288,7 @@ float ADCSensor::sample_autorange_() {
|
||||
}
|
||||
// Clean up calibration handle
|
||||
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
|
||||
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
|
||||
USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
|
||||
adc_cali_delete_scheme_curve_fitting(handle);
|
||||
#else
|
||||
adc_cali_delete_scheme_line_fitting(handle);
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import spi
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_CHANNEL, CONF_FREQUENCY, CONF_ID, CONF_WAIT_TIME
|
||||
|
||||
CODEOWNERS = ["@lygris", "@gabest11"]
|
||||
DEPENDENCIES = ["spi"]
|
||||
MULTI_CONF = True
|
||||
|
||||
ns = cg.esphome_ns.namespace("cc1101")
|
||||
CC1101Component = ns.class_("CC1101Component", cg.Component, spi.SPIDevice)
|
||||
|
||||
# Config keys
|
||||
CONF_OUTPUT_POWER = "output_power"
|
||||
CONF_RX_ATTENUATION = "rx_attenuation"
|
||||
CONF_DC_BLOCKING_FILTER = "dc_blocking_filter"
|
||||
CONF_IF_FREQUENCY = "if_frequency"
|
||||
CONF_FILTER_BANDWIDTH = "filter_bandwidth"
|
||||
CONF_CHANNEL_SPACING = "channel_spacing"
|
||||
CONF_FSK_DEVIATION = "fsk_deviation"
|
||||
CONF_MSK_DEVIATION = "msk_deviation"
|
||||
CONF_SYMBOL_RATE = "symbol_rate"
|
||||
CONF_SYNC_MODE = "sync_mode"
|
||||
CONF_CARRIER_SENSE_ABOVE_THRESHOLD = "carrier_sense_above_threshold"
|
||||
CONF_MODULATION_TYPE = "modulation_type"
|
||||
CONF_MANCHESTER = "manchester"
|
||||
CONF_NUM_PREAMBLE = "num_preamble"
|
||||
CONF_SYNC1 = "sync1"
|
||||
CONF_SYNC0 = "sync0"
|
||||
CONF_PKTLEN = "pktlen"
|
||||
CONF_MAGN_TARGET = "magn_target"
|
||||
CONF_MAX_LNA_GAIN = "max_lna_gain"
|
||||
CONF_MAX_DVGA_GAIN = "max_dvga_gain"
|
||||
CONF_CARRIER_SENSE_ABS_THR = "carrier_sense_abs_thr"
|
||||
CONF_CARRIER_SENSE_REL_THR = "carrier_sense_rel_thr"
|
||||
CONF_LNA_PRIORITY = "lna_priority"
|
||||
CONF_FILTER_LENGTH_FSK_MSK = "filter_length_fsk_msk"
|
||||
CONF_FILTER_LENGTH_ASK_OOK = "filter_length_ask_ook"
|
||||
CONF_FREEZE = "freeze"
|
||||
CONF_HYST_LEVEL = "hyst_level"
|
||||
|
||||
# Enums
|
||||
SyncMode = ns.enum("SyncMode", True)
|
||||
SYNC_MODE = {
|
||||
"None": SyncMode.SYNC_MODE_NONE,
|
||||
"15/16": SyncMode.SYNC_MODE_15_16,
|
||||
"16/16": SyncMode.SYNC_MODE_16_16,
|
||||
"30/32": SyncMode.SYNC_MODE_30_32,
|
||||
}
|
||||
|
||||
Modulation = ns.enum("Modulation", True)
|
||||
MODULATION = {
|
||||
"2-FSK": Modulation.MODULATION_2_FSK,
|
||||
"GFSK": Modulation.MODULATION_GFSK,
|
||||
"ASK/OOK": Modulation.MODULATION_ASK_OOK,
|
||||
"4-FSK": Modulation.MODULATION_4_FSK,
|
||||
"MSK": Modulation.MODULATION_MSK,
|
||||
}
|
||||
|
||||
RxAttenuation = ns.enum("RxAttenuation", True)
|
||||
RX_ATTENUATION = {
|
||||
"0dB": RxAttenuation.RX_ATTENUATION_0DB,
|
||||
"6dB": RxAttenuation.RX_ATTENUATION_6DB,
|
||||
"12dB": RxAttenuation.RX_ATTENUATION_12DB,
|
||||
"18dB": RxAttenuation.RX_ATTENUATION_18DB,
|
||||
}
|
||||
|
||||
MagnTarget = ns.enum("MagnTarget", True)
|
||||
MAGN_TARGET = {
|
||||
"24dB": MagnTarget.MAGN_TARGET_24DB,
|
||||
"27dB": MagnTarget.MAGN_TARGET_27DB,
|
||||
"30dB": MagnTarget.MAGN_TARGET_30DB,
|
||||
"33dB": MagnTarget.MAGN_TARGET_33DB,
|
||||
"36dB": MagnTarget.MAGN_TARGET_36DB,
|
||||
"38dB": MagnTarget.MAGN_TARGET_38DB,
|
||||
"40dB": MagnTarget.MAGN_TARGET_40DB,
|
||||
"42dB": MagnTarget.MAGN_TARGET_42DB,
|
||||
}
|
||||
|
||||
MaxLnaGain = ns.enum("MaxLnaGain", True)
|
||||
MAX_LNA_GAIN = {
|
||||
"Default": MaxLnaGain.MAX_LNA_GAIN_DEFAULT,
|
||||
"2.6dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_2P6DB,
|
||||
"6.1dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_6P1DB,
|
||||
"7.4dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_7P4DB,
|
||||
"9.2dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_9P2DB,
|
||||
"11.5dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_11P5DB,
|
||||
"14.6dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_14P6DB,
|
||||
"17.1dB": MaxLnaGain.MAX_LNA_GAIN_MINUS_17P1DB,
|
||||
}
|
||||
|
||||
MaxDvgaGain = ns.enum("MaxDvgaGain", True)
|
||||
MAX_DVGA_GAIN = {
|
||||
"Default": MaxDvgaGain.MAX_DVGA_GAIN_DEFAULT,
|
||||
"-1": MaxDvgaGain.MAX_DVGA_GAIN_MINUS_1,
|
||||
"-2": MaxDvgaGain.MAX_DVGA_GAIN_MINUS_2,
|
||||
"-3": MaxDvgaGain.MAX_DVGA_GAIN_MINUS_3,
|
||||
}
|
||||
|
||||
CarrierSenseRelThr = ns.enum("CarrierSenseRelThr", True)
|
||||
CARRIER_SENSE_REL_THR = {
|
||||
"Default": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_DEFAULT,
|
||||
"+6dB": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_PLUS_6DB,
|
||||
"+10dB": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_PLUS_10DB,
|
||||
"+14dB": CarrierSenseRelThr.CARRIER_SENSE_REL_THR_PLUS_14DB,
|
||||
}
|
||||
|
||||
FilterLengthFskMsk = ns.enum("FilterLengthFskMsk", True)
|
||||
FILTER_LENGTH_FSK_MSK = {
|
||||
"8": FilterLengthFskMsk.FILTER_LENGTH_8DB,
|
||||
"16": FilterLengthFskMsk.FILTER_LENGTH_16DB,
|
||||
"32": FilterLengthFskMsk.FILTER_LENGTH_32DB,
|
||||
"64": FilterLengthFskMsk.FILTER_LENGTH_64DB,
|
||||
}
|
||||
|
||||
FilterLengthAskOok = ns.enum("FilterLengthAskOok", True)
|
||||
FILTER_LENGTH_ASK_OOK = {
|
||||
"4dB": FilterLengthAskOok.FILTER_LENGTH_4DB,
|
||||
"8dB": FilterLengthAskOok.FILTER_LENGTH_8DB,
|
||||
"12dB": FilterLengthAskOok.FILTER_LENGTH_12DB,
|
||||
"16dB": FilterLengthAskOok.FILTER_LENGTH_16DB,
|
||||
}
|
||||
|
||||
Freeze = ns.enum("Freeze", True)
|
||||
FREEZE = {
|
||||
"Default": Freeze.FREEZE_DEFAULT,
|
||||
"On Sync": Freeze.FREEZE_ON_SYNC,
|
||||
"Analog Only": Freeze.FREEZE_ANALOG_ONLY,
|
||||
"Analog And Digital": Freeze.FREEZE_ANALOG_AND_DIGITAL,
|
||||
}
|
||||
|
||||
WaitTime = ns.enum("WaitTime", True)
|
||||
WAIT_TIME = {
|
||||
"8": WaitTime.WAIT_TIME_8_SAMPLES,
|
||||
"16": WaitTime.WAIT_TIME_16_SAMPLES,
|
||||
"24": WaitTime.WAIT_TIME_24_SAMPLES,
|
||||
"32": WaitTime.WAIT_TIME_32_SAMPLES,
|
||||
}
|
||||
|
||||
HystLevel = ns.enum("HystLevel", True)
|
||||
HYST_LEVEL = {
|
||||
"None": HystLevel.HYST_LEVEL_NONE,
|
||||
"Low": HystLevel.HYST_LEVEL_LOW,
|
||||
"Medium": HystLevel.HYST_LEVEL_MEDIUM,
|
||||
"High": HystLevel.HYST_LEVEL_HIGH,
|
||||
}
|
||||
|
||||
# Config key -> Validator mapping
|
||||
CONFIG_MAP = {
|
||||
CONF_OUTPUT_POWER: cv.float_range(min=-30.0, max=11.0),
|
||||
CONF_RX_ATTENUATION: cv.enum(RX_ATTENUATION, upper=False),
|
||||
CONF_DC_BLOCKING_FILTER: cv.boolean,
|
||||
CONF_FREQUENCY: cv.float_range(min=300000.0, max=928000.0),
|
||||
CONF_IF_FREQUENCY: cv.float_range(min=25, max=788),
|
||||
CONF_FILTER_BANDWIDTH: cv.float_range(min=58.0, max=812.0),
|
||||
CONF_CHANNEL: cv.uint8_t,
|
||||
CONF_CHANNEL_SPACING: cv.float_range(min=25, max=405),
|
||||
CONF_FSK_DEVIATION: cv.float_range(min=1.5, max=381),
|
||||
CONF_MSK_DEVIATION: cv.int_range(min=1, max=8),
|
||||
CONF_SYMBOL_RATE: cv.float_range(min=600, max=500000),
|
||||
CONF_SYNC_MODE: cv.enum(SYNC_MODE, upper=False),
|
||||
CONF_CARRIER_SENSE_ABOVE_THRESHOLD: cv.boolean,
|
||||
CONF_MODULATION_TYPE: cv.enum(MODULATION, upper=False),
|
||||
CONF_MANCHESTER: cv.boolean,
|
||||
CONF_NUM_PREAMBLE: cv.int_range(min=0, max=7),
|
||||
CONF_SYNC1: cv.hex_uint8_t,
|
||||
CONF_SYNC0: cv.hex_uint8_t,
|
||||
CONF_PKTLEN: cv.uint8_t,
|
||||
CONF_MAGN_TARGET: cv.enum(MAGN_TARGET, upper=False),
|
||||
CONF_MAX_LNA_GAIN: cv.enum(MAX_LNA_GAIN, upper=False),
|
||||
CONF_MAX_DVGA_GAIN: cv.enum(MAX_DVGA_GAIN, upper=False),
|
||||
CONF_CARRIER_SENSE_ABS_THR: cv.int_range(min=-8, max=7),
|
||||
CONF_CARRIER_SENSE_REL_THR: cv.enum(CARRIER_SENSE_REL_THR, upper=False),
|
||||
CONF_LNA_PRIORITY: cv.boolean,
|
||||
CONF_FILTER_LENGTH_FSK_MSK: cv.enum(FILTER_LENGTH_FSK_MSK, upper=False),
|
||||
CONF_FILTER_LENGTH_ASK_OOK: cv.enum(FILTER_LENGTH_ASK_OOK, upper=False),
|
||||
CONF_FREEZE: cv.enum(FREEZE, upper=False),
|
||||
CONF_WAIT_TIME: cv.enum(WAIT_TIME, upper=False),
|
||||
CONF_HYST_LEVEL: cv.enum(HYST_LEVEL, upper=False),
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema({cv.GenerateID(): cv.declare_id(CC1101Component)})
|
||||
.extend({cv.Optional(key): validator for key, validator in CONFIG_MAP.items()})
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(spi.spi_device_schema(cs_pin_required=True))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await spi.register_spi_device(var, config)
|
||||
|
||||
for key in CONFIG_MAP:
|
||||
if key in config:
|
||||
cg.add(getattr(var, f"set_{key}")(config[key]))
|
||||
|
||||
|
||||
# Actions
|
||||
BeginTxAction = ns.class_("BeginTxAction", automation.Action)
|
||||
BeginRxAction = ns.class_("BeginRxAction", automation.Action)
|
||||
ResetAction = ns.class_("ResetAction", automation.Action)
|
||||
SetIdleAction = ns.class_("SetIdleAction", automation.Action)
|
||||
|
||||
CC1101_ACTION_SCHEMA = cv.Schema(
|
||||
maybe_simple_id({cv.GenerateID(CONF_ID): cv.use_id(CC1101Component)})
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action("cc1101.begin_tx", BeginTxAction, CC1101_ACTION_SCHEMA)
|
||||
@automation.register_action("cc1101.begin_rx", BeginRxAction, CC1101_ACTION_SCHEMA)
|
||||
@automation.register_action("cc1101.reset", ResetAction, CC1101_ACTION_SCHEMA)
|
||||
@automation.register_action("cc1101.set_idle", SetIdleAction, CC1101_ACTION_SCHEMA)
|
||||
async def cc1101_action_to_code(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
return var
|
||||
@@ -0,0 +1,550 @@
|
||||
#include "cc1101.h"
|
||||
#include "cc1101pa.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
static const char *const TAG = "cc1101";
|
||||
|
||||
static void split_float(float value, int mbits, uint8_t &e, uint32_t &m) {
|
||||
int e_tmp;
|
||||
float m_tmp = std::frexp(value, &e_tmp);
|
||||
if (e_tmp <= mbits) {
|
||||
e = 0;
|
||||
m = 0;
|
||||
return;
|
||||
}
|
||||
e = static_cast<uint8_t>(e_tmp - mbits - 1);
|
||||
m = static_cast<uint32_t>(((m_tmp * 2 - 1) * (1 << (mbits + 1))) + 1) >> 1;
|
||||
if (m == (1UL << mbits)) {
|
||||
e = e + 1;
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CC1101Component::CC1101Component() {
|
||||
// Datasheet defaults
|
||||
memset(&this->state_, 0, sizeof(this->state_));
|
||||
this->state_.GDO2_CFG = 0x0D; // Serial Data (for RX on GDO2)
|
||||
this->state_.GDO1_CFG = 0x2E;
|
||||
this->state_.GDO0_CFG = 0x0D; // Serial Data (for RX on GDO0 / TX Input)
|
||||
this->state_.FIFO_THR = 7;
|
||||
this->state_.SYNC1 = 0xD3;
|
||||
this->state_.SYNC0 = 0x91;
|
||||
this->state_.PKTLEN = 0xFF;
|
||||
this->state_.APPEND_STATUS = 1;
|
||||
this->state_.LENGTH_CONFIG = 1;
|
||||
this->state_.CRC_EN = 1;
|
||||
this->state_.WHITE_DATA = 1;
|
||||
this->state_.FREQ_IF = 0x0F;
|
||||
this->state_.FREQ2 = 0x1E;
|
||||
this->state_.FREQ1 = 0xC4;
|
||||
this->state_.FREQ0 = 0xEC;
|
||||
this->state_.DRATE_E = 0x0C;
|
||||
this->state_.CHANBW_E = 0x02;
|
||||
this->state_.DRATE_M = 0x22;
|
||||
this->state_.SYNC_MODE = 2;
|
||||
this->state_.CHANSPC_E = 2;
|
||||
this->state_.NUM_PREAMBLE = 2;
|
||||
this->state_.CHANSPC_M = 0xF8;
|
||||
this->state_.DEVIATION_M = 7;
|
||||
this->state_.DEVIATION_E = 4;
|
||||
this->state_.RX_TIME = 7;
|
||||
this->state_.CCA_MODE = 3;
|
||||
this->state_.PO_TIMEOUT = 1;
|
||||
this->state_.FOC_LIMIT = 2;
|
||||
this->state_.FOC_POST_K = 1;
|
||||
this->state_.FOC_PRE_K = 2;
|
||||
this->state_.FOC_BS_CS_GATE = 1;
|
||||
this->state_.BS_POST_KP = 1;
|
||||
this->state_.BS_POST_KI = 1;
|
||||
this->state_.BS_PRE_KP = 2;
|
||||
this->state_.BS_PRE_KI = 1;
|
||||
this->state_.MAGN_TARGET = 3;
|
||||
this->state_.AGC_LNA_PRIORITY = 1;
|
||||
this->state_.FILTER_LENGTH = 1;
|
||||
this->state_.WAIT_TIME = 1;
|
||||
this->state_.HYST_LEVEL = 2;
|
||||
this->state_.WOREVT1 = 0x87;
|
||||
this->state_.WOREVT0 = 0x6B;
|
||||
this->state_.RC_CAL = 1;
|
||||
this->state_.EVENT1 = 7;
|
||||
this->state_.RC_PD = 1;
|
||||
this->state_.MIX_CURRENT = 2;
|
||||
this->state_.LODIV_BUF_CURRENT_RX = 1;
|
||||
this->state_.LNA2MIX_CURRENT = 1;
|
||||
this->state_.LNA_CURRENT = 1;
|
||||
this->state_.LODIV_BUF_CURRENT_TX = 1;
|
||||
this->state_.FSCAL3_LO = 9;
|
||||
this->state_.CHP_CURR_CAL_EN = 2;
|
||||
this->state_.FSCAL3_HI = 2;
|
||||
this->state_.FSCAL2 = 0x0A;
|
||||
this->state_.FSCAL1 = 0x20;
|
||||
this->state_.FSCAL0 = 0x0D;
|
||||
this->state_.RCCTRL1 = 0x41;
|
||||
this->state_.FSTEST = 0x59;
|
||||
this->state_.PTEST = 0x7F;
|
||||
this->state_.AGCTEST = 0x3F;
|
||||
this->state_.TEST2 = 0x88;
|
||||
this->state_.TEST1 = 0x31;
|
||||
this->state_.TEST0_LO = 1;
|
||||
this->state_.VCO_SEL_CAL_EN = 1;
|
||||
this->state_.TEST0_HI = 2;
|
||||
|
||||
// PKTCTRL0
|
||||
this->state_.PKT_FORMAT = 3;
|
||||
this->state_.LENGTH_CONFIG = 2;
|
||||
this->state_.FS_AUTOCAL = 1;
|
||||
|
||||
// Default Settings
|
||||
this->set_frequency(433920);
|
||||
this->set_if_frequency(153);
|
||||
this->set_filter_bandwidth(203);
|
||||
this->set_channel(0);
|
||||
this->set_channel_spacing(200);
|
||||
this->set_symbol_rate(5000);
|
||||
this->set_sync_mode(SyncMode::SYNC_MODE_NONE);
|
||||
this->set_carrier_sense_above_threshold(true);
|
||||
this->set_modulation_type(Modulation::MODULATION_ASK_OOK);
|
||||
this->set_magn_target(MagnTarget::MAGN_TARGET_42DB);
|
||||
this->set_max_lna_gain(MaxLnaGain::MAX_LNA_GAIN_DEFAULT);
|
||||
this->set_max_dvga_gain(MaxDvgaGain::MAX_DVGA_GAIN_MINUS_3);
|
||||
this->set_lna_priority(false);
|
||||
this->set_wait_time(WaitTime::WAIT_TIME_32_SAMPLES);
|
||||
|
||||
// CRITICAL: Initialize PA Table to avoid transmitting 0 power (Silence)
|
||||
memset(this->pa_table_, 0, sizeof(this->pa_table_));
|
||||
this->set_output_power(10.0f);
|
||||
}
|
||||
|
||||
void CC1101Component::setup() {
|
||||
this->spi_setup();
|
||||
this->cs_->digital_write(true);
|
||||
delayMicroseconds(1);
|
||||
this->cs_->digital_write(false);
|
||||
delayMicroseconds(1);
|
||||
this->cs_->digital_write(true);
|
||||
delayMicroseconds(41);
|
||||
this->cs_->digital_write(false);
|
||||
delay(5);
|
||||
|
||||
this->strobe_(Command::RES);
|
||||
delay(5);
|
||||
|
||||
this->read_(Register::PARTNUM);
|
||||
this->read_(Register::VERSION);
|
||||
this->chip_id_ = encode_uint16(this->state_.PARTNUM, this->state_.VERSION);
|
||||
ESP_LOGD(TAG, "CC1101 found! Chip ID: 0x%04X", this->chip_id_);
|
||||
if (this->state_.VERSION == 0 || this->state_.PARTNUM == 0xFF) {
|
||||
ESP_LOGE(TAG, "Failed to verify CC1101.");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
this->initialized_ = true;
|
||||
|
||||
for (uint8_t i = 0; i <= static_cast<uint8_t>(Register::TEST0); i++) {
|
||||
if (i == static_cast<uint8_t>(Register::FSTEST) || i == static_cast<uint8_t>(Register::AGCTEST)) {
|
||||
continue;
|
||||
}
|
||||
this->write_(static_cast<Register>(i));
|
||||
}
|
||||
this->write_(Register::PATABLE, this->pa_table_, sizeof(this->pa_table_));
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
|
||||
void CC1101Component::dump_config() {
|
||||
static const char *const MODULATION_NAMES[] = {"2-FSK", "GFSK", "UNUSED", "ASK/OOK",
|
||||
"4-FSK", "UNUSED", "UNUSED", "MSK"};
|
||||
int32_t freq = static_cast<int32_t>(this->state_.FREQ2 << 16 | this->state_.FREQ1 << 8 | this->state_.FREQ0) *
|
||||
XTAL_FREQUENCY / (1 << 16);
|
||||
float symbol_rate =
|
||||
(((256.0f + this->state_.DRATE_M) * (1 << this->state_.DRATE_E)) / (1 << 28)) * XTAL_FREQUENCY * 1000.0f;
|
||||
float bw = XTAL_FREQUENCY / (8.0f * (4 + this->state_.CHANBW_M) * (1 << this->state_.CHANBW_E));
|
||||
ESP_LOGCONFIG(TAG, "CC1101:");
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Chip ID: 0x%04X\n"
|
||||
" Frequency: %" PRId32 " kHz\n"
|
||||
" Channel: %u\n"
|
||||
" Modulation: %s\n"
|
||||
" Symbol Rate: %.0f baud\n"
|
||||
" Filter Bandwidth: %.1f kHz\n"
|
||||
" Output Power: %.1f dBm",
|
||||
this->chip_id_, freq, this->state_.CHANNR, MODULATION_NAMES[this->state_.MOD_FORMAT & 0x07],
|
||||
symbol_rate, bw, this->output_power_effective_);
|
||||
}
|
||||
|
||||
void CC1101Component::begin_tx() {
|
||||
// Ensure Packet Format is 3 (Async Serial), use GDO0 as input during TX
|
||||
this->write_(Register::PKTCTRL0, 0x32);
|
||||
ESP_LOGV(TAG, "Beginning TX sequence");
|
||||
this->strobe_(Command::TX);
|
||||
if (!this->wait_for_state_(State::TX, 50)) {
|
||||
ESP_LOGW(TAG, "Timed out waiting for TX state!");
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::begin_rx() {
|
||||
ESP_LOGV(TAG, "Beginning RX sequence");
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
|
||||
void CC1101Component::reset() {
|
||||
this->strobe_(Command::RES);
|
||||
this->setup();
|
||||
}
|
||||
|
||||
void CC1101Component::set_idle() {
|
||||
ESP_LOGV(TAG, "Setting IDLE state");
|
||||
this->enter_idle_();
|
||||
}
|
||||
|
||||
void CC1101Component::set_gdo0_config(uint8_t value) {
|
||||
this->state_.GDO0_CFG = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::IOCFG0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_gdo2_config(uint8_t value) {
|
||||
this->state_.GDO2_CFG = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::IOCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
bool CC1101Component::wait_for_state_(State target_state, uint32_t timeout_ms) {
|
||||
uint32_t start = millis();
|
||||
while (millis() - start < timeout_ms) {
|
||||
this->read_(Register::MARCSTATE);
|
||||
State s = static_cast<State>(this->state_.MARC_STATE);
|
||||
if (s == target_state) {
|
||||
return true;
|
||||
}
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CC1101Component::enter_idle_() {
|
||||
this->strobe_(Command::IDLE);
|
||||
this->wait_for_state_(State::IDLE);
|
||||
}
|
||||
|
||||
uint8_t CC1101Component::strobe_(Command cmd) {
|
||||
uint8_t index = static_cast<uint8_t>(cmd);
|
||||
if (cmd < Command::RES || cmd > Command::NOP) {
|
||||
return 0xFF;
|
||||
}
|
||||
this->enable();
|
||||
uint8_t status_byte = this->transfer_byte(index);
|
||||
this->disable();
|
||||
return status_byte;
|
||||
}
|
||||
|
||||
void CC1101Component::write_(Register reg) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index);
|
||||
this->write_array(&this->state_.regs()[index], 1);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void CC1101Component::write_(Register reg, uint8_t value) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->state_.regs()[index] = value;
|
||||
this->write_(reg);
|
||||
}
|
||||
|
||||
void CC1101Component::write_(Register reg, const uint8_t *buffer, size_t length) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index | BUS_WRITE | BUS_BURST);
|
||||
this->write_array(buffer, length);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void CC1101Component::read_(Register reg) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index | BUS_READ | BUS_BURST);
|
||||
this->state_.regs()[index] = this->transfer_byte(0);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
void CC1101Component::read_(Register reg, uint8_t *buffer, size_t length) {
|
||||
uint8_t index = static_cast<uint8_t>(reg);
|
||||
this->enable();
|
||||
this->write_byte(index | BUS_READ | BUS_BURST);
|
||||
this->read_array(buffer, length);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
// Setters
|
||||
void CC1101Component::set_output_power(float value) {
|
||||
this->output_power_requested_ = value;
|
||||
int32_t freq = static_cast<int32_t>(this->state_.FREQ2 << 16 | this->state_.FREQ1 << 8 | this->state_.FREQ0) *
|
||||
XTAL_FREQUENCY / (1 << 16);
|
||||
uint8_t a = 0xC0;
|
||||
if (freq >= 300000 && freq <= 348000) {
|
||||
a = PowerTableItem::find(PA_TABLE_315, sizeof(PA_TABLE_315) / sizeof(PA_TABLE_315[0]), value);
|
||||
} else if (freq >= 378000 && freq <= 464000) {
|
||||
a = PowerTableItem::find(PA_TABLE_433, sizeof(PA_TABLE_433) / sizeof(PA_TABLE_433[0]), value);
|
||||
} else if (freq >= 779000 && freq < 900000) {
|
||||
a = PowerTableItem::find(PA_TABLE_868, sizeof(PA_TABLE_868) / sizeof(PA_TABLE_868[0]), value);
|
||||
} else if (freq >= 900000 && freq <= 928000) {
|
||||
a = PowerTableItem::find(PA_TABLE_915, sizeof(PA_TABLE_915) / sizeof(PA_TABLE_915[0]), value);
|
||||
}
|
||||
|
||||
if (static_cast<Modulation>(this->state_.MOD_FORMAT) == Modulation::MODULATION_ASK_OOK) {
|
||||
this->pa_table_[0] = 0;
|
||||
this->pa_table_[1] = a;
|
||||
} else {
|
||||
this->pa_table_[0] = a;
|
||||
this->pa_table_[1] = 0;
|
||||
}
|
||||
this->output_power_effective_ = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::PATABLE, this->pa_table_, sizeof(this->pa_table_));
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_rx_attenuation(RxAttenuation value) {
|
||||
this->state_.CLOSE_IN_RX = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::FIFOTHR);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_dc_blocking_filter(bool value) {
|
||||
this->state_.DEM_DCFILT_OFF = value ? 0 : 1;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_frequency(float value) {
|
||||
int32_t freq = static_cast<int32_t>(value * (1 << 16) / XTAL_FREQUENCY);
|
||||
this->state_.FREQ2 = static_cast<uint8_t>(freq >> 16);
|
||||
this->state_.FREQ1 = static_cast<uint8_t>(freq >> 8);
|
||||
this->state_.FREQ0 = static_cast<uint8_t>(freq);
|
||||
if (this->initialized_) {
|
||||
this->enter_idle_();
|
||||
this->write_(Register::FREQ2);
|
||||
this->write_(Register::FREQ1);
|
||||
this->write_(Register::FREQ0);
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_if_frequency(float value) {
|
||||
this->state_.FREQ_IF = value * (1 << 10) / XTAL_FREQUENCY;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::FSCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_filter_bandwidth(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(XTAL_FREQUENCY / (value * 8), 2, e, m);
|
||||
this->state_.CHANBW_E = e;
|
||||
this->state_.CHANBW_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG4);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_channel(uint8_t value) {
|
||||
this->state_.CHANNR = value;
|
||||
if (this->initialized_) {
|
||||
this->enter_idle_();
|
||||
this->write_(Register::CHANNR);
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_channel_spacing(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(value * (1 << 18) / XTAL_FREQUENCY, 8, e, m);
|
||||
this->state_.CHANSPC_E = e;
|
||||
this->state_.CHANSPC_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG1);
|
||||
this->write_(Register::MDMCFG0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_fsk_deviation(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(value * (1 << 17) / XTAL_FREQUENCY, 3, e, m);
|
||||
this->state_.DEVIATION_E = e;
|
||||
this->state_.DEVIATION_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::DEVIATN);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_msk_deviation(uint8_t value) {
|
||||
this->state_.DEVIATION_E = 0;
|
||||
this->state_.DEVIATION_M = value - 1;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::DEVIATN);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_symbol_rate(float value) {
|
||||
uint8_t e;
|
||||
uint32_t m;
|
||||
split_float(value * (1 << 28) / (XTAL_FREQUENCY * 1000), 8, e, m);
|
||||
this->state_.DRATE_E = e;
|
||||
this->state_.DRATE_M = static_cast<uint8_t>(m);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG4);
|
||||
this->write_(Register::MDMCFG3);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_sync_mode(SyncMode value) {
|
||||
this->state_.SYNC_MODE = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_carrier_sense_above_threshold(bool value) {
|
||||
this->state_.CARRIER_SENSE_ABOVE_THRESHOLD = value ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_modulation_type(Modulation value) {
|
||||
this->state_.MOD_FORMAT = static_cast<uint8_t>(value);
|
||||
this->state_.PA_POWER = value == Modulation::MODULATION_ASK_OOK ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->enter_idle_();
|
||||
this->write_(Register::MDMCFG2);
|
||||
this->write_(Register::FREND0);
|
||||
this->strobe_(Command::RX);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_manchester(bool value) {
|
||||
this->state_.MANCHESTER_EN = value ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_num_preamble(uint8_t value) {
|
||||
this->state_.NUM_PREAMBLE = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::MDMCFG1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_sync1(uint8_t value) {
|
||||
this->state_.SYNC1 = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::SYNC1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_sync0(uint8_t value) {
|
||||
this->state_.SYNC0 = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::SYNC0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_pktlen(uint8_t value) {
|
||||
this->state_.PKTLEN = value;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::PKTLEN);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_magn_target(MagnTarget value) {
|
||||
this->state_.MAGN_TARGET = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_max_lna_gain(MaxLnaGain value) {
|
||||
this->state_.MAX_LNA_GAIN = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_max_dvga_gain(MaxDvgaGain value) {
|
||||
this->state_.MAX_DVGA_GAIN = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL2);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_carrier_sense_abs_thr(int8_t value) {
|
||||
this->state_.CARRIER_SENSE_ABS_THR = static_cast<uint8_t>(value & 0b1111);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_carrier_sense_rel_thr(CarrierSenseRelThr value) {
|
||||
this->state_.CARRIER_SENSE_REL_THR = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_lna_priority(bool value) {
|
||||
this->state_.AGC_LNA_PRIORITY = value ? 1 : 0;
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL1);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_filter_length_fsk_msk(FilterLengthFskMsk value) {
|
||||
this->state_.FILTER_LENGTH = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_filter_length_ask_ook(FilterLengthAskOok value) {
|
||||
this->state_.FILTER_LENGTH = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_freeze(Freeze value) {
|
||||
this->state_.AGC_FREEZE = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_wait_time(WaitTime value) {
|
||||
this->state_.WAIT_TIME = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
void CC1101Component::set_hyst_level(HystLevel value) {
|
||||
this->state_.HYST_LEVEL = static_cast<uint8_t>(value);
|
||||
if (this->initialized_) {
|
||||
this->write_(Register::AGCCTRL0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::cc1101
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "cc1101defs.h"
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
class CC1101Component : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_1MHZ> {
|
||||
public:
|
||||
CC1101Component();
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
// Actions
|
||||
void begin_tx();
|
||||
void begin_rx();
|
||||
void reset();
|
||||
void set_idle();
|
||||
|
||||
// GDO Pin Configuration
|
||||
void set_gdo0_config(uint8_t value);
|
||||
void set_gdo2_config(uint8_t value);
|
||||
|
||||
// Configuration Setters
|
||||
void set_output_power(float value);
|
||||
void set_rx_attenuation(RxAttenuation value);
|
||||
void set_dc_blocking_filter(bool value);
|
||||
|
||||
// Tuner settings
|
||||
void set_frequency(float value);
|
||||
void set_if_frequency(float value);
|
||||
void set_filter_bandwidth(float value);
|
||||
void set_channel(uint8_t value);
|
||||
void set_channel_spacing(float value);
|
||||
void set_fsk_deviation(float value);
|
||||
void set_msk_deviation(uint8_t value);
|
||||
void set_symbol_rate(float value);
|
||||
void set_sync_mode(SyncMode value);
|
||||
void set_carrier_sense_above_threshold(bool value);
|
||||
void set_modulation_type(Modulation value);
|
||||
void set_manchester(bool value);
|
||||
void set_num_preamble(uint8_t value);
|
||||
void set_sync1(uint8_t value);
|
||||
void set_sync0(uint8_t value);
|
||||
void set_pktlen(uint8_t value);
|
||||
|
||||
// AGC settings
|
||||
void set_magn_target(MagnTarget value);
|
||||
void set_max_lna_gain(MaxLnaGain value);
|
||||
void set_max_dvga_gain(MaxDvgaGain value);
|
||||
void set_carrier_sense_abs_thr(int8_t value);
|
||||
void set_carrier_sense_rel_thr(CarrierSenseRelThr value);
|
||||
void set_lna_priority(bool value);
|
||||
void set_filter_length_fsk_msk(FilterLengthFskMsk value);
|
||||
void set_filter_length_ask_ook(FilterLengthAskOok value);
|
||||
void set_freeze(Freeze value);
|
||||
void set_wait_time(WaitTime value);
|
||||
void set_hyst_level(HystLevel value);
|
||||
|
||||
protected:
|
||||
uint16_t chip_id_{0};
|
||||
bool initialized_{false};
|
||||
|
||||
float output_power_requested_{10.0f};
|
||||
float output_power_effective_{10.0f};
|
||||
uint8_t pa_table_[PA_TABLE_SIZE]{};
|
||||
|
||||
CC1101State state_;
|
||||
|
||||
// Low-level Helpers
|
||||
uint8_t strobe_(Command cmd);
|
||||
void write_(Register reg);
|
||||
void write_(Register reg, uint8_t value);
|
||||
void write_(Register reg, const uint8_t *buffer, size_t length);
|
||||
void read_(Register reg);
|
||||
void read_(Register reg, uint8_t *buffer, size_t length);
|
||||
|
||||
// State Management
|
||||
bool wait_for_state_(State target_state, uint32_t timeout_ms = 100);
|
||||
void enter_idle_();
|
||||
};
|
||||
|
||||
// Action Wrappers
|
||||
template<typename... Ts> class BeginTxAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->begin_tx(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class BeginRxAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->begin_rx(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class ResetAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->reset(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetIdleAction : public Action<Ts...>, public Parented<CC1101Component> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->set_idle(); }
|
||||
};
|
||||
|
||||
} // namespace esphome::cc1101
|
||||
@@ -0,0 +1,644 @@
|
||||
#pragma once
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
static constexpr float XTAL_FREQUENCY = 26000;
|
||||
|
||||
static constexpr uint8_t BUS_BURST = 0x40;
|
||||
static constexpr uint8_t BUS_READ = 0x80;
|
||||
static constexpr uint8_t BUS_WRITE = 0x00;
|
||||
static constexpr uint8_t BYTES_IN_RXFIFO = 0x7F; // byte number in RXfifo
|
||||
static constexpr size_t PA_TABLE_SIZE = 8;
|
||||
|
||||
enum class Register : uint8_t {
|
||||
IOCFG2 = 0x00, // GDO2 output pin configuration
|
||||
IOCFG1 = 0x01, // GDO1 output pin configuration
|
||||
IOCFG0 = 0x02, // GDO0 output pin configuration
|
||||
FIFOTHR = 0x03, // RX FIFO and TX FIFO thresholds
|
||||
SYNC1 = 0x04, // Sync word, high INT8U
|
||||
SYNC0 = 0x05, // Sync word, low INT8U
|
||||
PKTLEN = 0x06, // Packet length
|
||||
PKTCTRL1 = 0x07, // Packet automation control
|
||||
PKTCTRL0 = 0x08, // Packet automation control
|
||||
ADDR = 0x09, // Device address
|
||||
CHANNR = 0x0A, // Channel number
|
||||
FSCTRL1 = 0x0B, // Frequency synthesizer control
|
||||
FSCTRL0 = 0x0C, // Frequency synthesizer control
|
||||
FREQ2 = 0x0D, // Frequency control word, high INT8U
|
||||
FREQ1 = 0x0E, // Frequency control word, middle INT8U
|
||||
FREQ0 = 0x0F, // Frequency control word, low INT8U
|
||||
MDMCFG4 = 0x10, // Modem configuration
|
||||
MDMCFG3 = 0x11, // Modem configuration
|
||||
MDMCFG2 = 0x12, // Modem configuration
|
||||
MDMCFG1 = 0x13, // Modem configuration
|
||||
MDMCFG0 = 0x14, // Modem configuration
|
||||
DEVIATN = 0x15, // Modem deviation setting
|
||||
MCSM2 = 0x16, // Main Radio Control State Machine configuration
|
||||
MCSM1 = 0x17, // Main Radio Control State Machine configuration
|
||||
MCSM0 = 0x18, // Main Radio Control State Machine configuration
|
||||
FOCCFG = 0x19, // Frequency Offset Compensation configuration
|
||||
BSCFG = 0x1A, // Bit Synchronization configuration
|
||||
AGCCTRL2 = 0x1B, // AGC control
|
||||
AGCCTRL1 = 0x1C, // AGC control
|
||||
AGCCTRL0 = 0x1D, // AGC control
|
||||
WOREVT1 = 0x1E, // High INT8U Event 0 timeout
|
||||
WOREVT0 = 0x1F, // Low INT8U Event 0 timeout
|
||||
WORCTRL = 0x20, // Wake On Radio control
|
||||
FREND1 = 0x21, // Front end RX configuration
|
||||
FREND0 = 0x22, // Front end TX configuration
|
||||
FSCAL3 = 0x23, // Frequency synthesizer calibration
|
||||
FSCAL2 = 0x24, // Frequency synthesizer calibration
|
||||
FSCAL1 = 0x25, // Frequency synthesizer calibration
|
||||
FSCAL0 = 0x26, // Frequency synthesizer calibration
|
||||
RCCTRL1 = 0x27, // RC oscillator configuration
|
||||
RCCTRL0 = 0x28, // RC oscillator configuration
|
||||
FSTEST = 0x29, // Frequency synthesizer calibration control
|
||||
PTEST = 0x2A, // Production test
|
||||
AGCTEST = 0x2B, // AGC test
|
||||
TEST2 = 0x2C, // Various test settings
|
||||
TEST1 = 0x2D, // Various test settings
|
||||
TEST0 = 0x2E, // Various test settings
|
||||
UNUSED = 0x2F,
|
||||
PARTNUM = 0x30,
|
||||
VERSION = 0x31,
|
||||
FREQEST = 0x32,
|
||||
LQI = 0x33,
|
||||
RSSI = 0x34,
|
||||
MARCSTATE = 0x35,
|
||||
WORTIME1 = 0x36,
|
||||
WORTIME0 = 0x37,
|
||||
PKTSTATUS = 0x38,
|
||||
VCO_VC_DAC = 0x39,
|
||||
TXBYTES = 0x3A,
|
||||
RXBYTES = 0x3B,
|
||||
RCCTRL1_STATUS = 0x3C,
|
||||
RCCTRL0_STATUS = 0x3D,
|
||||
PATABLE = 0x3E,
|
||||
FIFO = 0x3F,
|
||||
};
|
||||
|
||||
enum class Command : uint8_t {
|
||||
RES = 0x30, // Reset chip.
|
||||
FSTXON = 0x31, // Enable and calibrate frequency synthesizer
|
||||
XOFF = 0x32, // Turn off crystal oscillator.
|
||||
CAL = 0x33, // Calibrate frequency synthesizer and turn it off
|
||||
RX = 0x34, // Enable RX.
|
||||
TX = 0x35, // Enable TX.
|
||||
IDLE = 0x36, // Exit RX / TX
|
||||
// 0x37 is RESERVED / UNDEFINED in CC1101 Datasheet
|
||||
WOR = 0x38, // Start automatic RX polling sequence (Wake-on-Radio)
|
||||
PWD = 0x39, // Enter power down mode when CSn goes high.
|
||||
FRX = 0x3A, // Flush the RX FIFO buffer.
|
||||
FTX = 0x3B, // Flush the TX FIFO buffer.
|
||||
WORRST = 0x3C, // Reset real time clock.
|
||||
NOP = 0x3D, // No operation.
|
||||
};
|
||||
|
||||
enum class State : uint8_t {
|
||||
SLEEP,
|
||||
IDLE,
|
||||
XOFF,
|
||||
VCOON_MC,
|
||||
REGON_MC,
|
||||
MANCAL,
|
||||
VCOON,
|
||||
REGON,
|
||||
STARTCAL,
|
||||
BWBOOST,
|
||||
FS_LOCK,
|
||||
IFADCON,
|
||||
ENDCAL,
|
||||
RX,
|
||||
RX_END,
|
||||
RX_RST,
|
||||
TXRX_SWITCH,
|
||||
RXFIFO_OVERFLOW,
|
||||
FSTXON,
|
||||
TX,
|
||||
TX_END,
|
||||
RXTX_SWITCH,
|
||||
TXFIFO_UNDERFLOW,
|
||||
};
|
||||
|
||||
enum class RxAttenuation : uint8_t {
|
||||
RX_ATTENUATION_0DB,
|
||||
RX_ATTENUATION_6DB,
|
||||
RX_ATTENUATION_12DB,
|
||||
RX_ATTENUATION_18DB,
|
||||
};
|
||||
|
||||
enum class SyncMode : uint8_t {
|
||||
SYNC_MODE_NONE,
|
||||
SYNC_MODE_15_16,
|
||||
SYNC_MODE_16_16,
|
||||
SYNC_MODE_30_32,
|
||||
};
|
||||
|
||||
enum class Modulation : uint8_t {
|
||||
MODULATION_2_FSK,
|
||||
MODULATION_GFSK,
|
||||
MODULATION_UNUSED_2,
|
||||
MODULATION_ASK_OOK,
|
||||
MODULATION_4_FSK,
|
||||
MODULATION_UNUSED_5,
|
||||
MODULATION_UNUSED_6,
|
||||
MODULATION_MSK,
|
||||
};
|
||||
|
||||
enum class MagnTarget : uint8_t {
|
||||
MAGN_TARGET_24DB,
|
||||
MAGN_TARGET_27DB,
|
||||
MAGN_TARGET_30DB,
|
||||
MAGN_TARGET_33DB,
|
||||
MAGN_TARGET_36DB,
|
||||
MAGN_TARGET_38DB,
|
||||
MAGN_TARGET_40DB,
|
||||
MAGN_TARGET_42DB,
|
||||
};
|
||||
|
||||
enum class MaxLnaGain : uint8_t {
|
||||
MAX_LNA_GAIN_DEFAULT,
|
||||
MAX_LNA_GAIN_MINUS_2P6DB,
|
||||
MAX_LNA_GAIN_MINUS_6P1DB,
|
||||
MAX_LNA_GAIN_MINUS_7P4DB,
|
||||
MAX_LNA_GAIN_MINUS_9P2DB,
|
||||
MAX_LNA_GAIN_MINUS_11P5DB,
|
||||
MAX_LNA_GAIN_MINUS_14P6DB,
|
||||
MAX_LNA_GAIN_MINUS_17P1DB,
|
||||
};
|
||||
|
||||
enum class MaxDvgaGain : uint8_t {
|
||||
MAX_DVGA_GAIN_DEFAULT,
|
||||
MAX_DVGA_GAIN_MINUS_1,
|
||||
MAX_DVGA_GAIN_MINUS_2,
|
||||
MAX_DVGA_GAIN_MINUS_3,
|
||||
};
|
||||
|
||||
enum class CarrierSenseRelThr : uint8_t {
|
||||
CARRIER_SENSE_REL_THR_DEFAULT,
|
||||
CARRIER_SENSE_REL_THR_PLUS_6DB,
|
||||
CARRIER_SENSE_REL_THR_PLUS_10DB,
|
||||
CARRIER_SENSE_REL_THR_PLUS_14DB,
|
||||
};
|
||||
|
||||
enum class FilterLengthFskMsk : uint8_t {
|
||||
FILTER_LENGTH_8DB,
|
||||
FILTER_LENGTH_16DB,
|
||||
FILTER_LENGTH_32DB,
|
||||
FILTER_LENGTH_64DB,
|
||||
};
|
||||
|
||||
enum class FilterLengthAskOok : uint8_t {
|
||||
FILTER_LENGTH_4DB,
|
||||
FILTER_LENGTH_8DB,
|
||||
FILTER_LENGTH_12DB,
|
||||
FILTER_LENGTH_16DB,
|
||||
};
|
||||
|
||||
enum class Freeze : uint8_t {
|
||||
FREEZE_DEFAULT,
|
||||
FREEZE_ON_SYNC,
|
||||
FREEZE_ANALOG_ONLY,
|
||||
FREEZE_ANALOG_AND_DIGITAL,
|
||||
};
|
||||
|
||||
enum class WaitTime : uint8_t {
|
||||
WAIT_TIME_8_SAMPLES,
|
||||
WAIT_TIME_16_SAMPLES,
|
||||
WAIT_TIME_24_SAMPLES,
|
||||
WAIT_TIME_32_SAMPLES,
|
||||
};
|
||||
|
||||
enum class HystLevel : uint8_t {
|
||||
HYST_LEVEL_NONE,
|
||||
HYST_LEVEL_LOW,
|
||||
HYST_LEVEL_MEDIUM,
|
||||
HYST_LEVEL_HIGH,
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) CC1101State {
|
||||
// Byte array accessors for bulk SPI transfers
|
||||
uint8_t *regs() { return reinterpret_cast<uint8_t *>(this); }
|
||||
const uint8_t *regs() const { return reinterpret_cast<const uint8_t *>(this); }
|
||||
|
||||
// 0x00
|
||||
union {
|
||||
uint8_t IOCFG2;
|
||||
struct {
|
||||
uint8_t GDO2_CFG : 6;
|
||||
uint8_t GDO2_INV : 1;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x01
|
||||
union {
|
||||
uint8_t IOCFG1;
|
||||
struct {
|
||||
uint8_t GDO1_CFG : 6;
|
||||
uint8_t GDO1_INV : 1;
|
||||
uint8_t GDO_DS : 1; // GDO, not GD0
|
||||
};
|
||||
};
|
||||
// 0x02
|
||||
union {
|
||||
uint8_t IOCFG0;
|
||||
struct {
|
||||
uint8_t GDO0_CFG : 6;
|
||||
uint8_t GDO0_INV : 1;
|
||||
uint8_t TEMP_SENSOR_ENABLE : 1;
|
||||
};
|
||||
};
|
||||
// 0x03
|
||||
union {
|
||||
uint8_t FIFOTHR;
|
||||
struct {
|
||||
uint8_t FIFO_THR : 4;
|
||||
uint8_t CLOSE_IN_RX : 2; // RxAttenuation
|
||||
uint8_t ADC_RETENTION : 1;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x04
|
||||
uint8_t SYNC1;
|
||||
// 0x05
|
||||
uint8_t SYNC0;
|
||||
// 0x06
|
||||
uint8_t PKTLEN;
|
||||
// 0x07
|
||||
union {
|
||||
uint8_t PKTCTRL1;
|
||||
struct {
|
||||
uint8_t ADR_CHK : 2;
|
||||
uint8_t APPEND_STATUS : 1;
|
||||
uint8_t CRC_AUTOFLUSH : 1;
|
||||
uint8_t : 1;
|
||||
uint8_t PQT : 3;
|
||||
};
|
||||
};
|
||||
// 0x08
|
||||
union {
|
||||
uint8_t PKTCTRL0;
|
||||
struct {
|
||||
uint8_t LENGTH_CONFIG : 2;
|
||||
uint8_t CRC_EN : 1;
|
||||
uint8_t : 1;
|
||||
uint8_t PKT_FORMAT : 2;
|
||||
uint8_t WHITE_DATA : 1;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x09
|
||||
uint8_t ADDR;
|
||||
// 0x0A
|
||||
uint8_t CHANNR;
|
||||
// 0x0B
|
||||
union {
|
||||
uint8_t FSCTRL1;
|
||||
struct {
|
||||
uint8_t FREQ_IF : 5;
|
||||
uint8_t RESERVED : 1; // hm?
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x0C
|
||||
uint8_t FSCTRL0;
|
||||
// 0x0D
|
||||
uint8_t FREQ2; // [7:6] always zero
|
||||
// 0x0E
|
||||
uint8_t FREQ1;
|
||||
// 0x0F
|
||||
uint8_t FREQ0;
|
||||
// 0x10
|
||||
union {
|
||||
uint8_t MDMCFG4;
|
||||
struct {
|
||||
uint8_t DRATE_E : 4;
|
||||
uint8_t CHANBW_M : 2;
|
||||
uint8_t CHANBW_E : 2;
|
||||
};
|
||||
};
|
||||
// 0x11
|
||||
union {
|
||||
uint8_t MDMCFG3;
|
||||
struct {
|
||||
uint8_t DRATE_M : 8;
|
||||
};
|
||||
};
|
||||
// 0x12
|
||||
union {
|
||||
uint8_t MDMCFG2;
|
||||
struct {
|
||||
uint8_t SYNC_MODE : 2;
|
||||
uint8_t CARRIER_SENSE_ABOVE_THRESHOLD : 1;
|
||||
uint8_t MANCHESTER_EN : 1;
|
||||
uint8_t MOD_FORMAT : 3; // Modulation
|
||||
uint8_t DEM_DCFILT_OFF : 1;
|
||||
};
|
||||
};
|
||||
// 0x13
|
||||
union {
|
||||
uint8_t MDMCFG1;
|
||||
struct {
|
||||
uint8_t CHANSPC_E : 2;
|
||||
uint8_t : 2;
|
||||
uint8_t NUM_PREAMBLE : 3;
|
||||
uint8_t FEC_EN : 1;
|
||||
};
|
||||
};
|
||||
// 0x14
|
||||
union {
|
||||
uint8_t MDMCFG0;
|
||||
struct {
|
||||
uint8_t CHANSPC_M : 8;
|
||||
};
|
||||
};
|
||||
// 0x15
|
||||
union {
|
||||
uint8_t DEVIATN;
|
||||
struct {
|
||||
uint8_t DEVIATION_M : 3;
|
||||
uint8_t : 1;
|
||||
uint8_t DEVIATION_E : 3;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x16
|
||||
union {
|
||||
uint8_t MCSM2;
|
||||
struct {
|
||||
uint8_t RX_TIME : 3;
|
||||
uint8_t RX_TIME_QUAL : 1;
|
||||
uint8_t RX_TIME_RSSI : 1;
|
||||
uint8_t : 3;
|
||||
};
|
||||
};
|
||||
// 0x17
|
||||
union {
|
||||
uint8_t MCSM1;
|
||||
struct {
|
||||
uint8_t TXOFF_MODE : 2;
|
||||
uint8_t RXOFF_MODE : 2;
|
||||
uint8_t CCA_MODE : 2;
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x18
|
||||
union {
|
||||
uint8_t MCSM0;
|
||||
struct {
|
||||
uint8_t XOSC_FORCE_ON : 1;
|
||||
uint8_t PIN_CTRL_EN : 1;
|
||||
uint8_t PO_TIMEOUT : 2;
|
||||
uint8_t FS_AUTOCAL : 2;
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x19
|
||||
union {
|
||||
uint8_t FOCCFG;
|
||||
struct {
|
||||
uint8_t FOC_LIMIT : 2;
|
||||
uint8_t FOC_POST_K : 1;
|
||||
uint8_t FOC_PRE_K : 2;
|
||||
uint8_t FOC_BS_CS_GATE : 1;
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x1A
|
||||
union {
|
||||
uint8_t BSCFG;
|
||||
struct {
|
||||
uint8_t BS_LIMIT : 2;
|
||||
uint8_t BS_POST_KP : 1;
|
||||
uint8_t BS_POST_KI : 1;
|
||||
uint8_t BS_PRE_KP : 2;
|
||||
uint8_t BS_PRE_KI : 2;
|
||||
};
|
||||
};
|
||||
// 0x1B
|
||||
union {
|
||||
uint8_t AGCCTRL2;
|
||||
struct {
|
||||
uint8_t MAGN_TARGET : 3; // MagnTarget
|
||||
uint8_t MAX_LNA_GAIN : 3; // MaxLnaGain
|
||||
uint8_t MAX_DVGA_GAIN : 2; // MaxDvgaGain
|
||||
};
|
||||
};
|
||||
// 0x1C
|
||||
union {
|
||||
uint8_t AGCCTRL1;
|
||||
struct {
|
||||
uint8_t CARRIER_SENSE_ABS_THR : 4;
|
||||
uint8_t CARRIER_SENSE_REL_THR : 2; // CarrierSenseRelThr
|
||||
uint8_t AGC_LNA_PRIORITY : 1;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x1D
|
||||
union {
|
||||
uint8_t AGCCTRL0;
|
||||
struct {
|
||||
uint8_t FILTER_LENGTH : 2; // FilterLengthFskMsk or FilterLengthAskOok
|
||||
uint8_t AGC_FREEZE : 2; // Freeze
|
||||
uint8_t WAIT_TIME : 2; // WaitTime
|
||||
uint8_t HYST_LEVEL : 2; // HystLevel
|
||||
};
|
||||
};
|
||||
// 0x1E
|
||||
uint8_t WOREVT1;
|
||||
// 0x1F
|
||||
uint8_t WOREVT0;
|
||||
// 0x20
|
||||
union {
|
||||
uint8_t WORCTRL;
|
||||
struct {
|
||||
uint8_t WOR_RES : 2;
|
||||
uint8_t : 1;
|
||||
uint8_t RC_CAL : 1;
|
||||
uint8_t EVENT1 : 3;
|
||||
uint8_t RC_PD : 1;
|
||||
};
|
||||
};
|
||||
// 0x21
|
||||
union {
|
||||
uint8_t FREND1;
|
||||
struct {
|
||||
uint8_t MIX_CURRENT : 2;
|
||||
uint8_t LODIV_BUF_CURRENT_RX : 2;
|
||||
uint8_t LNA2MIX_CURRENT : 2;
|
||||
uint8_t LNA_CURRENT : 2;
|
||||
};
|
||||
};
|
||||
// 0x22
|
||||
union {
|
||||
uint8_t FREND0;
|
||||
struct {
|
||||
uint8_t PA_POWER : 3;
|
||||
uint8_t : 1;
|
||||
uint8_t LODIV_BUF_CURRENT_TX : 2;
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x23
|
||||
union {
|
||||
uint8_t FSCAL3;
|
||||
struct {
|
||||
uint8_t FSCAL3_LO : 4;
|
||||
uint8_t CHP_CURR_CAL_EN : 2; // Disable charge pump calibration stage when 0.
|
||||
uint8_t FSCAL3_HI : 2;
|
||||
};
|
||||
};
|
||||
// 0x24
|
||||
union {
|
||||
// uint8_t FSCAL2;
|
||||
struct {
|
||||
uint8_t FSCAL2 : 5;
|
||||
uint8_t VCO_CORE_H_EN : 1;
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x25
|
||||
union {
|
||||
// uint8_t FSCAL1;
|
||||
struct {
|
||||
uint8_t FSCAL1 : 6;
|
||||
uint8_t : 2;
|
||||
};
|
||||
};
|
||||
// 0x26
|
||||
union {
|
||||
// uint8_t FSCAL0;
|
||||
struct {
|
||||
uint8_t FSCAL0 : 7;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x27
|
||||
union {
|
||||
// uint8_t RCCTRL1;
|
||||
struct {
|
||||
uint8_t RCCTRL1 : 7;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x28
|
||||
union {
|
||||
// uint8_t RCCTRL0;
|
||||
struct {
|
||||
uint8_t RCCTRL0 : 7;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x29
|
||||
uint8_t FSTEST;
|
||||
// 0x2A
|
||||
uint8_t PTEST;
|
||||
// 0x2B
|
||||
uint8_t AGCTEST;
|
||||
// 0x2C
|
||||
uint8_t TEST2;
|
||||
// 0x2D
|
||||
uint8_t TEST1;
|
||||
// 0x2E
|
||||
union {
|
||||
uint8_t TEST0;
|
||||
struct {
|
||||
uint8_t TEST0_LO : 1;
|
||||
uint8_t VCO_SEL_CAL_EN : 1; // Enable VCO selection calibration stage when 1
|
||||
uint8_t TEST0_HI : 6;
|
||||
};
|
||||
};
|
||||
// 0x2F
|
||||
uint8_t REG_2F;
|
||||
// 0x30
|
||||
uint8_t PARTNUM;
|
||||
// 0x31
|
||||
uint8_t VERSION;
|
||||
// 0x32
|
||||
union {
|
||||
uint8_t FREQEST;
|
||||
struct {
|
||||
int8_t FREQOFF_EST : 8;
|
||||
};
|
||||
};
|
||||
// 0x33
|
||||
union {
|
||||
uint8_t LQI;
|
||||
struct {
|
||||
uint8_t LQI_EST : 7;
|
||||
uint8_t LQI_CRC_OK : 1;
|
||||
};
|
||||
};
|
||||
// 0x34
|
||||
int8_t RSSI;
|
||||
// 0x35
|
||||
union {
|
||||
// uint8_t MARCSTATE;
|
||||
struct {
|
||||
uint8_t MARC_STATE : 5; // State
|
||||
uint8_t : 3;
|
||||
};
|
||||
};
|
||||
// 0x36
|
||||
uint8_t WORTIME1;
|
||||
// 0x37
|
||||
uint8_t WORTIME0;
|
||||
// 0x38
|
||||
union {
|
||||
uint8_t PKTSTATUS;
|
||||
struct {
|
||||
uint8_t GDO0 : 1;
|
||||
uint8_t : 1;
|
||||
uint8_t GDO2 : 1;
|
||||
uint8_t SFD : 1;
|
||||
uint8_t CCA : 1;
|
||||
uint8_t PQT_REACHED : 1;
|
||||
uint8_t CS : 1;
|
||||
uint8_t CRC_OK : 1; // same as LQI_CRC_OK?
|
||||
};
|
||||
};
|
||||
// 0x39
|
||||
uint8_t VCO_VC_DAC;
|
||||
// 0x3A
|
||||
union {
|
||||
uint8_t TXBYTES;
|
||||
struct {
|
||||
uint8_t NUM_TXBYTES : 7;
|
||||
uint8_t TXFIFO_UNDERFLOW : 1;
|
||||
};
|
||||
};
|
||||
// 0x3B
|
||||
union {
|
||||
uint8_t RXBYTES;
|
||||
struct {
|
||||
uint8_t NUM_RXBYTES : 7;
|
||||
uint8_t RXFIFO_OVERFLOW : 1;
|
||||
};
|
||||
};
|
||||
// 0x3C
|
||||
union {
|
||||
// uint8_t RCCTRL1_STATUS;
|
||||
struct {
|
||||
uint8_t RCCTRL1_STATUS : 7;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x3D
|
||||
union {
|
||||
// uint8_t RCCTRL0_STATUS;
|
||||
struct {
|
||||
uint8_t RCCTRL0_STATUS : 7;
|
||||
uint8_t : 1;
|
||||
};
|
||||
};
|
||||
// 0x3E
|
||||
uint8_t REG_3E;
|
||||
// 0x3F
|
||||
uint8_t REG_3F;
|
||||
};
|
||||
|
||||
static_assert(sizeof(CC1101State) == 0x40, "CC1101State size mismatch");
|
||||
|
||||
} // namespace esphome::cc1101
|
||||
@@ -0,0 +1,174 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
|
||||
namespace esphome::cc1101 {
|
||||
|
||||
// CC1101 Design Note DN013
|
||||
|
||||
struct PowerTableItem {
|
||||
uint8_t value;
|
||||
uint8_t dbm_diff; // starts from 12.0, diff to previous entry, scaled by 10
|
||||
|
||||
static uint8_t find(const PowerTableItem *items, size_t count, float &dbm_target) {
|
||||
int32_t dbmi = 120;
|
||||
int32_t dbmi_target = static_cast<int32_t>(std::lround(dbm_target * 10));
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
dbmi -= items[i].dbm_diff;
|
||||
if (dbmi_target >= dbmi) {
|
||||
// Skip invalid PA settings (magic numbers derived from TI DN013/SmartRC logic)
|
||||
if (items[i].value >= 0x61 && items[i].value <= 0x6F) {
|
||||
continue;
|
||||
}
|
||||
dbm_target = static_cast<float>(dbmi) / 10.0f;
|
||||
return items[i].value;
|
||||
}
|
||||
}
|
||||
dbm_target = -30.0f;
|
||||
return 0x03;
|
||||
}
|
||||
};
|
||||
|
||||
static const PowerTableItem PA_TABLE_315[] = {
|
||||
{0xC0, 14}, // C0 10.6 -35.3 -44.4 -57.8 -53.8 -58.3 -57.2 -57.8 -56.7 28.5
|
||||
{0xC3, 10}, // C3 9.6 -39.2 -45.3 -59.0 -54.2 -59.0 -57.5 -58.3 -57.2 26.2
|
||||
{0xC6, 11}, // C6 8.5 -43.2 -46.3 -59.2 -54.7 -59.1 -57.7 -58.3 -57.4 24.4
|
||||
{0xC9, 10}, // C9 7.5 -47.0 -47.3 -58.9 -55.0 -59.0 -57.9 -58.4 -57.5 23.0
|
||||
{0x81, 12}, // 81 6.3 -49.2 -45.7 -57.3 -53.6 -59.0 -56.0 -56.5 -57.5 19.5
|
||||
{0x85, 13}, // 85 5.0 -51.0 -47.2 -59.8 -54.2 -59.0 -56.9 -57.9 -58.0 18.3
|
||||
{0x88, 11}, // 88 3.9 -46.6 -48.1 -60.0 -55.0 -58.9 -57.5 -58.2 -58.2 17.4
|
||||
{0xCF, 11}, // CF 2.8 -49.8 -51.3 -57.6 -56.8 -59.1 -58.4 -58.1 -58.3 18.0
|
||||
{0x8D, 11}, // 8D 1.7 -43.8 -49.5 -58.9 -56.3 -58.8 -58.2 -58.4 -58.5 15.8
|
||||
{0x50, 10}, // 50 0.7 -59.2 -51.2 -59.0 -56.5 -59.0 -58.3 -58.3 -58.2 15.3
|
||||
{0x40, 10}, // 40 -0.3 -58.2 -52.1 -59.4 -56.9 -59.0 -58.4 -58.4 -58.3 14.7
|
||||
{0x3D, 10}, // 3D -1.3 -54.4 -48.4 -59.8 -57.5 -58.9 -58.3 -58.5 -58.5 19.3
|
||||
{0x55, 10}, // 55 -2.3 -56.7 -53.6 -59.7 -57.5 -59.1 -58.7 -58.4 -58.4 13.7
|
||||
{0x39, 11}, // 39 -3.4 -50.9 -49.5 -59.8 -58.0 -59.0 -58.5 -58.4 -58.4 16.8
|
||||
{0x2B, 15}, // 2B -4.9 -51.2 -50.4 -59.9 -58.0 -58.9 -58.7 -58.3 -58.4 15.6
|
||||
{0x29, 16}, // 29 -6.5 -51.8 -51.6 -59.9 -58.4 -59.0 -58.8 -58.3 -58.3 14.7
|
||||
{0x28, 10}, // 28 -7.5 -52.2 -52.5 -60.0 -58.6 -59.0 -58.8 -58.2 -58.4 14.3
|
||||
{0x27, 11}, // 27 -8.6 -52.9 -53.1 -60.0 -58.8 -59.1 -58.8 -58.3 -58.5 13.9
|
||||
{0x26, 12}, // 26 -9.8 -53.6 -54.3 -60.1 -58.7 -59.0 -58.7 -58.4 -58.4 13.4
|
||||
{0x25, 13}, // 25 -11.1 -54.3 -55.5 -60.1 -58.8 -59.1 -58.8 -58.4 -58.4 13.0
|
||||
{0x33, 11}, // 33 -12.2 -55.0 -56.3 -60.0 -58.7 -59.0 -58.9 -58.4 -58.4 12.8
|
||||
{0x1F, 11}, // 1F -13.3 -55.6 -57.2 -60.0 -58.8 -58.9 -58.9 -58.3 -58.4 12.4
|
||||
{0x1D, 12}, // 1D -14.5 -56.0 -58.0 -60.0 -58.8 -59.1 -58.7 -58.4 -58.5 12.1
|
||||
{0x32, 11}, // 32 -15.6 -56.9 -58.8 -59.9 -58.8 -59.0 -58.8 -58.3 -58.5 12.2
|
||||
{0x1A, 10}, // 1A -16.6 -57.3 -59.5 -59.9 -58.8 -59.1 -58.8 -58.4 -58.4 11.8
|
||||
{0x18, 19}, // 18 -18.5 -57.8 -60.3 -60.0 -58.8 -59.0 -58.9 -58.2 -58.5 11.6
|
||||
{0x17, 11}, // 17 -19.6 -58.7 -60.9 -60.0 -58.7 -58.9 -58.9 -58.5 -58.4 11.4
|
||||
{0x0C, 11}, // C -20.7 -59.4 -61.1 -60.0 -58.8 -59.1 -58.9 -58.4 -58.3 11.3
|
||||
{0x0A, 15}, // A -22.2 -59.9 -61.9 -60.0 -58.9 -59.0 -58.9 -58.4 -58.5 11.2
|
||||
{0x08, 18}, // 8 -24.0 -60.5 -62.5 -60.0 -58.7 -59.1 -58.8 -58.3 -58.5 11.1
|
||||
{0x07, 11}, // 7 -25.1 -61.3 -62.9 -60.1 -58.8 -59.1 -58.8 -58.4 -58.4 11.0
|
||||
{0x06, 13}, // 6 -26.4 -61.6 -63.2 -60.1 -58.7 -59.0 -58.9 -58.5 -58.5 11.0
|
||||
{0x05, 13}, // 5 -27.7 -62.3 -63.4 -60.1 -58.7 -59.2 -58.8 -58.4 -58.5 10.9
|
||||
{0x04, 19}, // 4 -29.6 -62.7 -63.6 -59.9 -58.7 -59.0 -58.9 -58.4 -58.4 10.8
|
||||
};
|
||||
|
||||
static const PowerTableItem PA_TABLE_433[] = {
|
||||
{0xC0, 21}, // C0 9.9 -43.4 -45.0 -53.9 -55.2 -55.8 -52.3 -55.6 29.1
|
||||
{0xC3, 11}, // C3 8.8 -49.3 -45.9 -55.9 -55.4 -57.2 -52.6 -57.5 26.9
|
||||
{0xC6, 10}, // C6 7.8 -56.2 -46.9 -56.9 -55.6 -58.2 -53.2 -57.9 25.2
|
||||
{0xC9, 10}, // C9 6.8 -56.1 -47.9 -57.3 -55.9 -58.5 -54.0 -56.9 23.8
|
||||
{0xCC, 10}, // CC 5.8 -52.8 -48.9 -57.0 -56.1 -58.4 -54.6 -56.2 22.6
|
||||
{0x85, 10}, // 85 4.8 -54.2 -53.0 -58.3 -55.0 -57.8 -56.8 -58.0 19.1
|
||||
{0x88, 12}, // 88 3.6 -56.2 -53.8 -58.3 -55.7 -58.1 -57.2 -58.2 18.2
|
||||
{0x8B, 13}, // 8B 2.3 -57.7 -54.5 -58.0 -56.3 -58.1 -57.5 -58.2 17.3
|
||||
{0x8E, 19}, // 8E 0.4 -58.0 -55.5 -57.8 -57.4 -58.2 -58.1 -58.4 16.2
|
||||
{0x40, 12}, // 40 -0.8 -59.7 -56.1 -58.2 -57.7 -58.4 -58.3 -58.2 15.4
|
||||
{0x3C, 13}, // 3C -2.1 -60.6 -57.3 -58.2 -58.0 -58.5 -58.4 -58.5 19.3
|
||||
{0x3A, 10}, // 3A -3.1 -59.5 -57.5 -58.3 -58.3 -58.6 -58.1 -58.6 18.1
|
||||
{0x8F, 15}, // 8F -4.6 -52.2 -57.7 -58.1 -58.8 -58.4 -58.7 -58.3 14.4
|
||||
{0x37, 10}, // 37 -5.6 -56.8 -58.3 -58.3 -58.8 -58.4 -58.5 -58.4 16.2
|
||||
{0x36, 12}, // 36 -6.8 -56.8 -58.9 -58.3 -58.8 -58.3 -58.5 -58.5 15.6
|
||||
{0x28, 10}, // 28 -7.8 -56.6 -59.0 -58.2 -59.0 -58.4 -58.5 -58.4 15.1
|
||||
{0x26, 21}, // 26 -9.9 -57.0 -59.4 -58.3 -59.0 -58.4 -58.7 -58.4 14.3
|
||||
{0x25, 15}, // 25 -11.4 -57.3 -59.7 -58.4 -59.0 -58.3 -58.7 -58.5 13.9
|
||||
{0x24, 19}, // 24 -13.3 -57.9 -59.9 -58.2 -59.0 -58.6 -58.7 -58.5 13.5
|
||||
{0x1E, 10}, // 1E -14.3 -58.4 -59.8 -58.2 -59.0 -58.4 -58.6 -58.6 13.2
|
||||
{0x1C, 12}, // 1C -15.5 -58.6 -59.9 -58.4 -58.8 -58.6 -58.8 -58.5 12.9
|
||||
{0x1A, 15}, // 1A -17.0 -59.4 -59.9 -58.3 -59.1 -58.5 -58.7 -58.4 12.7
|
||||
{0x18, 18}, // 18 -18.8 -60.2 -59.9 -58.2 -59.0 -58.5 -58.7 -58.6 12.5
|
||||
{0x17, 10}, // 17 -19.8 -60.6 -59.9 -58.2 -58.9 -58.4 -58.7 -58.4 12.4
|
||||
{0x0C, 12}, // C -21.0 -61.1 -59.9 -58.4 -59.0 -58.5 -58.7 -58.6 12.3
|
||||
{0x15, 15}, // 15 -22.5 -61.7 -60.0 -58.2 -59.1 -58.3 -58.6 -58.7 12.2
|
||||
{0x08, 18}, // 8 -24.3 -62.3 -59.9 -58.3 -59.0 -58.4 -58.8 -58.5 12.1
|
||||
{0x07, 10}, // 7 -25.3 -62.6 -59.9 -58.2 -59.0 -58.6 -58.7 -58.5 12.0
|
||||
{0x06, 12}, // 6 -26.5 -63.2 -59.9 -58.3 -58.9 -58.5 -58.6 -58.6 12.0
|
||||
{0x05, 14}, // 5 -27.9 -63.5 -59.8 -58.3 -59.1 -58.5 -58.7 -58.4 11.9
|
||||
{0x04, 16}, // 4 -29.5 -63.7 -59.9 -58.3 -58.9 -58.5 -58.5 -58.5 11.9
|
||||
};
|
||||
|
||||
static const PowerTableItem PA_TABLE_868[] = {
|
||||
{0xC0, 13}, // C0 10.7 -35.1 -58.6 -58.6 -57.5 -50.0 34.2
|
||||
{0xC3, 11}, // C3 9.6 -41.5 -58.5 -58.3 -57.4 -54.4 31.6
|
||||
{0xC6, 11}, // C6 8.5 -47.7 -58.5 -58.3 -57.6 -55.0 29.5
|
||||
{0xC9, 10}, // C9 7.5 -44.4 -58.5 -58.5 -57.7 -53.6 27.8
|
||||
{0xCC, 10}, // CC 6.5 -40.6 -58.6 -58.4 -57.6 -52.5 26.3
|
||||
{0xCE, 10}, // CE 5.5 -38.5 -58.5 -58.4 -57.8 -52.2 25.0
|
||||
{0x84, 11}, // 84 4.4 -35.3 -58.7 -58.5 -57.8 -55.8 20.3
|
||||
{0x87, 10}, // 87 3.4 -39.4 -58.6 -58.6 -57.8 -55.7 19.5
|
||||
{0xCF, 10}, // CF 2.4 -36.6 -58.6 -58.4 -57.7 -53.6 22.0
|
||||
{0x8C, 13}, // 8C 1.1 -50.2 -58.6 -58.5 -57.7 -55.9 17.9
|
||||
{0x50, 14}, // 50 -0.3 -42.1 -58.5 -58.5 -57.6 -57.1 16.9
|
||||
{0x40, 12}, // 40 -1.5 -43.2 -58.5 -58.7 -57.7 -57.2 16.1
|
||||
{0x3F, 11}, // 3F -2.6 -53.7 -58.6 -58.5 -57.8 -57.5 21.4
|
||||
{0x55, 10}, // 55 -3.6 -44.9 -58.6 -58.4 -57.8 -57.5 15.0
|
||||
{0x57, 12}, // 57 -4.8 -46.0 -58.6 -58.5 -57.6 -57.4 14.5
|
||||
{0x8F, 12}, // 8F -6.0 -51.6 -58.5 -58.6 -57.7 -57.1 15.0
|
||||
{0x2A, 14}, // 2A -7.4 -49.3 -58.5 -58.6 -57.7 -57.4 16.2
|
||||
{0x28, 16}, // 28 -9.0 -49.0 -58.5 -58.6 -57.7 -57.4 15.4
|
||||
{0x26, 20}, // 26 -11.0 -49.2 -58.5 -58.5 -57.7 -57.4 14.6
|
||||
{0x25, 15}, // 25 -12.5 -49.5 -58.6 -58.6 -57.8 -57.3 14.1
|
||||
{0x24, 18}, // 24 -14.3 -50.2 -58.5 -58.4 -57.8 -57.4 13.7
|
||||
{0x1D, 14}, // 1D -15.7 -50.7 -58.6 -58.6 -57.8 -57.5 13.3
|
||||
{0x1B, 13}, // 1B -17.0 -51.3 -58.5 -58.4 -57.7 -57.5 13.1
|
||||
{0x19, 16}, // 19 -18.6 -52.0 -58.6 -58.5 -57.8 -57.5 12.9
|
||||
{0x22, 10}, // 22 -19.6 -52.5 -58.5 -58.6 -57.7 -57.4 12.9
|
||||
{0x0D, 15}, // D -21.1 -53.3 -58.6 -58.6 -57.8 -57.4 12.6
|
||||
{0x0B, 12}, // B -22.3 -53.9 -58.6 -58.5 -57.8 -57.4 12.5
|
||||
{0x09, 15}, // 9 -23.8 -54.7 -58.5 -58.5 -57.8 -57.5 12.4
|
||||
{0x21, 10}, // 21 -24.8 -55.1 -58.5 -58.5 -57.7 -57.5 12.5
|
||||
{0x13, 17}, // 13 -26.5 -55.9 -58.6 -58.5 -57.6 -57.6 12.3
|
||||
{0x05, 12}, // 5 -27.7 -56.4 -58.4 -58.4 -57.7 -57.5 12.2
|
||||
{0x12, 12}, // 12 -28.9 -57.1 -58.4 -58.5 -57.7 -57.3 12.2
|
||||
};
|
||||
|
||||
static const PowerTableItem PA_TABLE_915[] = {
|
||||
{0xC0, 26}, // C0 9.4 -33.5 -58.5 -58.4 -55.8 -32.6 31.8
|
||||
{0xC3, 11}, // C3 8.3 -41.5 -58.6 -58.4 -56.3 -38.0 29.3
|
||||
{0xC6, 11}, // C6 7.2 -42.5 -58.5 -58.4 -56.7 -40.5 27.4
|
||||
{0xC9, 10}, // C9 6.2 -37.6 -58.6 -58.4 -57.2 -38.8 25.9
|
||||
{0xCD, 12}, // CD 5.0 -34.2 -58.6 -58.5 -57.5 -37.3 24.3
|
||||
{0x84, 11}, // 84 3.9 -32.0 -58.6 -58.4 -57.7 -40.1 19.7
|
||||
{0x87, 10}, // 87 2.9 -36.5 -58.4 -58.5 -57.7 -39.6 18.9
|
||||
{0x8A, 11}, // 8A 1.8 -42.2 -58.5 -58.4 -57.7 -39.6 18.1
|
||||
{0x8D, 13}, // 8D 0.5 -46.8 -58.5 -58.5 -57.7 -40.4 17.3
|
||||
{0x8E, 11}, // 8E -0.6 -46.6 -58.5 -58.5 -57.8 -41.1 16.7
|
||||
{0x51, 10}, // 51 -1.6 -38.7 -58.4 -58.5 -57.7 -46.9 16.0
|
||||
{0x3E, 11}, // 3E -2.7 -50.0 -58.5 -58.4 -57.6 -55.3 20.7
|
||||
{0x3B, 11}, // 3B -3.8 -50.7 -58.6 -58.4 -57.6 -55.2 18.9
|
||||
{0x39, 13}, // 39 -5.1 -50.0 -58.5 -58.5 -57.6 -54.0 17.7
|
||||
{0x2B, 13}, // 2B -6.4 -47.6 -58.4 -58.4 -57.8 -52.1 16.5
|
||||
{0x36, 15}, // 36 -7.9 -46.9 -58.5 -58.4 -57.7 -51.2 15.8
|
||||
{0x35, 14}, // 35 -9.3 -46.7 -58.6 -58.4 -57.7 -50.7 15.2
|
||||
{0x26, 16}, // 26 -10.9 -47.0 -58.6 -58.4 -57.8 -50.9 14.5
|
||||
{0x25, 14}, // 25 -12.3 -47.2 -58.6 -58.3 -57.7 -51.0 14.1
|
||||
{0x24, 18}, // 24 -14.1 -48.1 -58.4 -58.4 -57.8 -51.4 13.7
|
||||
{0x1D, 14}, // 1D -15.5 -48.7 -58.4 -58.5 -57.7 -51.9 13.2
|
||||
{0x1B, 13}, // 1B -16.8 -49.3 -58.6 -58.4 -57.8 -52.3 13.0
|
||||
{0x19, 15}, // 19 -18.3 -50.2 -58.5 -58.5 -57.6 -52.8 12.8
|
||||
{0x18, 10}, // 18 -19.3 -50.6 -58.5 -58.5 -57.7 -53.1 12.7
|
||||
{0x17, 10}, // 17 -20.3 -51.2 -58.6 -58.5 -57.8 -53.1 12.6
|
||||
{0x0C, 11}, // C -21.4 -51.8 -58.4 -58.5 -57.7 -53.4 12.5
|
||||
{0x0A, 13}, // A -22.7 -52.6 -58.5 -58.4 -57.7 -53.6 12.4
|
||||
{0x08, 16}, // 8 -24.3 -53.6 -58.4 -58.4 -57.6 -54.1 12.3
|
||||
{0x13, 19}, // 13 -26.2 -54.6 -58.4 -58.5 -57.7 -54.3 12.2
|
||||
{0x05, 11}, // 5 -27.3 -55.3 -58.4 -58.4 -57.8 -54.5 12.1
|
||||
{0x12, 13}, // 12 -28.6 -55.9 -58.6 -58.5 -57.7 -54.7 12.1
|
||||
{0x03, 12}, // 3 -29.8 -56.9 -58.5 -58.4 -57.7 -54.7 12.0
|
||||
};
|
||||
} // namespace esphome::cc1101
|
||||
@@ -9,27 +9,40 @@ void CST816Touchscreen::continue_setup_() {
|
||||
this->interrupt_pin_->setup();
|
||||
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
|
||||
}
|
||||
if (this->read_byte(REG_CHIP_ID, &this->chip_id_)) {
|
||||
switch (this->chip_id_) {
|
||||
case CST820_CHIP_ID:
|
||||
case CST826_CHIP_ID:
|
||||
case CST716_CHIP_ID:
|
||||
case CST816S_CHIP_ID:
|
||||
case CST816D_CHIP_ID:
|
||||
case CST816T_CHIP_ID:
|
||||
break;
|
||||
default:
|
||||
|
||||
if (!this->read_byte(REG_CHIP_ID, &this->chip_id_) && !this->skip_probe_) {
|
||||
this->status_set_error(LOG_STR("Failed to read chip ID"));
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
// CST826/CST836 return 0 for chip ID, need to read from factory ID register
|
||||
if (this->chip_id_ == 0) {
|
||||
if (!this->read_byte(REG_FACTORY_ID, &this->chip_id_) && !this->skip_probe_) {
|
||||
this->status_set_error(LOG_STR("Failed to read chip ID"));
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (this->chip_id_) {
|
||||
case CST716_CHIP_ID:
|
||||
case CST816S_CHIP_ID:
|
||||
case CST816D_CHIP_ID:
|
||||
case CST816T_CHIP_ID:
|
||||
case CST820_CHIP_ID:
|
||||
case CST826_CHIP_ID:
|
||||
case CST836_CHIP_ID:
|
||||
break;
|
||||
default:
|
||||
if (!this->skip_probe_) {
|
||||
ESP_LOGE(TAG, "Unknown chip ID: 0x%02X", this->chip_id_);
|
||||
this->status_set_error(LOG_STR("Unknown chip ID"));
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
this->write_byte(REG_IRQ_CTL, IRQ_EN_MOTION);
|
||||
} else if (!this->skip_probe_) {
|
||||
this->status_set_error(LOG_STR("Failed to read chip id"));
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->write_byte(REG_IRQ_CTL, IRQ_EN_MOTION);
|
||||
if (this->x_raw_max_ == this->x_raw_min_) {
|
||||
this->x_raw_max_ = this->display_->get_native_width();
|
||||
}
|
||||
@@ -80,11 +93,8 @@ void CST816Touchscreen::dump_config() {
|
||||
this->x_raw_min_, this->x_raw_max_, this->y_raw_min_, this->y_raw_max_);
|
||||
const char *name;
|
||||
switch (this->chip_id_) {
|
||||
case CST820_CHIP_ID:
|
||||
name = "CST820";
|
||||
break;
|
||||
case CST826_CHIP_ID:
|
||||
name = "CST826";
|
||||
case CST716_CHIP_ID:
|
||||
name = "CST716";
|
||||
break;
|
||||
case CST816S_CHIP_ID:
|
||||
name = "CST816S";
|
||||
@@ -92,12 +102,18 @@ void CST816Touchscreen::dump_config() {
|
||||
case CST816D_CHIP_ID:
|
||||
name = "CST816D";
|
||||
break;
|
||||
case CST716_CHIP_ID:
|
||||
name = "CST716";
|
||||
break;
|
||||
case CST816T_CHIP_ID:
|
||||
name = "CST816T";
|
||||
break;
|
||||
case CST820_CHIP_ID:
|
||||
name = "CST820";
|
||||
break;
|
||||
case CST826_CHIP_ID:
|
||||
name = "CST826";
|
||||
break;
|
||||
case CST836_CHIP_ID:
|
||||
name = "CST836";
|
||||
break;
|
||||
default:
|
||||
name = "Unknown";
|
||||
break;
|
||||
|
||||
@@ -19,12 +19,14 @@ static const uint8_t REG_YPOS_HIGH = 0x05;
|
||||
static const uint8_t REG_YPOS_LOW = 0x06;
|
||||
static const uint8_t REG_DIS_AUTOSLEEP = 0xFE;
|
||||
static const uint8_t REG_CHIP_ID = 0xA7;
|
||||
static const uint8_t REG_FACTORY_ID = 0xAA;
|
||||
static const uint8_t REG_FW_VERSION = 0xA9;
|
||||
static const uint8_t REG_SLEEP = 0xE5;
|
||||
static const uint8_t REG_IRQ_CTL = 0xFA;
|
||||
static const uint8_t IRQ_EN_MOTION = 0x70;
|
||||
|
||||
static const uint8_t CST826_CHIP_ID = 0x11;
|
||||
static const uint8_t CST836_CHIP_ID = 0x13;
|
||||
static const uint8_t CST820_CHIP_ID = 0xB7;
|
||||
static const uint8_t CST816S_CHIP_ID = 0xB4;
|
||||
static const uint8_t CST816D_CHIP_ID = 0xB6;
|
||||
|
||||
@@ -52,7 +52,10 @@ WAKEUP_PINS = {
|
||||
38,
|
||||
39,
|
||||
],
|
||||
VARIANT_ESP32C2: [0, 1, 2, 3, 4, 5],
|
||||
VARIANT_ESP32C3: [0, 1, 2, 3, 4, 5],
|
||||
VARIANT_ESP32C6: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||
VARIANT_ESP32H2: [7, 8, 9, 10, 11, 12, 13, 14],
|
||||
VARIANT_ESP32S2: [
|
||||
0,
|
||||
1,
|
||||
@@ -101,9 +104,6 @@ WAKEUP_PINS = {
|
||||
20,
|
||||
21,
|
||||
],
|
||||
VARIANT_ESP32C2: [0, 1, 2, 3, 4, 5],
|
||||
VARIANT_ESP32C6: [0, 1, 2, 3, 4, 5, 6, 7],
|
||||
VARIANT_ESP32H2: [7, 8, 9, 10, 11, 12, 13, 14],
|
||||
}
|
||||
|
||||
|
||||
@@ -122,10 +122,10 @@ def _validate_ex1_wakeup_mode(value):
|
||||
if value == "ANY_LOW":
|
||||
esp32.only_on_variant(
|
||||
supported=[
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
VARIANT_ESP32C6,
|
||||
VARIANT_ESP32H2,
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
],
|
||||
msg_prefix="ANY_LOW",
|
||||
)(value)
|
||||
|
||||
@@ -122,14 +122,14 @@ def get_cpu_frequencies(*frequencies):
|
||||
|
||||
CPU_FREQUENCIES = {
|
||||
VARIANT_ESP32: get_cpu_frequencies(80, 160, 240),
|
||||
VARIANT_ESP32S2: get_cpu_frequencies(80, 160, 240),
|
||||
VARIANT_ESP32S3: get_cpu_frequencies(80, 160, 240),
|
||||
VARIANT_ESP32C2: get_cpu_frequencies(80, 120),
|
||||
VARIANT_ESP32C3: get_cpu_frequencies(80, 160),
|
||||
VARIANT_ESP32C5: get_cpu_frequencies(80, 160, 240),
|
||||
VARIANT_ESP32C6: get_cpu_frequencies(80, 120, 160),
|
||||
VARIANT_ESP32H2: get_cpu_frequencies(16, 32, 48, 64, 96),
|
||||
VARIANT_ESP32P4: get_cpu_frequencies(40, 360, 400),
|
||||
VARIANT_ESP32S2: get_cpu_frequencies(80, 160, 240),
|
||||
VARIANT_ESP32S3: get_cpu_frequencies(80, 160, 240),
|
||||
}
|
||||
|
||||
# Make sure not missed here if a new variant added.
|
||||
@@ -921,6 +921,7 @@ async def to_code(config):
|
||||
)
|
||||
cg.set_cpp_standard("gnu++20")
|
||||
cg.add_build_flag("-DUSE_ESP32")
|
||||
cg.add_build_flag("-Wl,-z,noexecstack")
|
||||
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
|
||||
variant = config[CONF_VARIANT]
|
||||
cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{variant}")
|
||||
|
||||
@@ -13,36 +13,36 @@ KEY_SUBMODULES = "submodules"
|
||||
KEY_EXTRA_BUILD_FILES = "extra_build_files"
|
||||
|
||||
VARIANT_ESP32 = "ESP32"
|
||||
VARIANT_ESP32S2 = "ESP32S2"
|
||||
VARIANT_ESP32S3 = "ESP32S3"
|
||||
VARIANT_ESP32C2 = "ESP32C2"
|
||||
VARIANT_ESP32C3 = "ESP32C3"
|
||||
VARIANT_ESP32C5 = "ESP32C5"
|
||||
VARIANT_ESP32C6 = "ESP32C6"
|
||||
VARIANT_ESP32H2 = "ESP32H2"
|
||||
VARIANT_ESP32P4 = "ESP32P4"
|
||||
VARIANT_ESP32S2 = "ESP32S2"
|
||||
VARIANT_ESP32S3 = "ESP32S3"
|
||||
VARIANTS = [
|
||||
VARIANT_ESP32,
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
VARIANT_ESP32C2,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_ESP32C5,
|
||||
VARIANT_ESP32C6,
|
||||
VARIANT_ESP32H2,
|
||||
VARIANT_ESP32P4,
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
]
|
||||
|
||||
VARIANT_FRIENDLY = {
|
||||
VARIANT_ESP32: "ESP32",
|
||||
VARIANT_ESP32S2: "ESP32-S2",
|
||||
VARIANT_ESP32S3: "ESP32-S3",
|
||||
VARIANT_ESP32C2: "ESP32-C2",
|
||||
VARIANT_ESP32C3: "ESP32-C3",
|
||||
VARIANT_ESP32C5: "ESP32-C5",
|
||||
VARIANT_ESP32C6: "ESP32-C6",
|
||||
VARIANT_ESP32H2: "ESP32-H2",
|
||||
VARIANT_ESP32P4: "ESP32-P4",
|
||||
VARIANT_ESP32S2: "ESP32-S2",
|
||||
VARIANT_ESP32S3: "ESP32-S3",
|
||||
}
|
||||
|
||||
esp32_ns = cg.esphome_ns.namespace("esp32")
|
||||
|
||||
@@ -64,12 +64,12 @@ CAN_SPEEDS_ESP32_P4 = {**CAN_SPEEDS_ESP32_S2}
|
||||
|
||||
CAN_SPEEDS = {
|
||||
VARIANT_ESP32: CAN_SPEEDS_ESP32,
|
||||
VARIANT_ESP32S2: CAN_SPEEDS_ESP32_S2,
|
||||
VARIANT_ESP32S3: CAN_SPEEDS_ESP32_S3,
|
||||
VARIANT_ESP32C3: CAN_SPEEDS_ESP32_C3,
|
||||
VARIANT_ESP32C6: CAN_SPEEDS_ESP32_C6,
|
||||
VARIANT_ESP32H2: CAN_SPEEDS_ESP32_H2,
|
||||
VARIANT_ESP32P4: CAN_SPEEDS_ESP32_P4,
|
||||
VARIANT_ESP32S2: CAN_SPEEDS_ESP32_S2,
|
||||
VARIANT_ESP32S3: CAN_SPEEDS_ESP32_S3,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ static const char *const TAG = "esp32_can";
|
||||
|
||||
static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config) {
|
||||
switch (bitrate) {
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
case canbus::CAN_1KBPS:
|
||||
*t_config = (twai_timing_config_t) TWAI_TIMING_CONFIG_1KBITS();
|
||||
return true;
|
||||
|
||||
@@ -77,13 +77,13 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.SplitDefault(
|
||||
CONF_RMT_SYMBOLS,
|
||||
esp32=192,
|
||||
esp32_s2=192,
|
||||
esp32_s3=192,
|
||||
esp32_p4=192,
|
||||
esp32_c3=96,
|
||||
esp32_c5=96,
|
||||
esp32_c6=96,
|
||||
esp32_h2=96,
|
||||
esp32_p4=192,
|
||||
esp32_s2=192,
|
||||
esp32_s3=192,
|
||||
): cv.int_range(min=2),
|
||||
cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
|
||||
cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
|
||||
@@ -91,7 +91,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
|
||||
cv.Optional(CONF_USE_DMA): cv.All(
|
||||
esp32.only_on_variant(
|
||||
supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4]
|
||||
supported=[esp32.const.VARIANT_ESP32P4, esp32.const.VARIANT_ESP32S3]
|
||||
),
|
||||
cv.boolean,
|
||||
),
|
||||
|
||||
@@ -87,8 +87,8 @@ void EthernetComponent::setup() {
|
||||
.intr_flags = 0,
|
||||
};
|
||||
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
auto host = SPI2_HOST;
|
||||
#else
|
||||
auto host = SPI3_HOST;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import esphome.codegen as cg
|
||||
|
||||
gree_ns = cg.esphome_ns.namespace("gree")
|
||||
|
||||
@@ -3,11 +3,11 @@ from esphome.components import climate_ir
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_MODEL
|
||||
|
||||
from . import gree_ns
|
||||
|
||||
CODEOWNERS = ["@orestismers"]
|
||||
|
||||
AUTO_LOAD = ["climate_ir"]
|
||||
|
||||
gree_ns = cg.esphome_ns.namespace("gree")
|
||||
GreeClimate = gree_ns.class_("GreeClimate", climate_ir.ClimateIR)
|
||||
|
||||
Model = gree_ns.enum("Model")
|
||||
@@ -23,7 +23,7 @@ MODELS = {
|
||||
|
||||
CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(GreeClimate).extend(
|
||||
{
|
||||
cv.Required(CONF_MODEL): cv.enum(MODELS),
|
||||
cv.Required(CONF_MODEL): cv.enum(MODELS, lower=True),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -16,13 +16,28 @@ void GreeClimate::set_model(Model model) {
|
||||
this->model_ = model;
|
||||
}
|
||||
|
||||
void GreeClimate::set_mode_bit(uint8_t bit_mask, bool enabled) {
|
||||
if (enabled) {
|
||||
this->mode_bits_ |= bit_mask;
|
||||
} else {
|
||||
this->mode_bits_ &= ~bit_mask;
|
||||
}
|
||||
this->transmit_state();
|
||||
}
|
||||
|
||||
void GreeClimate::transmit_state() {
|
||||
uint8_t remote_state[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00};
|
||||
|
||||
remote_state[0] = this->fan_speed_() | this->operation_mode_();
|
||||
remote_state[1] = this->temperature_();
|
||||
|
||||
if (this->model_ == GREE_YAN || this->model_ == GREE_YX1FF || this->model_ == GREE_YAG) {
|
||||
if (this->model_ == GREE_YAN) {
|
||||
remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO, LIGHT, HEALTH, X-FAN
|
||||
remote_state[3] = 0x50; // bits 4..7 always 0101
|
||||
remote_state[4] = this->vertical_swing_();
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YX1FF || this->model_ == GREE_YAG) {
|
||||
remote_state[2] = 0x60;
|
||||
remote_state[3] = 0x50;
|
||||
remote_state[4] = this->vertical_swing_();
|
||||
@@ -41,7 +56,7 @@ void GreeClimate::transmit_state() {
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YAA || this->model_ == GREE_YAC || this->model_ == GREE_YAC1FB9) {
|
||||
remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN
|
||||
remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO, LIGHT, HEALTH, X-FAN
|
||||
remote_state[3] = 0x50; // bits 4..7 always 0101
|
||||
remote_state[6] = 0x20; // YAA1FB, FAA1FB1, YB1F2 bits 4..7 always 0010
|
||||
|
||||
@@ -52,6 +67,13 @@ void GreeClimate::transmit_state() {
|
||||
}
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YAN || this->model_ == GREE_YAA || this->model_ == GREE_YAC ||
|
||||
this->model_ == GREE_YAC1FB9) {
|
||||
// Merge the mode bits into remote_state[2]
|
||||
// Clear the mode bits (bits 4-7) and OR in the current mode_bits_
|
||||
remote_state[2] = (remote_state[2] & 0x0F) | this->mode_bits_;
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YX1FF) {
|
||||
if (this->fan_speed_() == GREE_FAN_TURBO) {
|
||||
remote_state[2] |= GREE_FAN_TURBO_BIT;
|
||||
|
||||
@@ -2,80 +2,79 @@
|
||||
|
||||
#include "esphome/components/climate_ir/climate_ir.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree {
|
||||
namespace esphome::gree {
|
||||
|
||||
// Values for GREE IR Controllers
|
||||
// Temperature
|
||||
const uint8_t GREE_TEMP_MIN = 16; // Celsius
|
||||
const uint8_t GREE_TEMP_MAX = 30; // Celsius
|
||||
static constexpr uint8_t GREE_TEMP_MIN = 16; // Celsius
|
||||
static constexpr uint8_t GREE_TEMP_MAX = 30; // Celsius
|
||||
|
||||
// Modes
|
||||
const uint8_t GREE_MODE_AUTO = 0x00;
|
||||
const uint8_t GREE_MODE_COOL = 0x01;
|
||||
const uint8_t GREE_MODE_HEAT = 0x04;
|
||||
const uint8_t GREE_MODE_DRY = 0x02;
|
||||
const uint8_t GREE_MODE_FAN = 0x03;
|
||||
static constexpr uint8_t GREE_MODE_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_MODE_COOL = 0x01;
|
||||
static constexpr uint8_t GREE_MODE_HEAT = 0x04;
|
||||
static constexpr uint8_t GREE_MODE_DRY = 0x02;
|
||||
static constexpr uint8_t GREE_MODE_FAN = 0x03;
|
||||
|
||||
const uint8_t GREE_MODE_OFF = 0x00;
|
||||
const uint8_t GREE_MODE_ON = 0x08;
|
||||
static constexpr uint8_t GREE_MODE_OFF = 0x00;
|
||||
static constexpr uint8_t GREE_MODE_ON = 0x08;
|
||||
|
||||
// Fan Speed
|
||||
const uint8_t GREE_FAN_AUTO = 0x00;
|
||||
const uint8_t GREE_FAN_1 = 0x10;
|
||||
const uint8_t GREE_FAN_2 = 0x20;
|
||||
const uint8_t GREE_FAN_3 = 0x30;
|
||||
static constexpr uint8_t GREE_FAN_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_FAN_1 = 0x10;
|
||||
static constexpr uint8_t GREE_FAN_2 = 0x20;
|
||||
static constexpr uint8_t GREE_FAN_3 = 0x30;
|
||||
|
||||
// IR Transmission
|
||||
const uint32_t GREE_IR_FREQUENCY = 38000;
|
||||
const uint32_t GREE_HEADER_MARK = 9000;
|
||||
const uint32_t GREE_HEADER_SPACE = 4000;
|
||||
const uint32_t GREE_BIT_MARK = 620;
|
||||
const uint32_t GREE_ONE_SPACE = 1600;
|
||||
const uint32_t GREE_ZERO_SPACE = 540;
|
||||
const uint32_t GREE_MESSAGE_SPACE = 19000;
|
||||
static constexpr uint32_t GREE_IR_FREQUENCY = 38000;
|
||||
static constexpr uint32_t GREE_HEADER_MARK = 9000;
|
||||
static constexpr uint32_t GREE_HEADER_SPACE = 4000;
|
||||
static constexpr uint32_t GREE_BIT_MARK = 620;
|
||||
static constexpr uint32_t GREE_ONE_SPACE = 1600;
|
||||
static constexpr uint32_t GREE_ZERO_SPACE = 540;
|
||||
static constexpr uint32_t GREE_MESSAGE_SPACE = 19000;
|
||||
|
||||
// Timing specific for YAC features (I-Feel mode)
|
||||
const uint32_t GREE_YAC_HEADER_MARK = 6000;
|
||||
const uint32_t GREE_YAC_HEADER_SPACE = 3000;
|
||||
const uint32_t GREE_YAC_BIT_MARK = 650;
|
||||
static constexpr uint32_t GREE_YAC_HEADER_MARK = 6000;
|
||||
static constexpr uint32_t GREE_YAC_HEADER_SPACE = 3000;
|
||||
static constexpr uint32_t GREE_YAC_BIT_MARK = 650;
|
||||
|
||||
// Timing specific to YAC1FB9
|
||||
const uint32_t GREE_YAC1FB9_HEADER_SPACE = 4500;
|
||||
const uint32_t GREE_YAC1FB9_MESSAGE_SPACE = 19980;
|
||||
static constexpr uint32_t GREE_YAC1FB9_HEADER_SPACE = 4500;
|
||||
static constexpr uint32_t GREE_YAC1FB9_MESSAGE_SPACE = 19980;
|
||||
|
||||
// State Frame size
|
||||
const uint8_t GREE_STATE_FRAME_SIZE = 8;
|
||||
static constexpr uint8_t GREE_STATE_FRAME_SIZE = 8;
|
||||
|
||||
// Only available on YAN
|
||||
// Vertical air directions. Note that these cannot be set on all heat pumps
|
||||
const uint8_t GREE_VDIR_AUTO = 0x00;
|
||||
const uint8_t GREE_VDIR_MANUAL = 0x00;
|
||||
const uint8_t GREE_VDIR_SWING = 0x01;
|
||||
const uint8_t GREE_VDIR_UP = 0x02;
|
||||
const uint8_t GREE_VDIR_MUP = 0x03;
|
||||
const uint8_t GREE_VDIR_MIDDLE = 0x04;
|
||||
const uint8_t GREE_VDIR_MDOWN = 0x05;
|
||||
const uint8_t GREE_VDIR_DOWN = 0x06;
|
||||
static constexpr uint8_t GREE_VDIR_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_VDIR_MANUAL = 0x00;
|
||||
static constexpr uint8_t GREE_VDIR_SWING = 0x01;
|
||||
static constexpr uint8_t GREE_VDIR_UP = 0x02;
|
||||
static constexpr uint8_t GREE_VDIR_MUP = 0x03;
|
||||
static constexpr uint8_t GREE_VDIR_MIDDLE = 0x04;
|
||||
static constexpr uint8_t GREE_VDIR_MDOWN = 0x05;
|
||||
static constexpr uint8_t GREE_VDIR_DOWN = 0x06;
|
||||
|
||||
// Only available on YAC/YAG
|
||||
// Horizontal air directions. Note that these cannot be set on all heat pumps
|
||||
const uint8_t GREE_HDIR_AUTO = 0x00;
|
||||
const uint8_t GREE_HDIR_MANUAL = 0x00;
|
||||
const uint8_t GREE_HDIR_SWING = 0x01;
|
||||
const uint8_t GREE_HDIR_LEFT = 0x02;
|
||||
const uint8_t GREE_HDIR_MLEFT = 0x03;
|
||||
const uint8_t GREE_HDIR_MIDDLE = 0x04;
|
||||
const uint8_t GREE_HDIR_MRIGHT = 0x05;
|
||||
const uint8_t GREE_HDIR_RIGHT = 0x06;
|
||||
static constexpr uint8_t GREE_HDIR_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_HDIR_MANUAL = 0x00;
|
||||
static constexpr uint8_t GREE_HDIR_SWING = 0x01;
|
||||
static constexpr uint8_t GREE_HDIR_LEFT = 0x02;
|
||||
static constexpr uint8_t GREE_HDIR_MLEFT = 0x03;
|
||||
static constexpr uint8_t GREE_HDIR_MIDDLE = 0x04;
|
||||
static constexpr uint8_t GREE_HDIR_MRIGHT = 0x05;
|
||||
static constexpr uint8_t GREE_HDIR_RIGHT = 0x06;
|
||||
|
||||
// Only available on YX1FF
|
||||
// Turbo (high) fan mode + sleep preset mode
|
||||
const uint8_t GREE_FAN_TURBO = 0x80;
|
||||
const uint8_t GREE_FAN_TURBO_BIT = 0x10;
|
||||
const uint8_t GREE_PRESET_NONE = 0x00;
|
||||
const uint8_t GREE_PRESET_SLEEP = 0x01;
|
||||
const uint8_t GREE_PRESET_SLEEP_BIT = 0x80;
|
||||
static constexpr uint8_t GREE_FAN_TURBO = 0x80;
|
||||
static constexpr uint8_t GREE_FAN_TURBO_BIT = 0x10;
|
||||
static constexpr uint8_t GREE_PRESET_NONE = 0x00;
|
||||
static constexpr uint8_t GREE_PRESET_SLEEP = 0x01;
|
||||
static constexpr uint8_t GREE_PRESET_SLEEP_BIT = 0x80;
|
||||
|
||||
// Model codes
|
||||
enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9, GREE_YX1FF, GREE_YAG };
|
||||
@@ -90,6 +89,7 @@ class GreeClimate : public climate_ir::ClimateIR {
|
||||
climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {}
|
||||
|
||||
void set_model(Model model);
|
||||
void set_mode_bit(uint8_t bit_mask, bool enabled);
|
||||
|
||||
protected:
|
||||
// Transmit via IR the state of this climate controller.
|
||||
@@ -103,7 +103,7 @@ class GreeClimate : public climate_ir::ClimateIR {
|
||||
uint8_t preset_();
|
||||
|
||||
Model model_{};
|
||||
uint8_t mode_bits_{0}; // Combined mode bits for remote_state[2]
|
||||
};
|
||||
|
||||
} // namespace gree
|
||||
} // namespace esphome
|
||||
} // namespace esphome::gree
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import switch
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_LIGHT, DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
|
||||
import esphome.final_validate as fv
|
||||
|
||||
from .. import gree_ns
|
||||
from ..climate import CONF_MODEL, GreeClimate
|
||||
|
||||
CODEOWNERS = ["@nagyrobi"]
|
||||
|
||||
GreeModeBitSwitch = gree_ns.class_("GreeModeBitSwitch", switch.Switch, cg.Component)
|
||||
|
||||
CONF_TURBO = "turbo"
|
||||
CONF_HEALTH = "health"
|
||||
CONF_XFAN = "xfan"
|
||||
CONF_GREE_ID = "gree_id"
|
||||
|
||||
# Switch configurations: (config_key, display_name, bit_mask, icon)
|
||||
SWITCH_CONFIGS = (
|
||||
(CONF_TURBO, "Gree Turbo Switch", 0x10, "mdi:car-turbocharger"),
|
||||
(CONF_LIGHT, "Gree Light Switch", 0x20, "mdi:led-outline"),
|
||||
(CONF_HEALTH, "Gree Health Switch", 0x40, "mdi:pine-tree"),
|
||||
(CONF_XFAN, "Gree X-FAN Switch", 0x80, "mdi:wall-sconce-flat"),
|
||||
)
|
||||
|
||||
SUPPORTED_MODELS = {
|
||||
"yan",
|
||||
"yaa",
|
||||
"yac",
|
||||
"yac1fb9",
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_GREE_ID): cv.use_id(GreeClimate),
|
||||
**{
|
||||
cv.Optional(key): switch.switch_schema(
|
||||
GreeModeBitSwitch,
|
||||
icon=icon,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
device_class=DEVICE_CLASS_SWITCH,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
)
|
||||
for key, _, _, icon in SWITCH_CONFIGS
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _validate_model(config):
|
||||
full_config = fv.full_config.get()
|
||||
climate_path = full_config.get_path_for_id(config[CONF_GREE_ID])[:-1]
|
||||
climate_conf = full_config.get_config_for_path(climate_path)
|
||||
if climate_conf[CONF_MODEL] not in SUPPORTED_MODELS:
|
||||
raise cv.Invalid(
|
||||
"Gree switches are only supported for the "
|
||||
+ ", ".join(SUPPORTED_MODELS)
|
||||
+ " models"
|
||||
)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _validate_model
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
parent = await cg.get_variable(config[CONF_GREE_ID])
|
||||
|
||||
for conf_key, name, bit_mask, _ in SWITCH_CONFIGS:
|
||||
if switch_conf := config.get(conf_key):
|
||||
sw = cg.new_Pvariable(switch_conf[cv.CONF_ID], name, bit_mask)
|
||||
await switch.register_switch(sw, switch_conf)
|
||||
await cg.register_component(sw, switch_conf)
|
||||
await cg.register_parented(sw, parent)
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "gree_switch.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree {
|
||||
|
||||
static const char *const TAG = "gree.switch";
|
||||
|
||||
void GreeModeBitSwitch::setup() {
|
||||
auto initial = this->get_initial_state_with_restore_mode();
|
||||
if (initial.has_value()) {
|
||||
this->write_state(*initial);
|
||||
}
|
||||
}
|
||||
|
||||
void GreeModeBitSwitch::dump_config() { log_switch(TAG, " ", this->name_, this); }
|
||||
|
||||
void GreeModeBitSwitch::write_state(bool state) {
|
||||
this->parent_->set_mode_bit(this->bit_mask_, state);
|
||||
this->publish_state(state);
|
||||
}
|
||||
|
||||
} // namespace gree
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
#include "esphome/components/gree/gree.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree {
|
||||
|
||||
class GreeModeBitSwitch : public switch_::Switch, public Component, public Parented<GreeClimate> {
|
||||
public:
|
||||
GreeModeBitSwitch(const char *name, uint8_t bit_mask) : name_(name), bit_mask_(bit_mask) {}
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void write_state(bool state) override;
|
||||
|
||||
protected:
|
||||
const char *name_;
|
||||
uint8_t bit_mask_;
|
||||
};
|
||||
|
||||
} // namespace gree
|
||||
} // namespace esphome
|
||||
@@ -72,13 +72,13 @@ I2S_ROLE_OPTIONS = {
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h (SOC_I2S_NUM)
|
||||
I2S_PORTS = {
|
||||
VARIANT_ESP32: 2,
|
||||
VARIANT_ESP32S2: 1,
|
||||
VARIANT_ESP32S3: 2,
|
||||
VARIANT_ESP32C3: 1,
|
||||
VARIANT_ESP32C5: 1,
|
||||
VARIANT_ESP32C6: 1,
|
||||
VARIANT_ESP32H2: 1,
|
||||
VARIANT_ESP32P4: 3,
|
||||
VARIANT_ESP32S2: 1,
|
||||
VARIANT_ESP32S3: 2,
|
||||
}
|
||||
|
||||
i2s_channel_fmt_t = cg.global_ns.enum("i2s_channel_fmt_t")
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <driver/uart.h>
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include <driver/usb_serial_jtag.h>
|
||||
#include <hal/usb_serial_jtag_ll.h>
|
||||
#endif
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
extern "C" {
|
||||
uint8_t temprature_sens_read();
|
||||
}
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "driver/temperature_sensor.h"
|
||||
#endif // USE_ESP32_VARIANT
|
||||
#endif // USE_ESP32
|
||||
@@ -27,9 +27,9 @@ namespace internal_temperature {
|
||||
|
||||
static const char *const TAG = "internal_temperature";
|
||||
#ifdef USE_ESP32
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
static temperature_sensor_handle_t tsensNew = NULL;
|
||||
#endif // USE_ESP32_VARIANT
|
||||
#endif // USE_ESP32
|
||||
@@ -43,9 +43,9 @@ void InternalTemperatureSensor::update() {
|
||||
ESP_LOGV(TAG, "Raw temperature value: %d", raw);
|
||||
temperature = (raw - 32) / 1.8f;
|
||||
success = (raw != 128);
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
esp_err_t result = temperature_sensor_get_celsius(tsensNew, &temperature);
|
||||
success = (result == ESP_OK);
|
||||
if (!success) {
|
||||
@@ -81,9 +81,9 @@ void InternalTemperatureSensor::update() {
|
||||
|
||||
void InternalTemperatureSensor::setup() {
|
||||
#ifdef USE_ESP32
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
|
||||
|
||||
esp_err_t result = temperature_sensor_install(&tsens_config, &tsensNew);
|
||||
|
||||
@@ -204,8 +204,10 @@ void LD2420Component::dump_config() {
|
||||
LOG_BUTTON(" ", "Factory Reset:", this->factory_reset_button_);
|
||||
LOG_BUTTON(" ", "Restart Module:", this->restart_module_button_);
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
ESP_LOGCONFIG(TAG, "Select:");
|
||||
LOG_SELECT(" ", "Operating Mode", this->operating_selector_);
|
||||
#endif
|
||||
if (ld2420::get_firmware_int(this->firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
ESP_LOGW(TAG, "Firmware version %s and older supports Simple Mode only", this->firmware_ver_);
|
||||
}
|
||||
@@ -237,12 +239,20 @@ void LD2420Component::setup() {
|
||||
memcpy(&this->new_config, &this->current_config, sizeof(this->current_config));
|
||||
if (ld2420::get_firmware_int(this->firmware_ver_) < CALIBRATE_VERSION_MIN) {
|
||||
this->set_operating_mode(OP_SIMPLE_MODE_STRING);
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
}
|
||||
#endif
|
||||
this->set_mode_(CMD_SYSTEM_MODE_SIMPLE);
|
||||
ESP_LOGW(TAG, "Firmware version %s and older supports Simple Mode only", this->firmware_ver_);
|
||||
} else {
|
||||
this->set_mode_(CMD_SYSTEM_MODE_ENERGY);
|
||||
this->operating_selector_->publish_state(OP_NORMAL_MODE_STRING);
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(OP_NORMAL_MODE_STRING);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef USE_NUMBER
|
||||
this->init_gate_config_numbers();
|
||||
@@ -382,8 +392,12 @@ void LD2420Component::set_operating_mode(const char *state) {
|
||||
// If unsupported firmware ignore mode select
|
||||
if (ld2420::get_firmware_int(firmware_ver_) >= CALIBRATE_VERSION_MIN) {
|
||||
this->current_operating_mode = find_uint8(OP_MODE_BY_STR, state);
|
||||
// Entering Auto Calibrate we need to clear the privoiuos data collection
|
||||
this->operating_selector_->publish_state(state);
|
||||
// Entering Auto Calibrate we need to clear the previous data collection
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(state);
|
||||
}
|
||||
#endif
|
||||
if (current_operating_mode == OP_CALIBRATE_MODE) {
|
||||
this->set_calibration_(true);
|
||||
for (uint8_t gate = 0; gate < TOTAL_GATES; gate++) {
|
||||
@@ -403,7 +417,11 @@ void LD2420Component::set_operating_mode(const char *state) {
|
||||
}
|
||||
} else {
|
||||
this->current_operating_mode = OP_SIMPLE_MODE;
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
#ifdef USE_SELECT
|
||||
if (this->operating_selector_ != nullptr) {
|
||||
this->operating_selector_->publish_state(OP_SIMPLE_MODE_STRING);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,14 +100,14 @@ CONF_TASK_LOG_BUFFER_SIZE = "task_log_buffer_size"
|
||||
|
||||
UART_SELECTION_ESP32 = {
|
||||
VARIANT_ESP32: [UART0, UART1, UART2],
|
||||
VARIANT_ESP32S2: [UART0, UART1, USB_CDC],
|
||||
VARIANT_ESP32S3: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32C3: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32C2: [UART0, UART1],
|
||||
VARIANT_ESP32C3: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32C5: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32C6: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32H2: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32P4: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
VARIANT_ESP32S2: [UART0, UART1, USB_CDC],
|
||||
VARIANT_ESP32S3: [UART0, UART1, USB_CDC, USB_SERIAL_JTAG],
|
||||
}
|
||||
|
||||
UART_SELECTION_ESP8266 = [UART0, UART0_SWAP, UART1]
|
||||
@@ -238,12 +238,12 @@ CONFIG_SCHEMA = cv.All(
|
||||
CONF_HARDWARE_UART,
|
||||
esp8266=UART0,
|
||||
esp32=UART0,
|
||||
esp32_s2=USB_CDC,
|
||||
esp32_s3=USB_SERIAL_JTAG,
|
||||
esp32_c3=USB_SERIAL_JTAG,
|
||||
esp32_c5=USB_SERIAL_JTAG,
|
||||
esp32_c6=USB_SERIAL_JTAG,
|
||||
esp32_p4=USB_SERIAL_JTAG,
|
||||
esp32_s2=USB_CDC,
|
||||
esp32_s3=USB_SERIAL_JTAG,
|
||||
rp2040=USB_CDC,
|
||||
bk72xx=DEFAULT,
|
||||
ln882x=DEFAULT,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import importlib
|
||||
import logging
|
||||
from pathlib import Path
|
||||
import pkgutil
|
||||
|
||||
from esphome.automation import build_automation, validate_automation
|
||||
@@ -26,6 +27,7 @@ from esphome.core import CORE, ID, Lambda
|
||||
from esphome.cpp_generator import MockObj
|
||||
from esphome.final_validate import full_config
|
||||
from esphome.helpers import write_file_if_changed
|
||||
from esphome.yaml_util import load_yaml
|
||||
|
||||
from . import defines as df, helpers, lv_validation as lvalid, widgets
|
||||
from .automation import disp_update, focused_widgets, refreshed_widgets
|
||||
@@ -37,7 +39,6 @@ from .encoders import (
|
||||
initial_focus_to_code,
|
||||
)
|
||||
from .gradient import GRADIENT_SCHEMA, gradients_to_code
|
||||
from .hello_world import get_hello_world
|
||||
from .keypads import KEYPADS_CONFIG, keypads_to_code
|
||||
from .lv_validation import lv_bool, lv_images_used
|
||||
from .lvcode import LvContext, LvglComponent, lvgl_static
|
||||
@@ -84,6 +85,7 @@ DEPENDENCIES = ["display"]
|
||||
AUTO_LOAD = ["key_provider"]
|
||||
CODEOWNERS = ["@clydebarrow"]
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
HELLO_WORLD_FILE = "hello_world.yaml"
|
||||
|
||||
|
||||
SIMPLE_TRIGGERS = (
|
||||
@@ -354,7 +356,8 @@ def display_schema(config):
|
||||
def add_hello_world(config):
|
||||
if df.CONF_WIDGETS not in config and CONF_PAGES not in config:
|
||||
LOGGER.info("No pages or widgets configured, creating default hello_world page")
|
||||
config[df.CONF_WIDGETS] = any_widget_schema()(get_hello_world())
|
||||
hello_world_path = Path(__file__).parent / HELLO_WORLD_FILE
|
||||
config[df.CONF_WIDGETS] = any_widget_schema()(load_yaml(hello_world_path))
|
||||
return config
|
||||
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
from io import StringIO
|
||||
|
||||
from esphome.yaml_util import parse_yaml
|
||||
|
||||
CONFIG = """
|
||||
- obj:
|
||||
id: hello_world_card_
|
||||
pad_all: 12
|
||||
bg_color: white
|
||||
height: 100%
|
||||
width: 100%
|
||||
scrollable: false
|
||||
widgets:
|
||||
- obj:
|
||||
align: top_mid
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
pad_all: 4
|
||||
scrollable: false
|
||||
height: size_content
|
||||
width: 100%
|
||||
layout:
|
||||
type: flex
|
||||
flex_flow: row
|
||||
flex_align_cross: center
|
||||
flex_align_track: start
|
||||
flex_align_main: space_between
|
||||
widgets:
|
||||
- button:
|
||||
checkable: true
|
||||
radius: 4
|
||||
text_font: montserrat_20
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Clicked!"
|
||||
widgets:
|
||||
- label:
|
||||
text: "Button"
|
||||
- label:
|
||||
id: hello_world_title_
|
||||
text: ESPHome
|
||||
text_font: montserrat_20
|
||||
width: 100%
|
||||
text_align: center
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_title_
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 400;
|
||||
- checkbox:
|
||||
text: Checkbox
|
||||
id: hello_world_checkbox_
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_checkbox_
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 240;
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Checked!"
|
||||
- obj:
|
||||
id: hello_world_container_
|
||||
align: center
|
||||
y: 14
|
||||
pad_all: 0
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
width: 100%
|
||||
height: size_content
|
||||
scrollable: false
|
||||
on_click:
|
||||
lvgl.spinner.update:
|
||||
id: hello_world_spinner_
|
||||
arc_color: springgreen
|
||||
layout:
|
||||
type: flex
|
||||
flex_flow: row_wrap
|
||||
flex_align_cross: center
|
||||
flex_align_track: center
|
||||
flex_align_main: space_evenly
|
||||
widgets:
|
||||
- spinner:
|
||||
id: hello_world_spinner_
|
||||
indicator:
|
||||
arc_color: tomato
|
||||
height: 100
|
||||
width: 100
|
||||
spin_time: 2s
|
||||
arc_length: 60deg
|
||||
widgets:
|
||||
- label:
|
||||
id: hello_world_label_
|
||||
text: "Hello World!"
|
||||
align: center
|
||||
- obj:
|
||||
id: hello_world_qrcode_
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 300 && lv_obj_get_height(lv_scr_act()) < 400;
|
||||
widgets:
|
||||
- label:
|
||||
text_font: montserrat_14
|
||||
text: esphome.io
|
||||
align: top_mid
|
||||
- qrcode:
|
||||
text: "https://esphome.io"
|
||||
size: 80
|
||||
align: bottom_mid
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_qrcode_
|
||||
|
||||
- slider:
|
||||
width: 80%
|
||||
align: bottom_mid
|
||||
on_value:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text:
|
||||
format: "%.0f%%"
|
||||
args: [x]
|
||||
"""
|
||||
|
||||
|
||||
def get_hello_world():
|
||||
with StringIO(CONFIG) as fp:
|
||||
return parse_yaml("hello_world", fp)
|
||||
@@ -0,0 +1,118 @@
|
||||
# This file defines a placeholder LVGL "Hello World" that is shown when no
|
||||
# widgets are configured.
|
||||
- obj:
|
||||
id: hello_world_card_
|
||||
pad_all: 12
|
||||
bg_color: white
|
||||
height: 100%
|
||||
width: 100%
|
||||
scrollable: false
|
||||
widgets:
|
||||
- obj:
|
||||
align: top_mid
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
pad_all: 4
|
||||
scrollable: false
|
||||
height: size_content
|
||||
width: 100%
|
||||
layout:
|
||||
type: flex
|
||||
flex_flow: row
|
||||
flex_align_cross: center
|
||||
flex_align_track: start
|
||||
flex_align_main: space_between
|
||||
widgets:
|
||||
- button:
|
||||
checkable: true
|
||||
radius: 4
|
||||
text_font: montserrat_20
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Clicked!"
|
||||
widgets:
|
||||
- label:
|
||||
text: "Button"
|
||||
- label:
|
||||
id: hello_world_title_
|
||||
text: ESPHome
|
||||
text_font: montserrat_20
|
||||
width: 100%
|
||||
text_align: center
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_title_
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 400;
|
||||
- checkbox:
|
||||
text: Checkbox
|
||||
id: hello_world_checkbox_
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_checkbox_
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 240;
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Checked!"
|
||||
- obj:
|
||||
id: hello_world_container_
|
||||
align: center
|
||||
y: 14
|
||||
pad_all: 0
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
width: 100%
|
||||
height: size_content
|
||||
scrollable: false
|
||||
on_click:
|
||||
lvgl.spinner.update:
|
||||
id: hello_world_spinner_
|
||||
arc_color: springgreen
|
||||
layout:
|
||||
type: flex
|
||||
flex_flow: row_wrap
|
||||
flex_align_cross: center
|
||||
flex_align_track: center
|
||||
flex_align_main: space_evenly
|
||||
widgets:
|
||||
- spinner:
|
||||
id: hello_world_spinner_
|
||||
indicator:
|
||||
arc_color: tomato
|
||||
height: 100
|
||||
width: 100
|
||||
spin_time: 2s
|
||||
arc_length: 60deg
|
||||
widgets:
|
||||
- label:
|
||||
id: hello_world_label_
|
||||
text: "Hello World!"
|
||||
align: center
|
||||
- obj:
|
||||
id: hello_world_qrcode_
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 300 && lv_obj_get_height(lv_scr_act()) < 400;
|
||||
widgets:
|
||||
- label:
|
||||
text_font: montserrat_14
|
||||
text: esphome.io
|
||||
align: top_mid
|
||||
- qrcode:
|
||||
text: "https://esphome.io"
|
||||
size: 80
|
||||
align: bottom_mid
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_qrcode_
|
||||
|
||||
- slider:
|
||||
width: 80%
|
||||
align: bottom_mid
|
||||
on_value:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text:
|
||||
format: "%.0f%%"
|
||||
args: [x]
|
||||
@@ -54,18 +54,18 @@ CONF_ENABLE_ECC = "enable_ecc"
|
||||
|
||||
SPIRAM_MODES = {
|
||||
VARIANT_ESP32: (TYPE_QUAD,),
|
||||
VARIANT_ESP32C5: (TYPE_QUAD,),
|
||||
VARIANT_ESP32S2: (TYPE_QUAD,),
|
||||
VARIANT_ESP32S3: (TYPE_QUAD, TYPE_OCTAL),
|
||||
VARIANT_ESP32C5: (TYPE_QUAD,),
|
||||
VARIANT_ESP32P4: (TYPE_HEX,),
|
||||
}
|
||||
|
||||
|
||||
SPIRAM_SPEEDS = {
|
||||
VARIANT_ESP32: (40, 80, 120),
|
||||
VARIANT_ESP32C5: (40, 80, 120),
|
||||
VARIANT_ESP32S2: (40, 80, 120),
|
||||
VARIANT_ESP32S3: (40, 80, 120),
|
||||
VARIANT_ESP32C5: (40, 80, 120),
|
||||
VARIANT_ESP32P4: (20, 100, 200),
|
||||
}
|
||||
|
||||
|
||||
@@ -131,13 +131,13 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
|
||||
cv.SplitDefault(
|
||||
CONF_RMT_SYMBOLS,
|
||||
esp32=192,
|
||||
esp32_s2=192,
|
||||
esp32_s3=192,
|
||||
esp32_p4=192,
|
||||
esp32_c3=96,
|
||||
esp32_c5=96,
|
||||
esp32_c6=96,
|
||||
esp32_h2=96,
|
||||
esp32_p4=192,
|
||||
esp32_s2=192,
|
||||
esp32_s3=192,
|
||||
): cv.All(cv.only_on_esp32, cv.int_range(min=2)),
|
||||
cv.Optional(CONF_FILTER_SYMBOLS): cv.All(
|
||||
cv.only_on_esp32, cv.int_range(min=0)
|
||||
@@ -148,7 +148,7 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
|
||||
): cv.All(cv.only_on_esp32, cv.int_range(min=2)),
|
||||
cv.Optional(CONF_USE_DMA): cv.All(
|
||||
esp32.only_on_variant(
|
||||
supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4]
|
||||
supported=[esp32.const.VARIANT_ESP32P4, esp32.const.VARIANT_ESP32S3]
|
||||
),
|
||||
cv.boolean,
|
||||
),
|
||||
|
||||
@@ -55,20 +55,20 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_EOT_LEVEL): cv.All(cv.only_on_esp32, cv.boolean),
|
||||
cv.Optional(CONF_USE_DMA): cv.All(
|
||||
esp32.only_on_variant(
|
||||
supported=[esp32.const.VARIANT_ESP32S3, esp32.const.VARIANT_ESP32P4]
|
||||
supported=[esp32.const.VARIANT_ESP32P4, esp32.const.VARIANT_ESP32S3]
|
||||
),
|
||||
cv.boolean,
|
||||
),
|
||||
cv.SplitDefault(
|
||||
CONF_RMT_SYMBOLS,
|
||||
esp32=64,
|
||||
esp32_s2=64,
|
||||
esp32_s3=48,
|
||||
esp32_p4=48,
|
||||
esp32_c3=48,
|
||||
esp32_c5=48,
|
||||
esp32_c6=48,
|
||||
esp32_h2=48,
|
||||
esp32_p4=48,
|
||||
esp32_s2=64,
|
||||
esp32_s3=48,
|
||||
): cv.All(cv.only_on_esp32, cv.int_range(min=2)),
|
||||
cv.Optional(CONF_NON_BLOCKING): cv.All(cv.only_on_esp32, cv.boolean),
|
||||
cv.Optional(CONF_ON_TRANSMIT): automation.validate_automation(single=True),
|
||||
|
||||
@@ -10,7 +10,9 @@ import esphome.codegen as cg
|
||||
from esphome.components import libretiny
|
||||
from esphome.components.libretiny.const import (
|
||||
COMPONENT_RTL87XX,
|
||||
FAMILY_RTL8710B,
|
||||
KEY_COMPONENT_DATA,
|
||||
KEY_FAMILY,
|
||||
KEY_LIBRETINY,
|
||||
LibreTinyComponent,
|
||||
)
|
||||
@@ -48,7 +50,9 @@ CONFIG_SCHEMA.prepend_extra(_set_core_data)
|
||||
async def to_code(config):
|
||||
# Use FreeRTOS 8.2.3+ for xTaskNotifyGive/ulTaskNotifyTake required by AsyncTCP 3.4.3+
|
||||
# https://github.com/esphome/esphome/issues/10220
|
||||
cg.add_platformio_option("custom_versions.freertos", "8.2.3")
|
||||
# Only for RTL8710B (ambz) - RTL8720C (ambz2) requires FreeRTOS 10.x
|
||||
if CORE.data[KEY_LIBRETINY][KEY_FAMILY] == FAMILY_RTL8710B:
|
||||
cg.add_platformio_option("custom_versions.freertos", "8.2.3")
|
||||
return await libretiny.component_to_code(config)
|
||||
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ def spi_mode_schema(mode):
|
||||
if pin_count == 8:
|
||||
onlys.append(
|
||||
only_on_variant(
|
||||
supported=[VARIANT_ESP32S3, VARIANT_ESP32S2, VARIANT_ESP32P4]
|
||||
supported=[VARIANT_ESP32P4, VARIANT_ESP32S2, VARIANT_ESP32S3]
|
||||
)
|
||||
)
|
||||
return cv.All(
|
||||
|
||||
@@ -24,7 +24,17 @@ void log_text_sensor(const char *tag, const char *prefix, const char *type, Text
|
||||
|
||||
class TextSensor : public EntityBase, public EntityBase_DeviceClass {
|
||||
public:
|
||||
std::string state;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
/// @deprecated Use get_raw_state() instead. This member will be removed in ESPHome 2026.6.0.
|
||||
ESPDEPRECATED("Use get_raw_state() instead of .raw_state. Will be removed in 2026.6.0", "2025.12.0")
|
||||
std::string raw_state;
|
||||
|
||||
TextSensor() = default;
|
||||
~TextSensor() = default;
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
/// Getter-syntax for .state.
|
||||
std::string get_state() const;
|
||||
@@ -49,15 +59,6 @@ class TextSensor : public EntityBase, public EntityBase_DeviceClass {
|
||||
/// Add a callback that will be called every time the sensor sends a raw value.
|
||||
void add_on_raw_state_callback(std::function<void(std::string)> callback);
|
||||
|
||||
std::string state;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
/// @deprecated Use get_raw_state() instead. This member will be removed in ESPHome 2026.6.0.
|
||||
ESPDEPRECATED("Use get_raw_state() instead of .raw_state. Will be removed in 2026.6.0", "2025.12.0")
|
||||
std::string raw_state;
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// ========== INTERNAL METHODS ==========
|
||||
// (In most use cases you won't need these)
|
||||
|
||||
|
||||
@@ -41,4 +41,4 @@ void TinyUSB::dump_config() {
|
||||
}
|
||||
|
||||
} // namespace esphome::tinyusb
|
||||
#endif
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -69,4 +69,4 @@ class TinyUSB : public Component {
|
||||
};
|
||||
|
||||
} // namespace esphome::tinyusb
|
||||
#endif
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
// Should not be needed, but it's required to pass CI clang-tidy checks
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include <vector>
|
||||
@@ -188,4 +188,4 @@ class USBHost : public Component {
|
||||
} // namespace usb_host
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Should not be needed, but it's required to pass CI clang-tidy checks
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "usb_host.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
@@ -531,4 +531,4 @@ void USBClient::release_trq(TransferRequest *trq) {
|
||||
|
||||
} // namespace usb_host
|
||||
} // namespace esphome
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Should not be needed, but it's required to pass CI clang-tidy checks
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "usb_host.h"
|
||||
#include <cinttypes>
|
||||
#include "esphome/core/log.h"
|
||||
@@ -31,4 +31,4 @@ void USBHost::loop() {
|
||||
} // namespace usb_host
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "usb_uart.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -78,4 +78,4 @@ void USBUartTypeCH34X::enable_channels() {
|
||||
}
|
||||
} // namespace usb_uart
|
||||
} // namespace esphome
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "usb_uart.h"
|
||||
#include "usb/usb_host.h"
|
||||
#include "esphome/core/log.h"
|
||||
@@ -123,4 +123,4 @@ void USBUartTypeCP210X::enable_channels() {
|
||||
}
|
||||
} // namespace usb_uart
|
||||
} // namespace esphome
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Should not be needed, but it's required to pass CI clang-tidy checks
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "usb_uart.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
@@ -392,4 +392,4 @@ void USBUartTypeCdcAcm::enable_channels() {
|
||||
|
||||
} // namespace usb_uart
|
||||
} // namespace esphome
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/components/uart/uart_component.h"
|
||||
@@ -173,4 +173,4 @@ class USBUartTypeCH34X : public USBUartTypeCdcAcm {
|
||||
} // namespace usb_uart
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3
|
||||
|
||||
@@ -740,9 +740,10 @@ def has_at_most_one_key(*keys):
|
||||
if not isinstance(obj, dict):
|
||||
raise Invalid("expected dictionary")
|
||||
|
||||
number = sum(k in keys for k in obj)
|
||||
if number > 1:
|
||||
raise Invalid(f"Cannot specify more than one of {', '.join(keys)}.")
|
||||
used = set(obj) & set(keys)
|
||||
if len(used) > 1:
|
||||
msg = "Cannot specify more than one of '" + "', '".join(used) + "'."
|
||||
raise MultipleInvalid([Invalid(msg, path=[k]) for k in used])
|
||||
return obj
|
||||
|
||||
return validate
|
||||
|
||||
@@ -541,8 +541,22 @@ class EsphomeCore:
|
||||
self.friendly_name: str | None = None
|
||||
# The area / zone of the node
|
||||
self.area: str | None = None
|
||||
# Additional data components can store temporary data in
|
||||
# The first key to this dict should always be the integration name
|
||||
# Additional data components can store temporary data in.
|
||||
# This dict is cleared between compilation runs.
|
||||
#
|
||||
# Usage pattern (use @dataclass for type safety):
|
||||
# DOMAIN = "my_component"
|
||||
#
|
||||
# @dataclass
|
||||
# class MyComponentData:
|
||||
# feature_enabled: bool = False
|
||||
#
|
||||
# def _get_data() -> MyComponentData:
|
||||
# if DOMAIN not in CORE.data:
|
||||
# CORE.data[DOMAIN] = MyComponentData()
|
||||
# return CORE.data[DOMAIN]
|
||||
#
|
||||
# The first key should always be the component domain name (DOMAIN constant).
|
||||
self.data = {}
|
||||
# The relative path to the configuration YAML
|
||||
self.config_path: Path | None = None
|
||||
|
||||
@@ -234,9 +234,9 @@
|
||||
|
||||
#if defined(USE_ESP32_VARIANT_ESP32S2)
|
||||
#define USE_LOGGER_USB_CDC
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C3) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C5) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32P4)
|
||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C5) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32P4) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#define USE_LOGGER_USB_CDC
|
||||
#define USE_LOGGER_USB_SERIAL_JTAG
|
||||
#endif
|
||||
|
||||
+12
-12
@@ -378,6 +378,18 @@ build_flags =
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32-P4 ;;;;;;;;
|
||||
|
||||
[env:esp32p4-idf]
|
||||
extends = common:esp32-idf
|
||||
board = esp32-p4-evboard
|
||||
|
||||
board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32p4-idf
|
||||
build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32P4
|
||||
|
||||
;;;;;;;; ESP32-S2 ;;;;;;;;
|
||||
|
||||
[env:esp32s2-arduino]
|
||||
@@ -466,18 +478,6 @@ build_flags =
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32-P4 ;;;;;;;;
|
||||
|
||||
[env:esp32p4-idf]
|
||||
extends = common:esp32-idf
|
||||
board = esp32-p4-evboard
|
||||
|
||||
board_build.esp-idf.sdkconfig_path = .temp/sdkconfig-esp32p4-idf
|
||||
build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32P4
|
||||
|
||||
;;;;;;;; RP2040 ;;;;;;;;
|
||||
|
||||
[env:rp2040-pico-arduino]
|
||||
|
||||
@@ -304,14 +304,14 @@ def test_all_predefined_models(
|
||||
config = {"model": name}
|
||||
|
||||
# Get the pins required by this model and find a compatible variant
|
||||
pins = [
|
||||
pin
|
||||
for pin in [
|
||||
model.get_default(pin, None)
|
||||
for pin in ("dc_pin", "reset_pin", "cs_pin")
|
||||
]
|
||||
if pin is not None
|
||||
]
|
||||
pins = []
|
||||
for pin_name in ("dc_pin", "reset_pin", "cs_pin", "enable_pin"):
|
||||
pin_value = model.get_default(pin_name, None)
|
||||
if pin_value is not None:
|
||||
if isinstance(pin_value, list):
|
||||
pins.extend(pin_value)
|
||||
else:
|
||||
pins.append(pin_value)
|
||||
choose_variant_with_pins(pins)
|
||||
|
||||
# Add required fields that don't have defaults
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
cc1101:
|
||||
id: transceiver
|
||||
cs_pin: ${cs_pin}
|
||||
frequency: 433920
|
||||
if_frequency: 153
|
||||
filter_bandwidth: 203
|
||||
channel: 0
|
||||
channel_spacing: 200
|
||||
symbol_rate: 5000
|
||||
modulation_type: ASK/OOK
|
||||
|
||||
button:
|
||||
- platform: template
|
||||
name: "CC1101 Button"
|
||||
on_press:
|
||||
then:
|
||||
- cc1101.begin_tx: transceiver
|
||||
- cc1101.begin_rx: transceiver
|
||||
- cc1101.set_idle: transceiver
|
||||
- cc1101.reset: transceiver
|
||||
@@ -0,0 +1,8 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO5
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp32-idf.yaml
|
||||
remote_receiver: !include ../../test_build_components/common/remote_receiver/esp32-idf.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -0,0 +1,8 @@
|
||||
substitutions:
|
||||
cs_pin: GPIO5
|
||||
|
||||
packages:
|
||||
spi: !include ../../test_build_components/common/spi/esp8266-ard.yaml
|
||||
remote_receiver: !include ../../test_build_components/common/remote_receiver/esp8266-ard.yaml
|
||||
|
||||
<<: !include common.yaml
|
||||
@@ -1,5 +1,18 @@
|
||||
climate:
|
||||
- platform: gree
|
||||
name: GREE
|
||||
model: generic
|
||||
id: my_gree_ac
|
||||
model: YAN
|
||||
transmitter_id: xmitr
|
||||
|
||||
switch:
|
||||
- platform: gree
|
||||
gree_id: my_gree_ac
|
||||
light:
|
||||
name: "AC Lights"
|
||||
turbo:
|
||||
name: "AC Turbo"
|
||||
health:
|
||||
name: "AC Health"
|
||||
xfan:
|
||||
name: "AC X-Fan"
|
||||
|
||||
@@ -8,6 +8,8 @@ substitutions:
|
||||
position:
|
||||
x: 79
|
||||
y: 82
|
||||
a: 15
|
||||
b: 20
|
||||
|
||||
esphome:
|
||||
name: test
|
||||
@@ -34,3 +36,5 @@ test_list:
|
||||
- '{{{"AA"}}}'
|
||||
- '"HELLO"'
|
||||
- '{ 79, 82 }'
|
||||
- a: 15 should be 15, overridden from command line
|
||||
b: 20 should stay as 20, not overridden
|
||||
|
||||
@@ -11,6 +11,13 @@ substitutions:
|
||||
position:
|
||||
x: 79
|
||||
y: 82
|
||||
a: 10
|
||||
b: 20
|
||||
|
||||
# The following key is only used by the test framework
|
||||
# to simulate command line substitutions
|
||||
command_line_substitutions:
|
||||
a: 15
|
||||
|
||||
test_list:
|
||||
- "$var1"
|
||||
@@ -35,3 +42,5 @@ test_list:
|
||||
- ${ '{{{"AA"}}}' }
|
||||
- ${ '"HELLO"' }
|
||||
- '{ ${position.x}, ${position.y} }'
|
||||
- a: ${a} should be 15, overridden from command line
|
||||
b: ${b} should stay as 20, not overridden
|
||||
|
||||
@@ -251,15 +251,6 @@ def test_split_default(framework, platform, variant, full, idf, arduino, simple)
|
||||
"host": "24",
|
||||
}
|
||||
|
||||
idf_mappings = {
|
||||
"esp32_idf": "4",
|
||||
"esp32_s2_idf": "7",
|
||||
"esp32_s3_idf": "10",
|
||||
"esp32_c3_idf": "13",
|
||||
"esp32_c6_idf": "16",
|
||||
"esp32_h2_idf": "19",
|
||||
}
|
||||
|
||||
arduino_mappings = {
|
||||
"esp32_arduino": "3",
|
||||
"esp32_s2_arduino": "6",
|
||||
@@ -269,6 +260,15 @@ def test_split_default(framework, platform, variant, full, idf, arduino, simple)
|
||||
"esp32_h2_arduino": "18",
|
||||
}
|
||||
|
||||
idf_mappings = {
|
||||
"esp32_idf": "4",
|
||||
"esp32_s2_idf": "7",
|
||||
"esp32_s3_idf": "10",
|
||||
"esp32_c3_idf": "13",
|
||||
"esp32_c6_idf": "16",
|
||||
"esp32_h2_idf": "19",
|
||||
}
|
||||
|
||||
schema = config_validation.Schema(
|
||||
{
|
||||
config_validation.SplitDefault(
|
||||
@@ -293,8 +293,8 @@ def test_split_default(framework, platform, variant, full, idf, arduino, simple)
|
||||
@pytest.mark.parametrize(
|
||||
"framework, platform, message",
|
||||
[
|
||||
("esp-idf", PLATFORM_ESP32, "ESP32 using esp-idf framework"),
|
||||
("arduino", PLATFORM_ESP32, "ESP32 using arduino framework"),
|
||||
("esp-idf", PLATFORM_ESP32, "ESP32 using esp-idf framework"),
|
||||
("arduino", PLATFORM_ESP8266, "ESP8266 using arduino framework"),
|
||||
("arduino", PLATFORM_RP2040, "RP2040 using arduino framework"),
|
||||
("arduino", PLATFORM_BK72XX, "BK72XX using arduino framework"),
|
||||
|
||||
@@ -2,13 +2,16 @@ import glob
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome import config as config_module, yaml_util
|
||||
from esphome.components import substitutions
|
||||
from esphome.components.packages import do_packages_pass
|
||||
from esphome.config import resolve_extend_remove
|
||||
from esphome.config_helpers import merge_config
|
||||
from esphome.const import CONF_PACKAGES, CONF_SUBSTITUTIONS
|
||||
from esphome.const import CONF_SUBSTITUTIONS
|
||||
from esphome.core import CORE
|
||||
from esphome.util import OrderedDict
|
||||
|
||||
@@ -91,13 +94,22 @@ REMOTES = {
|
||||
("https://github.com/esphome/repo2", "main"): "remotes/repo2/main",
|
||||
}
|
||||
|
||||
# Collect all input YAML files for test_substitutions_fixtures parametrized tests:
|
||||
HERE = Path(__file__).parent
|
||||
BASE_DIR = HERE / "fixtures" / "substitutions"
|
||||
SOURCES = sorted(glob.glob(str(BASE_DIR / "*.input.yaml")))
|
||||
assert SOURCES, f"test_substitutions_fixtures: No input YAML files found in {BASE_DIR}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"source_path",
|
||||
[Path(p) for p in SOURCES],
|
||||
ids=lambda p: p.name,
|
||||
)
|
||||
@patch("esphome.git.clone_or_update")
|
||||
def test_substitutions_fixtures(mock_clone_or_update, fixture_path):
|
||||
base_dir = fixture_path / "substitutions"
|
||||
sources = sorted(glob.glob(str(base_dir / "*.input.yaml")))
|
||||
assert sources, f"No input YAML files found in {base_dir}"
|
||||
|
||||
def test_substitutions_fixtures(
|
||||
mock_clone_or_update: MagicMock, source_path: Path
|
||||
) -> None:
|
||||
def fake_clone_or_update(
|
||||
*,
|
||||
url: str,
|
||||
@@ -116,72 +128,61 @@ def test_substitutions_fixtures(mock_clone_or_update, fixture_path):
|
||||
raise RuntimeError(
|
||||
f"Cannot find test repository for {url} @ {ref}. Check the REMOTES mapping in test_substitutions.py"
|
||||
)
|
||||
return base_dir / path, None
|
||||
return BASE_DIR / path, None
|
||||
|
||||
mock_clone_or_update.side_effect = fake_clone_or_update
|
||||
|
||||
failures = []
|
||||
for source_path in sources:
|
||||
source_path = Path(source_path)
|
||||
try:
|
||||
expected_path = source_path.with_suffix("").with_suffix(".approved.yaml")
|
||||
test_case = source_path.with_suffix("").stem
|
||||
expected_path = source_path.with_suffix("").with_suffix(".approved.yaml")
|
||||
test_case = source_path.with_suffix("").stem
|
||||
|
||||
# Load using ESPHome's YAML loader
|
||||
config = yaml_util.load_yaml(source_path)
|
||||
# Load using ESPHome's YAML loader
|
||||
config = yaml_util.load_yaml(source_path)
|
||||
|
||||
if CONF_PACKAGES in config:
|
||||
from esphome.components.packages import do_packages_pass
|
||||
command_line_substitutions = config.pop("command_line_substitutions", None)
|
||||
|
||||
config = do_packages_pass(config)
|
||||
config = do_packages_pass(config)
|
||||
|
||||
substitutions.do_substitution_pass(config, None)
|
||||
substitutions.do_substitution_pass(config, command_line_substitutions)
|
||||
|
||||
resolve_extend_remove(config)
|
||||
verify_database_result = verify_database(config)
|
||||
if verify_database_result is not None:
|
||||
raise AssertionError(verify_database_result)
|
||||
resolve_extend_remove(config)
|
||||
verify_database_result = verify_database(config)
|
||||
if verify_database_result is not None:
|
||||
raise AssertionError(verify_database_result)
|
||||
|
||||
# Also load expected using ESPHome's loader, or use {} if missing and DEV_MODE
|
||||
if expected_path.is_file():
|
||||
expected = yaml_util.load_yaml(expected_path)
|
||||
elif DEV_MODE:
|
||||
expected = {}
|
||||
else:
|
||||
assert expected_path.is_file(), (
|
||||
f"Expected file missing: {expected_path}"
|
||||
)
|
||||
# Also load expected using ESPHome's loader, or use {} if missing and DEV_MODE
|
||||
if expected_path.is_file():
|
||||
expected = yaml_util.load_yaml(expected_path)
|
||||
elif DEV_MODE:
|
||||
expected = {}
|
||||
else:
|
||||
assert expected_path.is_file(), f"Expected file missing: {expected_path}"
|
||||
|
||||
# Sort dicts only (not lists) for comparison
|
||||
got_sorted = sort_dicts(config)
|
||||
expected_sorted = sort_dicts(expected)
|
||||
# Sort dicts only (not lists) for comparison
|
||||
got_sorted = sort_dicts(config)
|
||||
expected_sorted = sort_dicts(expected)
|
||||
|
||||
if got_sorted != expected_sorted:
|
||||
diff = "\n".join(dict_diff(got_sorted, expected_sorted))
|
||||
msg = (
|
||||
f"Substitution result mismatch for {source_path.name}\n"
|
||||
f"Diff:\n{diff}\n\n"
|
||||
f"Got: {got_sorted}\n"
|
||||
f"Expected: {expected_sorted}"
|
||||
)
|
||||
# Write out the received file when test fails
|
||||
if DEV_MODE:
|
||||
received_path = source_path.with_name(f"{test_case}.received.yaml")
|
||||
write_yaml(received_path, config)
|
||||
print(msg)
|
||||
failures.append(msg)
|
||||
else:
|
||||
raise AssertionError(msg)
|
||||
except Exception as err:
|
||||
_LOGGER.error("Error in test file %s", source_path)
|
||||
raise err
|
||||
|
||||
if DEV_MODE and failures:
|
||||
print(f"\n{len(failures)} substitution test case(s) failed.")
|
||||
if got_sorted != expected_sorted:
|
||||
diff = "\n".join(dict_diff(got_sorted, expected_sorted))
|
||||
msg = (
|
||||
f"Substitution result mismatch for {source_path.name}\n"
|
||||
f"Diff:\n{diff}\n\n"
|
||||
f"Got: {got_sorted}\n"
|
||||
f"Expected: {expected_sorted}"
|
||||
)
|
||||
# Write out the received file when test fails
|
||||
if DEV_MODE:
|
||||
received_path = source_path.with_name(f"{test_case}.received.yaml")
|
||||
write_yaml(received_path, config)
|
||||
msg += f"\nWrote received file to {received_path}."
|
||||
raise AssertionError(msg)
|
||||
|
||||
if DEV_MODE:
|
||||
_LOGGER.error("Tests passed, but Dev mode is enabled.")
|
||||
assert not DEV_MODE # make sure DEV_MODE is disabled after you are finished.
|
||||
assert (
|
||||
not DEV_MODE # make sure DEV_MODE is disabled after you are finished.
|
||||
), (
|
||||
"Test passed but DEV_MODE must be disabled when running tests. Please set DEV_MODE=False."
|
||||
)
|
||||
|
||||
|
||||
def test_substitutions_with_command_line_maintains_ordered_dict() -> None:
|
||||
|
||||
Reference in New Issue
Block a user