mirror of
https://github.com/esphome/esphome.git
synced 2024-11-23 23:48:11 +01:00
Merge branch 'dev' into nrf52_core
This commit is contained in:
commit
be6e70702e
50 changed files with 816 additions and 201 deletions
4
.github/actions/build-image/action.yaml
vendored
4
.github/actions/build-image/action.yaml
vendored
|
@ -46,7 +46,7 @@ runs:
|
|||
|
||||
- name: Build and push to ghcr by digest
|
||||
id: build-ghcr
|
||||
uses: docker/build-push-action@v6.7.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
|
@ -72,7 +72,7 @@ runs:
|
|||
|
||||
- name: Build and push to dockerhub by digest
|
||||
id: build-dockerhub
|
||||
uses: docker/build-push-action@v6.7.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
|
|
2
.github/workflows/ci-docker.yml
vendored
2
.github/workflows/ci-docker.yml
vendored
|
@ -46,7 +46,7 @@ jobs:
|
|||
with:
|
||||
python-version: "3.9"
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
uses: docker/setup-buildx-action@v3.7.1
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3.2.0
|
||||
|
||||
|
|
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
|
@ -65,7 +65,7 @@ jobs:
|
|||
pip3 install build
|
||||
python3 -m build
|
||||
- name: Publish
|
||||
uses: pypa/gh-action-pypi-publish@v1.10.1
|
||||
uses: pypa/gh-action-pypi-publish@v1.10.3
|
||||
|
||||
deploy-docker:
|
||||
name: Build ESPHome ${{ matrix.platform }}
|
||||
|
@ -90,7 +90,7 @@ jobs:
|
|||
python-version: "3.9"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
uses: docker/setup-buildx-action@v3.7.1
|
||||
- name: Set up QEMU
|
||||
if: matrix.platform != 'linux/amd64'
|
||||
uses: docker/setup-qemu-action@v3.2.0
|
||||
|
@ -184,7 +184,7 @@ jobs:
|
|||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.6.1
|
||||
uses: docker/setup-buildx-action@v3.7.1
|
||||
|
||||
- name: Log in to docker hub
|
||||
if: matrix.registry == 'dockerhub'
|
||||
|
|
|
@ -24,6 +24,7 @@ esphome/components/ade7953_i2c/* @angelnu
|
|||
esphome/components/ade7953_spi/* @angelnu
|
||||
esphome/components/ads1118/* @solomondg1
|
||||
esphome/components/ags10/* @mak-42
|
||||
esphome/components/aic3204/* @kbx81
|
||||
esphome/components/airthings_ble/* @jeromelaban
|
||||
esphome/components/airthings_wave_base/* @jeromelaban @kpfleming @ncareau
|
||||
esphome/components/airthings_wave_mini/* @ncareau
|
||||
|
@ -47,6 +48,7 @@ esphome/components/at581x/* @X-Ryl669
|
|||
esphome/components/atc_mithermometer/* @ahpohl
|
||||
esphome/components/atm90e26/* @danieltwagner
|
||||
esphome/components/atm90e32/* @circuitsetup @descipher
|
||||
esphome/components/audio_dac/* @kbx81
|
||||
esphome/components/b_parasite/* @rbaron
|
||||
esphome/components/ballu/* @bazuchan
|
||||
esphome/components/bang_bang/* @OttoWinter
|
||||
|
|
0
esphome/components/aic3204/__init__.py
Normal file
0
esphome/components/aic3204/__init__.py
Normal file
173
esphome/components/aic3204/aic3204.cpp
Normal file
173
esphome/components/aic3204/aic3204.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
#include "aic3204.h"
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
|
||||
static const char *const TAG = "aic3204";
|
||||
|
||||
#define ERROR_CHECK(err, msg) \
|
||||
if (!(err)) { \
|
||||
ESP_LOGE(TAG, msg); \
|
||||
this->mark_failed(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
void AIC3204::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up AIC3204...");
|
||||
|
||||
// Set register page to 0
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
|
||||
// Initiate SW reset (PLL is powered off as part of reset)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_SW_RST, 0x01), "Software reset failed");
|
||||
// *** Program clock settings ***
|
||||
// Default is CODEC_CLKIN is from MCLK pin. Don't need to change this.
|
||||
// MDAC*NDAC*FOSR*48Khz = mClk (24.576 MHz when the XMOS is expecting 48kHz audio)
|
||||
// (See page 51 of https://www.ti.com/lit/ml/slaa557/slaa557.pdf)
|
||||
// We do need MDAC*DOSR/32 >= the resource compute level for the processing block
|
||||
// So here 2*128/32 = 8, which is equal to processing block 1 's resource compute
|
||||
// See page 5 of https://www.ti.com/lit/an/slaa404c/slaa404c.pdf for the workflow
|
||||
// for determining these settings.
|
||||
|
||||
// Power up NDAC and set to 2
|
||||
ERROR_CHECK(this->write_byte(AIC3204_NDAC, 0x82), "Set NDAC failed");
|
||||
// Power up MDAC and set to 2
|
||||
ERROR_CHECK(this->write_byte(AIC3204_MDAC, 0x82), "Set MDAC failed");
|
||||
// Program DOSR = 128
|
||||
ERROR_CHECK(this->write_byte(AIC3204_DOSR, 0x80), "Set DOSR failed");
|
||||
// Set Audio Interface Config: I2S, 32 bits, DOUT always driving
|
||||
ERROR_CHECK(this->write_byte(AIC3204_CODEC_IF, 0x30), "Set CODEC_IF failed");
|
||||
// For I2S Firmware only, set SCLK/MFP3 pin as Audio Data In
|
||||
ERROR_CHECK(this->write_byte(AIC3204_SCLK_MFP3, 0x02), "Set SCLK/MFP3 failed");
|
||||
ERROR_CHECK(this->write_byte(AIC3204_AUDIO_IF_4, 0x01), "Set AUDIO_IF_4 failed");
|
||||
ERROR_CHECK(this->write_byte(AIC3204_AUDIO_IF_5, 0x01), "Set AUDIO_IF_5 failed");
|
||||
// Program the DAC processing block to be used - PRB_P1
|
||||
ERROR_CHECK(this->write_byte(AIC3204_DAC_SIG_PROC, 0x01), "Set DAC_SIG_PROC failed");
|
||||
|
||||
// *** Select Page 1 ***
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x01), "Set page 1 failed");
|
||||
// Enable the internal AVDD_LDO:
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LDO_CTRL, 0x09), "Set LDO_CTRL failed");
|
||||
// *** Program Analog Blocks ***
|
||||
// Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PWR_CFG, 0x08), "Set PWR_CFG failed");
|
||||
// Enable Master Analog Power Control
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LDO_CTRL, 0x01), "Set LDO_CTRL failed");
|
||||
// Page 125: Common mode control register, set d6 to 1 to make the full chip common mode = 0.75 v
|
||||
// We are using the internal AVdd regulator with a nominal output of 1.72 V (see LDO_CTRL_REGISTER on page 123)
|
||||
// Page 86 says to only set the common mode voltage to 0.9 v if AVdd >= 1.8... but it isn't on our hardware
|
||||
// We also adjust the HPL and HPR gains to -2dB gian later in this config flow compensate (see page 47)
|
||||
// (All pages refer to the TLV320AIC3204 Application Reference Guide)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_CM_CTRL, 0x40), "Set CM_CTRL failed");
|
||||
// *** Set PowerTune Modes ***
|
||||
// Set the Left & Right DAC PowerTune mode to PTM_P3/4. Use Class-AB driver.
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PLAY_CFG1, 0x00), "Set PLAY_CFG1 failed");
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PLAY_CFG2, 0x00), "Set PLAY_CFG2 failed");
|
||||
// Set the REF charging time to 40ms
|
||||
ERROR_CHECK(this->write_byte(AIC3204_REF_STARTUP, 0x01), "Set REF_STARTUP failed");
|
||||
// HP soft stepping settings for optimal pop performance at power up
|
||||
// Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling
|
||||
// capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound.
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HP_START, 0x25), "Set HP_START failed");
|
||||
// Route Left DAC to HPL
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPL_ROUTE, 0x08), "Set HPL_ROUTE failed");
|
||||
// Route Right DAC to HPR
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPR_ROUTE, 0x08), "Set HPR_ROUTE failed");
|
||||
// Route Left DAC to LOL
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOL_ROUTE, 0x08), "Set LOL_ROUTE failed");
|
||||
// Route Right DAC to LOR
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOR_ROUTE, 0x08), "Set LOR_ROUTE failed");
|
||||
|
||||
// Unmute HPL and set gain to -2dB (see comment before configuring the AIC3204_CM_CTRL register)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPL_GAIN, 0x3e), "Set HPL_GAIN failed");
|
||||
// Unmute HPR and set gain to -2dB (see comment before configuring the AIC3204_CM_CTRL register)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPR_GAIN, 0x3e), "Set HPR_GAIN failed");
|
||||
// Unmute LOL and set gain to 0dB
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOL_DRV_GAIN, 0x00), "Set LOL_DRV_GAIN failed");
|
||||
// Unmute LOR and set gain to 0dB
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOR_DRV_GAIN, 0x00), "Set LOR_DRV_GAIN failed");
|
||||
|
||||
// Power up HPL and HPR, LOL and LOR drivers
|
||||
ERROR_CHECK(this->write_byte(AIC3204_OP_PWR_CTRL, 0x3C), "Set OP_PWR_CTRL failed");
|
||||
|
||||
// Wait for 2.5 sec for soft stepping to take effect before attempting power-up
|
||||
this->set_timeout(2500, [this]() {
|
||||
// *** Power Up DAC ***
|
||||
// Select Page 0
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set PAGE_CTRL failed");
|
||||
// Power up the Left and Right DAC Channels. Route Left data to Left DAC and Right data to Right DAC.
|
||||
// DAC Vol control soft step 1 step per DAC word clock.
|
||||
ERROR_CHECK(this->write_byte(AIC3204_DAC_CH_SET1, 0xd4), "Set DAC_CH_SET1 failed");
|
||||
// Set left and right DAC digital volume control
|
||||
ERROR_CHECK(this->write_volume_(), "Set volume failed");
|
||||
// Unmute left and right channels
|
||||
ERROR_CHECK(this->write_mute_(), "Set mute failed");
|
||||
});
|
||||
}
|
||||
|
||||
void AIC3204::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "AIC3204:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Communication with AIC3204 failed");
|
||||
}
|
||||
}
|
||||
|
||||
bool AIC3204::set_mute_off() {
|
||||
this->is_muted_ = false;
|
||||
return this->write_mute_();
|
||||
}
|
||||
|
||||
bool AIC3204::set_mute_on() {
|
||||
this->is_muted_ = true;
|
||||
return this->write_mute_();
|
||||
}
|
||||
|
||||
bool AIC3204::set_auto_mute_mode(uint8_t auto_mute_mode) {
|
||||
this->auto_mute_mode_ = auto_mute_mode & 0x07;
|
||||
ESP_LOGVV(TAG, "Setting auto_mute_mode to 0x%.2x", this->auto_mute_mode_);
|
||||
return this->write_mute_();
|
||||
}
|
||||
|
||||
bool AIC3204::set_volume(float volume) {
|
||||
this->volume_ = clamp<float>(volume, 0.0, 1.0);
|
||||
return this->write_volume_();
|
||||
}
|
||||
|
||||
bool AIC3204::is_muted() { return this->is_muted_; }
|
||||
|
||||
float AIC3204::volume() { return this->volume_; }
|
||||
|
||||
bool AIC3204::write_mute_() {
|
||||
uint8_t mute_mode_byte = this->auto_mute_mode_ << 4; // auto-mute control is bits 4-6
|
||||
mute_mode_byte |= this->is_muted_ ? 0x0c : 0x00; // mute bits are 2-3
|
||||
if (!this->write_byte(AIC3204_PAGE_CTRL, 0x00) || !this->write_byte(AIC3204_DAC_CH_SET2, mute_mode_byte)) {
|
||||
ESP_LOGE(TAG, "Writing mute modes failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AIC3204::write_volume_() {
|
||||
const int8_t dvc_min_byte = -127;
|
||||
const int8_t dvc_max_byte = 48;
|
||||
|
||||
int8_t volume_byte = dvc_min_byte + (this->volume_ * (dvc_max_byte - dvc_min_byte));
|
||||
volume_byte = clamp<int8_t>(volume_byte, dvc_min_byte, dvc_max_byte);
|
||||
|
||||
ESP_LOGVV(TAG, "Setting volume to 0x%.2x", volume_byte & 0xFF);
|
||||
|
||||
if ((!this->write_byte(AIC3204_PAGE_CTRL, 0x00)) || (!this->write_byte(AIC3204_DACL_VOL_D, volume_byte)) ||
|
||||
(!this->write_byte(AIC3204_DACR_VOL_D, volume_byte))) {
|
||||
ESP_LOGE(TAG, "Writing volume failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
88
esphome/components/aic3204/aic3204.h
Normal file
88
esphome/components/aic3204/aic3204.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/components/audio_dac/audio_dac.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
|
||||
// TLV320AIC3204 Register Addresses
|
||||
// Page 0
|
||||
static const uint8_t AIC3204_PAGE_CTRL = 0x00; // Register 0 - Page Control
|
||||
static const uint8_t AIC3204_SW_RST = 0x01; // Register 1 - Software Reset
|
||||
static const uint8_t AIC3204_CLK_PLL1 = 0x04; // Register 4 - Clock Setting Register 1, Multiplexers
|
||||
static const uint8_t AIC3204_CLK_PLL2 = 0x05; // Register 5 - Clock Setting Register 2, P and R values
|
||||
static const uint8_t AIC3204_CLK_PLL3 = 0x06; // Register 6 - Clock Setting Register 3, J values
|
||||
static const uint8_t AIC3204_NDAC = 0x0B; // Register 11 - NDAC Divider Value
|
||||
static const uint8_t AIC3204_MDAC = 0x0C; // Register 12 - MDAC Divider Value
|
||||
static const uint8_t AIC3204_DOSR = 0x0E; // Register 14 - DOSR Divider Value (LS Byte)
|
||||
static const uint8_t AIC3204_NADC = 0x12; // Register 18 - NADC Divider Value
|
||||
static const uint8_t AIC3204_MADC = 0x13; // Register 19 - MADC Divider Value
|
||||
static const uint8_t AIC3204_AOSR = 0x14; // Register 20 - AOSR Divider Value
|
||||
static const uint8_t AIC3204_CODEC_IF = 0x1B; // Register 27 - CODEC Interface Control
|
||||
static const uint8_t AIC3204_AUDIO_IF_4 = 0x1F; // Register 31 - Audio Interface Setting Register 4
|
||||
static const uint8_t AIC3204_AUDIO_IF_5 = 0x20; // Register 32 - Audio Interface Setting Register 5
|
||||
static const uint8_t AIC3204_SCLK_MFP3 = 0x38; // Register 56 - SCLK/MFP3 Function Control
|
||||
static const uint8_t AIC3204_DAC_SIG_PROC = 0x3C; // Register 60 - DAC Sig Processing Block Control
|
||||
static const uint8_t AIC3204_ADC_SIG_PROC = 0x3D; // Register 61 - ADC Sig Processing Block Control
|
||||
static const uint8_t AIC3204_DAC_CH_SET1 = 0x3F; // Register 63 - DAC Channel Setup 1
|
||||
static const uint8_t AIC3204_DAC_CH_SET2 = 0x40; // Register 64 - DAC Channel Setup 2
|
||||
static const uint8_t AIC3204_DACL_VOL_D = 0x41; // Register 65 - DAC Left Digital Vol Control
|
||||
static const uint8_t AIC3204_DACR_VOL_D = 0x42; // Register 66 - DAC Right Digital Vol Control
|
||||
static const uint8_t AIC3204_DRC_ENABLE = 0x44;
|
||||
static const uint8_t AIC3204_ADC_CH_SET = 0x51; // Register 81 - ADC Channel Setup
|
||||
static const uint8_t AIC3204_ADC_FGA_MUTE = 0x52; // Register 82 - ADC Fine Gain Adjust/Mute
|
||||
|
||||
// Page 1
|
||||
static const uint8_t AIC3204_PWR_CFG = 0x01; // Register 1 - Power Config
|
||||
static const uint8_t AIC3204_LDO_CTRL = 0x02; // Register 2 - LDO Control
|
||||
static const uint8_t AIC3204_PLAY_CFG1 = 0x03; // Register 3 - Playback Config 1
|
||||
static const uint8_t AIC3204_PLAY_CFG2 = 0x04; // Register 4 - Playback Config 2
|
||||
static const uint8_t AIC3204_OP_PWR_CTRL = 0x09; // Register 9 - Output Driver Power Control
|
||||
static const uint8_t AIC3204_CM_CTRL = 0x0A; // Register 10 - Common Mode Control
|
||||
static const uint8_t AIC3204_HPL_ROUTE = 0x0C; // Register 12 - HPL Routing Select
|
||||
static const uint8_t AIC3204_HPR_ROUTE = 0x0D; // Register 13 - HPR Routing Select
|
||||
static const uint8_t AIC3204_LOL_ROUTE = 0x0E; // Register 14 - LOL Routing Selection
|
||||
static const uint8_t AIC3204_LOR_ROUTE = 0x0F; // Register 15 - LOR Routing Selection
|
||||
static const uint8_t AIC3204_HPL_GAIN = 0x10; // Register 16 - HPL Driver Gain
|
||||
static const uint8_t AIC3204_HPR_GAIN = 0x11; // Register 17 - HPR Driver Gain
|
||||
static const uint8_t AIC3204_LOL_DRV_GAIN = 0x12; // Register 18 - LOL Driver Gain Setting
|
||||
static const uint8_t AIC3204_LOR_DRV_GAIN = 0x13; // Register 19 - LOR Driver Gain Setting
|
||||
static const uint8_t AIC3204_HP_START = 0x14; // Register 20 - Headphone Driver Startup
|
||||
static const uint8_t AIC3204_LPGA_P_ROUTE = 0x34; // Register 52 - Left PGA Positive Input Route
|
||||
static const uint8_t AIC3204_LPGA_N_ROUTE = 0x36; // Register 54 - Left PGA Negative Input Route
|
||||
static const uint8_t AIC3204_RPGA_P_ROUTE = 0x37; // Register 55 - Right PGA Positive Input Route
|
||||
static const uint8_t AIC3204_RPGA_N_ROUTE = 0x39; // Register 57 - Right PGA Negative Input Route
|
||||
static const uint8_t AIC3204_LPGA_VOL = 0x3B; // Register 59 - Left PGA Volume
|
||||
static const uint8_t AIC3204_RPGA_VOL = 0x3C; // Register 60 - Right PGA Volume
|
||||
static const uint8_t AIC3204_ADC_PTM = 0x3D; // Register 61 - ADC Power Tune Config
|
||||
static const uint8_t AIC3204_AN_IN_CHRG = 0x47; // Register 71 - Analog Input Quick Charging Config
|
||||
static const uint8_t AIC3204_REF_STARTUP = 0x7B; // Register 123 - Reference Power Up Config
|
||||
|
||||
class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
bool set_mute_off() override;
|
||||
bool set_mute_on() override;
|
||||
bool set_auto_mute_mode(uint8_t auto_mute_mode);
|
||||
bool set_volume(float volume) override;
|
||||
|
||||
bool is_muted() override;
|
||||
float volume() override;
|
||||
|
||||
protected:
|
||||
bool write_mute_();
|
||||
bool write_volume_();
|
||||
|
||||
uint8_t auto_mute_mode_{0};
|
||||
float volume_{0};
|
||||
};
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
52
esphome/components/aic3204/audio_dac.py
Normal file
52
esphome/components/aic3204/audio_dac.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c
|
||||
from esphome.components.audio_dac import AudioDac
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_MODE
|
||||
|
||||
CODEOWNERS = ["@kbx81"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
aic3204_ns = cg.esphome_ns.namespace("aic3204")
|
||||
AIC3204 = aic3204_ns.class_("AIC3204", AudioDac, cg.Component, i2c.I2CDevice)
|
||||
|
||||
SetAutoMuteAction = aic3204_ns.class_("SetAutoMuteAction", automation.Action)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(AIC3204),
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(i2c.i2c_device_schema(0x18))
|
||||
)
|
||||
|
||||
|
||||
SET_AUTO_MUTE_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(AIC3204),
|
||||
cv.Required(CONF_MODE): cv.templatable(cv.int_range(max=7, min=0)),
|
||||
},
|
||||
key=CONF_MODE,
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aic3204.set_auto_mute_mode", SetAutoMuteAction, SET_AUTO_MUTE_ACTION_SCHEMA
|
||||
)
|
||||
async def aic3204_set_volume_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config.get(CONF_MODE), args, int)
|
||||
cg.add(var.set_auto_mute_mode(template_))
|
||||
|
||||
return var
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
23
esphome/components/aic3204/automation.h
Normal file
23
esphome/components/aic3204/automation.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "aic3204.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
|
||||
template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit SetAutoMuteAction(AIC3204 *aic3204) : aic3204_(aic3204) {}
|
||||
|
||||
TEMPLATABLE_VALUE(uint8_t, auto_mute_mode)
|
||||
|
||||
void play(Ts... x) override { this->aic3204_->set_auto_mute_mode(this->auto_mute_mode_.value(x...)); }
|
||||
|
||||
protected:
|
||||
AIC3204 *aic3204_;
|
||||
};
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
57
esphome/components/audio_dac/__init__.py
Normal file
57
esphome/components/audio_dac/__init__.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_VOLUME
|
||||
from esphome.core import coroutine_with_priority
|
||||
|
||||
CODEOWNERS = ["@kbx81"]
|
||||
IS_PLATFORM_COMPONENT = True
|
||||
|
||||
audio_dac_ns = cg.esphome_ns.namespace("audio_dac")
|
||||
AudioDac = audio_dac_ns.class_("AudioDac")
|
||||
|
||||
MuteOffAction = audio_dac_ns.class_("MuteOffAction", automation.Action)
|
||||
MuteOnAction = audio_dac_ns.class_("MuteOnAction", automation.Action)
|
||||
SetVolumeAction = audio_dac_ns.class_("SetVolumeAction", automation.Action)
|
||||
|
||||
|
||||
MUTE_ACTION_SCHEMA = maybe_simple_id(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(AudioDac),
|
||||
}
|
||||
)
|
||||
|
||||
SET_VOLUME_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(AudioDac),
|
||||
cv.Required(CONF_VOLUME): cv.templatable(cv.percentage),
|
||||
},
|
||||
key=CONF_VOLUME,
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action("audio_dac.mute_off", MuteOffAction, MUTE_ACTION_SCHEMA)
|
||||
@automation.register_action("audio_dac.mute_on", MuteOnAction, MUTE_ACTION_SCHEMA)
|
||||
async def audio_dac_mute_action_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"audio_dac.set_volume", SetVolumeAction, SET_VOLUME_ACTION_SCHEMA
|
||||
)
|
||||
async def audio_dac_set_volume_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config.get(CONF_VOLUME), args, float)
|
||||
cg.add(var.set_volume(template_))
|
||||
|
||||
return var
|
||||
|
||||
|
||||
@coroutine_with_priority(100.0)
|
||||
async def to_code(config):
|
||||
cg.add_define("USE_AUDIO_DAC")
|
||||
cg.add_global(audio_dac_ns.using)
|
23
esphome/components/audio_dac/audio_dac.h
Normal file
23
esphome/components/audio_dac/audio_dac.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace audio_dac {
|
||||
|
||||
class AudioDac {
|
||||
public:
|
||||
virtual bool set_mute_off() = 0;
|
||||
virtual bool set_mute_on() = 0;
|
||||
virtual bool set_volume(float volume) = 0;
|
||||
|
||||
virtual bool is_muted() = 0;
|
||||
virtual float volume() = 0;
|
||||
|
||||
protected:
|
||||
bool is_muted_{false};
|
||||
};
|
||||
|
||||
} // namespace audio_dac
|
||||
} // namespace esphome
|
43
esphome/components/audio_dac/automation.h
Normal file
43
esphome/components/audio_dac/automation.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "audio_dac.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace audio_dac {
|
||||
|
||||
template<typename... Ts> class MuteOffAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit MuteOffAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {}
|
||||
|
||||
void play(Ts... x) override { this->audio_dac_->set_mute_off(); }
|
||||
|
||||
protected:
|
||||
AudioDac *audio_dac_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class MuteOnAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit MuteOnAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {}
|
||||
|
||||
void play(Ts... x) override { this->audio_dac_->set_mute_on(); }
|
||||
|
||||
protected:
|
||||
AudioDac *audio_dac_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class SetVolumeAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit SetVolumeAction(AudioDac *audio_dac) : audio_dac_(audio_dac) {}
|
||||
|
||||
TEMPLATABLE_VALUE(float, volume)
|
||||
|
||||
void play(Ts... x) override { this->audio_dac_->set_volume(this->volume_.value(x...)); }
|
||||
|
||||
protected:
|
||||
AudioDac *audio_dac_;
|
||||
};
|
||||
|
||||
} // namespace audio_dac
|
||||
} // namespace esphome
|
|
@ -157,8 +157,11 @@ void BangBangClimate::switch_to_action_(climate::ClimateAction action) {
|
|||
default:
|
||||
trig = nullptr;
|
||||
}
|
||||
assert(trig != nullptr);
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "trig not set - unsupported action");
|
||||
}
|
||||
this->action = action;
|
||||
this->prev_trigger_ = trig;
|
||||
this->publish_state();
|
||||
|
|
|
@ -13,8 +13,10 @@ float bedjet_temp_to_f(const uint8_t temp) {
|
|||
|
||||
/** Cleans up the packet before sending. */
|
||||
BedjetPacket *BedjetCodec::clean_packet_() {
|
||||
// So far no commands require more than 2 bytes of data.
|
||||
assert(this->packet_.data_length <= 2);
|
||||
// So far no commands require more than 2 bytes of data
|
||||
if (this->packet_.data_length > 2) {
|
||||
ESP_LOGW(TAG, "Packet may be malformed");
|
||||
}
|
||||
for (int i = this->packet_.data_length; i < 2; i++) {
|
||||
this->packet_.data[i] = '\0';
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ CONFIG_SCHEMA = cv.Schema(
|
|||
}
|
||||
).extend(uart.UART_DEVICE_SCHEMA)
|
||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
||||
"cse7766", baud_rate=4800, require_rx=True
|
||||
"cse7766", baud_rate=4800, parity="EVEN", require_rx=True
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ from esphome.const import (
|
|||
CONF_COMPONENTS,
|
||||
CONF_ESPHOME,
|
||||
CONF_FRAMEWORK,
|
||||
CONF_IGNORE_EFUSE_CUSTOM_MAC,
|
||||
CONF_IGNORE_EFUSE_MAC_CRC,
|
||||
CONF_NAME,
|
||||
CONF_PATH,
|
||||
|
@ -52,6 +53,7 @@ from .const import ( # noqa
|
|||
KEY_SDKCONFIG_OPTIONS,
|
||||
KEY_SUBMODULES,
|
||||
KEY_VARIANT,
|
||||
VARIANT_ESP32,
|
||||
VARIANT_FRIENDLY,
|
||||
VARIANTS,
|
||||
)
|
||||
|
@ -375,6 +377,15 @@ def final_validate(config):
|
|||
f"Please specify {CONF_FLASH_SIZE} within esp32 configuration only"
|
||||
)
|
||||
|
||||
if (
|
||||
config[CONF_VARIANT] != VARIANT_ESP32
|
||||
and CONF_ADVANCED in (conf_fw := config[CONF_FRAMEWORK])
|
||||
and CONF_IGNORE_EFUSE_MAC_CRC in conf_fw[CONF_ADVANCED]
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"{CONF_IGNORE_EFUSE_MAC_CRC} is not supported on {config[CONF_VARIANT]}"
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
|
@ -401,7 +412,10 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
|
|||
},
|
||||
cv.Optional(CONF_ADVANCED, default={}): cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean,
|
||||
cv.Optional(
|
||||
CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False
|
||||
): cv.boolean,
|
||||
cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC): cv.boolean,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list(
|
||||
|
@ -526,8 +540,10 @@ async def to_code(config):
|
|||
for name, value in conf[CONF_SDKCONFIG_OPTIONS].items():
|
||||
add_idf_sdkconfig_option(name, RawSdkconfigValue(value))
|
||||
|
||||
if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_MAC_CRC]:
|
||||
cg.add_define("USE_ESP32_IGNORE_EFUSE_MAC_CRC")
|
||||
if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]:
|
||||
cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC")
|
||||
if conf[CONF_ADVANCED].get(CONF_IGNORE_EFUSE_MAC_CRC):
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True)
|
||||
if (framework_ver.major, framework_ver.minor) >= (4, 4):
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False
|
||||
|
|
|
@ -6,7 +6,7 @@ import logging
|
|||
from pathlib import Path
|
||||
import re
|
||||
|
||||
from magic import Magic
|
||||
import puremagic
|
||||
|
||||
from esphome import core, external_files
|
||||
import esphome.codegen as cg
|
||||
|
@ -237,8 +237,8 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA)
|
|||
|
||||
|
||||
def load_svg_image(file: bytes, resize: tuple[int, int]):
|
||||
# Local import only to allow "validate_pillow_installed" to run *before* importing it
|
||||
# This import is only needed in case of SVG images; adding it
|
||||
# Local imports only to allow "validate_pillow_installed" to run *before* importing it
|
||||
# cairosvg is only needed in case of SVG images; adding it
|
||||
# to the top would force configurations not using SVG to also have it
|
||||
# installed for no reason.
|
||||
from cairosvg import svg2png
|
||||
|
@ -281,8 +281,7 @@ async def to_code(config):
|
|||
except Exception as e:
|
||||
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||
|
||||
mime = Magic(mime=True)
|
||||
file_type = mime.from_buffer(file_contents)
|
||||
file_type = puremagic.from_string(file_contents, mime=True)
|
||||
|
||||
resize = config.get(CONF_RESIZE)
|
||||
if "svg" in file_type:
|
||||
|
|
|
@ -12,7 +12,7 @@ from .defines import (
|
|||
)
|
||||
from .helpers import add_lv_use
|
||||
from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable
|
||||
from .schemas import ALL_STYLES
|
||||
from .schemas import ALL_STYLES, STYLE_REMAP
|
||||
from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr
|
||||
from .widgets import Widget, add_widgets, set_obj_properties, theme_widget_map
|
||||
from .widgets.obj import obj_spec
|
||||
|
@ -31,7 +31,8 @@ async def styles_to_code(config):
|
|||
value = await validator.process(value)
|
||||
if isinstance(value, list):
|
||||
value = "|".join(value)
|
||||
lv.call(f"style_set_{prop}", svar, literal(value))
|
||||
remapped_prop = STYLE_REMAP.get(prop, prop)
|
||||
lv.call(f"style_set_{remapped_prop}", svar, literal(value))
|
||||
|
||||
|
||||
async def theme_to_code(config):
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
|
||||
from esphome.components import sensor, i2c
|
||||
|
||||
from esphome.const import (
|
||||
CONF_AMMONIA,
|
||||
CONF_CARBON_MONOXIDE,
|
||||
CONF_ETHANOL,
|
||||
CONF_HYDROGEN,
|
||||
CONF_ID,
|
||||
CONF_METHANE,
|
||||
CONF_NITROGEN_DIOXIDE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_PARTS_PER_MILLION,
|
||||
)
|
||||
|
@ -12,13 +16,6 @@ from esphome.const import (
|
|||
CODEOWNERS = ["@jesserockz"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
CONF_CARBON_MONOXIDE = "carbon_monoxide"
|
||||
CONF_NITROGEN_DIOXIDE = "nitrogen_dioxide"
|
||||
CONF_METHANE = "methane"
|
||||
CONF_ETHANOL = "ethanol"
|
||||
CONF_HYDROGEN = "hydrogen"
|
||||
CONF_AMMONIA = "ammonia"
|
||||
|
||||
|
||||
mics_4514_ns = cg.esphome_ns.namespace("mics_4514")
|
||||
MICS4514Component = mics_4514_ns.class_(
|
||||
|
@ -31,6 +28,7 @@ SENSORS = [
|
|||
CONF_ETHANOL,
|
||||
CONF_HYDROGEN,
|
||||
CONF_AMMONIA,
|
||||
CONF_NITROGEN_DIOXIDE,
|
||||
]
|
||||
|
||||
common_sensor_schema = sensor.sensor_schema(
|
||||
|
@ -40,16 +38,7 @@ common_sensor_schema = sensor.sensor_schema(
|
|||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(MICS4514Component),
|
||||
cv.Optional(CONF_NITROGEN_DIOXIDE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_PARTS_PER_MILLION,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
accuracy_decimals=2,
|
||||
),
|
||||
}
|
||||
)
|
||||
cv.Schema({cv.GenerateID(): cv.declare_id(MICS4514Component)})
|
||||
.extend({cv.Optional(sensor_type): common_sensor_schema for sensor_type in SENSORS})
|
||||
.extend(i2c.i2c_device_schema(0x75))
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
|
@ -62,10 +51,6 @@ async def to_code(config):
|
|||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
for sensor_type in SENSORS:
|
||||
if sensor_type in config:
|
||||
sens = await sensor.new_sensor(config[sensor_type])
|
||||
if sensor_config := config.get(sensor_type):
|
||||
sens = await sensor.new_sensor(sensor_config)
|
||||
cg.add(getattr(var, f"set_{sensor_type}_sensor")(sens))
|
||||
|
||||
if CONF_NITROGEN_DIOXIDE in config:
|
||||
sens = await sensor.new_sensor(config[CONF_NITROGEN_DIOXIDE])
|
||||
cg.add(var.set_nitrogen_dioxide_sensor(sens))
|
||||
|
|
|
@ -53,12 +53,19 @@ pulse_counter_t BasicPulseCounterStorage::read_raw_value() {
|
|||
#ifdef HAS_PCNT
|
||||
bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
||||
static pcnt_unit_t next_pcnt_unit = PCNT_UNIT_0;
|
||||
static pcnt_channel_t next_pcnt_channel = PCNT_CHANNEL_0;
|
||||
this->pin = pin;
|
||||
this->pin->setup();
|
||||
this->pcnt_unit = next_pcnt_unit;
|
||||
this->pcnt_channel = next_pcnt_channel;
|
||||
next_pcnt_unit = pcnt_unit_t(int(next_pcnt_unit) + 1);
|
||||
if (int(next_pcnt_unit) >= PCNT_UNIT_0 + PCNT_UNIT_MAX) {
|
||||
next_pcnt_unit = PCNT_UNIT_0;
|
||||
next_pcnt_channel = pcnt_channel_t(int(next_pcnt_channel) + 1);
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(TAG, " PCNT Unit Number: %u", this->pcnt_unit);
|
||||
ESP_LOGCONFIG(TAG, " PCNT Channel Number: %u", this->pcnt_channel);
|
||||
|
||||
pcnt_count_mode_t rising = PCNT_COUNT_DIS, falling = PCNT_COUNT_DIS;
|
||||
switch (this->rising_edge_mode) {
|
||||
|
@ -94,7 +101,7 @@ bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
|||
.counter_h_lim = 0,
|
||||
.counter_l_lim = 0,
|
||||
.unit = this->pcnt_unit,
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.channel = this->pcnt_channel,
|
||||
};
|
||||
esp_err_t error = pcnt_unit_config(&pcnt_config);
|
||||
if (error != ESP_OK) {
|
||||
|
|
|
@ -55,6 +55,7 @@ struct HwPulseCounterStorage : public PulseCounterStorageBase {
|
|||
pulse_counter_t read_raw_value() override;
|
||||
|
||||
pcnt_unit_t pcnt_unit;
|
||||
pcnt_channel_t pcnt_channel;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -71,6 +71,14 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
|
|||
# return f"~1.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
||||
|
||||
|
||||
def _parse_platform_version(value):
|
||||
value = cv.string(value)
|
||||
if value.startswith("http"):
|
||||
return value
|
||||
|
||||
return f"https://github.com/maxgerhardt/platform-raspberrypi.git#{value}"
|
||||
|
||||
|
||||
# NOTE: Keep this in mind when updating the recommended version:
|
||||
# * The new version needs to be thoroughly validated before changing the
|
||||
# recommended version as otherwise a bunch of devices could be bricked
|
||||
|
@ -82,10 +90,9 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
|
|||
# - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico
|
||||
RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 9, 4)
|
||||
|
||||
# The platformio/raspberrypi version to use for arduino frameworks
|
||||
# - https://github.com/platformio/platform-raspberrypi/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi
|
||||
ARDUINO_PLATFORM_VERSION = cv.Version(1, 13, 0)
|
||||
# The raspberrypi platform version to use for arduino frameworks
|
||||
# - https://github.com/maxgerhardt/platform-raspberrypi/tags
|
||||
RECOMMENDED_ARDUINO_PLATFORM_VERSION = "v1.2.0-gcc12"
|
||||
|
||||
|
||||
def _arduino_check_versions(value):
|
||||
|
@ -111,7 +118,8 @@ def _arduino_check_versions(value):
|
|||
value[CONF_SOURCE] = source or _format_framework_arduino_version(version)
|
||||
|
||||
value[CONF_PLATFORM_VERSION] = value.get(
|
||||
CONF_PLATFORM_VERSION, _parse_platform_version(str(ARDUINO_PLATFORM_VERSION))
|
||||
CONF_PLATFORM_VERSION,
|
||||
_parse_platform_version(RECOMMENDED_ARDUINO_PLATFORM_VERSION),
|
||||
)
|
||||
|
||||
if version != RECOMMENDED_ARDUINO_FRAMEWORK_VERSION:
|
||||
|
@ -122,15 +130,6 @@ def _arduino_check_versions(value):
|
|||
return value
|
||||
|
||||
|
||||
def _parse_platform_version(value):
|
||||
try:
|
||||
# if platform version is a valid version constraint, prefix the default package
|
||||
cv.platformio_version_constraint(value)
|
||||
return f"platformio/raspberrypi@{value}"
|
||||
except cv.Invalid:
|
||||
return value
|
||||
|
||||
|
||||
ARDUINO_FRAMEWORK_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include <algorithm>
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace tcs34725 {
|
||||
|
@ -14,10 +15,7 @@ static const uint8_t TCS34725_REGISTER_ID = TCS34725_COMMAND_BIT | 0x12;
|
|||
static const uint8_t TCS34725_REGISTER_ATIME = TCS34725_COMMAND_BIT | 0x01;
|
||||
static const uint8_t TCS34725_REGISTER_CONTROL = TCS34725_COMMAND_BIT | 0x0F;
|
||||
static const uint8_t TCS34725_REGISTER_ENABLE = TCS34725_COMMAND_BIT | 0x00;
|
||||
static const uint8_t TCS34725_REGISTER_CDATAL = TCS34725_COMMAND_BIT | 0x14;
|
||||
static const uint8_t TCS34725_REGISTER_RDATAL = TCS34725_COMMAND_BIT | 0x16;
|
||||
static const uint8_t TCS34725_REGISTER_GDATAL = TCS34725_COMMAND_BIT | 0x18;
|
||||
static const uint8_t TCS34725_REGISTER_BDATAL = TCS34725_COMMAND_BIT | 0x1A;
|
||||
static const uint8_t TCS34725_REGISTER_CRGBDATAL = TCS34725_COMMAND_BIT | 0x14;
|
||||
|
||||
void TCS34725Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up TCS34725...");
|
||||
|
@ -75,12 +73,10 @@ float TCS34725Component::get_setup_priority() const { return setup_priority::DAT
|
|||
* @return Color temperature in degrees Kelvin
|
||||
*/
|
||||
void TCS34725Component::calculate_temperature_and_lux_(uint16_t r, uint16_t g, uint16_t b, uint16_t c) {
|
||||
float r2, g2, b2; /* RGB values minus IR component */
|
||||
float sat; /* Digital saturation level */
|
||||
float ir; /* Inferred IR content */
|
||||
|
||||
this->illuminance_ = 0; // Assign 0 value before calculation
|
||||
this->color_temperature_ = 0;
|
||||
this->illuminance_ = NAN;
|
||||
this->color_temperature_ = NAN;
|
||||
|
||||
const float ga = this->glass_attenuation_; // Glass Attenuation Factor
|
||||
static const float DF = 310.f; // Device Factor
|
||||
|
@ -89,6 +85,9 @@ void TCS34725Component::calculate_temperature_and_lux_(uint16_t r, uint16_t g, u
|
|||
static const float B_COEF = -0.444f; //
|
||||
static const float CT_COEF = 3810.f; // Color Temperature Coefficient
|
||||
static const float CT_OFFSET = 1391.f; // Color Temperatuer Offset
|
||||
static const float MAX_ILLUMINANCE = 100000.0f; // Cap illuminance at 100,000 lux
|
||||
static const float MAX_COLOR_TEMPERATURE = 15000.0f; // Maximum expected color temperature in Kelvin
|
||||
static const float MIN_COLOR_TEMPERATURE = 1000.0f; // Maximum reasonable color temperature in Kelvin
|
||||
|
||||
if (c == 0) {
|
||||
return;
|
||||
|
@ -139,69 +138,66 @@ void TCS34725Component::calculate_temperature_and_lux_(uint16_t r, uint16_t g, u
|
|||
if (c >= sat) {
|
||||
if (this->integration_time_auto_) {
|
||||
ESP_LOGI(TAG, "Saturation too high, sample discarded, autogain ongoing");
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGW(
|
||||
TAG,
|
||||
"Saturation too high, sample with saturation %.1f and clear %d treat values carefully or use grey filter",
|
||||
sat, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* AMS RGB sensors have no IR channel, so the IR content must be */
|
||||
/* calculated indirectly. */
|
||||
ir = ((r + g + b) > c) ? (r + g + b - c) / 2 : 0;
|
||||
|
||||
/* Remove the IR component from the raw RGB values */
|
||||
r2 = r - ir;
|
||||
g2 = g - ir;
|
||||
b2 = b - ir;
|
||||
|
||||
// discarding super low values? not recemmonded, and avoided by using auto gain.
|
||||
if (r2 == 0) {
|
||||
// legacy code
|
||||
if (!this->integration_time_auto_) {
|
||||
ESP_LOGW(TAG,
|
||||
"No light detected on red channel, switch to auto gain or adjust timing, values will be unreliable");
|
||||
"Saturation too high, sample with saturation %.1f and clear %d lux/color temperature cannot reliably "
|
||||
"calculated, reduce integration/gain or use a grey filter.",
|
||||
sat, c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Lux Calculation (DN40 3.2)
|
||||
|
||||
float g1 = R_COEF * r2 + G_COEF * g2 + B_COEF * b2;
|
||||
float g1 = R_COEF * (float) r + G_COEF * (float) g + B_COEF * (float) b;
|
||||
float cpl = (this->integration_time_ * this->gain_) / (ga * DF);
|
||||
this->illuminance_ = g1 / cpl;
|
||||
|
||||
this->illuminance_ = std::max(g1 / cpl, 0.0f);
|
||||
|
||||
if (this->illuminance_ > MAX_ILLUMINANCE) {
|
||||
ESP_LOGW(TAG, "Calculated illuminance greater than limit (%f), setting to NAN", this->illuminance_);
|
||||
this->illuminance_ = NAN;
|
||||
return;
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
ESP_LOGW(TAG, "Red channel is zero, cannot compute color temperature");
|
||||
return;
|
||||
}
|
||||
|
||||
// Color Temperature Calculation (DN40)
|
||||
/* A simple method of measuring color temp is to use the ratio of blue */
|
||||
/* to red light, taking IR cancellation into account. */
|
||||
this->color_temperature_ = (CT_COEF * b2) / /** Color temp coefficient. */
|
||||
r2 +
|
||||
CT_OFFSET; /** Color temp offset. */
|
||||
/* to red light. */
|
||||
|
||||
this->color_temperature_ = (CT_COEF * (float) b) / (float) r + CT_OFFSET;
|
||||
|
||||
// Ensure the color temperature stays within reasonable bounds
|
||||
if (this->color_temperature_ < MIN_COLOR_TEMPERATURE) {
|
||||
ESP_LOGW(TAG, "Calculated color temperature value too low (%f), setting to NAN", this->color_temperature_);
|
||||
this->color_temperature_ = NAN;
|
||||
} else if (this->color_temperature_ > MAX_COLOR_TEMPERATURE) {
|
||||
ESP_LOGW(TAG, "Calculated color temperature value too high (%f), setting to NAN", this->color_temperature_);
|
||||
this->color_temperature_ = NAN;
|
||||
}
|
||||
}
|
||||
|
||||
void TCS34725Component::update() {
|
||||
uint16_t raw_c;
|
||||
uint16_t raw_r;
|
||||
uint16_t raw_g;
|
||||
uint16_t raw_b;
|
||||
uint8_t data[8]; // Buffer to hold the 8 bytes (2 bytes for each of the 4 channels)
|
||||
|
||||
if (this->read_data_register_(TCS34725_REGISTER_CDATAL, raw_c) != i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
if (this->read_data_register_(TCS34725_REGISTER_RDATAL, raw_r) != i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
if (this->read_data_register_(TCS34725_REGISTER_GDATAL, raw_g) != i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
if (this->read_data_register_(TCS34725_REGISTER_BDATAL, raw_b) != i2c::ERROR_OK) {
|
||||
// Perform burst
|
||||
if (this->read_register(TCS34725_REGISTER_CRGBDATAL, data, 8) != i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGW(TAG, "Error reading TCS34725 sensor data");
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the data
|
||||
uint16_t raw_c = encode_uint16(data[1], data[0]); // Clear channel
|
||||
uint16_t raw_r = encode_uint16(data[3], data[2]); // Red channel
|
||||
uint16_t raw_g = encode_uint16(data[5], data[4]); // Green channel
|
||||
uint16_t raw_b = encode_uint16(data[7], data[6]); // Blue channel
|
||||
|
||||
ESP_LOGV(TAG, "Raw values clear=%d red=%d green=%d blue=%d", raw_c, raw_r, raw_g, raw_b);
|
||||
|
||||
float channel_c;
|
||||
|
|
|
@ -502,8 +502,9 @@ void ThermostatClimate::switch_to_action_(climate::ClimateAction action, bool pu
|
|||
}
|
||||
this->action = action;
|
||||
this->prev_action_trigger_ = trig;
|
||||
assert(trig != nullptr);
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
// if enabled, call the fan_only action with cooling/heating actions
|
||||
if (trig_fan != nullptr) {
|
||||
ESP_LOGVV(TAG, "Calling FAN_ONLY action with HEATING/COOLING action");
|
||||
|
@ -564,7 +565,6 @@ void ThermostatClimate::trigger_supplemental_action_() {
|
|||
}
|
||||
|
||||
if (trig != nullptr) {
|
||||
assert(trig != nullptr);
|
||||
trig->trigger();
|
||||
}
|
||||
}
|
||||
|
@ -634,8 +634,9 @@ void ThermostatClimate::switch_to_fan_mode_(climate::ClimateFanMode fan_mode, bo
|
|||
this->prev_fan_mode_trigger_ = nullptr;
|
||||
}
|
||||
this->start_timer_(thermostat::TIMER_FAN_MODE);
|
||||
assert(trig != nullptr);
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
this->prev_fan_mode_ = fan_mode;
|
||||
this->prev_fan_mode_trigger_ = trig;
|
||||
}
|
||||
|
@ -678,8 +679,9 @@ void ThermostatClimate::switch_to_mode_(climate::ClimateMode mode, bool publish_
|
|||
mode = climate::CLIMATE_MODE_HEAT_COOL;
|
||||
// trig = this->auto_mode_trigger_;
|
||||
}
|
||||
assert(trig != nullptr);
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
this->mode = mode;
|
||||
this->prev_mode_ = mode;
|
||||
this->prev_mode_trigger_ = trig;
|
||||
|
@ -718,8 +720,9 @@ void ThermostatClimate::switch_to_swing_mode_(climate::ClimateSwingMode swing_mo
|
|||
swing_mode = climate::CLIMATE_SWING_OFF;
|
||||
// trig = this->swing_mode_off_trigger_;
|
||||
}
|
||||
assert(trig != nullptr);
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
this->swing_mode = swing_mode;
|
||||
this->prev_swing_mode_ = swing_mode;
|
||||
this->prev_swing_mode_trigger_ = trig;
|
||||
|
@ -867,9 +870,10 @@ void ThermostatClimate::check_temperature_change_trigger_() {
|
|||
}
|
||||
// trigger the action
|
||||
Trigger<> *trig = this->temperature_change_trigger_;
|
||||
assert(trig != nullptr);
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
bool ThermostatClimate::cooling_required_() {
|
||||
auto temperature = this->supports_two_points_ ? this->target_temperature_high : this->target_temperature;
|
||||
|
@ -998,9 +1002,10 @@ void ThermostatClimate::change_preset_(climate::ClimatePreset preset) {
|
|||
this->preset.value() != preset) {
|
||||
// Fire any preset changed trigger if defined
|
||||
Trigger<> *trig = this->preset_change_trigger_;
|
||||
assert(trig != nullptr);
|
||||
this->preset = preset;
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
|
||||
this->refresh();
|
||||
ESP_LOGI(TAG, "Preset %s applied", LOG_STR_ARG(climate::climate_preset_to_string(preset)));
|
||||
|
@ -1023,9 +1028,10 @@ void ThermostatClimate::change_custom_preset_(const std::string &custom_preset)
|
|||
this->custom_preset.value() != custom_preset) {
|
||||
// Fire any preset changed trigger if defined
|
||||
Trigger<> *trig = this->preset_change_trigger_;
|
||||
assert(trig != nullptr);
|
||||
this->custom_preset = custom_preset;
|
||||
if (trig != nullptr) {
|
||||
trig->trigger();
|
||||
}
|
||||
|
||||
this->refresh();
|
||||
ESP_LOGI(TAG, "Custom preset %s applied", custom_preset.c_str());
|
||||
|
|
|
@ -219,10 +219,17 @@ void WebServer::handle_sensor_request(AsyncWebServerRequest *request, const UrlM
|
|||
for (sensor::Sensor *obj : App.get_sensors()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->sensor_json(obj, obj->state, DETAIL_STATE);
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->sensor_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
request->send(404);
|
||||
}
|
||||
std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail start_config) {
|
||||
|
@ -257,10 +264,17 @@ void WebServer::handle_text_sensor_request(AsyncWebServerRequest *request, const
|
|||
for (text_sensor::TextSensor *obj : App.get_text_sensors()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->text_sensor_json(obj, obj->state, DETAIL_STATE);
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->text_sensor_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
request->send(404);
|
||||
}
|
||||
std::string WebServer::text_sensor_json(text_sensor::TextSensor *obj, const std::string &value,
|
||||
|
@ -288,7 +302,12 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->switch_json(obj, obj->state, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->switch_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "toggle") {
|
||||
this->schedule_([obj]() { obj->toggle(); });
|
||||
|
@ -324,7 +343,15 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM
|
|||
for (button::Button *obj : App.get_buttons()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
if (match.method == "press") {
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->button_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "press") {
|
||||
this->schedule_([obj]() { obj->press(); });
|
||||
request->send(200);
|
||||
return;
|
||||
|
@ -357,10 +384,17 @@ void WebServer::handle_binary_sensor_request(AsyncWebServerRequest *request, con
|
|||
for (binary_sensor::BinarySensor *obj : App.get_binary_sensors()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
std::string data = this->binary_sensor_json(obj, obj->state, DETAIL_STATE);
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->binary_sensor_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
request->send(404);
|
||||
}
|
||||
std::string WebServer::binary_sensor_json(binary_sensor::BinarySensor *obj, bool value, JsonDetail start_config) {
|
||||
|
@ -388,7 +422,12 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->fan_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->fan_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "toggle") {
|
||||
this->schedule_([obj]() { obj->toggle().perform(); });
|
||||
|
@ -466,7 +505,12 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->light_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->light_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "toggle") {
|
||||
this->schedule_([obj]() { obj->toggle().perform(); });
|
||||
|
@ -577,9 +621,14 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->cover_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->cover_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
|
@ -653,7 +702,12 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->number_json(obj, obj->state, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->number_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
@ -717,8 +771,13 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat
|
|||
for (auto *obj : App.get_dates()) {
|
||||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
if (request->method() == HTTP_GET) {
|
||||
std::string data = this->date_json(obj, DETAIL_STATE);
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->date_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
@ -772,7 +831,12 @@ void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMat
|
|||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->time_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->time_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
@ -825,7 +889,12 @@ void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const Ur
|
|||
if (obj->get_object_id() != match.id)
|
||||
continue;
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->datetime_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->datetime_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
@ -880,8 +949,13 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->text_json(obj, obj->state, DETAIL_STATE);
|
||||
request->send(200, "text/json", data.c_str());
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->text_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (match.method != "set") {
|
||||
|
@ -995,11 +1069,15 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->climate_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->climate_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (match.method != "set") {
|
||||
request->send(404);
|
||||
return;
|
||||
|
@ -1149,7 +1227,12 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->lock_json(obj, obj->state, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->lock_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method == "lock") {
|
||||
this->schedule_([obj]() { obj->lock(); });
|
||||
|
@ -1192,9 +1275,14 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->valve_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->valve_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
|
@ -1257,7 +1345,12 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->alarm_control_panel_json(obj, obj->get_state(), DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->alarm_control_panel_json(obj, obj->get_state(), detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
@ -1314,7 +1407,12 @@ void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlM
|
|||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && match.method.empty()) {
|
||||
std::string data = this->update_json(obj, DETAIL_STATE);
|
||||
auto detail = DETAIL_STATE;
|
||||
auto *param = request->getParam("detail");
|
||||
if (param && param->value() == "all") {
|
||||
detail = DETAIL_ALL;
|
||||
}
|
||||
std::string data = this->update_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -131,16 +131,10 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi
|
|||
|
||||
void WiFiComponent::wifi_pre_setup_() {
|
||||
uint8_t mac[6];
|
||||
#ifdef USE_ESP32_IGNORE_EFUSE_MAC_CRC
|
||||
get_mac_address_raw(mac);
|
||||
set_mac_address(mac);
|
||||
ESP_LOGV(TAG, "Use EFuse MAC without checking CRC: %s", get_mac_address_pretty().c_str());
|
||||
#else
|
||||
if (has_custom_mac_address()) {
|
||||
get_mac_address_raw(mac);
|
||||
set_mac_address(mac);
|
||||
}
|
||||
#endif
|
||||
esp_err_t err = esp_netif_init();
|
||||
if (err != ERR_OK) {
|
||||
ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err));
|
||||
|
|
|
@ -753,6 +753,7 @@ def time_period_str_unit(value):
|
|||
"ns": "nanoseconds",
|
||||
"nanoseconds": "nanoseconds",
|
||||
"us": "microseconds",
|
||||
"µs": "microseconds",
|
||||
"microseconds": "microseconds",
|
||||
"ms": "milliseconds",
|
||||
"milliseconds": "milliseconds",
|
||||
|
|
|
@ -55,6 +55,7 @@ CONF_ALLOW_OTHER_USES = "allow_other_uses"
|
|||
CONF_ALPHA = "alpha"
|
||||
CONF_ALTITUDE = "altitude"
|
||||
CONF_AMBIENT_LIGHT = "ambient_light"
|
||||
CONF_AMMONIA = "ammonia"
|
||||
CONF_ANALOG = "analog"
|
||||
CONF_AND = "and"
|
||||
CONF_ANGLE = "angle"
|
||||
|
@ -112,6 +113,7 @@ CONF_CALIBRATE_LINEAR = "calibrate_linear"
|
|||
CONF_CALIBRATION = "calibration"
|
||||
CONF_CAPACITANCE = "capacitance"
|
||||
CONF_CAPACITY = "capacity"
|
||||
CONF_CARBON_MONOXIDE = "carbon_monoxide"
|
||||
CONF_CARRIER_DUTY_PERCENT = "carrier_duty_percent"
|
||||
CONF_CARRIER_FREQUENCY = "carrier_frequency"
|
||||
CONF_CERTIFICATE = "certificate"
|
||||
|
@ -265,6 +267,7 @@ CONF_ENUM_DATAPOINT = "enum_datapoint"
|
|||
CONF_EQUATION = "equation"
|
||||
CONF_ESP8266_DISABLE_SSL_SUPPORT = "esp8266_disable_ssl_support"
|
||||
CONF_ESPHOME = "esphome"
|
||||
CONF_ETHANOL = "ethanol"
|
||||
CONF_ETHERNET = "ethernet"
|
||||
CONF_EVENT = "event"
|
||||
CONF_EVENT_TYPE = "event_type"
|
||||
|
@ -363,6 +366,7 @@ CONF_HOURS = "hours"
|
|||
CONF_HSYNC_PIN = "hsync_pin"
|
||||
CONF_HUMIDITY = "humidity"
|
||||
CONF_HUMIDITY_SENSOR = "humidity_sensor"
|
||||
CONF_HYDROGEN = "hydrogen"
|
||||
CONF_HYSTERESIS = "hysteresis"
|
||||
CONF_I2C = "i2c"
|
||||
CONF_I2C_ID = "i2c_id"
|
||||
|
@ -378,6 +382,7 @@ CONF_IDLE_ACTION = "idle_action"
|
|||
CONF_IDLE_LEVEL = "idle_level"
|
||||
CONF_IDLE_TIME = "idle_time"
|
||||
CONF_IF = "if"
|
||||
CONF_IGNORE_EFUSE_CUSTOM_MAC = "ignore_efuse_custom_mac"
|
||||
CONF_IGNORE_EFUSE_MAC_CRC = "ignore_efuse_mac_crc"
|
||||
CONF_IGNORE_OUT_OF_RANGE = "ignore_out_of_range"
|
||||
CONF_IGNORE_PIN_VALIDATION_ERROR = "ignore_pin_validation_error"
|
||||
|
@ -478,6 +483,7 @@ CONF_MEDIA_PLAYER = "media_player"
|
|||
CONF_MEDIUM = "medium"
|
||||
CONF_MEMORY_BLOCKS = "memory_blocks"
|
||||
CONF_MESSAGE = "message"
|
||||
CONF_METHANE = "methane"
|
||||
CONF_METHOD = "method"
|
||||
CONF_MICROPHONE = "microphone"
|
||||
CONF_MIN_BRIGHTNESS = "min_brightness"
|
||||
|
@ -524,6 +530,7 @@ CONF_NBITS = "nbits"
|
|||
CONF_NEC = "nec"
|
||||
CONF_NETWORKS = "networks"
|
||||
CONF_NEW_PASSWORD = "new_password"
|
||||
CONF_NITROGEN_DIOXIDE = "nitrogen_dioxide"
|
||||
CONF_NOISE_LEVEL = "noise_level"
|
||||
CONF_NUM_ATTEMPTS = "num_attempts"
|
||||
CONF_NUM_CHANNELS = "num_channels"
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#define USE_LVGL_KEYBOARD
|
||||
#define USE_LVGL_ROTARY_ENCODER
|
||||
#define USE_LVGL_TOUCHSCREEN
|
||||
#define USE_MD5
|
||||
#define USE_MDNS
|
||||
#define USE_MEDIA_PLAYER
|
||||
#define USE_NEXTION_TFT_UPLOAD
|
||||
|
|
|
@ -45,9 +45,7 @@
|
|||
#endif
|
||||
#ifdef USE_ESP32
|
||||
#include "esp32/rom/crc.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC)
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#endif
|
||||
|
@ -679,13 +677,9 @@ void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parame
|
|||
static const uint8_t esphome_host_mac_address[6] = USE_ESPHOME_HOST_MAC_ADDRESS;
|
||||
memcpy(mac, esphome_host_mac_address, sizeof(esphome_host_mac_address));
|
||||
#elif defined(USE_ESP32)
|
||||
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC)
|
||||
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED)
|
||||
// When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default
|
||||
// returns the 802.15.4 EUI-64 address. Read directly from eFuse instead.
|
||||
// On some devices, the MAC address that is burnt into EFuse does not
|
||||
// match the CRC that goes along with it. For those devices, this
|
||||
// work-around reads and uses the MAC address as-is from EFuse,
|
||||
// without doing the CRC check.
|
||||
// returns the 802.15.4 EUI-64 address, so we read directly from eFuse instead.
|
||||
if (has_custom_mac_address()) {
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48);
|
||||
} else {
|
||||
|
@ -733,12 +727,13 @@ void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); }
|
|||
#endif
|
||||
|
||||
bool has_custom_mac_address() {
|
||||
#ifdef USE_ESP32
|
||||
#if defined(USE_ESP32) && !defined(USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC)
|
||||
uint8_t mac[6];
|
||||
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED) || defined(USE_ESP32_IGNORE_EFUSE_MAC_CRC)
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
|
||||
// do not use 'esp_efuse_mac_get_custom(mac)' because it drops an error in the logs whenever it fails
|
||||
#ifndef USE_ESP32_VARIANT_ESP32
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_USER_DATA_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
|
||||
#else
|
||||
return (esp_efuse_mac_get_custom(mac) == ESP_OK) && mac_address_is_valid(mac);
|
||||
return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
|
|
|
@ -90,9 +90,6 @@ esp32:
|
|||
RP2040_CONFIG = """
|
||||
rp2040:
|
||||
board: {board}
|
||||
framework:
|
||||
# Required until https://github.com/platformio/platform-raspberrypi/pull/36 is merged
|
||||
platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c
|
||||
"""
|
||||
|
||||
BK72XX_CONFIG = """
|
||||
|
|
|
@ -165,7 +165,7 @@ platform_packages =
|
|||
extends = common:arduino
|
||||
board_build.filesystem_size = 0.5m
|
||||
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12
|
||||
platform_packages =
|
||||
; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted
|
||||
earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.9.4/rp2040-3.9.4.zip
|
||||
|
|
|
@ -15,7 +15,7 @@ click==8.1.7
|
|||
esphome-dashboard==20240620.0
|
||||
aioesphomeapi==24.6.2
|
||||
zeroconf==0.132.2
|
||||
python-magic==0.4.27
|
||||
puremagic==1.27
|
||||
ruamel.yaml==0.18.6 # dashboard_import
|
||||
|
||||
# esp-idf requires this, but doesn't bundle it by default
|
||||
|
|
|
@ -108,7 +108,7 @@ def clang_options(idedata):
|
|||
cmd.extend(["-isystem", directory])
|
||||
|
||||
# add library include directories using -isystem to suppress their errors
|
||||
for directory in sorted(set(idedata["includes"]["build"])):
|
||||
for directory in list(idedata["includes"]["build"]):
|
||||
# skip our own directories, we add those later
|
||||
if (
|
||||
not directory.startswith(f"{root_path}/")
|
||||
|
|
15
tests/components/aic3204/common.yaml
Normal file
15
tests/components/aic3204/common.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
esphome:
|
||||
on_boot:
|
||||
then:
|
||||
- audio_dac.mute_off:
|
||||
- audio_dac.mute_on:
|
||||
- audio_dac.set_volume:
|
||||
volume: 50%
|
||||
|
||||
i2c:
|
||||
- id: i2c_aic3204
|
||||
scl: ${scl_pin}
|
||||
sda: ${sda_pin}
|
||||
|
||||
audio_dac:
|
||||
- platform: aic3204
|
5
tests/components/aic3204/test.esp32-ard.yaml
Normal file
5
tests/components/aic3204/test.esp32-ard.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO16
|
||||
sda_pin: GPIO17
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/aic3204/test.esp32-c3-ard.yaml
Normal file
5
tests/components/aic3204/test.esp32-c3-ard.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/aic3204/test.esp32-c3-idf.yaml
Normal file
5
tests/components/aic3204/test.esp32-c3-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/aic3204/test.esp32-idf.yaml
Normal file
5
tests/components/aic3204/test.esp32-idf.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO16
|
||||
sda_pin: GPIO17
|
||||
|
||||
<<: !include common.yaml
|
5
tests/components/aic3204/test.esp8266-ard.yaml
Normal file
5
tests/components/aic3204/test.esp8266-ard.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
substitutions:
|
||||
scl_pin: GPIO5
|
||||
sda_pin: GPIO4
|
||||
|
||||
<<: !include common.yaml
|
|
@ -5,6 +5,7 @@ uart:
|
|||
rx_pin:
|
||||
number: 16
|
||||
baud_rate: 4800
|
||||
parity: EVEN
|
||||
|
||||
sensor:
|
||||
- platform: cse7766
|
||||
|
|
|
@ -5,6 +5,7 @@ uart:
|
|||
rx_pin:
|
||||
number: 5
|
||||
baud_rate: 4800
|
||||
parity: EVEN
|
||||
|
||||
sensor:
|
||||
- platform: cse7766
|
||||
|
|
|
@ -5,6 +5,7 @@ uart:
|
|||
rx_pin:
|
||||
number: 5
|
||||
baud_rate: 4800
|
||||
parity: EVEN
|
||||
|
||||
sensor:
|
||||
- platform: cse7766
|
||||
|
|
|
@ -5,6 +5,7 @@ uart:
|
|||
rx_pin:
|
||||
number: 16
|
||||
baud_rate: 4800
|
||||
parity: EVEN
|
||||
|
||||
sensor:
|
||||
- platform: cse7766
|
||||
|
|
|
@ -5,6 +5,7 @@ uart:
|
|||
rx_pin:
|
||||
number: 5
|
||||
baud_rate: 4800
|
||||
parity: EVEN
|
||||
|
||||
sensor:
|
||||
- platform: cse7766
|
||||
|
|
|
@ -5,6 +5,7 @@ uart:
|
|||
rx_pin:
|
||||
number: 5
|
||||
baud_rate: 4800
|
||||
parity: EVEN
|
||||
|
||||
sensor:
|
||||
- platform: cse7766
|
||||
|
|
|
@ -12,7 +12,7 @@ light:
|
|||
num_leds: 60
|
||||
rmt_channel: 1
|
||||
rgb_order: RGB
|
||||
bit0_high: 100us
|
||||
bit0_low: 100us
|
||||
bit1_high: 100us
|
||||
bit1_low: 100us
|
||||
bit0_high: 100µs
|
||||
bit0_low: 100µs
|
||||
bit1_high: 100µs
|
||||
bit1_low: 100µs
|
||||
|
|
|
@ -12,7 +12,7 @@ light:
|
|||
num_leds: 60
|
||||
rmt_channel: 2
|
||||
rgb_order: RGB
|
||||
bit0_high: 100us
|
||||
bit0_low: 100us
|
||||
bit1_high: 100us
|
||||
bit1_low: 100us
|
||||
bit0_high: 100µs
|
||||
bit0_low: 100µs
|
||||
bit1_high: 100µs
|
||||
bit1_low: 100µs
|
||||
|
|
|
@ -67,6 +67,9 @@ lvgl:
|
|||
border_width: 2
|
||||
pad_all: 4
|
||||
align: center
|
||||
- id: image_recolor
|
||||
image_recolor: 0x10ca1e
|
||||
image_recolor_opa: cover
|
||||
|
||||
touchscreens:
|
||||
- touchscreen_id: tft_touch
|
||||
|
|
|
@ -4,9 +4,6 @@ esphome:
|
|||
|
||||
rp2040:
|
||||
board: rpipicow
|
||||
framework:
|
||||
# Waiting for https://github.com/platformio/platform-raspberrypi/pull/36
|
||||
platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git#5e87ae34ca025274df25b3303e9e9cb6c120123c
|
||||
|
||||
logger:
|
||||
level: VERY_VERBOSE
|
||||
|
|
Loading…
Reference in a new issue