mirror of
https://github.com/esphome/esphome.git
synced 2026-03-03 03:08:21 -07:00
Merge branch 'dev' into optimize-warn-blocking-guard
Resolve conflict in component.cpp: keep destructor removed (moved to header as = default) and keep #ifdef USE_SETUP_PRIORITY_OVERRIDE guard from dev. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,11 @@ static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
|
||||
static constexpr uint8_t MAX_PING_RETRIES = 60;
|
||||
static constexpr uint16_t PING_RETRY_INTERVAL = 1000;
|
||||
static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS * 5) / 2;
|
||||
// Timeout for completing the handshake (Noise transport + HelloRequest).
|
||||
// A stalled handshake from a buggy client or network glitch holds a connection
|
||||
// slot, which can prevent legitimate clients from reconnecting. Also hardens
|
||||
// against the less likely case of intentional connection slot exhaustion.
|
||||
static constexpr uint32_t HANDSHAKE_TIMEOUT_MS = 15000;
|
||||
|
||||
static constexpr auto ESPHOME_VERSION_REF = StringRef::from_lit(ESPHOME_VERSION);
|
||||
|
||||
@@ -205,7 +210,12 @@ void APIConnection::loop() {
|
||||
this->fatal_error_with_log_(LOG_STR("Reading failed"), err);
|
||||
return;
|
||||
} else {
|
||||
this->last_traffic_ = now;
|
||||
// Only update last_traffic_ after authentication to ensure the
|
||||
// handshake timeout is an absolute deadline from connection start.
|
||||
// Pre-auth messages (e.g. PingRequest) must not reset the timer.
|
||||
if (this->is_authenticated()) {
|
||||
this->last_traffic_ = now;
|
||||
}
|
||||
// read a packet
|
||||
this->read_message(buffer.data_len, buffer.type, buffer.data);
|
||||
if (this->flags_.remove)
|
||||
@@ -223,6 +233,15 @@ void APIConnection::loop() {
|
||||
this->process_active_iterator_();
|
||||
}
|
||||
|
||||
// Disconnect clients that haven't completed the handshake in time.
|
||||
// Stale half-open connections from buggy clients or network issues can
|
||||
// accumulate and block legitimate clients from reconnecting.
|
||||
if (!this->is_authenticated() && now - this->last_traffic_ > HANDSHAKE_TIMEOUT_MS) {
|
||||
this->on_fatal_error();
|
||||
this->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("handshake timeout; disconnecting"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->flags_.sent_ping) {
|
||||
// Disconnect if not responded within 2.5*keepalive
|
||||
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
|
||||
@@ -1484,6 +1503,8 @@ void APIConnection::complete_authentication_() {
|
||||
}
|
||||
|
||||
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
|
||||
// Reset traffic timer so keepalive starts from authentication, not connection start
|
||||
this->last_traffic_ = App.get_loop_component_start_time();
|
||||
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("connected"));
|
||||
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
|
||||
{
|
||||
|
||||
@@ -474,7 +474,7 @@ APIError APINoiseFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer, s
|
||||
// buf_start[1], buf_start[2] to be set after encryption
|
||||
|
||||
// Write message header (to be encrypted)
|
||||
const uint8_t msg_offset = 3;
|
||||
constexpr uint8_t msg_offset = 3;
|
||||
buf_start[msg_offset] = static_cast<uint8_t>(msg.message_type >> 8); // type high byte
|
||||
buf_start[msg_offset + 1] = static_cast<uint8_t>(msg.message_type); // type low byte
|
||||
buf_start[msg_offset + 2] = static_cast<uint8_t>(msg.payload_size >> 8); // data_len high byte
|
||||
|
||||
@@ -92,7 +92,10 @@ void APIServer::setup() {
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
if (logger::global_logger != nullptr) {
|
||||
logger::global_logger->add_log_listener(this);
|
||||
logger::global_logger->add_log_callback(
|
||||
this, [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
static_cast<APIServer *>(self)->on_log(level, tag, message, message_len);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -37,10 +37,6 @@ struct SavedNoisePsk {
|
||||
|
||||
class APIServer : public Component,
|
||||
public Controller
|
||||
#ifdef USE_LOGGER
|
||||
,
|
||||
public logger::LogListener
|
||||
#endif
|
||||
#ifdef USE_CAMERA
|
||||
,
|
||||
public camera::CameraListener
|
||||
@@ -56,7 +52,7 @@ class APIServer : public Component,
|
||||
void on_shutdown() override;
|
||||
bool teardown() override;
|
||||
#ifdef USE_LOGGER
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override;
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
|
||||
#endif
|
||||
#ifdef USE_CAMERA
|
||||
void on_camera_image(const std::shared_ptr<camera::CameraImage> &image) override;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.esp32 import add_idf_component, include_builtin_idf_component
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_BITS_PER_SAMPLE, CONF_NUM_CHANNELS, CONF_SAMPLE_RATE
|
||||
from esphome.core import CORE
|
||||
import esphome.final_validate as fv
|
||||
|
||||
CODEOWNERS = ["@kahrendt"]
|
||||
DOMAIN = "audio"
|
||||
audio_ns = cg.esphome_ns.namespace("audio")
|
||||
|
||||
AudioFile = audio_ns.struct("AudioFile")
|
||||
@@ -14,9 +18,38 @@ AUDIO_FILE_TYPE_ENUM = {
|
||||
"WAV": AudioFileType.WAV,
|
||||
"MP3": AudioFileType.MP3,
|
||||
"FLAC": AudioFileType.FLAC,
|
||||
"OPUS": AudioFileType.OPUS,
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class AudioData:
|
||||
flac_support: bool = False
|
||||
mp3_support: bool = False
|
||||
opus_support: bool = False
|
||||
|
||||
|
||||
def _get_data() -> AudioData:
|
||||
if DOMAIN not in CORE.data:
|
||||
CORE.data[DOMAIN] = AudioData()
|
||||
return CORE.data[DOMAIN]
|
||||
|
||||
|
||||
def request_flac_support() -> None:
|
||||
"""Request FLAC codec support for audio decoding."""
|
||||
_get_data().flac_support = True
|
||||
|
||||
|
||||
def request_mp3_support() -> None:
|
||||
"""Request MP3 codec support for audio decoding."""
|
||||
_get_data().mp3_support = True
|
||||
|
||||
|
||||
def request_opus_support() -> None:
|
||||
"""Request Opus codec support for audio decoding."""
|
||||
_get_data().opus_support = True
|
||||
|
||||
|
||||
CONF_MIN_BITS_PER_SAMPLE = "min_bits_per_sample"
|
||||
CONF_MAX_BITS_PER_SAMPLE = "max_bits_per_sample"
|
||||
CONF_MIN_CHANNELS = "min_channels"
|
||||
@@ -173,3 +206,12 @@ async def to_code(config):
|
||||
name="esphome/esp-audio-libs",
|
||||
ref="2.0.3",
|
||||
)
|
||||
|
||||
data = _get_data()
|
||||
if data.flac_support:
|
||||
cg.add_define("USE_AUDIO_FLAC_SUPPORT")
|
||||
if data.mp3_support:
|
||||
cg.add_define("USE_AUDIO_MP3_SUPPORT")
|
||||
if data.opus_support:
|
||||
cg.add_define("USE_AUDIO_OPUS_SUPPORT")
|
||||
add_idf_component(name="esphome/micro-opus", ref="0.3.3")
|
||||
|
||||
@@ -46,6 +46,10 @@ const char *audio_file_type_to_string(AudioFileType file_type) {
|
||||
#ifdef USE_AUDIO_MP3_SUPPORT
|
||||
case AudioFileType::MP3:
|
||||
return "MP3";
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
case AudioFileType::OPUS:
|
||||
return "OPUS";
|
||||
#endif
|
||||
case AudioFileType::WAV:
|
||||
return "WAV";
|
||||
|
||||
@@ -112,6 +112,9 @@ enum class AudioFileType : uint8_t {
|
||||
#endif
|
||||
#ifdef USE_AUDIO_MP3_SUPPORT
|
||||
MP3,
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
OPUS,
|
||||
#endif
|
||||
WAV,
|
||||
};
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace audio {
|
||||
|
||||
static const char *const TAG = "audio.decoder";
|
||||
|
||||
static const uint32_t DECODING_TIMEOUT_MS = 50; // The decode function will yield after this duration
|
||||
static const uint32_t READ_WRITE_TIMEOUT_MS = 20; // Timeout for transferring audio data
|
||||
|
||||
@@ -79,6 +82,14 @@ esp_err_t AudioDecoder::start(AudioFileType audio_file_type) {
|
||||
// Always reallocate the output transfer buffer to the smallest necessary size
|
||||
this->output_transfer_buffer_->reallocate(this->free_buffer_required_);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
case AudioFileType::OPUS:
|
||||
this->opus_decoder_ = make_unique<micro_opus::OggOpusDecoder>();
|
||||
this->free_buffer_required_ =
|
||||
this->output_transfer_buffer_->capacity(); // Adjusted and reallocated after reading the header
|
||||
this->decoder_buffers_internally_ = true;
|
||||
break;
|
||||
#endif
|
||||
case AudioFileType::WAV:
|
||||
this->wav_decoder_ = make_unique<esp_audio_libs::wav_decoder::WAVDecoder>();
|
||||
@@ -158,8 +169,9 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
|
||||
// Decode more audio
|
||||
|
||||
// Only shift data on the first loop iteration to avoid unnecessary, slow moves
|
||||
size_t bytes_read = this->input_transfer_buffer_->transfer_data_from_source(pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS),
|
||||
first_loop_iteration);
|
||||
// If the decoder buffers internally, then never shift
|
||||
size_t bytes_read = this->input_transfer_buffer_->transfer_data_from_source(
|
||||
pdMS_TO_TICKS(READ_WRITE_TIMEOUT_MS), first_loop_iteration && !this->decoder_buffers_internally_);
|
||||
|
||||
if (!first_loop_iteration && (this->input_transfer_buffer_->available() < bytes_processed)) {
|
||||
// Less data is available than what was processed in last iteration, so don't attempt to decode.
|
||||
@@ -195,6 +207,11 @@ AudioDecoderState AudioDecoder::decode(bool stop_gracefully) {
|
||||
case AudioFileType::MP3:
|
||||
state = this->decode_mp3_();
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
case AudioFileType::OPUS:
|
||||
state = this->decode_opus_();
|
||||
break;
|
||||
#endif
|
||||
case AudioFileType::WAV:
|
||||
state = this->decode_wav_();
|
||||
@@ -339,6 +356,45 @@ FileDecoderState AudioDecoder::decode_mp3_() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
FileDecoderState AudioDecoder::decode_opus_() {
|
||||
bool processed_header = this->opus_decoder_->is_initialized();
|
||||
|
||||
size_t bytes_consumed, samples_decoded;
|
||||
|
||||
micro_opus::OggOpusResult result = this->opus_decoder_->decode(
|
||||
this->input_transfer_buffer_->get_buffer_start(), this->input_transfer_buffer_->available(),
|
||||
this->output_transfer_buffer_->get_buffer_end(), this->output_transfer_buffer_->free(), bytes_consumed,
|
||||
samples_decoded);
|
||||
|
||||
if (result == micro_opus::OGG_OPUS_OK) {
|
||||
if (!processed_header && this->opus_decoder_->is_initialized()) {
|
||||
// Header processed and stream info is available
|
||||
this->audio_stream_info_ =
|
||||
audio::AudioStreamInfo(this->opus_decoder_->get_bit_depth(), this->opus_decoder_->get_channels(),
|
||||
this->opus_decoder_->get_sample_rate());
|
||||
}
|
||||
if (samples_decoded > 0 && this->audio_stream_info_.has_value()) {
|
||||
// Some audio was processed
|
||||
this->output_transfer_buffer_->increase_buffer_length(
|
||||
this->audio_stream_info_.value().frames_to_bytes(samples_decoded));
|
||||
}
|
||||
this->input_transfer_buffer_->decrease_buffer_length(bytes_consumed);
|
||||
} else if (result == micro_opus::OGG_OPUS_OUTPUT_BUFFER_TOO_SMALL) {
|
||||
// Reallocate to decode the packet on the next call
|
||||
this->free_buffer_required_ = this->opus_decoder_->get_required_output_buffer_size();
|
||||
if (!this->output_transfer_buffer_->reallocate(this->free_buffer_required_)) {
|
||||
// Couldn't reallocate output buffer
|
||||
return FileDecoderState::FAILED;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Opus decoder failed: %" PRId8, result);
|
||||
return FileDecoderState::POTENTIALLY_FAILED;
|
||||
}
|
||||
return FileDecoderState::MORE_TO_PROCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
FileDecoderState AudioDecoder::decode_wav_() {
|
||||
if (!this->audio_stream_info_.has_value()) {
|
||||
// Header hasn't been processed
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
#endif
|
||||
#include <wav_decoder.h>
|
||||
|
||||
// micro-opus
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
#include <micro_opus/ogg_opus_decoder.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace audio {
|
||||
|
||||
@@ -47,7 +52,7 @@ class AudioDecoder {
|
||||
* @brief Class that facilitates decoding an audio file.
|
||||
* The audio file is read from a ring buffer source, decoded, and sent to an audio sink (ring buffer or speaker
|
||||
* component).
|
||||
* Supports wav, flac, and mp3 formats.
|
||||
* Supports wav, flac, mp3, and ogg opus formats.
|
||||
*/
|
||||
public:
|
||||
/// @brief Allocates the input and output transfer buffers
|
||||
@@ -55,7 +60,7 @@ class AudioDecoder {
|
||||
/// @param output_buffer_size Size of the output transfer buffer in bytes.
|
||||
AudioDecoder(size_t input_buffer_size, size_t output_buffer_size);
|
||||
|
||||
/// @brief Deallocates the MP3 decoder (the flac and wav decoders are deallocated automatically)
|
||||
/// @brief Deallocates the MP3 decoder (the flac, opus, and wav decoders are deallocated automatically)
|
||||
~AudioDecoder();
|
||||
|
||||
/// @brief Adds a source ring buffer for raw file data. Takes ownership of the ring buffer in a shared_ptr.
|
||||
@@ -108,6 +113,10 @@ class AudioDecoder {
|
||||
#ifdef USE_AUDIO_MP3_SUPPORT
|
||||
FileDecoderState decode_mp3_();
|
||||
esp_audio_libs::helix_decoder::HMP3Decoder mp3_decoder_;
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
FileDecoderState decode_opus_();
|
||||
std::unique_ptr<micro_opus::OggOpusDecoder> opus_decoder_;
|
||||
#endif
|
||||
FileDecoderState decode_wav_();
|
||||
|
||||
@@ -124,6 +133,8 @@ class AudioDecoder {
|
||||
bool end_of_file_{false};
|
||||
bool wav_has_known_end_{false};
|
||||
|
||||
bool decoder_buffers_internally_{false};
|
||||
|
||||
bool pause_output_{false};
|
||||
|
||||
uint32_t accumulated_frames_written_{0};
|
||||
|
||||
@@ -197,6 +197,11 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
|
||||
else if (str_endswith_ignore_case(url, ".flac")) {
|
||||
file_type = AudioFileType::FLAC;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
else if (str_endswith_ignore_case(url, ".opus")) {
|
||||
file_type = AudioFileType::OPUS;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
file_type = AudioFileType::NONE;
|
||||
@@ -241,6 +246,14 @@ AudioFileType AudioReader::get_audio_type(const char *content_type) {
|
||||
if (strcasecmp(content_type, "audio/flac") == 0 || strcasecmp(content_type, "audio/x-flac") == 0) {
|
||||
return AudioFileType::FLAC;
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
// Match "audio/ogg" with a codecs parameter containing "opus"
|
||||
// Valid forms: audio/ogg;codecs=opus, audio/ogg; codecs="opus", etc.
|
||||
// Plain "audio/ogg" without a codecs parameter is not matched, as those are almost always Ogg Vorbis streams
|
||||
if (strncasecmp(content_type, "audio/ogg", 9) == 0 && strcasestr(content_type + 9, "opus") != nullptr) {
|
||||
return AudioFileType::OPUS;
|
||||
}
|
||||
#endif
|
||||
return AudioFileType::NONE;
|
||||
}
|
||||
|
||||
@@ -165,6 +165,8 @@ size_t AudioSinkTransferBuffer::transfer_data_to_sink(TickType_t ticks_to_wait,
|
||||
if (this->ring_buffer_.use_count() > 0) {
|
||||
bytes_written =
|
||||
this->ring_buffer_->write_without_replacement((void *) this->data_start_, this->available(), ticks_to_wait);
|
||||
} else if (this->sink_callback_ != nullptr) {
|
||||
bytes_written = this->sink_callback_->audio_sink_write(this->data_start_, this->available(), ticks_to_wait);
|
||||
}
|
||||
|
||||
this->decrease_buffer_length(bytes_written);
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
namespace esphome {
|
||||
namespace audio {
|
||||
|
||||
/// @brief Abstract interface for writing decoded audio data to a sink.
|
||||
class AudioSinkCallback {
|
||||
public:
|
||||
virtual size_t audio_sink_write(uint8_t *data, size_t length, TickType_t ticks_to_wait) = 0;
|
||||
};
|
||||
|
||||
class AudioTransferBuffer {
|
||||
/*
|
||||
* @brief Class that facilitates tranferring data between a buffer and an audio source or sink.
|
||||
@@ -108,6 +114,10 @@ class AudioSinkTransferBuffer : public AudioTransferBuffer {
|
||||
void set_sink(speaker::Speaker *speaker) { this->speaker_ = speaker; }
|
||||
#endif
|
||||
|
||||
/// @brief Adds a callback as the transfer buffer's sink.
|
||||
/// @param callback Pointer to the AudioSinkCallback implementation
|
||||
void set_sink(AudioSinkCallback *callback) { this->sink_callback_ = callback; }
|
||||
|
||||
void clear_buffered_data() override;
|
||||
|
||||
bool has_buffered_data() const override;
|
||||
@@ -116,6 +126,7 @@ class AudioSinkTransferBuffer : public AudioTransferBuffer {
|
||||
#ifdef USE_SPEAKER
|
||||
speaker::Speaker *speaker_{nullptr};
|
||||
#endif
|
||||
AudioSinkCallback *sink_callback_{nullptr};
|
||||
};
|
||||
|
||||
class AudioSourceTransferBuffer : public AudioTransferBuffer {
|
||||
|
||||
@@ -87,7 +87,10 @@ void BLENUS::setup() {
|
||||
global_ble_nus = this;
|
||||
#ifdef USE_LOGGER
|
||||
if (logger::global_logger != nullptr && this->expose_log_) {
|
||||
logger::global_logger->add_log_listener(this);
|
||||
logger::global_logger->add_log_callback(
|
||||
this, [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
static_cast<BLENUS *>(self)->on_log(level, tag, message, message_len);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -10,12 +10,7 @@
|
||||
|
||||
namespace esphome::ble_nus {
|
||||
|
||||
class BLENUS : public Component
|
||||
#ifdef USE_LOGGER
|
||||
,
|
||||
public logger::LogListener
|
||||
#endif
|
||||
{
|
||||
class BLENUS : public Component {
|
||||
enum TxStatus {
|
||||
TX_DISABLED,
|
||||
TX_ENABLED,
|
||||
@@ -29,7 +24,7 @@ class BLENUS : public Component
|
||||
size_t write_array(const uint8_t *data, size_t len);
|
||||
void set_expose_log(bool expose_log) { this->expose_log_ = expose_log; }
|
||||
#ifdef USE_LOGGER
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override;
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
namespace esphome::bluetooth_proxy {
|
||||
|
||||
static const esp_err_t ESP_GATT_NOT_CONNECTED = -1;
|
||||
static const int DONE_SENDING_SERVICES = -2;
|
||||
static const int INIT_SENDING_SERVICES = -3;
|
||||
static constexpr esp_err_t ESP_GATT_NOT_CONNECTED = -1;
|
||||
static constexpr int DONE_SENDING_SERVICES = -2;
|
||||
static constexpr int INIT_SENDING_SERVICES = -3;
|
||||
|
||||
using namespace esp32_ble_client;
|
||||
|
||||
@@ -35,8 +35,8 @@ using namespace esp32_ble_client;
|
||||
// Version 3: New connection API
|
||||
// Version 4: Pairing support
|
||||
// Version 5: Cache clear support
|
||||
static const uint32_t LEGACY_ACTIVE_CONNECTIONS_VERSION = 5;
|
||||
static const uint32_t LEGACY_PASSIVE_ONLY_VERSION = 1;
|
||||
static constexpr uint32_t LEGACY_ACTIVE_CONNECTIONS_VERSION = 5;
|
||||
static constexpr uint32_t LEGACY_PASSIVE_ONLY_VERSION = 1;
|
||||
|
||||
enum BluetoothProxyFeature : uint32_t {
|
||||
FEATURE_PASSIVE_SCAN = 1 << 0,
|
||||
|
||||
@@ -15,29 +15,29 @@ static const char *const TAG = "cse7761";
|
||||
* https://github.com/arendst/Tasmota/blob/development/tasmota/xnrg_19_cse7761.ino
|
||||
\*********************************************************************************************/
|
||||
|
||||
static const int CSE7761_UREF = 42563; // RmsUc
|
||||
static const int CSE7761_IREF = 52241; // RmsIAC
|
||||
static const int CSE7761_PREF = 44513; // PowerPAC
|
||||
static constexpr int CSE7761_UREF = 42563; // RmsUc
|
||||
static constexpr int CSE7761_IREF = 52241; // RmsIAC
|
||||
static constexpr int CSE7761_PREF = 44513; // PowerPAC
|
||||
|
||||
static const uint8_t CSE7761_REG_SYSCON = 0x00; // (2) System Control Register (0x0A04)
|
||||
static const uint8_t CSE7761_REG_EMUCON = 0x01; // (2) Metering control register (0x0000)
|
||||
static const uint8_t CSE7761_REG_EMUCON2 = 0x13; // (2) Metering control register 2 (0x0001)
|
||||
static const uint8_t CSE7761_REG_PULSE1SEL = 0x1D; // (2) Pin function output select register (0x3210)
|
||||
static constexpr uint8_t CSE7761_REG_SYSCON = 0x00; // (2) System Control Register (0x0A04)
|
||||
static constexpr uint8_t CSE7761_REG_EMUCON = 0x01; // (2) Metering control register (0x0000)
|
||||
static constexpr uint8_t CSE7761_REG_EMUCON2 = 0x13; // (2) Metering control register 2 (0x0001)
|
||||
static constexpr uint8_t CSE7761_REG_PULSE1SEL = 0x1D; // (2) Pin function output select register (0x3210)
|
||||
|
||||
static const uint8_t CSE7761_REG_RMSIA = 0x24; // (3) The effective value of channel A current (0x000000)
|
||||
static const uint8_t CSE7761_REG_RMSIB = 0x25; // (3) The effective value of channel B current (0x000000)
|
||||
static const uint8_t CSE7761_REG_RMSU = 0x26; // (3) Voltage RMS (0x000000)
|
||||
static const uint8_t CSE7761_REG_POWERPA = 0x2C; // (4) Channel A active power, update rate 27.2Hz (0x00000000)
|
||||
static const uint8_t CSE7761_REG_POWERPB = 0x2D; // (4) Channel B active power, update rate 27.2Hz (0x00000000)
|
||||
static const uint8_t CSE7761_REG_SYSSTATUS = 0x43; // (1) System status register
|
||||
static constexpr uint8_t CSE7761_REG_RMSIA = 0x24; // (3) The effective value of channel A current (0x000000)
|
||||
static constexpr uint8_t CSE7761_REG_RMSIB = 0x25; // (3) The effective value of channel B current (0x000000)
|
||||
static constexpr uint8_t CSE7761_REG_RMSU = 0x26; // (3) Voltage RMS (0x000000)
|
||||
static constexpr uint8_t CSE7761_REG_POWERPA = 0x2C; // (4) Channel A active power, update rate 27.2Hz (0x00000000)
|
||||
static constexpr uint8_t CSE7761_REG_POWERPB = 0x2D; // (4) Channel B active power, update rate 27.2Hz (0x00000000)
|
||||
static constexpr uint8_t CSE7761_REG_SYSSTATUS = 0x43; // (1) System status register
|
||||
|
||||
static const uint8_t CSE7761_REG_COEFFCHKSUM = 0x6F; // (2) Coefficient checksum
|
||||
static const uint8_t CSE7761_REG_RMSIAC = 0x70; // (2) Channel A effective current conversion coefficient
|
||||
static constexpr uint8_t CSE7761_REG_COEFFCHKSUM = 0x6F; // (2) Coefficient checksum
|
||||
static constexpr uint8_t CSE7761_REG_RMSIAC = 0x70; // (2) Channel A effective current conversion coefficient
|
||||
|
||||
static const uint8_t CSE7761_SPECIAL_COMMAND = 0xEA; // Start special command
|
||||
static const uint8_t CSE7761_CMD_RESET = 0x96; // Reset command, after receiving the command, the chip resets
|
||||
static const uint8_t CSE7761_CMD_CLOSE_WRITE = 0xDC; // Close write operation
|
||||
static const uint8_t CSE7761_CMD_ENABLE_WRITE = 0xE5; // Enable write operation
|
||||
static constexpr uint8_t CSE7761_SPECIAL_COMMAND = 0xEA; // Start special command
|
||||
static constexpr uint8_t CSE7761_CMD_RESET = 0x96; // Reset command, after receiving the command, the chip resets
|
||||
static constexpr uint8_t CSE7761_CMD_CLOSE_WRITE = 0xDC; // Close write operation
|
||||
static constexpr uint8_t CSE7761_CMD_ENABLE_WRITE = 0xE5; // Enable write operation
|
||||
|
||||
enum CSE7761 { RMS_IAC, RMS_IBC, RMS_UC, POWER_PAC, POWER_PBC, POWER_SC, ENERGY_AC, ENERGY_BC };
|
||||
|
||||
|
||||
@@ -9,8 +9,7 @@ namespace esphome {
|
||||
namespace display {
|
||||
static const char *const TAG = "display";
|
||||
|
||||
const Color COLOR_OFF(0, 0, 0, 0);
|
||||
const Color COLOR_ON(255, 255, 255, 255);
|
||||
// COLOR_OFF and COLOR_ON are now inline constexpr in display.h
|
||||
|
||||
void Display::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); }
|
||||
void Display::clear() { this->fill(COLOR_OFF); }
|
||||
|
||||
@@ -298,9 +298,9 @@ using display_writer_t = DisplayWriter<Display>;
|
||||
}
|
||||
|
||||
/// Turn the pixel OFF.
|
||||
extern const Color COLOR_OFF;
|
||||
inline constexpr Color COLOR_OFF(0, 0, 0, 0);
|
||||
/// Turn the pixel ON.
|
||||
extern const Color COLOR_ON;
|
||||
inline constexpr Color COLOR_ON(255, 255, 255, 255);
|
||||
|
||||
class BaseImage {
|
||||
public:
|
||||
|
||||
@@ -44,9 +44,9 @@ from esphome.const import (
|
||||
from esphome.core import CORE, HexInt, TimePeriod
|
||||
from esphome.coroutine import CoroPriority, coroutine_with_priority
|
||||
import esphome.final_validate as fv
|
||||
from esphome.helpers import copy_file_if_changed, write_file_if_changed
|
||||
from esphome.helpers import copy_file_if_changed, rmtree, write_file_if_changed
|
||||
from esphome.types import ConfigType
|
||||
from esphome.writer import clean_cmake_cache, rmtree
|
||||
from esphome.writer import clean_cmake_cache
|
||||
|
||||
from .boards import BOARDS, STANDARD_BOARDS
|
||||
from .const import ( # noqa
|
||||
|
||||
@@ -21,9 +21,9 @@ extern "C" __attribute__((weak)) void initArduino() {}
|
||||
|
||||
namespace esphome {
|
||||
|
||||
void IRAM_ATTR HOT yield() { vPortYield(); }
|
||||
void HOT yield() { vPortYield(); }
|
||||
uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); }
|
||||
void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
|
||||
void HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); }
|
||||
uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); }
|
||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||
void arch_restart() {
|
||||
@@ -44,7 +44,7 @@ void arch_init() {
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
#endif
|
||||
}
|
||||
void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); }
|
||||
void HOT arch_feed_wdt() { esp_task_wdt_reset(); }
|
||||
|
||||
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
|
||||
uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); }
|
||||
|
||||
@@ -16,17 +16,17 @@ static const char *const TAG = "esp32_ble_client";
|
||||
// Intermediate connection parameters for standard operation
|
||||
// ESP-IDF defaults (12.5-15ms) are too slow for stable connections through WiFi-based BLE proxies,
|
||||
// causing disconnections. These medium parameters balance responsiveness with bandwidth usage.
|
||||
static const uint16_t MEDIUM_MIN_CONN_INTERVAL = 0x07; // 7 * 1.25ms = 8.75ms
|
||||
static const uint16_t MEDIUM_MAX_CONN_INTERVAL = 0x09; // 9 * 1.25ms = 11.25ms
|
||||
static constexpr uint16_t MEDIUM_MIN_CONN_INTERVAL = 0x07; // 7 * 1.25ms = 8.75ms
|
||||
static constexpr uint16_t MEDIUM_MAX_CONN_INTERVAL = 0x09; // 9 * 1.25ms = 11.25ms
|
||||
// The timeout value was increased from 6s to 8s to address stability issues observed
|
||||
// in certain BLE devices when operating through WiFi-based BLE proxies. The longer
|
||||
// timeout reduces the likelihood of disconnections during periods of high latency.
|
||||
static const uint16_t MEDIUM_CONN_TIMEOUT = 800; // 800 * 10ms = 8s
|
||||
static constexpr uint16_t MEDIUM_CONN_TIMEOUT = 800; // 800 * 10ms = 8s
|
||||
|
||||
// Fastest connection parameters for devices with short discovery timeouts
|
||||
static const uint16_t FAST_MIN_CONN_INTERVAL = 0x06; // 6 * 1.25ms = 7.5ms (BLE minimum)
|
||||
static const uint16_t FAST_MAX_CONN_INTERVAL = 0x06; // 6 * 1.25ms = 7.5ms
|
||||
static const uint16_t FAST_CONN_TIMEOUT = 1000; // 1000 * 10ms = 10s
|
||||
static constexpr uint16_t FAST_MIN_CONN_INTERVAL = 0x06; // 6 * 1.25ms = 7.5ms (BLE minimum)
|
||||
static constexpr uint16_t FAST_MAX_CONN_INTERVAL = 0x06; // 6 * 1.25ms = 7.5ms
|
||||
static constexpr uint16_t FAST_CONN_TIMEOUT = 1000; // 1000 * 10ms = 10s
|
||||
static const esp_bt_uuid_t NOTIFY_DESC_UUID = {
|
||||
.len = ESP_UUID_LEN_16,
|
||||
.uuid =
|
||||
|
||||
@@ -57,12 +57,12 @@ class BLECharacteristic {
|
||||
ESPBTUUID get_uuid() { return this->uuid_; }
|
||||
std::vector<uint8_t> &get_value() { return this->value_; }
|
||||
|
||||
static const uint32_t PROPERTY_READ = 1 << 0;
|
||||
static const uint32_t PROPERTY_WRITE = 1 << 1;
|
||||
static const uint32_t PROPERTY_NOTIFY = 1 << 2;
|
||||
static const uint32_t PROPERTY_BROADCAST = 1 << 3;
|
||||
static const uint32_t PROPERTY_INDICATE = 1 << 4;
|
||||
static const uint32_t PROPERTY_WRITE_NR = 1 << 5;
|
||||
static constexpr uint32_t PROPERTY_READ = 1 << 0;
|
||||
static constexpr uint32_t PROPERTY_WRITE = 1 << 1;
|
||||
static constexpr uint32_t PROPERTY_NOTIFY = 1 << 2;
|
||||
static constexpr uint32_t PROPERTY_BROADCAST = 1 << 3;
|
||||
static constexpr uint32_t PROPERTY_INDICATE = 1 << 4;
|
||||
static constexpr uint32_t PROPERTY_WRITE_NR = 1 << 5;
|
||||
|
||||
bool is_created();
|
||||
bool is_failed();
|
||||
|
||||
@@ -22,8 +22,10 @@ from esphome.const import (
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_VSYNC_PIN,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
from esphome.core.entity_helpers import setup_entity
|
||||
import esphome.final_validate as fv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -84,6 +86,18 @@ FRAME_SIZES = {
|
||||
"2560X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920,
|
||||
"QSXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920,
|
||||
}
|
||||
ESP32CameraPixelFormat = esp32_camera_ns.enum("ESP32CameraPixelFormat")
|
||||
PIXEL_FORMATS = {
|
||||
"RGB565": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_RGB565,
|
||||
"YUV422": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_YUV422,
|
||||
"YUV420": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_YUV420,
|
||||
"GRAYSCALE": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_GRAYSCALE,
|
||||
"JPEG": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_JPEG,
|
||||
"RGB888": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_RGB888,
|
||||
"RAW": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_RAW,
|
||||
"RGB444": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_RGB444,
|
||||
"RGB555": ESP32CameraPixelFormat.ESP32_PIXEL_FORMAT_RGB555,
|
||||
}
|
||||
ESP32GainControlMode = esp32_camera_ns.enum("ESP32GainControlMode")
|
||||
ENUM_GAIN_CONTROL_MODE = {
|
||||
"MANUAL": ESP32GainControlMode.ESP32_GC_MODE_MANU,
|
||||
@@ -131,6 +145,7 @@ CONF_EXTERNAL_CLOCK = "external_clock"
|
||||
CONF_I2C_PINS = "i2c_pins"
|
||||
CONF_POWER_DOWN_PIN = "power_down_pin"
|
||||
# image
|
||||
CONF_PIXEL_FORMAT = "pixel_format"
|
||||
CONF_JPEG_QUALITY = "jpeg_quality"
|
||||
CONF_VERTICAL_FLIP = "vertical_flip"
|
||||
CONF_HORIZONTAL_MIRROR = "horizontal_mirror"
|
||||
@@ -171,6 +186,21 @@ def validate_fb_location_(value):
|
||||
return validator(value)
|
||||
|
||||
|
||||
def validate_jpeg_quality(config: ConfigType) -> ConfigType:
|
||||
quality = config.get(CONF_JPEG_QUALITY)
|
||||
pixel_format = config.get(CONF_PIXEL_FORMAT, "JPEG")
|
||||
|
||||
if quality == 0:
|
||||
# Set default JPEG quality if not specified for backwards compatibility
|
||||
if pixel_format == "JPEG":
|
||||
config[CONF_JPEG_QUALITY] = 10
|
||||
# For pixel formats other than JPEG, the valid 0 means no conversion
|
||||
elif quality < 6 or quality > 63:
|
||||
raise cv.Invalid(f"jpeg_quality must be between 6 and 63, got {quality}")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.ENTITY_BASE_SCHEMA.extend(
|
||||
{
|
||||
@@ -206,7 +236,12 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_RESOLUTION, default="640X480"): cv.enum(
|
||||
FRAME_SIZES, upper=True
|
||||
),
|
||||
cv.Optional(CONF_JPEG_QUALITY, default=10): cv.int_range(min=6, max=63),
|
||||
cv.Optional(CONF_PIXEL_FORMAT, default="JPEG"): cv.enum(
|
||||
PIXEL_FORMATS, upper=True
|
||||
),
|
||||
cv.Optional(CONF_JPEG_QUALITY, default=0): cv.Any(
|
||||
cv.one_of(0), cv.int_range(min=6, max=63)
|
||||
),
|
||||
cv.Optional(CONF_CONTRAST, default=0): camera_range_param,
|
||||
cv.Optional(CONF_BRIGHTNESS, default=0): camera_range_param,
|
||||
cv.Optional(CONF_SATURATION, default=0): camera_range_param,
|
||||
@@ -270,11 +305,21 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
validate_jpeg_quality,
|
||||
cv.has_exactly_one_key(CONF_I2C_PINS, CONF_I2C_ID),
|
||||
)
|
||||
|
||||
|
||||
def _final_validate(config):
|
||||
# Check psram requirement for non-JPEG formats
|
||||
if (
|
||||
config.get(CONF_PIXEL_FORMAT, "JPEG") != "JPEG"
|
||||
and psram_domain not in CORE.loaded_integrations
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"Non-JPEG pixel formats require the '{psram_domain}' component for JPEG conversion"
|
||||
)
|
||||
|
||||
if CONF_I2C_PINS not in config:
|
||||
return
|
||||
fconf = fv.full_config.get()
|
||||
@@ -298,6 +343,7 @@ SETTERS = {
|
||||
CONF_RESET_PIN: "set_reset_pin",
|
||||
CONF_POWER_DOWN_PIN: "set_power_down_pin",
|
||||
# image
|
||||
CONF_PIXEL_FORMAT: "set_pixel_format",
|
||||
CONF_JPEG_QUALITY: "set_jpeg_quality",
|
||||
CONF_VERTICAL_FLIP: "set_vertical_flip",
|
||||
CONF_HORIZONTAL_MIRROR: "set_horizontal_mirror",
|
||||
@@ -351,6 +397,8 @@ async def to_code(config):
|
||||
cg.add(var.set_frame_size(config[CONF_RESOLUTION]))
|
||||
|
||||
cg.add_define("USE_CAMERA")
|
||||
if config[CONF_JPEG_QUALITY] != 0 and config[CONF_PIXEL_FORMAT] != "JPEG":
|
||||
cg.add_define("USE_ESP32_CAMERA_JPEG_CONVERSION")
|
||||
|
||||
add_idf_component(name="espressif/esp32-camera", ref="2.1.1")
|
||||
add_idf_sdkconfig_option("CONFIG_SCCB_HARDWARE_I2C_DRIVER_NEW", True)
|
||||
|
||||
@@ -16,6 +16,74 @@ static constexpr size_t FRAMEBUFFER_TASK_STACK_SIZE = 1792;
|
||||
static constexpr uint32_t FRAME_LOG_INTERVAL_MS = 60000;
|
||||
#endif
|
||||
|
||||
static const char *frame_size_to_str(framesize_t size) {
|
||||
switch (size) {
|
||||
case FRAMESIZE_QQVGA:
|
||||
return "160x120 (QQVGA)";
|
||||
case FRAMESIZE_QCIF:
|
||||
return "176x155 (QCIF)";
|
||||
case FRAMESIZE_HQVGA:
|
||||
return "240x176 (HQVGA)";
|
||||
case FRAMESIZE_QVGA:
|
||||
return "320x240 (QVGA)";
|
||||
case FRAMESIZE_CIF:
|
||||
return "400x296 (CIF)";
|
||||
case FRAMESIZE_VGA:
|
||||
return "640x480 (VGA)";
|
||||
case FRAMESIZE_SVGA:
|
||||
return "800x600 (SVGA)";
|
||||
case FRAMESIZE_XGA:
|
||||
return "1024x768 (XGA)";
|
||||
case FRAMESIZE_SXGA:
|
||||
return "1280x1024 (SXGA)";
|
||||
case FRAMESIZE_UXGA:
|
||||
return "1600x1200 (UXGA)";
|
||||
case FRAMESIZE_FHD:
|
||||
return "1920x1080 (FHD)";
|
||||
case FRAMESIZE_P_HD:
|
||||
return "720x1280 (P_HD)";
|
||||
case FRAMESIZE_P_3MP:
|
||||
return "864x1536 (P_3MP)";
|
||||
case FRAMESIZE_QXGA:
|
||||
return "2048x1536 (QXGA)";
|
||||
case FRAMESIZE_QHD:
|
||||
return "2560x1440 (QHD)";
|
||||
case FRAMESIZE_WQXGA:
|
||||
return "2560x1600 (WQXGA)";
|
||||
case FRAMESIZE_P_FHD:
|
||||
return "1080x1920 (P_FHD)";
|
||||
case FRAMESIZE_QSXGA:
|
||||
return "2560x1920 (QSXGA)";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pixel_format_to_str(pixformat_t format) {
|
||||
switch (format) {
|
||||
case PIXFORMAT_RGB565:
|
||||
return "RGB565";
|
||||
case PIXFORMAT_YUV422:
|
||||
return "YUV422";
|
||||
case PIXFORMAT_YUV420:
|
||||
return "YUV420";
|
||||
case PIXFORMAT_GRAYSCALE:
|
||||
return "GRAYSCALE";
|
||||
case PIXFORMAT_JPEG:
|
||||
return "JPEG";
|
||||
case PIXFORMAT_RGB888:
|
||||
return "RGB888";
|
||||
case PIXFORMAT_RAW:
|
||||
return "RAW";
|
||||
case PIXFORMAT_RGB444:
|
||||
return "RGB444";
|
||||
case PIXFORMAT_RGB555:
|
||||
return "RGB555";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------- public API (derivated) ---------------- */
|
||||
void ESP32Camera::setup() {
|
||||
#ifdef USE_I2C
|
||||
@@ -68,64 +136,9 @@ void ESP32Camera::dump_config() {
|
||||
this->name_.c_str(), YESNO(this->is_internal()), conf.pin_d0, conf.pin_d1, conf.pin_d2, conf.pin_d3,
|
||||
conf.pin_d4, conf.pin_d5, conf.pin_d6, conf.pin_d7, conf.pin_vsync, conf.pin_href, conf.pin_pclk,
|
||||
conf.pin_xclk, conf.xclk_freq_hz, conf.pin_sccb_sda, conf.pin_sccb_scl, conf.pin_reset);
|
||||
switch (this->config_.frame_size) {
|
||||
case FRAMESIZE_QQVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 160x120 (QQVGA)");
|
||||
break;
|
||||
case FRAMESIZE_QCIF:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 176x155 (QCIF)");
|
||||
break;
|
||||
case FRAMESIZE_HQVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 240x176 (HQVGA)");
|
||||
break;
|
||||
case FRAMESIZE_QVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 320x240 (QVGA)");
|
||||
break;
|
||||
case FRAMESIZE_CIF:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 400x296 (CIF)");
|
||||
break;
|
||||
case FRAMESIZE_VGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 640x480 (VGA)");
|
||||
break;
|
||||
case FRAMESIZE_SVGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 800x600 (SVGA)");
|
||||
break;
|
||||
case FRAMESIZE_XGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1024x768 (XGA)");
|
||||
break;
|
||||
case FRAMESIZE_SXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1280x1024 (SXGA)");
|
||||
break;
|
||||
case FRAMESIZE_UXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1600x1200 (UXGA)");
|
||||
break;
|
||||
case FRAMESIZE_FHD:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1920x1080 (FHD)");
|
||||
break;
|
||||
case FRAMESIZE_P_HD:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 720x1280 (P_HD)");
|
||||
break;
|
||||
case FRAMESIZE_P_3MP:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 864x1536 (P_3MP)");
|
||||
break;
|
||||
case FRAMESIZE_QXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 2048x1536 (QXGA)");
|
||||
break;
|
||||
case FRAMESIZE_QHD:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 2560x1440 (QHD)");
|
||||
break;
|
||||
case FRAMESIZE_WQXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 2560x1600 (WQXGA)");
|
||||
break;
|
||||
case FRAMESIZE_P_FHD:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 1080x1920 (P_FHD)");
|
||||
break;
|
||||
case FRAMESIZE_QSXGA:
|
||||
ESP_LOGCONFIG(TAG, " Resolution: 2560x1920 (QSXGA)");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Resolution: %s", frame_size_to_str(this->config_.frame_size));
|
||||
ESP_LOGCONFIG(TAG, " Pixel Format: %s", pixel_format_to_str(this->config_.pixel_format));
|
||||
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, " Setup Failed: %s", esp_err_to_name(this->init_error_));
|
||||
@@ -184,8 +197,19 @@ void ESP32Camera::loop() {
|
||||
// check if we can return the image
|
||||
if (this->can_return_image_()) {
|
||||
// return image
|
||||
auto *fb = this->current_image_->get_raw_buffer();
|
||||
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
|
||||
#ifdef USE_ESP32_CAMERA_JPEG_CONVERSION
|
||||
if (this->config_.pixel_format != PIXFORMAT_JPEG && this->config_.jpeg_quality > 0) {
|
||||
// for non-JPEG format, we need to free the data and raw buffer
|
||||
auto *jpg_buf = this->current_image_->get_data_buffer();
|
||||
free(jpg_buf); // NOLINT(cppcoreguidelines-no-malloc)
|
||||
auto *fb = this->current_image_->get_raw_buffer();
|
||||
this->fb_allocator_.deallocate(fb, 1);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
auto *fb = this->current_image_->get_raw_buffer();
|
||||
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
|
||||
}
|
||||
this->current_image_.reset();
|
||||
}
|
||||
|
||||
@@ -212,6 +236,38 @@ void ESP32Camera::loop() {
|
||||
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_ESP32_CAMERA_JPEG_CONVERSION
|
||||
if (this->config_.pixel_format != PIXFORMAT_JPEG && this->config_.jpeg_quality > 0) {
|
||||
// for non-JPEG format, we need to convert the frame to JPEG
|
||||
uint8_t *jpg_buf;
|
||||
size_t jpg_buf_len;
|
||||
size_t width = fb->width;
|
||||
size_t height = fb->height;
|
||||
struct timeval timestamp = fb->timestamp;
|
||||
bool ok = frame2jpg(fb, 100 - this->config_.jpeg_quality, &jpg_buf, &jpg_buf_len);
|
||||
// return the original frame buffer to the queue
|
||||
xQueueSend(this->framebuffer_return_queue_, &fb, portMAX_DELAY);
|
||||
if (!ok) {
|
||||
ESP_LOGE(TAG, "Failed to convert frame to JPEG!");
|
||||
return;
|
||||
}
|
||||
// create a new camera_fb_t for the JPEG data
|
||||
fb = this->fb_allocator_.allocate(1);
|
||||
if (fb == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for camera frame buffer!");
|
||||
free(jpg_buf); // NOLINT(cppcoreguidelines-no-malloc)
|
||||
return;
|
||||
}
|
||||
memset(fb, 0, sizeof(camera_fb_t));
|
||||
fb->buf = jpg_buf;
|
||||
fb->len = jpg_buf_len;
|
||||
fb->width = width;
|
||||
fb->height = height;
|
||||
fb->format = PIXFORMAT_JPEG;
|
||||
fb->timestamp = timestamp;
|
||||
}
|
||||
#endif
|
||||
this->current_image_ = std::make_shared<ESP32CameraImage>(fb, this->single_requesters_ | this->stream_requesters_);
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
@@ -342,6 +398,37 @@ void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
void ESP32Camera::set_pixel_format(ESP32CameraPixelFormat format) {
|
||||
switch (format) {
|
||||
case ESP32_PIXEL_FORMAT_RGB565:
|
||||
this->config_.pixel_format = PIXFORMAT_RGB565;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_YUV422:
|
||||
this->config_.pixel_format = PIXFORMAT_YUV422;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_YUV420:
|
||||
this->config_.pixel_format = PIXFORMAT_YUV420;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_GRAYSCALE:
|
||||
this->config_.pixel_format = PIXFORMAT_GRAYSCALE;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_JPEG:
|
||||
this->config_.pixel_format = PIXFORMAT_JPEG;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_RGB888:
|
||||
this->config_.pixel_format = PIXFORMAT_RGB888;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_RAW:
|
||||
this->config_.pixel_format = PIXFORMAT_RAW;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_RGB444:
|
||||
this->config_.pixel_format = PIXFORMAT_RGB444;
|
||||
break;
|
||||
case ESP32_PIXEL_FORMAT_RGB555:
|
||||
this->config_.pixel_format = PIXFORMAT_RGB555;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; }
|
||||
void ESP32Camera::set_vertical_flip(bool vertical_flip) { this->vertical_flip_ = vertical_flip; }
|
||||
void ESP32Camera::set_horizontal_mirror(bool horizontal_mirror) { this->horizontal_mirror_ = horizontal_mirror; }
|
||||
|
||||
@@ -41,6 +41,18 @@ enum ESP32CameraFrameSize {
|
||||
ESP32_CAMERA_SIZE_2560X1920, // QSXGA
|
||||
};
|
||||
|
||||
enum ESP32CameraPixelFormat {
|
||||
ESP32_PIXEL_FORMAT_RGB565,
|
||||
ESP32_PIXEL_FORMAT_YUV422,
|
||||
ESP32_PIXEL_FORMAT_YUV420,
|
||||
ESP32_PIXEL_FORMAT_GRAYSCALE,
|
||||
ESP32_PIXEL_FORMAT_JPEG,
|
||||
ESP32_PIXEL_FORMAT_RGB888,
|
||||
ESP32_PIXEL_FORMAT_RAW,
|
||||
ESP32_PIXEL_FORMAT_RGB444,
|
||||
ESP32_PIXEL_FORMAT_RGB555,
|
||||
};
|
||||
|
||||
enum ESP32AgcGainCeiling {
|
||||
ESP32_GAINCEILING_2X = GAINCEILING_2X,
|
||||
ESP32_GAINCEILING_4X = GAINCEILING_4X,
|
||||
@@ -126,6 +138,7 @@ class ESP32Camera : public camera::Camera {
|
||||
void set_reset_pin(uint8_t pin);
|
||||
void set_power_down_pin(uint8_t pin);
|
||||
/* -- image */
|
||||
void set_pixel_format(ESP32CameraPixelFormat format);
|
||||
void set_frame_size(ESP32CameraFrameSize size);
|
||||
void set_jpeg_quality(uint8_t quality);
|
||||
void set_vertical_flip(bool vertical_flip);
|
||||
@@ -220,6 +233,7 @@ class ESP32Camera : public camera::Camera {
|
||||
#ifdef USE_I2C
|
||||
i2c::InternalI2CBus *i2c_bus_{nullptr};
|
||||
#endif // USE_I2C
|
||||
RAMAllocator<camera_fb_t> fb_allocator_{RAMAllocator<camera_fb_t>::ALLOC_INTERNAL};
|
||||
};
|
||||
|
||||
class ESP32CameraImageTrigger : public Trigger<CameraImageData>, public camera::CameraListener {
|
||||
|
||||
@@ -14,9 +14,9 @@ extern "C" {
|
||||
|
||||
namespace esphome {
|
||||
|
||||
void IRAM_ATTR HOT yield() { ::yield(); }
|
||||
void HOT yield() { ::yield(); }
|
||||
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
||||
void IRAM_ATTR HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
void HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||
void arch_restart() {
|
||||
@@ -27,7 +27,7 @@ void arch_restart() {
|
||||
}
|
||||
}
|
||||
void arch_init() {}
|
||||
void IRAM_ATTR HOT arch_feed_wdt() { system_soft_wdt_feed(); }
|
||||
void HOT arch_feed_wdt() { system_soft_wdt_feed(); }
|
||||
|
||||
uint8_t progmem_read_byte(const uint8_t *addr) {
|
||||
return pgm_read_byte(addr); // NOLINT
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
void IRAM_ATTR HOT yield() { ::sched_yield(); }
|
||||
void HOT yield() { ::sched_yield(); }
|
||||
uint32_t IRAM_ATTR HOT millis() {
|
||||
struct timespec spec;
|
||||
clock_gettime(CLOCK_MONOTONIC, &spec);
|
||||
@@ -19,7 +19,7 @@ uint32_t IRAM_ATTR HOT millis() {
|
||||
uint32_t ms = round(spec.tv_nsec / 1e6);
|
||||
return ((uint32_t) seconds) * 1000U + ms;
|
||||
}
|
||||
void IRAM_ATTR HOT delay(uint32_t ms) {
|
||||
void HOT delay(uint32_t ms) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = ms / 1000;
|
||||
ts.tv_nsec = (ms % 1000) * 1000000;
|
||||
@@ -48,7 +48,7 @@ void arch_restart() { exit(0); }
|
||||
void arch_init() {
|
||||
// pass
|
||||
}
|
||||
void IRAM_ATTR HOT arch_feed_wdt() {
|
||||
void HOT arch_feed_wdt() {
|
||||
// pass
|
||||
}
|
||||
|
||||
|
||||
@@ -302,15 +302,19 @@ async def http_request_action_to_code(config, action_id, template_arg, args):
|
||||
lambda_ = await cg.process_lambda(json_, args_, return_type=cg.void)
|
||||
cg.add(var.set_json(lambda_))
|
||||
else:
|
||||
cg.add(var.init_json(len(json_)))
|
||||
for key in json_:
|
||||
template_ = await cg.templatable(json_[key], args, cg.std_string)
|
||||
cg.add(var.add_json(key, template_))
|
||||
for key, value in config.get(CONF_REQUEST_HEADERS, {}).items():
|
||||
request_headers = config.get(CONF_REQUEST_HEADERS, {})
|
||||
if request_headers:
|
||||
cg.add(var.init_request_headers(len(request_headers)))
|
||||
for key, value in request_headers.items():
|
||||
template_ = await cg.templatable(value, args, cg.const_char_ptr)
|
||||
cg.add(var.add_request_header(key, template_))
|
||||
|
||||
for value in config.get(CONF_COLLECT_HEADERS, []):
|
||||
cg.add(var.add_collect_header(value))
|
||||
cg.add(var.add_collect_header(value.lower()))
|
||||
|
||||
if response_conf := config.get(CONF_ON_RESPONSE):
|
||||
if capture_response:
|
||||
|
||||
@@ -22,23 +22,15 @@ void HttpRequestComponent::dump_config() {
|
||||
}
|
||||
|
||||
std::string HttpContainer::get_response_header(const std::string &header_name) {
|
||||
auto response_headers = this->get_response_headers();
|
||||
auto header_name_lower_case = str_lower_case(header_name);
|
||||
if (response_headers.count(header_name_lower_case) == 0) {
|
||||
ESP_LOGW(TAG, "No header with name %s found", header_name_lower_case.c_str());
|
||||
return "";
|
||||
} else {
|
||||
auto values = response_headers[header_name_lower_case];
|
||||
if (values.empty()) {
|
||||
ESP_LOGE(TAG, "header with name %s returned an empty list, this shouldn't happen",
|
||||
header_name_lower_case.c_str());
|
||||
return "";
|
||||
} else {
|
||||
auto header_value = values.front();
|
||||
ESP_LOGD(TAG, "Header with name %s found with value %s", header_name_lower_case.c_str(), header_value.c_str());
|
||||
return header_value;
|
||||
auto lower = str_lower_case(header_name);
|
||||
for (const auto &entry : this->response_headers_) {
|
||||
if (entry.name == lower) {
|
||||
ESP_LOGD(TAG, "Header with name %s found with value %s", lower.c_str(), entry.value.c_str());
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
ESP_LOGW(TAG, "No header with name %s found", lower.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace esphome::http_request
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
@@ -80,6 +79,16 @@ inline bool is_redirect(int const status) {
|
||||
*/
|
||||
inline bool is_success(int const status) { return status >= HTTP_STATUS_OK && status < HTTP_STATUS_MULTIPLE_CHOICES; }
|
||||
|
||||
/// Check if a header name should be collected (linear scan, fine for small lists)
|
||||
inline bool should_collect_header(const std::vector<std::string> &lower_case_collect_headers,
|
||||
const std::string &lower_header_name) {
|
||||
for (const auto &h : lower_case_collect_headers) {
|
||||
if (h == lower_header_name)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* HTTP Container Read Semantics
|
||||
* =============================
|
||||
@@ -258,20 +267,13 @@ class HttpContainer : public Parented<HttpRequestComponent> {
|
||||
return !this->is_chunked_ && this->bytes_read_ >= this->content_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get response headers.
|
||||
*
|
||||
* @return The key is the lower case response header name, the value is the header value.
|
||||
*/
|
||||
std::map<std::string, std::list<std::string>> get_response_headers() { return this->response_headers_; }
|
||||
|
||||
std::string get_response_header(const std::string &header_name);
|
||||
|
||||
protected:
|
||||
size_t bytes_read_{0};
|
||||
bool secure_{false};
|
||||
bool is_chunked_{false}; ///< True if response uses chunked transfer encoding
|
||||
std::map<std::string, std::list<std::string>> response_headers_{};
|
||||
std::vector<Header> response_headers_{};
|
||||
};
|
||||
|
||||
/// Read data from HTTP container into buffer with timeout handling
|
||||
@@ -333,8 +335,8 @@ class HttpRequestComponent : public Component {
|
||||
return this->start(url, "GET", "", request_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> get(const std::string &url, const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) {
|
||||
return this->start(url, "GET", "", request_headers, collect_headers);
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->start(url, "GET", "", request_headers, lower_case_collect_headers);
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body) {
|
||||
return this->start(url, "POST", body, {});
|
||||
@@ -345,29 +347,40 @@ class HttpRequestComponent : public Component {
|
||||
}
|
||||
std::shared_ptr<HttpContainer> post(const std::string &url, const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) {
|
||||
return this->start(url, "POST", body, request_headers, collect_headers);
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->start(url, "POST", body, request_headers, lower_case_collect_headers);
|
||||
}
|
||||
|
||||
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::list<Header> &request_headers) {
|
||||
return this->start(url, method, body, request_headers, {});
|
||||
// Call perform() directly to avoid ambiguity with the std::set overload
|
||||
return this->perform(url, method, body, request_headers, {});
|
||||
}
|
||||
|
||||
// Remove before 2027.1.0
|
||||
ESPDEPRECATED("Pass collect_headers as std::vector<std::string> instead of std::set. Removed in 2027.1.0.",
|
||||
"2026.7.0")
|
||||
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) {
|
||||
std::vector<std::string> lower;
|
||||
lower.reserve(collect_headers.size());
|
||||
for (const auto &h : collect_headers) {
|
||||
lower.push_back(str_lower_case(h));
|
||||
}
|
||||
return this->perform(url, method, body, request_headers, lower);
|
||||
}
|
||||
|
||||
std::shared_ptr<HttpContainer> start(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) {
|
||||
std::set<std::string> lower_case_collect_headers;
|
||||
for (const std::string &collect_header : collect_headers) {
|
||||
lower_case_collect_headers.insert(str_lower_case(collect_header));
|
||||
}
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
return this->perform(url, method, body, request_headers, lower_case_collect_headers);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method,
|
||||
const std::string &body, const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) = 0;
|
||||
const std::vector<std::string> &lower_case_collect_headers) = 0;
|
||||
const char *useragent_{nullptr};
|
||||
bool follow_redirects_{};
|
||||
uint16_t redirect_limit_{};
|
||||
@@ -385,13 +398,15 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
TEMPLATABLE_VALUE(bool, capture_response)
|
||||
#endif
|
||||
|
||||
void init_request_headers(size_t count) { this->request_headers_.init(count); }
|
||||
void add_request_header(const char *key, TemplatableValue<const char *, Ts...> value) {
|
||||
this->request_headers_.insert({key, value});
|
||||
this->request_headers_.push_back({key, value});
|
||||
}
|
||||
|
||||
void add_collect_header(const char *value) { this->collect_headers_.insert(value); }
|
||||
void add_collect_header(const char *value) { this->lower_case_collect_headers_.push_back(value); }
|
||||
|
||||
void add_json(const char *key, TemplatableValue<std::string, Ts...> value) { this->json_.insert({key, value}); }
|
||||
void init_json(size_t count) { this->json_.init(count); }
|
||||
void add_json(const char *key, TemplatableValue<std::string, Ts...> value) { this->json_.push_back({key, value}); }
|
||||
|
||||
void set_json(std::function<void(Ts..., JsonObject)> json_func) { this->json_func_ = json_func; }
|
||||
|
||||
@@ -431,7 +446,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
}
|
||||
|
||||
auto container = this->parent_->start(this->url_.value(x...), this->method_.value(x...), body, request_headers,
|
||||
this->collect_headers_);
|
||||
this->lower_case_collect_headers_);
|
||||
|
||||
auto captured_args = std::make_tuple(x...);
|
||||
|
||||
@@ -493,9 +508,9 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
}
|
||||
void encode_json_func_(Ts... x, JsonObject root) { this->json_func_(x..., root); }
|
||||
HttpRequestComponent *parent_;
|
||||
std::map<const char *, TemplatableValue<const char *, Ts...>> request_headers_{};
|
||||
std::set<std::string> collect_headers_{"content-type", "content-length"};
|
||||
std::map<const char *, TemplatableValue<std::string, Ts...>> json_{};
|
||||
FixedVector<std::pair<const char *, TemplatableValue<const char *, Ts...>>> request_headers_{};
|
||||
std::vector<std::string> lower_case_collect_headers_{"content-type", "content-length"};
|
||||
FixedVector<std::pair<const char *, TemplatableValue<std::string, Ts...>>> json_{};
|
||||
std::function<void(Ts..., JsonObject)> json_func_{nullptr};
|
||||
#ifdef USE_HTTP_REQUEST_RESPONSE
|
||||
Trigger<std::shared_ptr<HttpContainer>, std::string &, Ts...> success_trigger_with_response_;
|
||||
|
||||
@@ -27,7 +27,7 @@ static constexpr int ESP8266_SSL_ERR_OOM = -1000;
|
||||
std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &url, const std::string &method,
|
||||
const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) {
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
if (!network::is_connected()) {
|
||||
this->status_momentary_error("failed", 1000);
|
||||
ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
|
||||
@@ -107,9 +107,9 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
}
|
||||
|
||||
// returned needed headers must be collected before the requests
|
||||
const char *header_keys[collect_headers.size()];
|
||||
const char *header_keys[lower_case_collect_headers.size()];
|
||||
int index = 0;
|
||||
for (auto const &header_name : collect_headers) {
|
||||
for (auto const &header_name : lower_case_collect_headers) {
|
||||
header_keys[index++] = header_name.c_str();
|
||||
}
|
||||
container->client_.collectHeaders(header_keys, index);
|
||||
@@ -160,14 +160,14 @@ std::shared_ptr<HttpContainer> HttpRequestArduino::perform(const std::string &ur
|
||||
// Still return the container, so it can be used to get the status code and error message
|
||||
}
|
||||
|
||||
container->response_headers_ = {};
|
||||
container->response_headers_.clear();
|
||||
auto header_count = container->client_.headers();
|
||||
for (int i = 0; i < header_count; i++) {
|
||||
const std::string header_name = str_lower_case(container->client_.headerName(i).c_str());
|
||||
if (collect_headers.count(header_name) > 0) {
|
||||
if (should_collect_header(lower_case_collect_headers, header_name)) {
|
||||
std::string header_value = container->client_.header(i).c_str();
|
||||
ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
|
||||
container->response_headers_[header_name].push_back(header_value);
|
||||
container->response_headers_.push_back({header_name, header_value});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class HttpRequestArduino : public HttpRequestComponent {
|
||||
protected:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) override;
|
||||
const std::vector<std::string> &lower_case_collect_headers) override;
|
||||
};
|
||||
|
||||
} // namespace esphome::http_request
|
||||
|
||||
@@ -19,7 +19,7 @@ static const char *const TAG = "http_request.host";
|
||||
std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url, const std::string &method,
|
||||
const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &response_headers) {
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
if (!network::is_connected()) {
|
||||
this->status_momentary_error("failed", 1000);
|
||||
ESP_LOGW(TAG, "HTTP Request failed; Not connected to network");
|
||||
@@ -116,8 +116,8 @@ std::shared_ptr<HttpContainer> HttpRequestHost::perform(const std::string &url,
|
||||
for (auto header : response.headers) {
|
||||
ESP_LOGD(TAG, "Header: %s: %s", header.first.c_str(), header.second.c_str());
|
||||
auto lower_name = str_lower_case(header.first);
|
||||
if (response_headers.find(lower_name) != response_headers.end()) {
|
||||
container->response_headers_[lower_name].emplace_back(header.second);
|
||||
if (should_collect_header(lower_case_collect_headers, lower_name)) {
|
||||
container->response_headers_.push_back({lower_name, header.second});
|
||||
}
|
||||
}
|
||||
container->duration_ms = millis() - start;
|
||||
|
||||
@@ -20,7 +20,7 @@ class HttpRequestHost : public HttpRequestComponent {
|
||||
public:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &response_headers) override;
|
||||
const std::vector<std::string> &lower_case_collect_headers) override;
|
||||
void set_ca_path(const char *ca_path) { this->ca_path_ = ca_path; }
|
||||
|
||||
protected:
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace esphome::http_request {
|
||||
static const char *const TAG = "http_request.idf";
|
||||
|
||||
struct UserData {
|
||||
const std::set<std::string> &collect_headers;
|
||||
std::map<std::string, std::list<std::string>> response_headers;
|
||||
const std::vector<std::string> &lower_case_collect_headers;
|
||||
std::vector<Header> &response_headers;
|
||||
};
|
||||
|
||||
void HttpRequestIDF::dump_config() {
|
||||
@@ -38,10 +38,10 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
|
||||
switch (evt->event_id) {
|
||||
case HTTP_EVENT_ON_HEADER: {
|
||||
const std::string header_name = str_lower_case(evt->header_key);
|
||||
if (user_data->collect_headers.count(header_name)) {
|
||||
if (should_collect_header(user_data->lower_case_collect_headers, header_name)) {
|
||||
const std::string header_value = evt->header_value;
|
||||
ESP_LOGD(TAG, "Received response header, name: %s, value: %s", header_name.c_str(), header_value.c_str());
|
||||
user_data->response_headers[header_name].push_back(header_value);
|
||||
user_data->response_headers.push_back({header_name, header_value});
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ esp_err_t HttpRequestIDF::http_event_handler(esp_http_client_event_t *evt) {
|
||||
std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, const std::string &method,
|
||||
const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) {
|
||||
const std::vector<std::string> &lower_case_collect_headers) {
|
||||
if (!network::is_connected()) {
|
||||
this->status_momentary_error("failed", 1000);
|
||||
ESP_LOGE(TAG, "HTTP Request failed; Not connected to network");
|
||||
@@ -110,8 +110,6 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
|
||||
watchdog::WatchdogManager wdm(this->get_watchdog_timeout());
|
||||
|
||||
config.event_handler = http_event_handler;
|
||||
auto user_data = UserData{collect_headers, {}};
|
||||
config.user_data = static_cast<void *>(&user_data);
|
||||
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
@@ -120,6 +118,9 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
|
||||
|
||||
container->set_secure(secure);
|
||||
|
||||
auto user_data = UserData{lower_case_collect_headers, container->response_headers_};
|
||||
esp_http_client_set_user_data(client, static_cast<void *>(&user_data));
|
||||
|
||||
for (const auto &header : request_headers) {
|
||||
esp_http_client_set_header(client, header.name.c_str(), header.value.c_str());
|
||||
}
|
||||
@@ -164,7 +165,6 @@ std::shared_ptr<HttpContainer> HttpRequestIDF::perform(const std::string &url, c
|
||||
container->feed_wdt();
|
||||
container->status_code = esp_http_client_get_status_code(client);
|
||||
container->feed_wdt();
|
||||
container->set_response_headers(user_data.response_headers);
|
||||
container->duration_ms = millis() - start;
|
||||
if (is_success(container->status_code)) {
|
||||
return container;
|
||||
|
||||
@@ -21,11 +21,8 @@ class HttpContainerIDF : public HttpContainer {
|
||||
/// @brief Feeds the watchdog timer if the executing task has one attached
|
||||
void feed_wdt();
|
||||
|
||||
void set_response_headers(std::map<std::string, std::list<std::string>> &response_headers) {
|
||||
this->response_headers_ = std::move(response_headers);
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class HttpRequestIDF;
|
||||
esp_http_client_handle_t client_;
|
||||
};
|
||||
|
||||
@@ -41,7 +38,7 @@ class HttpRequestIDF : public HttpRequestComponent {
|
||||
protected:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::list<Header> &request_headers,
|
||||
const std::set<std::string> &collect_headers) override;
|
||||
const std::vector<std::string> &lower_case_collect_headers) override;
|
||||
// if zero ESP-IDF will use DEFAULT_HTTP_BUF_SIZE
|
||||
uint16_t buffer_size_rx_{};
|
||||
uint16_t buffer_size_tx_{};
|
||||
|
||||
@@ -63,73 +63,73 @@ namespace esphome::ld2420 {
|
||||
static const char *const TAG = "ld2420";
|
||||
|
||||
// Local const's
|
||||
static const uint16_t REFRESH_RATE_MS = 1000;
|
||||
static constexpr uint16_t REFRESH_RATE_MS = 1000;
|
||||
|
||||
// Command sets
|
||||
static const uint16_t CMD_DISABLE_CONF = 0x00FE;
|
||||
static const uint16_t CMD_ENABLE_CONF = 0x00FF;
|
||||
static const uint16_t CMD_PARM_HIGH_TRESH = 0x0012;
|
||||
static const uint16_t CMD_PARM_LOW_TRESH = 0x0021;
|
||||
static const uint16_t CMD_PROTOCOL_VER = 0x0002;
|
||||
static const uint16_t CMD_READ_ABD_PARAM = 0x0008;
|
||||
static const uint16_t CMD_READ_REG_ADDR = 0x0020;
|
||||
static const uint16_t CMD_READ_REGISTER = 0x0002;
|
||||
static const uint16_t CMD_READ_SERIAL_NUM = 0x0011;
|
||||
static const uint16_t CMD_READ_SYS_PARAM = 0x0013;
|
||||
static const uint16_t CMD_READ_VERSION = 0x0000;
|
||||
static const uint16_t CMD_RESTART = 0x0068;
|
||||
static const uint16_t CMD_SYSTEM_MODE = 0x0000;
|
||||
static const uint16_t CMD_SYSTEM_MODE_GR = 0x0003;
|
||||
static const uint16_t CMD_SYSTEM_MODE_MTT = 0x0001;
|
||||
static const uint16_t CMD_SYSTEM_MODE_SIMPLE = 0x0064;
|
||||
static const uint16_t CMD_SYSTEM_MODE_DEBUG = 0x0000;
|
||||
static const uint16_t CMD_SYSTEM_MODE_ENERGY = 0x0004;
|
||||
static const uint16_t CMD_SYSTEM_MODE_VS = 0x0002;
|
||||
static const uint16_t CMD_WRITE_ABD_PARAM = 0x0007;
|
||||
static const uint16_t CMD_WRITE_REGISTER = 0x0001;
|
||||
static const uint16_t CMD_WRITE_SYS_PARAM = 0x0012;
|
||||
static constexpr uint16_t CMD_DISABLE_CONF = 0x00FE;
|
||||
static constexpr uint16_t CMD_ENABLE_CONF = 0x00FF;
|
||||
static constexpr uint16_t CMD_PARM_HIGH_TRESH = 0x0012;
|
||||
static constexpr uint16_t CMD_PARM_LOW_TRESH = 0x0021;
|
||||
static constexpr uint16_t CMD_PROTOCOL_VER = 0x0002;
|
||||
static constexpr uint16_t CMD_READ_ABD_PARAM = 0x0008;
|
||||
static constexpr uint16_t CMD_READ_REG_ADDR = 0x0020;
|
||||
static constexpr uint16_t CMD_READ_REGISTER = 0x0002;
|
||||
static constexpr uint16_t CMD_READ_SERIAL_NUM = 0x0011;
|
||||
static constexpr uint16_t CMD_READ_SYS_PARAM = 0x0013;
|
||||
static constexpr uint16_t CMD_READ_VERSION = 0x0000;
|
||||
static constexpr uint16_t CMD_RESTART = 0x0068;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE = 0x0000;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE_GR = 0x0003;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE_MTT = 0x0001;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE_SIMPLE = 0x0064;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE_DEBUG = 0x0000;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE_ENERGY = 0x0004;
|
||||
static constexpr uint16_t CMD_SYSTEM_MODE_VS = 0x0002;
|
||||
static constexpr uint16_t CMD_WRITE_ABD_PARAM = 0x0007;
|
||||
static constexpr uint16_t CMD_WRITE_REGISTER = 0x0001;
|
||||
static constexpr uint16_t CMD_WRITE_SYS_PARAM = 0x0012;
|
||||
|
||||
static const uint8_t CMD_ABD_DATA_REPLY_SIZE = 0x04;
|
||||
static const uint8_t CMD_ABD_DATA_REPLY_START = 0x0A;
|
||||
static const uint8_t CMD_MAX_BYTES = 0x64;
|
||||
static const uint8_t CMD_REG_DATA_REPLY_SIZE = 0x02;
|
||||
static constexpr uint8_t CMD_ABD_DATA_REPLY_SIZE = 0x04;
|
||||
static constexpr uint8_t CMD_ABD_DATA_REPLY_START = 0x0A;
|
||||
static constexpr uint8_t CMD_MAX_BYTES = 0x64;
|
||||
static constexpr uint8_t CMD_REG_DATA_REPLY_SIZE = 0x02;
|
||||
|
||||
static const uint8_t LD2420_ERROR_NONE = 0x00;
|
||||
static const uint8_t LD2420_ERROR_TIMEOUT = 0x02;
|
||||
static const uint8_t LD2420_ERROR_UNKNOWN = 0x01;
|
||||
static constexpr uint8_t LD2420_ERROR_NONE = 0x00;
|
||||
static constexpr uint8_t LD2420_ERROR_TIMEOUT = 0x02;
|
||||
static constexpr uint8_t LD2420_ERROR_UNKNOWN = 0x01;
|
||||
|
||||
// Register address values
|
||||
static const uint16_t CMD_MIN_GATE_REG = 0x0000;
|
||||
static const uint16_t CMD_MAX_GATE_REG = 0x0001;
|
||||
static const uint16_t CMD_TIMEOUT_REG = 0x0004;
|
||||
static const uint16_t CMD_GATE_MOVE_THRESH[TOTAL_GATES] = {0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015,
|
||||
0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B,
|
||||
0x001C, 0x001D, 0x001E, 0x001F};
|
||||
static const uint16_t CMD_GATE_STILL_THRESH[TOTAL_GATES] = {0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025,
|
||||
0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B,
|
||||
0x002C, 0x002D, 0x002E, 0x002F};
|
||||
static const uint32_t FACTORY_MOVE_THRESH[TOTAL_GATES] = {60000, 30000, 400, 250, 250, 250, 250, 250,
|
||||
250, 250, 250, 250, 250, 250, 250, 250};
|
||||
static const uint32_t FACTORY_STILL_THRESH[TOTAL_GATES] = {40000, 20000, 200, 200, 200, 200, 200, 150,
|
||||
150, 100, 100, 100, 100, 100, 100, 100};
|
||||
static const uint16_t FACTORY_TIMEOUT = 120;
|
||||
static const uint16_t FACTORY_MIN_GATE = 1;
|
||||
static const uint16_t FACTORY_MAX_GATE = 12;
|
||||
static constexpr uint16_t CMD_MIN_GATE_REG = 0x0000;
|
||||
static constexpr uint16_t CMD_MAX_GATE_REG = 0x0001;
|
||||
static constexpr uint16_t CMD_TIMEOUT_REG = 0x0004;
|
||||
static constexpr uint16_t CMD_GATE_MOVE_THRESH[TOTAL_GATES] = {0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015,
|
||||
0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B,
|
||||
0x001C, 0x001D, 0x001E, 0x001F};
|
||||
static constexpr uint16_t CMD_GATE_STILL_THRESH[TOTAL_GATES] = {0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025,
|
||||
0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B,
|
||||
0x002C, 0x002D, 0x002E, 0x002F};
|
||||
static constexpr uint32_t FACTORY_MOVE_THRESH[TOTAL_GATES] = {60000, 30000, 400, 250, 250, 250, 250, 250,
|
||||
250, 250, 250, 250, 250, 250, 250, 250};
|
||||
static constexpr uint32_t FACTORY_STILL_THRESH[TOTAL_GATES] = {40000, 20000, 200, 200, 200, 200, 200, 150,
|
||||
150, 100, 100, 100, 100, 100, 100, 100};
|
||||
static constexpr uint16_t FACTORY_TIMEOUT = 120;
|
||||
static constexpr uint16_t FACTORY_MIN_GATE = 1;
|
||||
static constexpr uint16_t FACTORY_MAX_GATE = 12;
|
||||
|
||||
// COMMAND_BYTE Header & Footer
|
||||
static const uint32_t CMD_FRAME_FOOTER = 0x01020304;
|
||||
static const uint32_t CMD_FRAME_HEADER = 0xFAFBFCFD;
|
||||
static const uint32_t DEBUG_FRAME_FOOTER = 0xFAFBFCFD;
|
||||
static const uint32_t DEBUG_FRAME_HEADER = 0x1410BFAA;
|
||||
static const uint32_t ENERGY_FRAME_FOOTER = 0xF5F6F7F8;
|
||||
static const uint32_t ENERGY_FRAME_HEADER = 0xF1F2F3F4;
|
||||
static const int CALIBRATE_VERSION_MIN = 154;
|
||||
static const uint8_t CMD_FRAME_COMMAND = 6;
|
||||
static const uint8_t CMD_FRAME_DATA_LENGTH = 4;
|
||||
static const uint8_t CMD_FRAME_STATUS = 7;
|
||||
static const uint8_t CMD_ERROR_WORD = 8;
|
||||
static const uint8_t ENERGY_SENSOR_START = 9;
|
||||
static const uint8_t CALIBRATE_REPORT_INTERVAL = 4;
|
||||
static constexpr uint32_t CMD_FRAME_FOOTER = 0x01020304;
|
||||
static constexpr uint32_t CMD_FRAME_HEADER = 0xFAFBFCFD;
|
||||
static constexpr uint32_t DEBUG_FRAME_FOOTER = 0xFAFBFCFD;
|
||||
static constexpr uint32_t DEBUG_FRAME_HEADER = 0x1410BFAA;
|
||||
static constexpr uint32_t ENERGY_FRAME_FOOTER = 0xF5F6F7F8;
|
||||
static constexpr uint32_t ENERGY_FRAME_HEADER = 0xF1F2F3F4;
|
||||
static constexpr int CALIBRATE_VERSION_MIN = 154;
|
||||
static constexpr uint8_t CMD_FRAME_COMMAND = 6;
|
||||
static constexpr uint8_t CMD_FRAME_DATA_LENGTH = 4;
|
||||
static constexpr uint8_t CMD_FRAME_STATUS = 7;
|
||||
static constexpr uint8_t CMD_ERROR_WORD = 8;
|
||||
static constexpr uint8_t ENERGY_SENSOR_START = 9;
|
||||
static constexpr uint8_t CALIBRATE_REPORT_INTERVAL = 4;
|
||||
static const char *const OP_NORMAL_MODE_STRING = "Normal";
|
||||
static const char *const OP_SIMPLE_MODE_STRING = "Simple";
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
namespace esphome::ld2420 {
|
||||
|
||||
static const uint8_t CALIBRATE_SAMPLES = 64;
|
||||
static const uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer
|
||||
static const uint8_t TOTAL_GATES = 16;
|
||||
static constexpr uint8_t CALIBRATE_SAMPLES = 64;
|
||||
static constexpr uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer
|
||||
static constexpr uint8_t TOTAL_GATES = 16;
|
||||
|
||||
enum OpMode : uint8_t {
|
||||
OP_NORMAL_MODE = 1,
|
||||
|
||||
@@ -11,10 +11,10 @@ void loop();
|
||||
|
||||
namespace esphome {
|
||||
|
||||
void IRAM_ATTR HOT yield() { ::yield(); }
|
||||
void HOT yield() { ::yield(); }
|
||||
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||
void IRAM_ATTR HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
void HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { ::delayMicroseconds(us); }
|
||||
|
||||
void arch_init() {
|
||||
@@ -30,7 +30,7 @@ void arch_restart() {
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
void IRAM_ATTR HOT arch_feed_wdt() { lt_wdt_feed(); }
|
||||
void HOT arch_feed_wdt() { lt_wdt_feed(); }
|
||||
uint32_t arch_get_cpu_cycle_count() { return lt_cpu_get_cycle_count(); }
|
||||
uint32_t arch_get_cpu_freq_hz() { return lt_cpu_get_freq(); }
|
||||
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
|
||||
|
||||
@@ -40,26 +40,25 @@ struct device;
|
||||
|
||||
namespace esphome::logger {
|
||||
|
||||
/** Interface for receiving log messages without std::function overhead.
|
||||
/** Lightweight callback for receiving log messages without virtual dispatch overhead.
|
||||
*
|
||||
* Components can implement this interface instead of using lambdas with std::function
|
||||
* to reduce flash usage from std::function type erasure machinery.
|
||||
* Replaces the former LogListener virtual interface to eliminate per-implementer
|
||||
* vtable sub-tables and thunk code (~39 bytes saved per class that used LogListener).
|
||||
*
|
||||
* Usage:
|
||||
* class MyComponent : public Component, public LogListener {
|
||||
* public:
|
||||
* void setup() override {
|
||||
* if (logger::global_logger != nullptr)
|
||||
* logger::global_logger->add_log_listener(this);
|
||||
* }
|
||||
* void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override {
|
||||
* // Handle log message
|
||||
* }
|
||||
* };
|
||||
* // In your component's setup():
|
||||
* if (logger::global_logger != nullptr)
|
||||
* logger::global_logger->add_log_callback(
|
||||
* this, [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
* static_cast<MyComponent *>(self)->on_log(level, tag, message, message_len);
|
||||
* });
|
||||
*/
|
||||
class LogListener {
|
||||
public:
|
||||
virtual void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) = 0;
|
||||
struct LogCallback {
|
||||
void *instance;
|
||||
void (*fn)(void *, uint8_t, const char *, const char *, size_t);
|
||||
void invoke(uint8_t level, const char *tag, const char *message, size_t message_len) const {
|
||||
this->fn(this->instance, level, tag, message, message_len);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef USE_LOGGER_LEVEL_LISTENERS
|
||||
@@ -187,11 +186,13 @@ class Logger : public Component {
|
||||
inline uint8_t level_for(const char *tag);
|
||||
|
||||
#ifdef USE_LOG_LISTENERS
|
||||
/// Register a log listener to receive log messages
|
||||
void add_log_listener(LogListener *listener) { this->log_listeners_.push_back(listener); }
|
||||
/// Register a log callback to receive log messages
|
||||
void add_log_callback(void *instance, void (*fn)(void *, uint8_t, const char *, const char *, size_t)) {
|
||||
this->log_callbacks_.push_back(LogCallback{instance, fn});
|
||||
}
|
||||
#else
|
||||
/// No-op when log listeners are disabled
|
||||
void add_log_listener(LogListener *listener) {}
|
||||
void add_log_callback(void *instance, void (*fn)(void *, uint8_t, const char *, const char *, size_t)) {}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOGGER_LEVEL_LISTENERS
|
||||
@@ -253,11 +254,11 @@ class Logger : public Component {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Helper to notify log listeners
|
||||
// Helper to notify log callbacks
|
||||
inline void HOT notify_listeners_(uint8_t level, const char *tag, const LogBuffer &buf) {
|
||||
#ifdef USE_LOG_LISTENERS
|
||||
for (auto *listener : this->log_listeners_)
|
||||
listener->on_log(level, tag, buf.data, buf.pos);
|
||||
for (auto &cb : this->log_callbacks_)
|
||||
cb.invoke(level, tag, buf.data, buf.pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -341,8 +342,8 @@ class Logger : public Component {
|
||||
std::map<const char *, uint8_t, CStrCompare> log_levels_{};
|
||||
#endif
|
||||
#ifdef USE_LOG_LISTENERS
|
||||
StaticVector<LogListener *, ESPHOME_LOG_MAX_LISTENERS>
|
||||
log_listeners_; // Log message listeners (API, MQTT, syslog, etc.)
|
||||
StaticVector<LogCallback, ESPHOME_LOG_MAX_LISTENERS>
|
||||
log_callbacks_; // Log message callbacks (API, MQTT, syslog, etc.)
|
||||
#endif
|
||||
#ifdef USE_LOGGER_LEVEL_LISTENERS
|
||||
std::vector<LoggerLevelListener *> level_listeners_; // Log level change listeners
|
||||
@@ -478,15 +479,16 @@ class Logger : public Component {
|
||||
};
|
||||
extern Logger *global_logger; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
class LoggerMessageTrigger : public Trigger<uint8_t, const char *, const char *>, public LogListener {
|
||||
class LoggerMessageTrigger : public Trigger<uint8_t, const char *, const char *> {
|
||||
public:
|
||||
explicit LoggerMessageTrigger(Logger *parent, uint8_t level) : level_(level) { parent->add_log_listener(this); }
|
||||
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override {
|
||||
(void) message_len;
|
||||
if (level <= this->level_) {
|
||||
this->trigger(level, tag, message);
|
||||
}
|
||||
explicit LoggerMessageTrigger(Logger *parent, uint8_t level) : level_(level) {
|
||||
parent->add_log_callback(this,
|
||||
[](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
auto *trigger = static_cast<LoggerMessageTrigger *>(self);
|
||||
if (level <= trigger->level_) {
|
||||
trigger->trigger(level, tag, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -21,7 +21,7 @@ DEPENDENCIES = ["network"]
|
||||
# Components that create mDNS services at runtime
|
||||
# IMPORTANT: If you add a new component here, you must also update the corresponding
|
||||
# #ifdef blocks in mdns_component.cpp compile_records_() method
|
||||
COMPONENTS_WITH_MDNS_SERVICES = ("api", "prometheus", "web_server")
|
||||
COMPONENTS_WITH_MDNS_SERVICES = ("api", "prometheus", "sendspin", "web_server")
|
||||
|
||||
mdns_ns = cg.esphome_ns.namespace("mdns")
|
||||
MDNSComponent = mdns_ns.class_("MDNSComponent", cg.Component)
|
||||
|
||||
@@ -29,6 +29,10 @@ static const char *const TAG = "mdns";
|
||||
#define USE_WEBSERVER_PORT 80 // NOLINT
|
||||
#endif
|
||||
|
||||
#ifndef USE_SENDSPIN_PORT
|
||||
#define USE_SENDSPIN_PORT 8928 // NOLINT
|
||||
#endif
|
||||
|
||||
// Define all constant strings using the macro
|
||||
MDNS_STATIC_CONST_CHAR(SERVICE_TCP, "_tcp");
|
||||
|
||||
@@ -150,6 +154,18 @@ void MDNSComponent::compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUN
|
||||
prom_service.port = USE_WEBSERVER_PORT;
|
||||
#endif
|
||||
|
||||
#ifdef USE_SENDSPIN
|
||||
MDNS_STATIC_CONST_CHAR(SERVICE_SENDSPIN, "_sendspin");
|
||||
MDNS_STATIC_CONST_CHAR(TXT_SENDSPIN_PATH, "path");
|
||||
MDNS_STATIC_CONST_CHAR(VALUE_SENDSPIN_PATH, "/sendspin");
|
||||
|
||||
auto &sendspin_service = services.emplace_next();
|
||||
sendspin_service.service_type = MDNS_STR(SERVICE_SENDSPIN);
|
||||
sendspin_service.proto = MDNS_STR(SERVICE_TCP);
|
||||
sendspin_service.port = USE_SENDSPIN_PORT;
|
||||
sendspin_service.txt_records = {{MDNS_STR(TXT_SENDSPIN_PATH), MDNS_STR(VALUE_SENDSPIN_PATH)}};
|
||||
#endif
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
|
||||
|
||||
@@ -159,7 +175,8 @@ void MDNSComponent::compile_records_(StaticVector<MDNSService, MDNS_SERVICE_COUN
|
||||
web_service.port = USE_WEBSERVER_PORT;
|
||||
#endif
|
||||
|
||||
#if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_WEBSERVER) && !defined(USE_MDNS_EXTRA_SERVICES)
|
||||
#if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_SENDSPIN) && !defined(USE_WEBSERVER) && \
|
||||
!defined(USE_MDNS_EXTRA_SERVICES)
|
||||
MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
|
||||
MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
|
||||
|
||||
|
||||
@@ -35,86 +35,73 @@ MEDIA_PLAYER_FORMAT_PURPOSE_ENUM = {
|
||||
"announcement": MediaPlayerFormatPurpose.PURPOSE_ANNOUNCEMENT,
|
||||
}
|
||||
|
||||
|
||||
PlayAction = media_player_ns.class_(
|
||||
"PlayAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
PlayMediaAction = media_player_ns.class_(
|
||||
"PlayMediaAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
ToggleAction = media_player_ns.class_(
|
||||
"ToggleAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
PauseAction = media_player_ns.class_(
|
||||
"PauseAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
StopAction = media_player_ns.class_(
|
||||
"StopAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
VolumeUpAction = media_player_ns.class_(
|
||||
"VolumeUpAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
VolumeDownAction = media_player_ns.class_(
|
||||
"VolumeDownAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
VolumeSetAction = media_player_ns.class_(
|
||||
"VolumeSetAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
TurnOnAction = media_player_ns.class_(
|
||||
"TurnOnAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
TurnOffAction = media_player_ns.class_(
|
||||
"TurnOffAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
|
||||
# Local config key constants
|
||||
CONF_ANNOUNCEMENT = "announcement"
|
||||
CONF_ON_PLAY = "on_play"
|
||||
CONF_ON_PAUSE = "on_pause"
|
||||
CONF_ON_ANNOUNCEMENT = "on_announcement"
|
||||
CONF_MEDIA_URL = "media_url"
|
||||
|
||||
StateTrigger = media_player_ns.class_("StateTrigger", automation.Trigger.template())
|
||||
IdleTrigger = media_player_ns.class_("IdleTrigger", automation.Trigger.template())
|
||||
PlayTrigger = media_player_ns.class_("PlayTrigger", automation.Trigger.template())
|
||||
PauseTrigger = media_player_ns.class_("PauseTrigger", automation.Trigger.template())
|
||||
AnnoucementTrigger = media_player_ns.class_(
|
||||
"AnnouncementTrigger", automation.Trigger.template()
|
||||
# Command actions that all share the same schema and codegen handler
|
||||
_COMMAND_ACTIONS = [
|
||||
"play",
|
||||
"pause",
|
||||
"stop",
|
||||
"toggle",
|
||||
"volume_up",
|
||||
"volume_down",
|
||||
"turn_on",
|
||||
"turn_off",
|
||||
"next",
|
||||
"previous",
|
||||
"mute",
|
||||
"unmute",
|
||||
"repeat_off",
|
||||
"repeat_one",
|
||||
"repeat_all",
|
||||
"shuffle",
|
||||
"unshuffle",
|
||||
"group_join",
|
||||
"clear_playlist",
|
||||
]
|
||||
|
||||
# State triggers: (config_key, C++ class name)
|
||||
_STATE_TRIGGERS = [
|
||||
(CONF_ON_STATE, "StateTrigger"),
|
||||
(CONF_ON_IDLE, "IdleTrigger"),
|
||||
(CONF_ON_PLAY, "PlayTrigger"),
|
||||
(CONF_ON_PAUSE, "PauseTrigger"),
|
||||
(CONF_ON_ANNOUNCEMENT, "AnnouncementTrigger"),
|
||||
(CONF_ON_TURN_ON, "OnTrigger"),
|
||||
(CONF_ON_TURN_OFF, "OffTrigger"),
|
||||
]
|
||||
|
||||
# State conditions that all share the same schema and codegen handler
|
||||
_STATE_CONDITIONS = [
|
||||
"idle",
|
||||
"paused",
|
||||
"playing",
|
||||
"announcing",
|
||||
"on",
|
||||
"off",
|
||||
"muted",
|
||||
]
|
||||
|
||||
# Special action classes with custom schemas/handlers
|
||||
PlayMediaAction = media_player_ns.class_(
|
||||
"PlayMediaAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
OnTrigger = media_player_ns.class_("OnTrigger", automation.Trigger.template())
|
||||
OffTrigger = media_player_ns.class_("OffTrigger", automation.Trigger.template())
|
||||
IsIdleCondition = media_player_ns.class_("IsIdleCondition", automation.Condition)
|
||||
IsPausedCondition = media_player_ns.class_("IsPausedCondition", automation.Condition)
|
||||
IsPlayingCondition = media_player_ns.class_("IsPlayingCondition", automation.Condition)
|
||||
IsAnnouncingCondition = media_player_ns.class_(
|
||||
"IsAnnouncingCondition", automation.Condition
|
||||
VolumeSetAction = media_player_ns.class_(
|
||||
"VolumeSetAction", automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
IsOnCondition = media_player_ns.class_("IsOnCondition", automation.Condition)
|
||||
IsOffCondition = media_player_ns.class_("IsOffCondition", automation.Condition)
|
||||
|
||||
|
||||
async def setup_media_player_core_(var, config):
|
||||
await setup_entity(var, config, "media_player")
|
||||
for conf in config.get(CONF_ON_STATE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_IDLE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_PLAY, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_PAUSE, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_ANNOUNCEMENT, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_TURN_ON, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf in config.get(CONF_ON_TURN_OFF, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
for conf_key, _ in _STATE_TRIGGERS:
|
||||
for conf in config.get(conf_key, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
|
||||
async def register_media_player(var, config):
|
||||
@@ -133,41 +120,14 @@ async def new_media_player(config, *args):
|
||||
|
||||
_MEDIA_PLAYER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
|
||||
{
|
||||
cv.Optional(CONF_ON_STATE): automation.validate_automation(
|
||||
cv.Optional(conf_key): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
media_player_ns.class_(class_name, automation.Trigger.template())
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_IDLE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(IdleTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_PLAY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PlayTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_PAUSE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ANNOUNCEMENT): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(AnnoucementTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_TURN_ON): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OnTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_TURN_OFF): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(OffTrigger),
|
||||
}
|
||||
),
|
||||
)
|
||||
for conf_key, class_name in _STATE_TRIGGERS
|
||||
}
|
||||
)
|
||||
|
||||
@@ -228,56 +188,48 @@ async def media_player_play_media_action(config, action_id, template_arg, args):
|
||||
return var
|
||||
|
||||
|
||||
@automation.register_action("media_player.play", PlayAction, MEDIA_PLAYER_ACTION_SCHEMA)
|
||||
@automation.register_action(
|
||||
"media_player.toggle", ToggleAction, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"media_player.pause", PauseAction, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action("media_player.stop", StopAction, MEDIA_PLAYER_ACTION_SCHEMA)
|
||||
@automation.register_action(
|
||||
"media_player.volume_up", VolumeUpAction, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"media_player.volume_down", VolumeDownAction, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"media_player.turn_on", TurnOnAction, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)
|
||||
@automation.register_action(
|
||||
"media_player.turn_off", TurnOffAction, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)
|
||||
async def media_player_action(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
|
||||
cg.add(var.set_announcement(announcement))
|
||||
return var
|
||||
def _snake_to_camel(name):
|
||||
return "".join(word.capitalize() for word in name.split("_"))
|
||||
|
||||
|
||||
@automation.register_condition(
|
||||
"media_player.is_idle", IsIdleCondition, MEDIA_PLAYER_CONDITION_SCHEMA
|
||||
)
|
||||
@automation.register_condition(
|
||||
"media_player.is_paused", IsPausedCondition, MEDIA_PLAYER_CONDITION_SCHEMA
|
||||
)
|
||||
@automation.register_condition(
|
||||
"media_player.is_playing", IsPlayingCondition, MEDIA_PLAYER_CONDITION_SCHEMA
|
||||
)
|
||||
@automation.register_condition(
|
||||
"media_player.is_announcing", IsAnnouncingCondition, MEDIA_PLAYER_CONDITION_SCHEMA
|
||||
)
|
||||
@automation.register_condition(
|
||||
"media_player.is_on", IsOnCondition, MEDIA_PLAYER_CONDITION_SCHEMA
|
||||
)
|
||||
@automation.register_condition(
|
||||
"media_player.is_off", IsOffCondition, MEDIA_PLAYER_CONDITION_SCHEMA
|
||||
)
|
||||
async def media_player_condition(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
return var
|
||||
def _register_command_actions():
|
||||
async def handler(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
|
||||
cg.add(var.set_announcement(announcement))
|
||||
return var
|
||||
|
||||
for action_name in _COMMAND_ACTIONS:
|
||||
class_name = f"{_snake_to_camel(action_name)}Action"
|
||||
action_class = media_player_ns.class_(
|
||||
class_name, automation.Action, cg.Parented.template(MediaPlayer)
|
||||
)
|
||||
automation.register_action(
|
||||
f"media_player.{action_name}", action_class, MEDIA_PLAYER_ACTION_SCHEMA
|
||||
)(handler)
|
||||
|
||||
|
||||
_register_command_actions()
|
||||
|
||||
|
||||
def _register_state_conditions():
|
||||
async def handler(config, action_id, template_arg, args):
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
return var
|
||||
|
||||
for condition_name in _STATE_CONDITIONS:
|
||||
class_name = f"Is{_snake_to_camel(condition_name)}Condition"
|
||||
condition_class = media_player_ns.class_(class_name, automation.Condition)
|
||||
automation.register_condition(
|
||||
f"media_player.is_{condition_name}",
|
||||
condition_class,
|
||||
MEDIA_PLAYER_CONDITION_SCHEMA,
|
||||
)(handler)
|
||||
|
||||
|
||||
_register_state_conditions()
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
|
||||
@@ -32,6 +32,28 @@ template<typename... Ts>
|
||||
using TurnOnAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_TURN_ON, Ts...>;
|
||||
template<typename... Ts>
|
||||
using TurnOffAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_TURN_OFF, Ts...>;
|
||||
template<typename... Ts>
|
||||
using NextAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_NEXT, Ts...>;
|
||||
template<typename... Ts>
|
||||
using PreviousAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_PREVIOUS, Ts...>;
|
||||
template<typename... Ts>
|
||||
using MuteAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_MUTE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using UnmuteAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_UNMUTE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using RepeatOffAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_OFF, Ts...>;
|
||||
template<typename... Ts>
|
||||
using RepeatOneAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ONE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using RepeatAllAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_REPEAT_ALL, Ts...>;
|
||||
template<typename... Ts>
|
||||
using ShuffleAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_SHUFFLE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using UnshuffleAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_UNSHUFFLE, Ts...>;
|
||||
template<typename... Ts>
|
||||
using GroupJoinAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_GROUP_JOIN, Ts...>;
|
||||
template<typename... Ts>
|
||||
using ClearPlaylistAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST, Ts...>;
|
||||
|
||||
template<typename... Ts> class PlayMediaAction : public Action<Ts...>, public Parented<MediaPlayer> {
|
||||
TEMPLATABLE_VALUE(std::string, media_url)
|
||||
@@ -105,5 +127,10 @@ template<typename... Ts> class IsOffCondition : public Condition<Ts...>, public
|
||||
bool check(const Ts &...x) override { return this->parent_->state == MediaPlayerState::MEDIA_PLAYER_STATE_OFF; }
|
||||
};
|
||||
|
||||
template<typename... Ts> class IsMutedCondition : public Condition<Ts...>, public Parented<MediaPlayer> {
|
||||
public:
|
||||
bool check(const Ts &...x) override { return this->parent_->is_muted(); }
|
||||
};
|
||||
|
||||
} // namespace media_player
|
||||
} // namespace esphome
|
||||
|
||||
@@ -60,11 +60,39 @@ const char *media_player_command_to_string(MediaPlayerCommand command) {
|
||||
return "TURN_ON";
|
||||
case MEDIA_PLAYER_COMMAND_TURN_OFF:
|
||||
return "TURN_OFF";
|
||||
case MEDIA_PLAYER_COMMAND_NEXT:
|
||||
return "NEXT";
|
||||
case MEDIA_PLAYER_COMMAND_PREVIOUS:
|
||||
return "PREVIOUS";
|
||||
case MEDIA_PLAYER_COMMAND_REPEAT_ALL:
|
||||
return "REPEAT_ALL";
|
||||
case MEDIA_PLAYER_COMMAND_SHUFFLE:
|
||||
return "SHUFFLE";
|
||||
case MEDIA_PLAYER_COMMAND_UNSHUFFLE:
|
||||
return "UNSHUFFLE";
|
||||
case MEDIA_PLAYER_COMMAND_GROUP_JOIN:
|
||||
return "GROUP_JOIN";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayerTraits::set_supports_pause(bool supports_pause) {
|
||||
if (supports_pause) {
|
||||
this->feature_flags_ |= MediaPlayerEntityFeature::PAUSE | MediaPlayerEntityFeature::PLAY;
|
||||
} else {
|
||||
this->feature_flags_ &= ~(MediaPlayerEntityFeature::PAUSE | MediaPlayerEntityFeature::PLAY);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayerTraits::set_supports_turn_off_on(bool supports_turn_off_on) {
|
||||
if (supports_turn_off_on) {
|
||||
this->feature_flags_ |= MediaPlayerEntityFeature::TURN_OFF | MediaPlayerEntityFeature::TURN_ON;
|
||||
} else {
|
||||
this->feature_flags_ &= ~(MediaPlayerEntityFeature::TURN_OFF | MediaPlayerEntityFeature::TURN_ON);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayerCall::validate_() {
|
||||
if (this->media_url_.has_value()) {
|
||||
if (this->command_.has_value() && this->command_.value() != MEDIA_PLAYER_COMMAND_ENQUEUE) {
|
||||
@@ -125,6 +153,30 @@ MediaPlayerCall &MediaPlayerCall::set_command(const char *command) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_TURN_ON);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("TURN_OFF")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_TURN_OFF);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("VOLUME_UP")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_VOLUME_UP);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("VOLUME_DOWN")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_VOLUME_DOWN);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("ENQUEUE")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_ENQUEUE);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("REPEAT_ONE")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_REPEAT_ONE);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("REPEAT_OFF")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_REPEAT_OFF);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("REPEAT_ALL")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_REPEAT_ALL);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("CLEAR_PLAYLIST")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("NEXT")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_NEXT);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("PREVIOUS")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_PREVIOUS);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("SHUFFLE")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_SHUFFLE);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("UNSHUFFLE")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_UNSHUFFLE);
|
||||
} else if (ESPHOME_strcasecmp_P(command, ESPHOME_PSTR("GROUP_JOIN")) == 0) {
|
||||
this->set_command(MEDIA_PLAYER_COMMAND_GROUP_JOIN);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized command %s", this->parent_->get_name().c_str(), command);
|
||||
}
|
||||
|
||||
@@ -58,6 +58,12 @@ enum MediaPlayerCommand : uint8_t {
|
||||
MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST = 11,
|
||||
MEDIA_PLAYER_COMMAND_TURN_ON = 12,
|
||||
MEDIA_PLAYER_COMMAND_TURN_OFF = 13,
|
||||
MEDIA_PLAYER_COMMAND_NEXT = 14,
|
||||
MEDIA_PLAYER_COMMAND_PREVIOUS = 15,
|
||||
MEDIA_PLAYER_COMMAND_REPEAT_ALL = 16,
|
||||
MEDIA_PLAYER_COMMAND_SHUFFLE = 17,
|
||||
MEDIA_PLAYER_COMMAND_UNSHUFFLE = 18,
|
||||
MEDIA_PLAYER_COMMAND_GROUP_JOIN = 19,
|
||||
};
|
||||
const char *media_player_command_to_string(MediaPlayerCommand command);
|
||||
|
||||
@@ -74,38 +80,40 @@ struct MediaPlayerSupportedFormat {
|
||||
uint32_t sample_bytes;
|
||||
};
|
||||
|
||||
// Base features always reported for all media players
|
||||
static constexpr uint32_t BASE_MEDIA_PLAYER_FEATURES =
|
||||
MediaPlayerEntityFeature::PLAY_MEDIA | MediaPlayerEntityFeature::BROWSE_MEDIA | MediaPlayerEntityFeature::STOP |
|
||||
MediaPlayerEntityFeature::VOLUME_SET | MediaPlayerEntityFeature::VOLUME_MUTE |
|
||||
MediaPlayerEntityFeature::MEDIA_ANNOUNCE;
|
||||
|
||||
class MediaPlayer;
|
||||
|
||||
class MediaPlayerTraits {
|
||||
public:
|
||||
MediaPlayerTraits() = default;
|
||||
|
||||
void set_supports_pause(bool supports_pause) { this->supports_pause_ = supports_pause; }
|
||||
bool get_supports_pause() const { return this->supports_pause_; }
|
||||
|
||||
void set_supports_turn_off_on(bool supports_turn_off_on) { this->supports_turn_off_on_ = supports_turn_off_on; }
|
||||
bool get_supports_turn_off_on() const { return this->supports_turn_off_on_; }
|
||||
uint32_t get_feature_flags() const { return this->feature_flags_; }
|
||||
void add_feature_flags(uint32_t feature_flags) { this->feature_flags_ |= feature_flags; }
|
||||
void clear_feature_flags(uint32_t feature_flags) { this->feature_flags_ &= ~feature_flags; }
|
||||
// Returns true only if all specified flags are set
|
||||
bool has_feature_flags(uint32_t feature_flags) const {
|
||||
return (this->feature_flags_ & feature_flags) == feature_flags;
|
||||
}
|
||||
|
||||
std::vector<MediaPlayerSupportedFormat> &get_supported_formats() { return this->supported_formats_; }
|
||||
|
||||
uint32_t get_feature_flags() const {
|
||||
uint32_t flags = 0;
|
||||
flags |= MediaPlayerEntityFeature::PLAY_MEDIA | MediaPlayerEntityFeature::BROWSE_MEDIA |
|
||||
MediaPlayerEntityFeature::STOP | MediaPlayerEntityFeature::VOLUME_SET |
|
||||
MediaPlayerEntityFeature::VOLUME_MUTE | MediaPlayerEntityFeature::MEDIA_ANNOUNCE;
|
||||
if (this->get_supports_pause()) {
|
||||
flags |= MediaPlayerEntityFeature::PAUSE | MediaPlayerEntityFeature::PLAY;
|
||||
}
|
||||
if (this->get_supports_turn_off_on()) {
|
||||
flags |= MediaPlayerEntityFeature::TURN_OFF | MediaPlayerEntityFeature::TURN_ON;
|
||||
}
|
||||
return flags;
|
||||
// Legacy setters/getters are kept for backward compatibility
|
||||
void set_supports_pause(bool supports_pause);
|
||||
bool get_supports_pause() const { return this->has_feature_flags(MediaPlayerEntityFeature::PAUSE); }
|
||||
|
||||
void set_supports_turn_off_on(bool supports_turn_off_on);
|
||||
bool get_supports_turn_off_on() const {
|
||||
return this->has_feature_flags(MediaPlayerEntityFeature::TURN_ON | MediaPlayerEntityFeature::TURN_OFF);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<MediaPlayerSupportedFormat> supported_formats_{};
|
||||
bool supports_pause_{false};
|
||||
bool supports_turn_off_on_{false};
|
||||
uint32_t feature_flags_{BASE_MEDIA_PLAYER_FEATURES};
|
||||
};
|
||||
|
||||
class MediaPlayerCall {
|
||||
|
||||
@@ -114,11 +114,11 @@ struct QueueElement {
|
||||
|
||||
class MQTTBackendESP32 final : public MQTTBackend {
|
||||
public:
|
||||
static const size_t MQTT_BUFFER_SIZE = 4096;
|
||||
static const size_t TASK_STACK_SIZE = 3072;
|
||||
static const size_t TASK_STACK_SIZE_TLS = 4096; // Larger stack for TLS operations
|
||||
static const ssize_t TASK_PRIORITY = 5;
|
||||
static const uint8_t MQTT_QUEUE_LENGTH = 30; // 30*12 bytes = 360
|
||||
static constexpr size_t MQTT_BUFFER_SIZE = 4096;
|
||||
static constexpr size_t TASK_STACK_SIZE = 3072;
|
||||
static constexpr size_t TASK_STACK_SIZE_TLS = 4096; // Larger stack for TLS operations
|
||||
static constexpr ssize_t TASK_PRIORITY = 5;
|
||||
static constexpr uint8_t MQTT_QUEUE_LENGTH = 30; // 30*12 bytes = 360
|
||||
|
||||
void set_keep_alive(uint16_t keep_alive) final { this->keep_alive_ = keep_alive; }
|
||||
void set_client_id(const char *client_id) final { this->client_id_ = client_id; }
|
||||
|
||||
@@ -64,7 +64,10 @@ void MQTTClientComponent::setup() {
|
||||
});
|
||||
#ifdef USE_LOGGER
|
||||
if (this->is_log_message_enabled() && logger::global_logger != nullptr) {
|
||||
logger::global_logger->add_log_listener(this);
|
||||
logger::global_logger->add_log_callback(
|
||||
this, [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
static_cast<MQTTClientComponent *>(self)->on_log(level, tag, message, message_len);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -99,12 +99,7 @@ enum MQTTClientState {
|
||||
|
||||
class MQTTComponent;
|
||||
|
||||
class MQTTClientComponent : public Component
|
||||
#ifdef USE_LOGGER
|
||||
,
|
||||
public logger::LogListener
|
||||
#endif
|
||||
{
|
||||
class MQTTClientComponent : public Component {
|
||||
public:
|
||||
MQTTClientComponent();
|
||||
|
||||
@@ -252,7 +247,7 @@ class MQTTClientComponent : public Component
|
||||
float get_setup_priority() const override;
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override;
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
|
||||
#endif
|
||||
|
||||
void on_message(const std::string &topic, const std::string &payload);
|
||||
|
||||
@@ -8,137 +8,137 @@ namespace esphome {
|
||||
namespace nfc {
|
||||
|
||||
// Header info
|
||||
static const uint8_t NCI_PKT_HEADER_SIZE = 3; // NCI packet (pkt) headers are always three bytes
|
||||
static const uint8_t NCI_PKT_MT_GID_OFFSET = 0; // NCI packet (pkt) MT and GID offsets
|
||||
static const uint8_t NCI_PKT_OID_OFFSET = 1; // NCI packet (pkt) OID offset
|
||||
static const uint8_t NCI_PKT_LENGTH_OFFSET = 2; // NCI packet (pkt) message length (size) offset
|
||||
static const uint8_t NCI_PKT_PAYLOAD_OFFSET = 3; // NCI packet (pkt) payload offset
|
||||
static constexpr uint8_t NCI_PKT_HEADER_SIZE = 3; // NCI packet (pkt) headers are always three bytes
|
||||
static constexpr uint8_t NCI_PKT_MT_GID_OFFSET = 0; // NCI packet (pkt) MT and GID offsets
|
||||
static constexpr uint8_t NCI_PKT_OID_OFFSET = 1; // NCI packet (pkt) OID offset
|
||||
static constexpr uint8_t NCI_PKT_LENGTH_OFFSET = 2; // NCI packet (pkt) message length (size) offset
|
||||
static constexpr uint8_t NCI_PKT_PAYLOAD_OFFSET = 3; // NCI packet (pkt) payload offset
|
||||
// Important masks
|
||||
static const uint8_t NCI_PKT_MT_MASK = 0xE0; // NCI packet (pkt) message type mask
|
||||
static const uint8_t NCI_PKT_PBF_MASK = 0x10; // packet boundary flag bit
|
||||
static const uint8_t NCI_PKT_GID_MASK = 0x0F;
|
||||
static const uint8_t NCI_PKT_OID_MASK = 0x3F;
|
||||
static constexpr uint8_t NCI_PKT_MT_MASK = 0xE0; // NCI packet (pkt) message type mask
|
||||
static constexpr uint8_t NCI_PKT_PBF_MASK = 0x10; // packet boundary flag bit
|
||||
static constexpr uint8_t NCI_PKT_GID_MASK = 0x0F;
|
||||
static constexpr uint8_t NCI_PKT_OID_MASK = 0x3F;
|
||||
// Message types
|
||||
static const uint8_t NCI_PKT_MT_DATA = 0x00; // For sending commands to NFC endpoint (card/tag)
|
||||
static const uint8_t NCI_PKT_MT_CTRL_COMMAND = 0x20; // For sending commands to NFCC
|
||||
static const uint8_t NCI_PKT_MT_CTRL_RESPONSE = 0x40; // Response from NFCC to commands
|
||||
static const uint8_t NCI_PKT_MT_CTRL_NOTIFICATION = 0x60; // Notification from NFCC
|
||||
static constexpr uint8_t NCI_PKT_MT_DATA = 0x00; // For sending commands to NFC endpoint (card/tag)
|
||||
static constexpr uint8_t NCI_PKT_MT_CTRL_COMMAND = 0x20; // For sending commands to NFCC
|
||||
static constexpr uint8_t NCI_PKT_MT_CTRL_RESPONSE = 0x40; // Response from NFCC to commands
|
||||
static constexpr uint8_t NCI_PKT_MT_CTRL_NOTIFICATION = 0x60; // Notification from NFCC
|
||||
// GIDs
|
||||
static const uint8_t NCI_CORE_GID = 0x0;
|
||||
static const uint8_t RF_GID = 0x1;
|
||||
static const uint8_t NFCEE_GID = 0x1;
|
||||
static const uint8_t NCI_PROPRIETARY_GID = 0xF;
|
||||
static constexpr uint8_t NCI_CORE_GID = 0x0;
|
||||
static constexpr uint8_t RF_GID = 0x1;
|
||||
static constexpr uint8_t NFCEE_GID = 0x1;
|
||||
static constexpr uint8_t NCI_PROPRIETARY_GID = 0xF;
|
||||
// OIDs
|
||||
static const uint8_t NCI_CORE_RESET_OID = 0x00;
|
||||
static const uint8_t NCI_CORE_INIT_OID = 0x01;
|
||||
static const uint8_t NCI_CORE_SET_CONFIG_OID = 0x02;
|
||||
static const uint8_t NCI_CORE_GET_CONFIG_OID = 0x03;
|
||||
static const uint8_t NCI_CORE_CONN_CREATE_OID = 0x04;
|
||||
static const uint8_t NCI_CORE_CONN_CLOSE_OID = 0x05;
|
||||
static const uint8_t NCI_CORE_CONN_CREDITS_OID = 0x06;
|
||||
static const uint8_t NCI_CORE_GENERIC_ERROR_OID = 0x07;
|
||||
static const uint8_t NCI_CORE_INTERFACE_ERROR_OID = 0x08;
|
||||
static constexpr uint8_t NCI_CORE_RESET_OID = 0x00;
|
||||
static constexpr uint8_t NCI_CORE_INIT_OID = 0x01;
|
||||
static constexpr uint8_t NCI_CORE_SET_CONFIG_OID = 0x02;
|
||||
static constexpr uint8_t NCI_CORE_GET_CONFIG_OID = 0x03;
|
||||
static constexpr uint8_t NCI_CORE_CONN_CREATE_OID = 0x04;
|
||||
static constexpr uint8_t NCI_CORE_CONN_CLOSE_OID = 0x05;
|
||||
static constexpr uint8_t NCI_CORE_CONN_CREDITS_OID = 0x06;
|
||||
static constexpr uint8_t NCI_CORE_GENERIC_ERROR_OID = 0x07;
|
||||
static constexpr uint8_t NCI_CORE_INTERFACE_ERROR_OID = 0x08;
|
||||
|
||||
static const uint8_t RF_DISCOVER_MAP_OID = 0x00;
|
||||
static const uint8_t RF_SET_LISTEN_MODE_ROUTING_OID = 0x01;
|
||||
static const uint8_t RF_GET_LISTEN_MODE_ROUTING_OID = 0x02;
|
||||
static const uint8_t RF_DISCOVER_OID = 0x03;
|
||||
static const uint8_t RF_DISCOVER_SELECT_OID = 0x04;
|
||||
static const uint8_t RF_INTF_ACTIVATED_OID = 0x05;
|
||||
static const uint8_t RF_DEACTIVATE_OID = 0x06;
|
||||
static const uint8_t RF_FIELD_INFO_OID = 0x07;
|
||||
static const uint8_t RF_T3T_POLLING_OID = 0x08;
|
||||
static const uint8_t RF_NFCEE_ACTION_OID = 0x09;
|
||||
static const uint8_t RF_NFCEE_DISCOVERY_REQ_OID = 0x0A;
|
||||
static const uint8_t RF_PARAMETER_UPDATE_OID = 0x0B;
|
||||
static constexpr uint8_t RF_DISCOVER_MAP_OID = 0x00;
|
||||
static constexpr uint8_t RF_SET_LISTEN_MODE_ROUTING_OID = 0x01;
|
||||
static constexpr uint8_t RF_GET_LISTEN_MODE_ROUTING_OID = 0x02;
|
||||
static constexpr uint8_t RF_DISCOVER_OID = 0x03;
|
||||
static constexpr uint8_t RF_DISCOVER_SELECT_OID = 0x04;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_OID = 0x05;
|
||||
static constexpr uint8_t RF_DEACTIVATE_OID = 0x06;
|
||||
static constexpr uint8_t RF_FIELD_INFO_OID = 0x07;
|
||||
static constexpr uint8_t RF_T3T_POLLING_OID = 0x08;
|
||||
static constexpr uint8_t RF_NFCEE_ACTION_OID = 0x09;
|
||||
static constexpr uint8_t RF_NFCEE_DISCOVERY_REQ_OID = 0x0A;
|
||||
static constexpr uint8_t RF_PARAMETER_UPDATE_OID = 0x0B;
|
||||
|
||||
static const uint8_t NFCEE_DISCOVER_OID = 0x00;
|
||||
static const uint8_t NFCEE_MODE_SET_OID = 0x01;
|
||||
static constexpr uint8_t NFCEE_DISCOVER_OID = 0x00;
|
||||
static constexpr uint8_t NFCEE_MODE_SET_OID = 0x01;
|
||||
// Interfaces
|
||||
static const uint8_t INTF_NFCEE_DIRECT = 0x00;
|
||||
static const uint8_t INTF_FRAME = 0x01;
|
||||
static const uint8_t INTF_ISODEP = 0x02;
|
||||
static const uint8_t INTF_NFCDEP = 0x03;
|
||||
static const uint8_t INTF_TAGCMD = 0x80; // NXP proprietary
|
||||
static constexpr uint8_t INTF_NFCEE_DIRECT = 0x00;
|
||||
static constexpr uint8_t INTF_FRAME = 0x01;
|
||||
static constexpr uint8_t INTF_ISODEP = 0x02;
|
||||
static constexpr uint8_t INTF_NFCDEP = 0x03;
|
||||
static constexpr uint8_t INTF_TAGCMD = 0x80; // NXP proprietary
|
||||
// Bit rates
|
||||
static const uint8_t NFC_BIT_RATE_106 = 0x00;
|
||||
static const uint8_t NFC_BIT_RATE_212 = 0x01;
|
||||
static const uint8_t NFC_BIT_RATE_424 = 0x02;
|
||||
static const uint8_t NFC_BIT_RATE_848 = 0x03;
|
||||
static const uint8_t NFC_BIT_RATE_1695 = 0x04;
|
||||
static const uint8_t NFC_BIT_RATE_3390 = 0x05;
|
||||
static const uint8_t NFC_BIT_RATE_6780 = 0x06;
|
||||
static constexpr uint8_t NFC_BIT_RATE_106 = 0x00;
|
||||
static constexpr uint8_t NFC_BIT_RATE_212 = 0x01;
|
||||
static constexpr uint8_t NFC_BIT_RATE_424 = 0x02;
|
||||
static constexpr uint8_t NFC_BIT_RATE_848 = 0x03;
|
||||
static constexpr uint8_t NFC_BIT_RATE_1695 = 0x04;
|
||||
static constexpr uint8_t NFC_BIT_RATE_3390 = 0x05;
|
||||
static constexpr uint8_t NFC_BIT_RATE_6780 = 0x06;
|
||||
// Protocols
|
||||
static const uint8_t PROT_UNDETERMINED = 0x00;
|
||||
static const uint8_t PROT_T1T = 0x01;
|
||||
static const uint8_t PROT_T2T = 0x02;
|
||||
static const uint8_t PROT_T3T = 0x03;
|
||||
static const uint8_t PROT_ISODEP = 0x04;
|
||||
static const uint8_t PROT_NFCDEP = 0x05;
|
||||
static const uint8_t PROT_T5T = 0x06;
|
||||
static const uint8_t PROT_MIFARE = 0x80;
|
||||
static constexpr uint8_t PROT_UNDETERMINED = 0x00;
|
||||
static constexpr uint8_t PROT_T1T = 0x01;
|
||||
static constexpr uint8_t PROT_T2T = 0x02;
|
||||
static constexpr uint8_t PROT_T3T = 0x03;
|
||||
static constexpr uint8_t PROT_ISODEP = 0x04;
|
||||
static constexpr uint8_t PROT_NFCDEP = 0x05;
|
||||
static constexpr uint8_t PROT_T5T = 0x06;
|
||||
static constexpr uint8_t PROT_MIFARE = 0x80;
|
||||
// RF Technologies
|
||||
static const uint8_t NFC_RF_TECH_A = 0x00;
|
||||
static const uint8_t NFC_RF_TECH_B = 0x01;
|
||||
static const uint8_t NFC_RF_TECH_F = 0x02;
|
||||
static const uint8_t NFC_RF_TECH_15693 = 0x03;
|
||||
static constexpr uint8_t NFC_RF_TECH_A = 0x00;
|
||||
static constexpr uint8_t NFC_RF_TECH_B = 0x01;
|
||||
static constexpr uint8_t NFC_RF_TECH_F = 0x02;
|
||||
static constexpr uint8_t NFC_RF_TECH_15693 = 0x03;
|
||||
// RF Technology & Modes
|
||||
static const uint8_t MODE_MASK = 0xF0;
|
||||
static const uint8_t MODE_LISTEN_MASK = 0x80;
|
||||
static const uint8_t MODE_POLL = 0x00;
|
||||
static constexpr uint8_t MODE_MASK = 0xF0;
|
||||
static constexpr uint8_t MODE_LISTEN_MASK = 0x80;
|
||||
static constexpr uint8_t MODE_POLL = 0x00;
|
||||
|
||||
static const uint8_t TECH_PASSIVE_NFCA = 0x00;
|
||||
static const uint8_t TECH_PASSIVE_NFCB = 0x01;
|
||||
static const uint8_t TECH_PASSIVE_NFCF = 0x02;
|
||||
static const uint8_t TECH_ACTIVE_NFCA = 0x03;
|
||||
static const uint8_t TECH_ACTIVE_NFCF = 0x05;
|
||||
static const uint8_t TECH_PASSIVE_15693 = 0x06;
|
||||
static constexpr uint8_t TECH_PASSIVE_NFCA = 0x00;
|
||||
static constexpr uint8_t TECH_PASSIVE_NFCB = 0x01;
|
||||
static constexpr uint8_t TECH_PASSIVE_NFCF = 0x02;
|
||||
static constexpr uint8_t TECH_ACTIVE_NFCA = 0x03;
|
||||
static constexpr uint8_t TECH_ACTIVE_NFCF = 0x05;
|
||||
static constexpr uint8_t TECH_PASSIVE_15693 = 0x06;
|
||||
// Status codes
|
||||
static const uint8_t STATUS_OK = 0x00;
|
||||
static const uint8_t STATUS_REJECTED = 0x01;
|
||||
static const uint8_t STATUS_RF_FRAME_CORRUPTED = 0x02;
|
||||
static const uint8_t STATUS_FAILED = 0x03;
|
||||
static const uint8_t STATUS_NOT_INITIALIZED = 0x04;
|
||||
static const uint8_t STATUS_SYNTAX_ERROR = 0x05;
|
||||
static const uint8_t STATUS_SEMANTIC_ERROR = 0x06;
|
||||
static const uint8_t STATUS_INVALID_PARAM = 0x09;
|
||||
static const uint8_t STATUS_MESSAGE_SIZE_EXCEEDED = 0x0A;
|
||||
static const uint8_t DISCOVERY_ALREADY_STARTED = 0xA0;
|
||||
static const uint8_t DISCOVERY_TARGET_ACTIVATION_FAILED = 0xA1;
|
||||
static const uint8_t DISCOVERY_TEAR_DOWN = 0xA2;
|
||||
static const uint8_t RF_TRANSMISSION_ERROR = 0xB0;
|
||||
static const uint8_t RF_PROTOCOL_ERROR = 0xB1;
|
||||
static const uint8_t RF_TIMEOUT_ERROR = 0xB2;
|
||||
static const uint8_t NFCEE_INTERFACE_ACTIVATION_FAILED = 0xC0;
|
||||
static const uint8_t NFCEE_TRANSMISSION_ERROR = 0xC1;
|
||||
static const uint8_t NFCEE_PROTOCOL_ERROR = 0xC2;
|
||||
static const uint8_t NFCEE_TIMEOUT_ERROR = 0xC3;
|
||||
static constexpr uint8_t STATUS_OK = 0x00;
|
||||
static constexpr uint8_t STATUS_REJECTED = 0x01;
|
||||
static constexpr uint8_t STATUS_RF_FRAME_CORRUPTED = 0x02;
|
||||
static constexpr uint8_t STATUS_FAILED = 0x03;
|
||||
static constexpr uint8_t STATUS_NOT_INITIALIZED = 0x04;
|
||||
static constexpr uint8_t STATUS_SYNTAX_ERROR = 0x05;
|
||||
static constexpr uint8_t STATUS_SEMANTIC_ERROR = 0x06;
|
||||
static constexpr uint8_t STATUS_INVALID_PARAM = 0x09;
|
||||
static constexpr uint8_t STATUS_MESSAGE_SIZE_EXCEEDED = 0x0A;
|
||||
static constexpr uint8_t DISCOVERY_ALREADY_STARTED = 0xA0;
|
||||
static constexpr uint8_t DISCOVERY_TARGET_ACTIVATION_FAILED = 0xA1;
|
||||
static constexpr uint8_t DISCOVERY_TEAR_DOWN = 0xA2;
|
||||
static constexpr uint8_t RF_TRANSMISSION_ERROR = 0xB0;
|
||||
static constexpr uint8_t RF_PROTOCOL_ERROR = 0xB1;
|
||||
static constexpr uint8_t RF_TIMEOUT_ERROR = 0xB2;
|
||||
static constexpr uint8_t NFCEE_INTERFACE_ACTIVATION_FAILED = 0xC0;
|
||||
static constexpr uint8_t NFCEE_TRANSMISSION_ERROR = 0xC1;
|
||||
static constexpr uint8_t NFCEE_PROTOCOL_ERROR = 0xC2;
|
||||
static constexpr uint8_t NFCEE_TIMEOUT_ERROR = 0xC3;
|
||||
// Deactivation types/reasons
|
||||
static const uint8_t DEACTIVATION_TYPE_IDLE = 0x00;
|
||||
static const uint8_t DEACTIVATION_TYPE_SLEEP = 0x01;
|
||||
static const uint8_t DEACTIVATION_TYPE_SLEEP_AF = 0x02;
|
||||
static const uint8_t DEACTIVATION_TYPE_DISCOVERY = 0x03;
|
||||
static constexpr uint8_t DEACTIVATION_TYPE_IDLE = 0x00;
|
||||
static constexpr uint8_t DEACTIVATION_TYPE_SLEEP = 0x01;
|
||||
static constexpr uint8_t DEACTIVATION_TYPE_SLEEP_AF = 0x02;
|
||||
static constexpr uint8_t DEACTIVATION_TYPE_DISCOVERY = 0x03;
|
||||
// RF discover map modes
|
||||
static const uint8_t RF_DISCOVER_MAP_MODE_POLL = 0x1;
|
||||
static const uint8_t RF_DISCOVER_MAP_MODE_LISTEN = 0x2;
|
||||
static constexpr uint8_t RF_DISCOVER_MAP_MODE_POLL = 0x1;
|
||||
static constexpr uint8_t RF_DISCOVER_MAP_MODE_LISTEN = 0x2;
|
||||
// RF discover notification types
|
||||
static const uint8_t RF_DISCOVER_NTF_NT_LAST = 0x00;
|
||||
static const uint8_t RF_DISCOVER_NTF_NT_LAST_RL = 0x01;
|
||||
static const uint8_t RF_DISCOVER_NTF_NT_MORE = 0x02;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_NT_LAST = 0x00;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_NT_LAST_RL = 0x01;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_NT_MORE = 0x02;
|
||||
// Important message offsets
|
||||
static const uint8_t RF_DISCOVER_NTF_DISCOVERY_ID = 0 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_DISCOVER_NTF_PROTOCOL = 1 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_DISCOVER_NTF_MODE_TECH = 2 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_DISCOVER_NTF_RF_TECH_LENGTH = 3 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_DISCOVER_NTF_RF_TECH_PARAMS = 4 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_DISCOVERY_ID = 0 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_INTERFACE = 1 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_PROTOCOL = 2 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_MODE_TECH = 3 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_MAX_SIZE = 4 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_INIT_CRED = 5 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_RF_TECH_LENGTH = 6 + NCI_PKT_HEADER_SIZE;
|
||||
static const uint8_t RF_INTF_ACTIVATED_NTF_RF_TECH_PARAMS = 7 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_DISCOVERY_ID = 0 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_PROTOCOL = 1 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_MODE_TECH = 2 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_RF_TECH_LENGTH = 3 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_DISCOVER_NTF_RF_TECH_PARAMS = 4 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_DISCOVERY_ID = 0 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_INTERFACE = 1 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_PROTOCOL = 2 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_MODE_TECH = 3 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_MAX_SIZE = 4 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_INIT_CRED = 5 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_RF_TECH_LENGTH = 6 + NCI_PKT_HEADER_SIZE;
|
||||
static constexpr uint8_t RF_INTF_ACTIVATED_NTF_RF_TECH_PARAMS = 7 + NCI_PKT_HEADER_SIZE;
|
||||
|
||||
} // namespace nfc
|
||||
} // namespace esphome
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
namespace esphome {
|
||||
namespace nfc {
|
||||
|
||||
static const uint8_t MAX_NDEF_RECORDS = 4;
|
||||
static constexpr uint8_t MAX_NDEF_RECORDS = 4;
|
||||
|
||||
class NdefMessage {
|
||||
public:
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
namespace esphome {
|
||||
namespace nfc {
|
||||
|
||||
static const uint8_t TNF_EMPTY = 0x00;
|
||||
static const uint8_t TNF_WELL_KNOWN = 0x01;
|
||||
static const uint8_t TNF_MIME_MEDIA = 0x02;
|
||||
static const uint8_t TNF_ABSOLUTE_URI = 0x03;
|
||||
static const uint8_t TNF_EXTERNAL_TYPE = 0x04;
|
||||
static const uint8_t TNF_UNKNOWN = 0x05;
|
||||
static const uint8_t TNF_UNCHANGED = 0x06;
|
||||
static const uint8_t TNF_RESERVED = 0x07;
|
||||
static constexpr uint8_t TNF_EMPTY = 0x00;
|
||||
static constexpr uint8_t TNF_WELL_KNOWN = 0x01;
|
||||
static constexpr uint8_t TNF_MIME_MEDIA = 0x02;
|
||||
static constexpr uint8_t TNF_ABSOLUTE_URI = 0x03;
|
||||
static constexpr uint8_t TNF_EXTERNAL_TYPE = 0x04;
|
||||
static constexpr uint8_t TNF_UNKNOWN = 0x05;
|
||||
static constexpr uint8_t TNF_UNCHANGED = 0x06;
|
||||
static constexpr uint8_t TNF_RESERVED = 0x07;
|
||||
|
||||
class NdefRecord {
|
||||
public:
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace esphome {
|
||||
namespace nfc {
|
||||
|
||||
static const uint8_t PAYLOAD_IDENTIFIERS_COUNT = 0x23;
|
||||
static constexpr uint8_t PAYLOAD_IDENTIFIERS_COUNT = 0x23;
|
||||
static const char *const PAYLOAD_IDENTIFIERS[] = {"",
|
||||
"http://www.",
|
||||
"https://www.",
|
||||
|
||||
@@ -12,47 +12,47 @@
|
||||
namespace esphome {
|
||||
namespace nfc {
|
||||
|
||||
static const uint8_t MIFARE_CLASSIC_BLOCK_SIZE = 16;
|
||||
static const uint8_t MIFARE_CLASSIC_LONG_TLV_SIZE = 4;
|
||||
static const uint8_t MIFARE_CLASSIC_SHORT_TLV_SIZE = 2;
|
||||
static const uint8_t MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW = 4;
|
||||
static const uint8_t MIFARE_CLASSIC_BLOCKS_PER_SECT_HIGH = 16;
|
||||
static const uint8_t MIFARE_CLASSIC_16BLOCK_SECT_START = 32;
|
||||
static constexpr uint8_t MIFARE_CLASSIC_BLOCK_SIZE = 16;
|
||||
static constexpr uint8_t MIFARE_CLASSIC_LONG_TLV_SIZE = 4;
|
||||
static constexpr uint8_t MIFARE_CLASSIC_SHORT_TLV_SIZE = 2;
|
||||
static constexpr uint8_t MIFARE_CLASSIC_BLOCKS_PER_SECT_LOW = 4;
|
||||
static constexpr uint8_t MIFARE_CLASSIC_BLOCKS_PER_SECT_HIGH = 16;
|
||||
static constexpr uint8_t MIFARE_CLASSIC_16BLOCK_SECT_START = 32;
|
||||
|
||||
static const uint8_t MIFARE_ULTRALIGHT_PAGE_SIZE = 4;
|
||||
static const uint8_t MIFARE_ULTRALIGHT_READ_SIZE = 4;
|
||||
static const uint8_t MIFARE_ULTRALIGHT_DATA_START_PAGE = 4;
|
||||
static const uint8_t MIFARE_ULTRALIGHT_MAX_PAGE = 63;
|
||||
static constexpr uint8_t MIFARE_ULTRALIGHT_PAGE_SIZE = 4;
|
||||
static constexpr uint8_t MIFARE_ULTRALIGHT_READ_SIZE = 4;
|
||||
static constexpr uint8_t MIFARE_ULTRALIGHT_DATA_START_PAGE = 4;
|
||||
static constexpr uint8_t MIFARE_ULTRALIGHT_MAX_PAGE = 63;
|
||||
|
||||
static const uint8_t TAG_TYPE_MIFARE_CLASSIC = 0;
|
||||
static const uint8_t TAG_TYPE_1 = 1;
|
||||
static const uint8_t TAG_TYPE_2 = 2;
|
||||
static const uint8_t TAG_TYPE_3 = 3;
|
||||
static const uint8_t TAG_TYPE_4 = 4;
|
||||
static const uint8_t TAG_TYPE_UNKNOWN = 99;
|
||||
static constexpr uint8_t TAG_TYPE_MIFARE_CLASSIC = 0;
|
||||
static constexpr uint8_t TAG_TYPE_1 = 1;
|
||||
static constexpr uint8_t TAG_TYPE_2 = 2;
|
||||
static constexpr uint8_t TAG_TYPE_3 = 3;
|
||||
static constexpr uint8_t TAG_TYPE_4 = 4;
|
||||
static constexpr uint8_t TAG_TYPE_UNKNOWN = 99;
|
||||
|
||||
// Mifare Commands
|
||||
static const uint8_t MIFARE_CMD_AUTH_A = 0x60;
|
||||
static const uint8_t MIFARE_CMD_AUTH_B = 0x61;
|
||||
static const uint8_t MIFARE_CMD_HALT = 0x50;
|
||||
static const uint8_t MIFARE_CMD_READ = 0x30;
|
||||
static const uint8_t MIFARE_CMD_WRITE = 0xA0;
|
||||
static const uint8_t MIFARE_CMD_WRITE_ULTRALIGHT = 0xA2;
|
||||
static constexpr uint8_t MIFARE_CMD_AUTH_A = 0x60;
|
||||
static constexpr uint8_t MIFARE_CMD_AUTH_B = 0x61;
|
||||
static constexpr uint8_t MIFARE_CMD_HALT = 0x50;
|
||||
static constexpr uint8_t MIFARE_CMD_READ = 0x30;
|
||||
static constexpr uint8_t MIFARE_CMD_WRITE = 0xA0;
|
||||
static constexpr uint8_t MIFARE_CMD_WRITE_ULTRALIGHT = 0xA2;
|
||||
|
||||
// Mifare Ack/Nak
|
||||
static const uint8_t MIFARE_CMD_ACK = 0x0A;
|
||||
static const uint8_t MIFARE_CMD_NAK_INVALID_XFER_BUFF_VALID = 0x00;
|
||||
static const uint8_t MIFARE_CMD_NAK_CRC_ERROR_XFER_BUFF_VALID = 0x01;
|
||||
static const uint8_t MIFARE_CMD_NAK_INVALID_XFER_BUFF_INVALID = 0x04;
|
||||
static const uint8_t MIFARE_CMD_NAK_CRC_ERROR_XFER_BUFF_INVALID = 0x05;
|
||||
static constexpr uint8_t MIFARE_CMD_ACK = 0x0A;
|
||||
static constexpr uint8_t MIFARE_CMD_NAK_INVALID_XFER_BUFF_VALID = 0x00;
|
||||
static constexpr uint8_t MIFARE_CMD_NAK_CRC_ERROR_XFER_BUFF_VALID = 0x01;
|
||||
static constexpr uint8_t MIFARE_CMD_NAK_INVALID_XFER_BUFF_INVALID = 0x04;
|
||||
static constexpr uint8_t MIFARE_CMD_NAK_CRC_ERROR_XFER_BUFF_INVALID = 0x05;
|
||||
|
||||
static const char *const MIFARE_CLASSIC = "Mifare Classic";
|
||||
static const char *const NFC_FORUM_TYPE_2 = "NFC Forum Type 2";
|
||||
static const char *const ERROR = "Error";
|
||||
|
||||
static const uint8_t DEFAULT_KEY[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
static const uint8_t NDEF_KEY[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
|
||||
static const uint8_t MAD_KEY[6] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
|
||||
static constexpr uint8_t DEFAULT_KEY[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
static constexpr uint8_t NDEF_KEY[6] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7};
|
||||
static constexpr uint8_t MAD_KEY[6] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5};
|
||||
|
||||
/// Max UID size is 10 bytes, formatted as "XX-XX-XX-XX-XX-XX-XX-XX-XX-XX\0" = 30 chars
|
||||
static constexpr size_t FORMAT_UID_BUFFER_SIZE = 30;
|
||||
|
||||
@@ -58,9 +58,9 @@ union FuData {
|
||||
float f32;
|
||||
};
|
||||
|
||||
static const uint16_t MAGIC_NUMBER = 0x4553;
|
||||
static const uint16_t MAGIC_PING = 0x5048;
|
||||
static const uint32_t PREF_HASH = 0x45535043;
|
||||
static constexpr uint16_t MAGIC_NUMBER = 0x4553;
|
||||
static constexpr uint16_t MAGIC_PING = 0x5048;
|
||||
static constexpr uint32_t PREF_HASH = 0x45535043;
|
||||
enum DataKey {
|
||||
ZERO_FILL_KEY,
|
||||
DATA_KEY,
|
||||
|
||||
@@ -8,11 +8,7 @@ namespace pca9685 {
|
||||
|
||||
static const char *const TAG = "pca9685";
|
||||
|
||||
const uint8_t PCA9685_MODE_INVERTED = 0x10;
|
||||
const uint8_t PCA9685_MODE_OUTPUT_ONACK = 0x08;
|
||||
const uint8_t PCA9685_MODE_OUTPUT_TOTEM_POLE = 0x04;
|
||||
const uint8_t PCA9685_MODE_OUTNE_HIGHZ = 0x02;
|
||||
const uint8_t PCA9685_MODE_OUTNE_LOW = 0x01;
|
||||
// PCA9685 mode constants are now inline constexpr in pca9685_output.h
|
||||
|
||||
static const uint8_t PCA9685_REGISTER_SOFTWARE_RESET = 0x06;
|
||||
static const uint8_t PCA9685_REGISTER_MODE1 = 0x00;
|
||||
|
||||
@@ -13,15 +13,15 @@ enum class PhaseBalancer {
|
||||
};
|
||||
|
||||
/// Inverts polarity of channel output signal
|
||||
extern const uint8_t PCA9685_MODE_INVERTED;
|
||||
inline constexpr uint8_t PCA9685_MODE_INVERTED = 0x10;
|
||||
/// Channel update happens upon ACK (post-set) rather than on STOP (endTransmission)
|
||||
extern const uint8_t PCA9685_MODE_OUTPUT_ONACK;
|
||||
inline constexpr uint8_t PCA9685_MODE_OUTPUT_ONACK = 0x08;
|
||||
/// Use a totem-pole (push-pull) style output rather than an open-drain structure.
|
||||
extern const uint8_t PCA9685_MODE_OUTPUT_TOTEM_POLE;
|
||||
inline constexpr uint8_t PCA9685_MODE_OUTPUT_TOTEM_POLE = 0x04;
|
||||
/// For active low output enable, sets channel output to high-impedance state
|
||||
extern const uint8_t PCA9685_MODE_OUTNE_HIGHZ;
|
||||
inline constexpr uint8_t PCA9685_MODE_OUTNE_HIGHZ = 0x02;
|
||||
/// Similarly, sets channel output to high if in totem-pole mode, otherwise
|
||||
extern const uint8_t PCA9685_MODE_OUTNE_LOW;
|
||||
inline constexpr uint8_t PCA9685_MODE_OUTNE_LOW = 0x01;
|
||||
|
||||
class PCA9685Output;
|
||||
|
||||
|
||||
@@ -14,48 +14,48 @@
|
||||
namespace esphome {
|
||||
namespace pn7150 {
|
||||
|
||||
static const uint16_t NFCC_DEFAULT_TIMEOUT = 10;
|
||||
static const uint16_t NFCC_INIT_TIMEOUT = 50;
|
||||
static const uint16_t NFCC_TAG_WRITE_TIMEOUT = 15;
|
||||
static constexpr uint16_t NFCC_DEFAULT_TIMEOUT = 10;
|
||||
static constexpr uint16_t NFCC_INIT_TIMEOUT = 50;
|
||||
static constexpr uint16_t NFCC_TAG_WRITE_TIMEOUT = 15;
|
||||
|
||||
static const uint8_t NFCC_MAX_COMM_FAILS = 3;
|
||||
static const uint8_t NFCC_MAX_ERROR_COUNT = 10;
|
||||
static constexpr uint8_t NFCC_MAX_COMM_FAILS = 3;
|
||||
static constexpr uint8_t NFCC_MAX_ERROR_COUNT = 10;
|
||||
|
||||
static const uint8_t XCHG_DATA_OID = 0x10;
|
||||
static const uint8_t MF_SECTORSEL_OID = 0x32;
|
||||
static const uint8_t MFC_AUTHENTICATE_OID = 0x40;
|
||||
static const uint8_t TEST_PRBS_OID = 0x30;
|
||||
static const uint8_t TEST_ANTENNA_OID = 0x3D;
|
||||
static const uint8_t TEST_GET_REGISTER_OID = 0x33;
|
||||
static constexpr uint8_t XCHG_DATA_OID = 0x10;
|
||||
static constexpr uint8_t MF_SECTORSEL_OID = 0x32;
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_OID = 0x40;
|
||||
static constexpr uint8_t TEST_PRBS_OID = 0x30;
|
||||
static constexpr uint8_t TEST_ANTENNA_OID = 0x3D;
|
||||
static constexpr uint8_t TEST_GET_REGISTER_OID = 0x33;
|
||||
|
||||
static const uint8_t MFC_AUTHENTICATE_PARAM_KS_A = 0x00; // key select A
|
||||
static const uint8_t MFC_AUTHENTICATE_PARAM_KS_B = 0x80; // key select B
|
||||
static const uint8_t MFC_AUTHENTICATE_PARAM_EMBED_KEY = 0x10;
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_PARAM_KS_A = 0x00; // key select A
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_PARAM_KS_B = 0x80; // key select B
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_PARAM_EMBED_KEY = 0x10;
|
||||
|
||||
static const uint8_t CARD_EMU_T4T_APP_SELECT[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76,
|
||||
0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
|
||||
static const uint8_t CARD_EMU_T4T_CC[] = {0x00, 0x0F, 0x20, 0x00, 0xFF, 0x00, 0xFF, 0x04,
|
||||
0x06, 0xE1, 0x04, 0x00, 0xFF, 0x00, 0x00};
|
||||
static const uint8_t CARD_EMU_T4T_CC_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x03};
|
||||
static const uint8_t CARD_EMU_T4T_NDEF_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x04};
|
||||
static const uint8_t CARD_EMU_T4T_READ[] = {0x00, 0xB0};
|
||||
static const uint8_t CARD_EMU_T4T_WRITE[] = {0x00, 0xD6};
|
||||
static const uint8_t CARD_EMU_T4T_OK[] = {0x90, 0x00};
|
||||
static const uint8_t CARD_EMU_T4T_NOK[] = {0x6A, 0x82};
|
||||
static constexpr uint8_t CARD_EMU_T4T_APP_SELECT[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76,
|
||||
0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
|
||||
static constexpr uint8_t CARD_EMU_T4T_CC[] = {0x00, 0x0F, 0x20, 0x00, 0xFF, 0x00, 0xFF, 0x04,
|
||||
0x06, 0xE1, 0x04, 0x00, 0xFF, 0x00, 0x00};
|
||||
static constexpr uint8_t CARD_EMU_T4T_CC_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x03};
|
||||
static constexpr uint8_t CARD_EMU_T4T_NDEF_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x04};
|
||||
static constexpr uint8_t CARD_EMU_T4T_READ[] = {0x00, 0xB0};
|
||||
static constexpr uint8_t CARD_EMU_T4T_WRITE[] = {0x00, 0xD6};
|
||||
static constexpr uint8_t CARD_EMU_T4T_OK[] = {0x90, 0x00};
|
||||
static constexpr uint8_t CARD_EMU_T4T_NOK[] = {0x6A, 0x82};
|
||||
|
||||
static const uint8_t CORE_CONFIG_SOLO[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0x01, // TOTAL_DURATION (low)...
|
||||
0x00}; // TOTAL_DURATION (high): 1 ms
|
||||
static constexpr uint8_t CORE_CONFIG_SOLO[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0x01, // TOTAL_DURATION (low)...
|
||||
0x00}; // TOTAL_DURATION (high): 1 ms
|
||||
|
||||
static const uint8_t CORE_CONFIG_RW_CE[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0xF8, // TOTAL_DURATION (low)...
|
||||
0x02}; // TOTAL_DURATION (high): 760 ms
|
||||
static constexpr uint8_t CORE_CONFIG_RW_CE[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0xF8, // TOTAL_DURATION (low)...
|
||||
0x02}; // TOTAL_DURATION (high): 760 ms
|
||||
|
||||
static const uint8_t PMU_CFG[] = {
|
||||
static constexpr uint8_t PMU_CFG[] = {
|
||||
0x01, // Number of parameters
|
||||
0xA0, 0x0E, // ext. tag
|
||||
3, // length
|
||||
@@ -64,7 +64,7 @@ static const uint8_t PMU_CFG[] = {
|
||||
0x01, // RFU; must be 0x00 for CFG1 and 0x01 for CFG2
|
||||
};
|
||||
|
||||
static const uint8_t RF_DISCOVER_MAP_CONFIG[] = { // poll modes
|
||||
static constexpr uint8_t RF_DISCOVER_MAP_CONFIG[] = { // poll modes
|
||||
nfc::PROT_T1T, nfc::RF_DISCOVER_MAP_MODE_POLL,
|
||||
nfc::INTF_FRAME, // poll mode
|
||||
nfc::PROT_T2T, nfc::RF_DISCOVER_MAP_MODE_POLL,
|
||||
@@ -76,28 +76,29 @@ static const uint8_t RF_DISCOVER_MAP_CONFIG[] = { // poll modes
|
||||
nfc::PROT_MIFARE, nfc::RF_DISCOVER_MAP_MODE_POLL,
|
||||
nfc::INTF_TAGCMD}; // poll mode
|
||||
|
||||
static const uint8_t RF_DISCOVERY_LISTEN_CONFIG[] = {nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
static constexpr uint8_t RF_DISCOVERY_LISTEN_CONFIG[] = {
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
|
||||
static const uint8_t RF_DISCOVERY_POLL_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF}; // poll mode
|
||||
static constexpr uint8_t RF_DISCOVERY_POLL_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF}; // poll mode
|
||||
|
||||
static const uint8_t RF_DISCOVERY_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF, // poll mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
static constexpr uint8_t RF_DISCOVERY_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF, // poll mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
|
||||
static const uint8_t RF_LISTEN_MODE_ROUTING_CONFIG[] = {0x00, // "more" (another message is coming)
|
||||
1, // number of table entries
|
||||
0x01, // type = protocol-based
|
||||
3, // length
|
||||
0, // DH NFCEE ID, a static ID representing the DH-NFCEE
|
||||
0x01, // power state
|
||||
nfc::PROT_ISODEP}; // protocol
|
||||
static constexpr uint8_t RF_LISTEN_MODE_ROUTING_CONFIG[] = {0x00, // "more" (another message is coming)
|
||||
1, // number of table entries
|
||||
0x01, // type = protocol-based
|
||||
3, // length
|
||||
0, // DH NFCEE ID, a static ID representing the DH-NFCEE
|
||||
0x01, // power state
|
||||
nfc::PROT_ISODEP}; // protocol
|
||||
|
||||
enum class CardEmulationState : uint8_t {
|
||||
CARD_EMU_IDLE,
|
||||
|
||||
@@ -14,48 +14,48 @@
|
||||
namespace esphome {
|
||||
namespace pn7160 {
|
||||
|
||||
static const uint16_t NFCC_DEFAULT_TIMEOUT = 10;
|
||||
static const uint16_t NFCC_INIT_TIMEOUT = 50;
|
||||
static const uint16_t NFCC_TAG_WRITE_TIMEOUT = 15;
|
||||
static constexpr uint16_t NFCC_DEFAULT_TIMEOUT = 10;
|
||||
static constexpr uint16_t NFCC_INIT_TIMEOUT = 50;
|
||||
static constexpr uint16_t NFCC_TAG_WRITE_TIMEOUT = 15;
|
||||
|
||||
static const uint8_t NFCC_MAX_COMM_FAILS = 3;
|
||||
static const uint8_t NFCC_MAX_ERROR_COUNT = 10;
|
||||
static constexpr uint8_t NFCC_MAX_COMM_FAILS = 3;
|
||||
static constexpr uint8_t NFCC_MAX_ERROR_COUNT = 10;
|
||||
|
||||
static const uint8_t XCHG_DATA_OID = 0x10;
|
||||
static const uint8_t MF_SECTORSEL_OID = 0x32;
|
||||
static const uint8_t MFC_AUTHENTICATE_OID = 0x40;
|
||||
static const uint8_t TEST_PRBS_OID = 0x30;
|
||||
static const uint8_t TEST_ANTENNA_OID = 0x3D;
|
||||
static const uint8_t TEST_GET_REGISTER_OID = 0x33;
|
||||
static constexpr uint8_t XCHG_DATA_OID = 0x10;
|
||||
static constexpr uint8_t MF_SECTORSEL_OID = 0x32;
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_OID = 0x40;
|
||||
static constexpr uint8_t TEST_PRBS_OID = 0x30;
|
||||
static constexpr uint8_t TEST_ANTENNA_OID = 0x3D;
|
||||
static constexpr uint8_t TEST_GET_REGISTER_OID = 0x33;
|
||||
|
||||
static const uint8_t MFC_AUTHENTICATE_PARAM_KS_A = 0x00; // key select A
|
||||
static const uint8_t MFC_AUTHENTICATE_PARAM_KS_B = 0x80; // key select B
|
||||
static const uint8_t MFC_AUTHENTICATE_PARAM_EMBED_KEY = 0x10;
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_PARAM_KS_A = 0x00; // key select A
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_PARAM_KS_B = 0x80; // key select B
|
||||
static constexpr uint8_t MFC_AUTHENTICATE_PARAM_EMBED_KEY = 0x10;
|
||||
|
||||
static const uint8_t CARD_EMU_T4T_APP_SELECT[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76,
|
||||
0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
|
||||
static const uint8_t CARD_EMU_T4T_CC[] = {0x00, 0x0F, 0x20, 0x00, 0xFF, 0x00, 0xFF, 0x04,
|
||||
0x06, 0xE1, 0x04, 0x00, 0xFF, 0x00, 0x00};
|
||||
static const uint8_t CARD_EMU_T4T_CC_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x03};
|
||||
static const uint8_t CARD_EMU_T4T_NDEF_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x04};
|
||||
static const uint8_t CARD_EMU_T4T_READ[] = {0x00, 0xB0};
|
||||
static const uint8_t CARD_EMU_T4T_WRITE[] = {0x00, 0xD6};
|
||||
static const uint8_t CARD_EMU_T4T_OK[] = {0x90, 0x00};
|
||||
static const uint8_t CARD_EMU_T4T_NOK[] = {0x6A, 0x82};
|
||||
static constexpr uint8_t CARD_EMU_T4T_APP_SELECT[] = {0x00, 0xA4, 0x04, 0x00, 0x07, 0xD2, 0x76,
|
||||
0x00, 0x00, 0x85, 0x01, 0x01, 0x00};
|
||||
static constexpr uint8_t CARD_EMU_T4T_CC[] = {0x00, 0x0F, 0x20, 0x00, 0xFF, 0x00, 0xFF, 0x04,
|
||||
0x06, 0xE1, 0x04, 0x00, 0xFF, 0x00, 0x00};
|
||||
static constexpr uint8_t CARD_EMU_T4T_CC_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x03};
|
||||
static constexpr uint8_t CARD_EMU_T4T_NDEF_SELECT[] = {0x00, 0xA4, 0x00, 0x0C, 0x02, 0xE1, 0x04};
|
||||
static constexpr uint8_t CARD_EMU_T4T_READ[] = {0x00, 0xB0};
|
||||
static constexpr uint8_t CARD_EMU_T4T_WRITE[] = {0x00, 0xD6};
|
||||
static constexpr uint8_t CARD_EMU_T4T_OK[] = {0x90, 0x00};
|
||||
static constexpr uint8_t CARD_EMU_T4T_NOK[] = {0x6A, 0x82};
|
||||
|
||||
static const uint8_t CORE_CONFIG_SOLO[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0x01, // TOTAL_DURATION (low)...
|
||||
0x00}; // TOTAL_DURATION (high): 1 ms
|
||||
static constexpr uint8_t CORE_CONFIG_SOLO[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0x01, // TOTAL_DURATION (low)...
|
||||
0x00}; // TOTAL_DURATION (high): 1 ms
|
||||
|
||||
static const uint8_t CORE_CONFIG_RW_CE[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0xF8, // TOTAL_DURATION (low)...
|
||||
0x02}; // TOTAL_DURATION (high): 760 ms
|
||||
static constexpr uint8_t CORE_CONFIG_RW_CE[] = {0x01, // Number of parameter fields
|
||||
0x00, // config param identifier (TOTAL_DURATION)
|
||||
0x02, // length of value
|
||||
0xF8, // TOTAL_DURATION (low)...
|
||||
0x02}; // TOTAL_DURATION (high): 760 ms
|
||||
|
||||
static const uint8_t PMU_CFG[] = {
|
||||
static constexpr uint8_t PMU_CFG[] = {
|
||||
0x01, // Number of parameters
|
||||
0xA0, 0x0E, // ext. tag
|
||||
11, // length
|
||||
@@ -74,7 +74,7 @@ static const uint8_t PMU_CFG[] = {
|
||||
0x0C, // RFU
|
||||
};
|
||||
|
||||
static const uint8_t RF_DISCOVER_MAP_CONFIG[] = { // poll modes
|
||||
static constexpr uint8_t RF_DISCOVER_MAP_CONFIG[] = { // poll modes
|
||||
nfc::PROT_T1T, nfc::RF_DISCOVER_MAP_MODE_POLL,
|
||||
nfc::INTF_FRAME, // poll mode
|
||||
nfc::PROT_T2T, nfc::RF_DISCOVER_MAP_MODE_POLL,
|
||||
@@ -86,33 +86,34 @@ static const uint8_t RF_DISCOVER_MAP_CONFIG[] = { // poll modes
|
||||
nfc::PROT_MIFARE, nfc::RF_DISCOVER_MAP_MODE_POLL,
|
||||
nfc::INTF_TAGCMD}; // poll mode
|
||||
|
||||
static const uint8_t RF_DISCOVERY_LISTEN_CONFIG[] = {nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
static constexpr uint8_t RF_DISCOVERY_LISTEN_CONFIG[] = {
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
|
||||
static const uint8_t RF_DISCOVERY_POLL_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF}; // poll mode
|
||||
static constexpr uint8_t RF_DISCOVERY_POLL_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF}; // poll mode
|
||||
|
||||
static const uint8_t RF_DISCOVERY_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF, // poll mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
static constexpr uint8_t RF_DISCOVERY_CONFIG[] = {nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCA, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCB, // poll mode
|
||||
nfc::MODE_POLL | nfc::TECH_PASSIVE_NFCF, // poll mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCA, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCB, // listen mode
|
||||
nfc::MODE_LISTEN_MASK | nfc::TECH_PASSIVE_NFCF}; // listen mode
|
||||
|
||||
static const uint8_t RF_LISTEN_MODE_ROUTING_CONFIG[] = {0x00, // "more" (another message is coming)
|
||||
2, // number of table entries
|
||||
0x01, // type = protocol-based
|
||||
3, // length
|
||||
0, // DH NFCEE ID, a static ID representing the DH-NFCEE
|
||||
0x07, // power state
|
||||
nfc::PROT_ISODEP, // protocol
|
||||
0x00, // type = technology-based
|
||||
3, // length
|
||||
0, // DH NFCEE ID, a static ID representing the DH-NFCEE
|
||||
0x07, // power state
|
||||
nfc::TECH_PASSIVE_NFCA}; // technology
|
||||
static constexpr uint8_t RF_LISTEN_MODE_ROUTING_CONFIG[] = {0x00, // "more" (another message is coming)
|
||||
2, // number of table entries
|
||||
0x01, // type = protocol-based
|
||||
3, // length
|
||||
0, // DH NFCEE ID, a static ID representing the DH-NFCEE
|
||||
0x07, // power state
|
||||
nfc::PROT_ISODEP, // protocol
|
||||
0x00, // type = technology-based
|
||||
3, // length
|
||||
0, // DH NFCEE ID, a static ID representing the DH-NFCEE
|
||||
0x07, // power state
|
||||
nfc::TECH_PASSIVE_NFCA}; // technology
|
||||
|
||||
enum class CardEmulationState : uint8_t {
|
||||
CARD_EMU_IDLE,
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
namespace esphome {
|
||||
namespace pn7160_spi {
|
||||
|
||||
static const uint8_t TDD_SPI_READ = 0xFF;
|
||||
static const uint8_t TDD_SPI_WRITE = 0x0A;
|
||||
static constexpr uint8_t TDD_SPI_READ = 0xFF;
|
||||
static constexpr uint8_t TDD_SPI_WRITE = 0x0A;
|
||||
|
||||
class PN7160Spi : public pn7160::PN7160,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef HAS_PCNT
|
||||
#include <esp_clk_tree.h>
|
||||
#include <esp_private/esp_clk.h>
|
||||
#include <hal/pcnt_ll.h>
|
||||
#endif
|
||||
|
||||
@@ -117,9 +117,7 @@ bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
|
||||
}
|
||||
|
||||
if (this->filter_us != 0) {
|
||||
uint32_t apb_freq;
|
||||
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_APB, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &apb_freq);
|
||||
uint32_t max_glitch_ns = PCNT_LL_MAX_GLITCH_WIDTH * 1000000u / apb_freq;
|
||||
uint32_t max_glitch_ns = PCNT_LL_MAX_GLITCH_WIDTH * 1000000u / (uint32_t) esp_clk_apb_freq();
|
||||
pcnt_glitch_filter_config_t filter_config = {
|
||||
.max_glitch_ns = std::min(this->filter_us * 1000u, max_glitch_ns),
|
||||
};
|
||||
|
||||
@@ -6,10 +6,10 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.abbwelcome";
|
||||
|
||||
static const uint32_t BIT_ONE_SPACE_US = 102;
|
||||
static const uint32_t BIT_ZERO_MARK_US = 32; // 18-44
|
||||
static const uint32_t BIT_ZERO_SPACE_US = BIT_ONE_SPACE_US - BIT_ZERO_MARK_US;
|
||||
static const uint16_t BYTE_SPACE_US = 210;
|
||||
static constexpr uint32_t BIT_ONE_SPACE_US = 102;
|
||||
static constexpr uint32_t BIT_ZERO_MARK_US = 32; // 18-44
|
||||
static constexpr uint32_t BIT_ZERO_SPACE_US = BIT_ONE_SPACE_US - BIT_ZERO_MARK_US;
|
||||
static constexpr uint16_t BYTE_SPACE_US = 210;
|
||||
|
||||
uint8_t ABBWelcomeData::calc_cs_() const {
|
||||
uint8_t checksum = 0;
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
static const uint8_t MAX_DATA_LENGTH = 15;
|
||||
static const uint8_t DATA_LENGTH_MASK = 0x3f;
|
||||
static constexpr uint8_t MAX_DATA_LENGTH = 15;
|
||||
static constexpr uint8_t DATA_LENGTH_MASK = 0x3f;
|
||||
|
||||
/*
|
||||
Message Format:
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.aeha";
|
||||
|
||||
static const uint16_t BITWISE = 425;
|
||||
static const uint16_t HEADER_HIGH_US = BITWISE * 8;
|
||||
static const uint16_t HEADER_LOW_US = BITWISE * 4;
|
||||
static const uint16_t BIT_HIGH_US = BITWISE;
|
||||
static const uint16_t BIT_ONE_LOW_US = BITWISE * 3;
|
||||
static const uint16_t BIT_ZERO_LOW_US = BITWISE;
|
||||
static const uint16_t TRAILER = BITWISE;
|
||||
static constexpr uint16_t BITWISE = 425;
|
||||
static constexpr uint16_t HEADER_HIGH_US = BITWISE * 8;
|
||||
static constexpr uint16_t HEADER_LOW_US = BITWISE * 4;
|
||||
static constexpr uint16_t BIT_HIGH_US = BITWISE;
|
||||
static constexpr uint16_t BIT_ONE_LOW_US = BITWISE * 3;
|
||||
static constexpr uint16_t BIT_ZERO_LOW_US = BITWISE;
|
||||
static constexpr uint16_t TRAILER = BITWISE;
|
||||
|
||||
void AEHAProtocol::encode(RemoteTransmitData *dst, const AEHAData &data) {
|
||||
dst->reserve(2 + 32 + (data.data.size() * 2) + 1);
|
||||
|
||||
@@ -8,11 +8,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.byronsx";
|
||||
|
||||
static const uint32_t BIT_TIME_US = 333;
|
||||
static const uint8_t NBITS_ADDRESS = 8;
|
||||
static const uint8_t NBITS_COMMAND = 4;
|
||||
static const uint8_t NBITS_START_BIT = 1;
|
||||
static const uint8_t NBITS_DATA = NBITS_ADDRESS + NBITS_COMMAND /*+ NBITS_COMMAND*/;
|
||||
static constexpr uint32_t BIT_TIME_US = 333;
|
||||
static constexpr uint8_t NBITS_ADDRESS = 8;
|
||||
static constexpr uint8_t NBITS_COMMAND = 4;
|
||||
static constexpr uint8_t NBITS_START_BIT = 1;
|
||||
static constexpr uint8_t NBITS_DATA = NBITS_ADDRESS + NBITS_COMMAND /*+ NBITS_COMMAND*/;
|
||||
|
||||
/*
|
||||
ByronSX Protocol
|
||||
|
||||
@@ -7,10 +7,10 @@ namespace remote_base {
|
||||
static const char *const CANALSAT_TAG = "remote.canalsat";
|
||||
static const char *const CANALSATLD_TAG = "remote.canalsatld";
|
||||
|
||||
static const uint16_t CANALSAT_FREQ = 55500;
|
||||
static const uint16_t CANALSATLD_FREQ = 56000;
|
||||
static const uint16_t CANALSAT_UNIT = 250;
|
||||
static const uint16_t CANALSATLD_UNIT = 320;
|
||||
static constexpr uint16_t CANALSAT_FREQ = 55500;
|
||||
static constexpr uint16_t CANALSATLD_FREQ = 56000;
|
||||
static constexpr uint16_t CANALSAT_UNIT = 250;
|
||||
static constexpr uint16_t CANALSATLD_UNIT = 320;
|
||||
|
||||
CanalSatProtocol::CanalSatProtocol() {
|
||||
this->frequency_ = CANALSAT_FREQ;
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.dish";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 400;
|
||||
static const uint32_t HEADER_LOW_US = 6100;
|
||||
static const uint32_t BIT_HIGH_US = 400;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1700;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 2800;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 400;
|
||||
static constexpr uint32_t HEADER_LOW_US = 6100;
|
||||
static constexpr uint32_t BIT_HIGH_US = 400;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1700;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 2800;
|
||||
|
||||
void DishProtocol::encode(RemoteTransmitData *dst, const DishData &data) {
|
||||
dst->reserve(138);
|
||||
|
||||
@@ -6,12 +6,12 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.dooya";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 5000;
|
||||
static const uint32_t HEADER_LOW_US = 1500;
|
||||
static const uint32_t BIT_ZERO_HIGH_US = 350;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 750;
|
||||
static const uint32_t BIT_ONE_HIGH_US = 750;
|
||||
static const uint32_t BIT_ONE_LOW_US = 350;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 5000;
|
||||
static constexpr uint32_t HEADER_LOW_US = 1500;
|
||||
static constexpr uint32_t BIT_ZERO_HIGH_US = 350;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 750;
|
||||
static constexpr uint32_t BIT_ONE_HIGH_US = 750;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 350;
|
||||
|
||||
void DooyaProtocol::encode(RemoteTransmitData *dst, const DooyaData &data) {
|
||||
dst->set_carrier_frequency(0);
|
||||
|
||||
@@ -8,18 +8,18 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.drayton";
|
||||
|
||||
static const uint32_t BIT_TIME_US = 500;
|
||||
static const uint8_t CARRIER_KHZ = 2;
|
||||
static const uint8_t NBITS_PREAMBLE = 12;
|
||||
static const uint8_t NBITS_SYNC = 4;
|
||||
static const uint8_t NBITS_ADDRESS = 16;
|
||||
static const uint8_t NBITS_CHANNEL = 5;
|
||||
static const uint8_t NBITS_COMMAND = 7;
|
||||
static const uint8_t NDATABITS = NBITS_ADDRESS + NBITS_CHANNEL + NBITS_COMMAND;
|
||||
static const uint8_t MIN_RX_SRC = (NDATABITS + NBITS_SYNC / 2);
|
||||
static constexpr uint32_t BIT_TIME_US = 500;
|
||||
static constexpr uint8_t CARRIER_KHZ = 2;
|
||||
static constexpr uint8_t NBITS_PREAMBLE = 12;
|
||||
static constexpr uint8_t NBITS_SYNC = 4;
|
||||
static constexpr uint8_t NBITS_ADDRESS = 16;
|
||||
static constexpr uint8_t NBITS_CHANNEL = 5;
|
||||
static constexpr uint8_t NBITS_COMMAND = 7;
|
||||
static constexpr uint8_t NDATABITS = NBITS_ADDRESS + NBITS_CHANNEL + NBITS_COMMAND;
|
||||
static constexpr uint8_t MIN_RX_SRC = (NDATABITS + NBITS_SYNC / 2);
|
||||
|
||||
static const uint8_t CMD_ON = 0x41;
|
||||
static const uint8_t CMD_OFF = 0x02;
|
||||
static constexpr uint8_t CMD_ON = 0x41;
|
||||
static constexpr uint8_t CMD_OFF = 0x02;
|
||||
|
||||
/*
|
||||
Drayton Protocol
|
||||
|
||||
@@ -6,12 +6,12 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.jvc";
|
||||
|
||||
static const uint8_t NBITS = 16;
|
||||
static const uint32_t HEADER_HIGH_US = 8400;
|
||||
static const uint32_t HEADER_LOW_US = 4200;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1725;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 525;
|
||||
static const uint32_t BIT_HIGH_US = 525;
|
||||
static constexpr uint8_t NBITS = 16;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 8400;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4200;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1725;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 525;
|
||||
static constexpr uint32_t BIT_HIGH_US = 525;
|
||||
|
||||
void JVCProtocol::encode(RemoteTransmitData *dst, const JVCData &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
@@ -8,18 +8,18 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.keeloq";
|
||||
|
||||
static const uint32_t BIT_TIME_US = 380;
|
||||
static const uint8_t NBITS_PREAMBLE = 12;
|
||||
static const uint8_t NBITS_REPEAT = 1;
|
||||
static const uint8_t NBITS_VLOW = 1;
|
||||
static const uint8_t NBITS_SERIAL = 28;
|
||||
static const uint8_t NBITS_BUTTONS = 4;
|
||||
static const uint8_t NBITS_DISC = 12;
|
||||
static const uint8_t NBITS_SYNC_CNT = 16;
|
||||
static constexpr uint32_t BIT_TIME_US = 380;
|
||||
static constexpr uint8_t NBITS_PREAMBLE = 12;
|
||||
static constexpr uint8_t NBITS_REPEAT = 1;
|
||||
static constexpr uint8_t NBITS_VLOW = 1;
|
||||
static constexpr uint8_t NBITS_SERIAL = 28;
|
||||
static constexpr uint8_t NBITS_BUTTONS = 4;
|
||||
static constexpr uint8_t NBITS_DISC = 12;
|
||||
static constexpr uint8_t NBITS_SYNC_CNT = 16;
|
||||
|
||||
static const uint8_t NBITS_FIXED_DATA = NBITS_REPEAT + NBITS_VLOW + NBITS_BUTTONS + NBITS_SERIAL;
|
||||
static const uint8_t NBITS_ENCRYPTED_DATA = NBITS_BUTTONS + NBITS_DISC + NBITS_SYNC_CNT;
|
||||
static const uint8_t NBITS_DATA = NBITS_FIXED_DATA + NBITS_ENCRYPTED_DATA;
|
||||
static constexpr uint8_t NBITS_FIXED_DATA = NBITS_REPEAT + NBITS_VLOW + NBITS_BUTTONS + NBITS_SERIAL;
|
||||
static constexpr uint8_t NBITS_ENCRYPTED_DATA = NBITS_BUTTONS + NBITS_DISC + NBITS_SYNC_CNT;
|
||||
static constexpr uint8_t NBITS_DATA = NBITS_FIXED_DATA + NBITS_ENCRYPTED_DATA;
|
||||
|
||||
/*
|
||||
KeeLoq Protocol
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.lg";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 8000;
|
||||
static const uint32_t HEADER_LOW_US = 4000;
|
||||
static const uint32_t BIT_HIGH_US = 600;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1600;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 550;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 8000;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4000;
|
||||
static constexpr uint32_t BIT_HIGH_US = 600;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1600;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 550;
|
||||
|
||||
void LGProtocol::encode(RemoteTransmitData *dst, const LGData &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
@@ -10,11 +10,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.magiquest";
|
||||
|
||||
static const uint32_t MAGIQUEST_UNIT = 288; // us
|
||||
static const uint32_t MAGIQUEST_ONE_MARK = 2 * MAGIQUEST_UNIT;
|
||||
static const uint32_t MAGIQUEST_ONE_SPACE = 2 * MAGIQUEST_UNIT;
|
||||
static const uint32_t MAGIQUEST_ZERO_MARK = MAGIQUEST_UNIT;
|
||||
static const uint32_t MAGIQUEST_ZERO_SPACE = 3 * MAGIQUEST_UNIT;
|
||||
static constexpr uint32_t MAGIQUEST_UNIT = 288; // us
|
||||
static constexpr uint32_t MAGIQUEST_ONE_MARK = 2 * MAGIQUEST_UNIT;
|
||||
static constexpr uint32_t MAGIQUEST_ONE_SPACE = 2 * MAGIQUEST_UNIT;
|
||||
static constexpr uint32_t MAGIQUEST_ZERO_MARK = MAGIQUEST_UNIT;
|
||||
static constexpr uint32_t MAGIQUEST_ZERO_SPACE = 3 * MAGIQUEST_UNIT;
|
||||
|
||||
void MagiQuestProtocol::encode(RemoteTransmitData *dst, const MagiQuestData &data) {
|
||||
dst->reserve(101); // 2 start bits, 48 data bits, 1 stop bit
|
||||
|
||||
@@ -62,7 +62,7 @@ class MideaData {
|
||||
this->data_[idx] |= (value << shift);
|
||||
}
|
||||
void set_mask_(uint8_t idx, bool state, uint8_t mask = 255) { this->set_value_(idx, state ? mask : 0, mask); }
|
||||
static const uint8_t OFFSET_CS = 5;
|
||||
static constexpr uint8_t OFFSET_CS = 5;
|
||||
// 48-bits data
|
||||
std::array<uint8_t, 6> data_;
|
||||
// Calculate checksum
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.nec";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 9000;
|
||||
static const uint32_t HEADER_LOW_US = 4500;
|
||||
static const uint32_t BIT_HIGH_US = 560;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 9000;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4500;
|
||||
static constexpr uint32_t BIT_HIGH_US = 560;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 560;
|
||||
|
||||
void NECProtocol::encode(RemoteTransmitData *dst, const NECData &data) {
|
||||
ESP_LOGD(TAG, "Sending NEC: address=0x%04X, command=0x%04X command_repeats=%d", data.address, data.command,
|
||||
|
||||
@@ -6,18 +6,18 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.nexa";
|
||||
|
||||
static const uint8_t NBITS = 32;
|
||||
static const uint32_t HEADER_HIGH_US = 319;
|
||||
static const uint32_t HEADER_LOW_US = 2610;
|
||||
static const uint32_t BIT_HIGH_US = 319;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1000;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 140;
|
||||
static constexpr uint8_t NBITS = 32;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 319;
|
||||
static constexpr uint32_t HEADER_LOW_US = 2610;
|
||||
static constexpr uint32_t BIT_HIGH_US = 319;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1000;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 140;
|
||||
|
||||
static const uint32_t TX_HEADER_HIGH_US = 250;
|
||||
static const uint32_t TX_HEADER_LOW_US = TX_HEADER_HIGH_US * 10;
|
||||
static const uint32_t TX_BIT_HIGH_US = 250;
|
||||
static const uint32_t TX_BIT_ONE_LOW_US = TX_BIT_HIGH_US * 5;
|
||||
static const uint32_t TX_BIT_ZERO_LOW_US = TX_BIT_HIGH_US * 1;
|
||||
static constexpr uint32_t TX_HEADER_HIGH_US = 250;
|
||||
static constexpr uint32_t TX_HEADER_LOW_US = TX_HEADER_HIGH_US * 10;
|
||||
static constexpr uint32_t TX_BIT_HIGH_US = 250;
|
||||
static constexpr uint32_t TX_BIT_ONE_LOW_US = TX_BIT_HIGH_US * 5;
|
||||
static constexpr uint32_t TX_BIT_ZERO_LOW_US = TX_BIT_HIGH_US * 1;
|
||||
|
||||
void NexaProtocol::one(RemoteTransmitData *dst) const {
|
||||
// '1' => '10'
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.panasonic";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 3502;
|
||||
static const uint32_t HEADER_LOW_US = 1750;
|
||||
static const uint32_t BIT_HIGH_US = 502;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 400;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1244;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 3502;
|
||||
static constexpr uint32_t HEADER_LOW_US = 1750;
|
||||
static constexpr uint32_t BIT_HIGH_US = 502;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 400;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1244;
|
||||
|
||||
void PanasonicProtocol::encode(RemoteTransmitData *dst, const PanasonicData &data) {
|
||||
dst->reserve(100);
|
||||
|
||||
@@ -6,12 +6,12 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.pioneer";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 9000;
|
||||
static const uint32_t HEADER_LOW_US = 4500;
|
||||
static const uint32_t BIT_HIGH_US = 560;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static const uint32_t TRAILER_SPACE_US = 25500;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 9000;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4500;
|
||||
static constexpr uint32_t BIT_HIGH_US = 560;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static constexpr uint32_t TRAILER_SPACE_US = 25500;
|
||||
|
||||
void PioneerProtocol::encode(RemoteTransmitData *dst, const PioneerData &data) {
|
||||
uint32_t address1 = ((data.rc_code_1 & 0xff00) | (~(data.rc_code_1 >> 8) & 0xff));
|
||||
|
||||
@@ -59,18 +59,18 @@ bool ProntoData::operator==(const ProntoData &rhs) const {
|
||||
}
|
||||
|
||||
// DO NOT EXPORT from this file
|
||||
static const uint16_t MICROSECONDS_T_MAX = 0xFFFFU;
|
||||
static const uint16_t LEARNED_TOKEN = 0x0000U;
|
||||
static const uint16_t LEARNED_NON_MODULATED_TOKEN = 0x0100U;
|
||||
static const uint16_t BITS_IN_HEXADECIMAL = 4U;
|
||||
static const uint16_t DIGITS_IN_PRONTO_NUMBER = 4U;
|
||||
static const uint16_t NUMBERS_IN_PREAMBLE = 4U;
|
||||
static const uint16_t HEX_MASK = 0xFU;
|
||||
static const uint32_t REFERENCE_FREQUENCY = 4145146UL;
|
||||
static const uint16_t FALLBACK_FREQUENCY = 64767U; // To use with frequency = 0;
|
||||
static const uint32_t MICROSECONDS_IN_SECONDS = 1000000UL;
|
||||
static const uint16_t PRONTO_DEFAULT_GAP = 45000;
|
||||
static const uint16_t MARK_EXCESS_MICROS = 20;
|
||||
static constexpr uint16_t MICROSECONDS_T_MAX = 0xFFFFU;
|
||||
static constexpr uint16_t LEARNED_TOKEN = 0x0000U;
|
||||
static constexpr uint16_t LEARNED_NON_MODULATED_TOKEN = 0x0100U;
|
||||
static constexpr uint16_t BITS_IN_HEXADECIMAL = 4U;
|
||||
static constexpr uint16_t DIGITS_IN_PRONTO_NUMBER = 4U;
|
||||
static constexpr uint16_t NUMBERS_IN_PREAMBLE = 4U;
|
||||
static constexpr uint16_t HEX_MASK = 0xFU;
|
||||
static constexpr uint32_t REFERENCE_FREQUENCY = 4145146UL;
|
||||
static constexpr uint16_t FALLBACK_FREQUENCY = 64767U; // To use with frequency = 0;
|
||||
static constexpr uint32_t MICROSECONDS_IN_SECONDS = 1000000UL;
|
||||
static constexpr uint16_t PRONTO_DEFAULT_GAP = 45000;
|
||||
static constexpr uint16_t MARK_EXCESS_MICROS = 20;
|
||||
static constexpr size_t PRONTO_LOG_CHUNK_SIZE = 230;
|
||||
|
||||
static uint16_t to_frequency_k_hz(uint16_t code) {
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.rc5";
|
||||
|
||||
static const uint32_t BIT_TIME_US = 889;
|
||||
static const uint8_t NBITS = 14;
|
||||
static constexpr uint32_t BIT_TIME_US = 889;
|
||||
static constexpr uint8_t NBITS = 14;
|
||||
|
||||
void RC5Protocol::encode(RemoteTransmitData *dst, const RC5Data &data) {
|
||||
static bool toggle = false;
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const RC6_TAG = "remote.rc6";
|
||||
|
||||
static const uint16_t RC6_FREQ = 36000;
|
||||
static const uint16_t RC6_UNIT = 444;
|
||||
static const uint16_t RC6_HEADER_MARK = (6 * RC6_UNIT);
|
||||
static const uint16_t RC6_HEADER_SPACE = (2 * RC6_UNIT);
|
||||
static const uint16_t RC6_MODE_MASK = 0x07;
|
||||
static constexpr uint16_t RC6_FREQ = 36000;
|
||||
static constexpr uint16_t RC6_UNIT = 444;
|
||||
static constexpr uint16_t RC6_HEADER_MARK = (6 * RC6_UNIT);
|
||||
static constexpr uint16_t RC6_HEADER_SPACE = (2 * RC6_UNIT);
|
||||
static constexpr uint16_t RC6_MODE_MASK = 0x07;
|
||||
|
||||
void RC6Protocol::encode(RemoteTransmitData *dst, const RC6Data &data) {
|
||||
dst->reserve(44);
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.roomba";
|
||||
|
||||
static const uint8_t NBITS = 8;
|
||||
static const uint32_t BIT_ONE_HIGH_US = 3000;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1000;
|
||||
static const uint32_t BIT_ZERO_HIGH_US = BIT_ONE_LOW_US;
|
||||
static const uint32_t BIT_ZERO_LOW_US = BIT_ONE_HIGH_US;
|
||||
static constexpr uint8_t NBITS = 8;
|
||||
static constexpr uint32_t BIT_ONE_HIGH_US = 3000;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1000;
|
||||
static constexpr uint32_t BIT_ZERO_HIGH_US = BIT_ONE_LOW_US;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = BIT_ONE_HIGH_US;
|
||||
|
||||
void RoombaProtocol::encode(RemoteTransmitData *dst, const RoombaData &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
@@ -6,17 +6,17 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.samsung36";
|
||||
|
||||
static const uint8_t NBITS = 78;
|
||||
static constexpr uint8_t NBITS = 78;
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 4500;
|
||||
static const uint32_t HEADER_LOW_US = 4500;
|
||||
static const uint32_t BIT_HIGH_US = 500;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1500;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 500;
|
||||
static const uint32_t MIDDLE_HIGH_US = 500;
|
||||
static const uint32_t MIDDLE_LOW_US = 4500;
|
||||
static const uint32_t FOOTER_HIGH_US = 500;
|
||||
static const uint32_t FOOTER_LOW_US = 59000;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 4500;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4500;
|
||||
static constexpr uint32_t BIT_HIGH_US = 500;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1500;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 500;
|
||||
static constexpr uint32_t MIDDLE_HIGH_US = 500;
|
||||
static constexpr uint32_t MIDDLE_LOW_US = 4500;
|
||||
static constexpr uint32_t FOOTER_HIGH_US = 500;
|
||||
static constexpr uint32_t FOOTER_LOW_US = 59000;
|
||||
|
||||
void Samsung36Protocol::encode(RemoteTransmitData *dst, const Samsung36Data &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.samsung";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 4500;
|
||||
static const uint32_t HEADER_LOW_US = 4500;
|
||||
static const uint32_t BIT_HIGH_US = 560;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static const uint32_t FOOTER_HIGH_US = 560;
|
||||
static const uint32_t FOOTER_LOW_US = 560;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 4500;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4500;
|
||||
static constexpr uint32_t BIT_HIGH_US = 560;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static constexpr uint32_t FOOTER_HIGH_US = 560;
|
||||
static constexpr uint32_t FOOTER_LOW_US = 560;
|
||||
|
||||
void SamsungProtocol::encode(RemoteTransmitData *dst, const SamsungData &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.sony";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 2400;
|
||||
static const uint32_t HEADER_LOW_US = 600;
|
||||
static const uint32_t BIT_ONE_HIGH_US = 1200;
|
||||
static const uint32_t BIT_ZERO_HIGH_US = 600;
|
||||
static const uint32_t BIT_LOW_US = 600;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 2400;
|
||||
static constexpr uint32_t HEADER_LOW_US = 600;
|
||||
static constexpr uint32_t BIT_ONE_HIGH_US = 1200;
|
||||
static constexpr uint32_t BIT_ZERO_HIGH_US = 600;
|
||||
static constexpr uint32_t BIT_LOW_US = 600;
|
||||
|
||||
void SonyProtocol::encode(RemoteTransmitData *dst, const SonyData &data) {
|
||||
dst->set_carrier_frequency(40000);
|
||||
|
||||
@@ -13,16 +13,16 @@ static const char *const TAG = "remote.symphony";
|
||||
// footer-gap handling used there.
|
||||
|
||||
// Symphony protocol timing specifications (tuned to handset captures)
|
||||
static const uint32_t BIT_ZERO_HIGH_US = 460; // short
|
||||
static const uint32_t BIT_ZERO_LOW_US = 1260; // long
|
||||
static const uint32_t BIT_ONE_HIGH_US = 1260; // long
|
||||
static const uint32_t BIT_ONE_LOW_US = 460; // short
|
||||
static const uint32_t CARRIER_FREQUENCY = 38000;
|
||||
static constexpr uint32_t BIT_ZERO_HIGH_US = 460; // short
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 1260; // long
|
||||
static constexpr uint32_t BIT_ONE_HIGH_US = 1260; // long
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 460; // short
|
||||
static constexpr uint32_t CARRIER_FREQUENCY = 38000;
|
||||
|
||||
// IRremoteESP8266 reference: kSymphonyFooterGap = 4 * (mark + space)
|
||||
static const uint32_t FOOTER_GAP_US = 4 * (BIT_ZERO_HIGH_US + BIT_ZERO_LOW_US);
|
||||
static constexpr uint32_t FOOTER_GAP_US = 4 * (BIT_ZERO_HIGH_US + BIT_ZERO_LOW_US);
|
||||
// Typical inter-frame gap (~34.8 ms observed)
|
||||
static const uint32_t INTER_FRAME_GAP_US = 34760;
|
||||
static constexpr uint32_t INTER_FRAME_GAP_US = 34760;
|
||||
|
||||
void SymphonyProtocol::encode(RemoteTransmitData *dst, const SymphonyData &data) {
|
||||
dst->set_carrier_frequency(CARRIER_FREQUENCY);
|
||||
|
||||
@@ -7,14 +7,14 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.toshibaac";
|
||||
|
||||
static const uint32_t HEADER_HIGH_US = 4500;
|
||||
static const uint32_t HEADER_LOW_US = 4500;
|
||||
static const uint32_t BIT_HIGH_US = 560;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static const uint32_t FOOTER_HIGH_US = 560;
|
||||
static const uint32_t FOOTER_LOW_US = 4500;
|
||||
static const uint16_t PACKET_SPACE = 5500;
|
||||
static constexpr uint32_t HEADER_HIGH_US = 4500;
|
||||
static constexpr uint32_t HEADER_LOW_US = 4500;
|
||||
static constexpr uint32_t BIT_HIGH_US = 560;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1690;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 560;
|
||||
static constexpr uint32_t FOOTER_HIGH_US = 560;
|
||||
static constexpr uint32_t FOOTER_LOW_US = 4500;
|
||||
static constexpr uint16_t PACKET_SPACE = 5500;
|
||||
|
||||
void ToshibaAcProtocol::encode(RemoteTransmitData *dst, const ToshibaAcData &data) {
|
||||
dst->set_carrier_frequency(38000);
|
||||
|
||||
@@ -6,12 +6,12 @@ namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.toto";
|
||||
|
||||
static const uint32_t PREAMBLE_HIGH_US = 6200;
|
||||
static const uint32_t PREAMBLE_LOW_US = 2800;
|
||||
static const uint32_t BIT_HIGH_US = 550;
|
||||
static const uint32_t BIT_ONE_LOW_US = 1700;
|
||||
static const uint32_t BIT_ZERO_LOW_US = 550;
|
||||
static const uint32_t TOTO_HEADER = 0x2008;
|
||||
static constexpr uint32_t PREAMBLE_HIGH_US = 6200;
|
||||
static constexpr uint32_t PREAMBLE_LOW_US = 2800;
|
||||
static constexpr uint32_t BIT_HIGH_US = 550;
|
||||
static constexpr uint32_t BIT_ONE_LOW_US = 1700;
|
||||
static constexpr uint32_t BIT_ZERO_LOW_US = 550;
|
||||
static constexpr uint32_t TOTO_HEADER = 0x2008;
|
||||
|
||||
void TotoProtocol::encode(RemoteTransmitData *dst, const TotoData &data) {
|
||||
uint32_t payload = 0;
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
void IRAM_ATTR HOT yield() { ::yield(); }
|
||||
void HOT yield() { ::yield(); }
|
||||
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
|
||||
void IRAM_ATTR HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
void HOT delay(uint32_t ms) { ::delay(ms); }
|
||||
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
|
||||
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); }
|
||||
void arch_restart() {
|
||||
@@ -27,7 +27,7 @@ void arch_init() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void IRAM_ATTR HOT arch_feed_wdt() { watchdog_update(); }
|
||||
void HOT arch_feed_wdt() { watchdog_update(); }
|
||||
|
||||
uint8_t progmem_read_byte(const uint8_t *addr) {
|
||||
return pgm_read_byte(addr); // NOLINT
|
||||
|
||||
@@ -680,6 +680,11 @@ class LWIPRawListenImpl final : public LWIPRawImpl {
|
||||
};
|
||||
|
||||
std::unique_ptr<Socket> socket(int domain, int type, int protocol) {
|
||||
if (type != SOCK_STREAM) {
|
||||
ESP_LOGE(TAG, "UDP sockets not supported on this platform, use WiFiUDP");
|
||||
errno = EPROTOTYPE;
|
||||
return nullptr;
|
||||
}
|
||||
auto *pcb = tcp_new();
|
||||
if (pcb == nullptr)
|
||||
return nullptr;
|
||||
|
||||
@@ -26,7 +26,6 @@ from esphome.const import (
|
||||
from esphome.core import CORE, HexInt
|
||||
from esphome.core.entity_helpers import inherit_property_from
|
||||
from esphome.external_files import download_content
|
||||
from esphome.final_validate import full_config
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -37,6 +36,10 @@ DEPENDENCIES = ["network"]
|
||||
CODEOWNERS = ["@kahrendt", "@synesthesiam"]
|
||||
DOMAIN = "media_player"
|
||||
|
||||
CODEC_SUPPORT_ALL = "all"
|
||||
CODEC_SUPPORT_NEEDED = "needed"
|
||||
CODEC_SUPPORT_NONE = "none"
|
||||
|
||||
TYPE_LOCAL = "local"
|
||||
TYPE_WEB = "web"
|
||||
|
||||
@@ -110,6 +113,8 @@ def _get_supported_format_struct(pipeline, type):
|
||||
args.append(("format", "flac"))
|
||||
elif pipeline[CONF_FORMAT] == "MP3":
|
||||
args.append(("format", "mp3"))
|
||||
elif pipeline[CONF_FORMAT] == "OPUS":
|
||||
args.append(("format", "opus"))
|
||||
elif pipeline[CONF_FORMAT] == "WAV":
|
||||
args.append(("format", "wav"))
|
||||
|
||||
@@ -173,6 +178,13 @@ def _read_audio_file_and_type(file_config):
|
||||
media_file_type = audio.AUDIO_FILE_TYPE_ENUM["MP3"]
|
||||
elif file_type in ("flac"):
|
||||
media_file_type = audio.AUDIO_FILE_TYPE_ENUM["FLAC"]
|
||||
elif (
|
||||
file_type in ("ogg")
|
||||
and len(data) >= 36
|
||||
and data.startswith(b"OggS")
|
||||
and data[28:36] == b"OpusHead"
|
||||
):
|
||||
media_file_type = audio.AUDIO_FILE_TYPE_ENUM["OPUS"]
|
||||
|
||||
return data, media_file_type
|
||||
|
||||
@@ -199,6 +211,10 @@ def _validate_pipeline(config):
|
||||
inherit_property_from(CONF_NUM_CHANNELS, CONF_SPEAKER)(config)
|
||||
inherit_property_from(CONF_SAMPLE_RATE, CONF_SPEAKER)(config)
|
||||
|
||||
# Opus only supports 48 kHz
|
||||
if config.get(CONF_FORMAT) == "OPUS" and config.get(CONF_SAMPLE_RATE) != 48000:
|
||||
raise cv.Invalid("Opus only supports a sample rate of 48000 Hz")
|
||||
|
||||
# Validate the transcoder settings is compatible with the speaker
|
||||
audio.final_validate_audio_schema(
|
||||
"speaker media_player",
|
||||
@@ -225,12 +241,27 @@ def _validate_repeated_speaker(config):
|
||||
|
||||
|
||||
def _final_validate(config):
|
||||
# Default to using codec if psram is enabled
|
||||
if (use_codec := config.get(CONF_CODEC_SUPPORT_ENABLED)) is None:
|
||||
use_codec = psram.DOMAIN in full_config.get()
|
||||
conf_id = config[CONF_ID].id
|
||||
core_data = CORE.data.setdefault(DOMAIN, {conf_id: {}})
|
||||
core_data[conf_id][CONF_CODEC_SUPPORT_ENABLED] = use_codec
|
||||
# Normalize boolean values to string equivalents
|
||||
codec_mode = config[CONF_CODEC_SUPPORT_ENABLED]
|
||||
if codec_mode is True:
|
||||
codec_mode = CODEC_SUPPORT_ALL
|
||||
elif codec_mode is False:
|
||||
codec_mode = CODEC_SUPPORT_NONE
|
||||
|
||||
use_codec = codec_mode != CODEC_SUPPORT_NONE
|
||||
|
||||
# In "needed" mode, collect formats from pipelines and files
|
||||
needed_formats = set()
|
||||
need_all = False
|
||||
if codec_mode == CODEC_SUPPORT_NEEDED:
|
||||
for pipeline_key in (CONF_ANNOUNCEMENT_PIPELINE, CONF_MEDIA_PIPELINE):
|
||||
if pipeline := config.get(pipeline_key):
|
||||
fmt = pipeline[CONF_FORMAT]
|
||||
if fmt == "NONE":
|
||||
# No preferred format means any format could arrive
|
||||
need_all = True
|
||||
else:
|
||||
needed_formats.add(fmt)
|
||||
|
||||
for file_config in config.get(CONF_FILES, []):
|
||||
_, media_file_type = _read_audio_file_and_type(file_config)
|
||||
@@ -243,6 +274,26 @@ def _final_validate(config):
|
||||
raise cv.Invalid(
|
||||
f"Unsupported local media file type, set {CONF_CODEC_SUPPORT_ENABLED} to true or convert the media file to wav"
|
||||
)
|
||||
# In "needed" mode, add file format to needed codecs
|
||||
if codec_mode == CODEC_SUPPORT_NEEDED:
|
||||
for fmt_name, fmt_enum in audio.AUDIO_FILE_TYPE_ENUM.items():
|
||||
if str(media_file_type) == str(fmt_enum):
|
||||
if fmt_name not in ("WAV", "NONE"):
|
||||
needed_formats.add(fmt_name)
|
||||
break
|
||||
|
||||
# Request codec support
|
||||
if codec_mode == CODEC_SUPPORT_ALL or need_all:
|
||||
audio.request_flac_support()
|
||||
audio.request_mp3_support()
|
||||
audio.request_opus_support()
|
||||
elif codec_mode == CODEC_SUPPORT_NEEDED:
|
||||
if "FLAC" in needed_formats:
|
||||
audio.request_flac_support()
|
||||
if "MP3" in needed_formats:
|
||||
audio.request_mp3_support()
|
||||
if "OPUS" in needed_formats:
|
||||
audio.request_opus_support()
|
||||
|
||||
return config
|
||||
|
||||
@@ -307,7 +358,17 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_BUFFER_SIZE, default=1000000): cv.int_range(
|
||||
min=4000, max=4000000
|
||||
),
|
||||
cv.Optional(CONF_CODEC_SUPPORT_ENABLED): cv.boolean,
|
||||
cv.Optional(
|
||||
CONF_CODEC_SUPPORT_ENABLED, default=CODEC_SUPPORT_NEEDED
|
||||
): cv.Any(
|
||||
cv.boolean,
|
||||
cv.one_of(
|
||||
CODEC_SUPPORT_ALL,
|
||||
CODEC_SUPPORT_NEEDED,
|
||||
CODEC_SUPPORT_NONE,
|
||||
lower=True,
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_FILES): cv.ensure_list(MEDIA_FILE_TYPE_SCHEMA),
|
||||
cv.Optional(CONF_TASK_STACK_IN_PSRAM): cv.All(
|
||||
cv.boolean, cv.requires_component(psram.DOMAIN)
|
||||
@@ -340,11 +401,6 @@ FINAL_VALIDATE_SCHEMA = cv.All(
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
if CORE.data[DOMAIN][config[CONF_ID].id][CONF_CODEC_SUPPORT_ENABLED]:
|
||||
# Compile all supported audio codecs
|
||||
cg.add_define("USE_AUDIO_FLAC_SUPPORT", True)
|
||||
cg.add_define("USE_AUDIO_MP3_SUPPORT", True)
|
||||
|
||||
var = await media_player.new_media_player(config)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
|
||||
@@ -13,7 +13,12 @@ namespace speaker {
|
||||
static const uint32_t INITIAL_BUFFER_MS = 1000; // Start playback after buffering this duration of the file
|
||||
|
||||
static const uint32_t READ_TASK_STACK_SIZE = 5 * 1024;
|
||||
// Opus decoding uses more stack than other codecs
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
static const uint32_t DECODE_TASK_STACK_SIZE = 5 * 1024;
|
||||
#else
|
||||
static const uint32_t DECODE_TASK_STACK_SIZE = 3 * 1024;
|
||||
#endif
|
||||
|
||||
static const uint32_t INFO_ERROR_QUEUE_COUNT = 5;
|
||||
|
||||
@@ -552,6 +557,11 @@ void AudioPipeline::decode_task(void *params) {
|
||||
case audio::AudioFileType::FLAC:
|
||||
initial_bytes_to_buffer /= 2; // Estimate the FLAC compression factor is 2
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_AUDIO_OPUS_SUPPORT
|
||||
case audio::AudioFileType::OPUS:
|
||||
initial_bytes_to_buffer /= 8; // Estimate the Opus compression factor is 8
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -18,7 +18,12 @@ constexpr int LOG_LEVEL_TO_SYSLOG_SEVERITY[] = {
|
||||
7 // VERY_VERBOSE
|
||||
};
|
||||
|
||||
void Syslog::setup() { logger::global_logger->add_log_listener(this); }
|
||||
void Syslog::setup() {
|
||||
logger::global_logger->add_log_callback(
|
||||
this, [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
static_cast<Syslog *>(self)->on_log(level, tag, message, message_len);
|
||||
});
|
||||
}
|
||||
|
||||
void Syslog::on_log(uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
this->log_(level, tag, message, message_len);
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/logger/logger.h"
|
||||
#include "esphome/components/udp/udp_component.h"
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
|
||||
#ifdef USE_NETWORK
|
||||
namespace esphome::syslog {
|
||||
class Syslog : public Component, public Parented<udp::UDPComponent>, public logger::LogListener {
|
||||
class Syslog : public Component, public Parented<udp::UDPComponent> {
|
||||
public:
|
||||
Syslog(int level, time::RealTimeClock *time) : log_level_(level), time_(time) {}
|
||||
void setup() override;
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override;
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
|
||||
void set_strip(bool strip) { this->strip_ = strip; }
|
||||
void set_facility(int facility) { this->facility_ = facility; }
|
||||
|
||||
|
||||
@@ -26,17 +26,7 @@ const uint8_t TLC59208F_MODE1_SUB3 = (1 << 1);
|
||||
// 0: device doesn't respond to i2c all-call 3, 1*: responds to all-call
|
||||
const uint8_t TLC59208F_MODE1_ALLCALL = (1 << 0);
|
||||
|
||||
// 0*: Group dimming, 1: Group blinking
|
||||
const uint8_t TLC59208F_MODE2_DMBLNK = (1 << 5);
|
||||
// 0*: Output change on Stop command, 1: Output change on ACK
|
||||
const uint8_t TLC59208F_MODE2_OCH = (1 << 3);
|
||||
// 0*: WDT disabled, 1: WDT enabled
|
||||
const uint8_t TLC59208F_MODE2_WDTEN = (1 << 2);
|
||||
// WDT timeouts
|
||||
const uint8_t TLC59208F_MODE2_WDT_5MS = (0 << 0);
|
||||
const uint8_t TLC59208F_MODE2_WDT_15MS = (1 << 0);
|
||||
const uint8_t TLC59208F_MODE2_WDT_25MS = (2 << 0);
|
||||
const uint8_t TLC59208F_MODE2_WDT_35MS = (3 << 0);
|
||||
// TLC59208F MODE2 constants are now inline constexpr in tlc59208f_output.h
|
||||
|
||||
// --- Special function ---
|
||||
// Call address to perform software reset, no devices will ACK
|
||||
|
||||
@@ -9,16 +9,16 @@ namespace esphome {
|
||||
namespace tlc59208f {
|
||||
|
||||
// 0*: Group dimming, 1: Group blinking
|
||||
extern const uint8_t TLC59208F_MODE2_DMBLNK;
|
||||
inline constexpr uint8_t TLC59208F_MODE2_DMBLNK = (1 << 5);
|
||||
// 0*: Output change on Stop command, 1: Output change on ACK
|
||||
extern const uint8_t TLC59208F_MODE2_OCH;
|
||||
inline constexpr uint8_t TLC59208F_MODE2_OCH = (1 << 3);
|
||||
// 0*: WDT disabled, 1: WDT enabled
|
||||
extern const uint8_t TLC59208F_MODE2_WDTEN;
|
||||
inline constexpr uint8_t TLC59208F_MODE2_WDTEN = (1 << 2);
|
||||
// WDT timeouts
|
||||
extern const uint8_t TLC59208F_MODE2_WDT_5MS;
|
||||
extern const uint8_t TLC59208F_MODE2_WDT_15MS;
|
||||
extern const uint8_t TLC59208F_MODE2_WDT_25MS;
|
||||
extern const uint8_t TLC59208F_MODE2_WDT_35MS;
|
||||
inline constexpr uint8_t TLC59208F_MODE2_WDT_5MS = (0 << 0);
|
||||
inline constexpr uint8_t TLC59208F_MODE2_WDT_15MS = (1 << 0);
|
||||
inline constexpr uint8_t TLC59208F_MODE2_WDT_25MS = (2 << 0);
|
||||
inline constexpr uint8_t TLC59208F_MODE2_WDT_35MS = (3 << 0);
|
||||
|
||||
class TLC59208FOutput;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_DATA, CONF_ID, CONF_PORT, CONF_TRIGGER_ID
|
||||
from esphome.core import ID
|
||||
from esphome.cpp_generator import MockObj
|
||||
from esphome.types import ConfigType
|
||||
|
||||
CODEOWNERS = ["@clydebarrow"]
|
||||
DEPENDENCIES = ["network"]
|
||||
@@ -65,33 +66,47 @@ RELOCATED = {
|
||||
)
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = cv.COMPONENT_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(UDPComponent),
|
||||
cv.Optional(CONF_PORT, default=18511): cv.Any(
|
||||
cv.port,
|
||||
cv.Schema(
|
||||
|
||||
def _consume_udp_sockets(config: ConfigType) -> ConfigType:
|
||||
"""Register socket needs for UDP component."""
|
||||
from esphome.components import socket
|
||||
|
||||
# UDP uses up to 2 sockets: 1 broadcast + 1 listen
|
||||
# Whether each is used depends on code generation, so register worst case
|
||||
socket.consume_sockets(2, "udp")(config)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.COMPONENT_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(UDPComponent),
|
||||
cv.Optional(CONF_PORT, default=18511): cv.Any(
|
||||
cv.port,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_LISTEN_PORT): cv.port,
|
||||
cv.Required(CONF_BROADCAST_PORT): cv.port,
|
||||
}
|
||||
),
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_LISTEN_ADDRESS, default="255.255.255.255"
|
||||
): cv.ipv4address_multi_broadcast,
|
||||
cv.Optional(CONF_ADDRESSES, default=["255.255.255.255"]): cv.ensure_list(
|
||||
cv.ipv4address,
|
||||
),
|
||||
cv.Optional(CONF_ON_RECEIVE): automation.validate_automation(
|
||||
{
|
||||
cv.Required(CONF_LISTEN_PORT): cv.port,
|
||||
cv.Required(CONF_BROADCAST_PORT): cv.port,
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
Trigger.template(trigger_args)
|
||||
),
|
||||
}
|
||||
),
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_LISTEN_ADDRESS, default="255.255.255.255"
|
||||
): cv.ipv4address_multi_broadcast,
|
||||
cv.Optional(CONF_ADDRESSES, default=["255.255.255.255"]): cv.ensure_list(
|
||||
cv.ipv4address,
|
||||
),
|
||||
cv.Optional(CONF_ON_RECEIVE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
Trigger.template(trigger_args)
|
||||
),
|
||||
}
|
||||
),
|
||||
}
|
||||
).extend(RELOCATED)
|
||||
}
|
||||
).extend(RELOCATED),
|
||||
_consume_udp_sockets,
|
||||
)
|
||||
|
||||
|
||||
async def register_udp_client(var, config):
|
||||
|
||||
@@ -144,9 +144,10 @@ def _consume_web_server_sockets(config: ConfigType) -> ConfigType:
|
||||
"""Register socket needs for web_server component."""
|
||||
from esphome.components import socket
|
||||
|
||||
# Web server needs 1 listening socket + typically 2 concurrent client connections
|
||||
# (browser makes 2 connections for page + event stream)
|
||||
sockets_needed = 3
|
||||
# Web server needs 1 listening socket + typically 5 concurrent client connections
|
||||
# (browser opens connections for page resources, SSE event stream, and POST
|
||||
# requests for entity control which may linger before closing)
|
||||
sockets_needed = 6
|
||||
socket.consume_sockets(sockets_needed, "web_server")(config)
|
||||
return config
|
||||
|
||||
|
||||
@@ -395,7 +395,10 @@ void WebServer::setup() {
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
if (logger::global_logger != nullptr && this->expose_log_) {
|
||||
logger::global_logger->add_log_listener(this);
|
||||
logger::global_logger->add_log_callback(
|
||||
this, [](void *self, uint8_t level, const char *tag, const char *message, size_t message_len) {
|
||||
static_cast<WebServer *>(self)->on_log(level, tag, message, message_len);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1546,16 +1549,16 @@ std::string WebServer::climate_json_(climate::Climate *obj, JsonDetail start_con
|
||||
for (auto const &custom_preset : traits.get_supported_custom_presets())
|
||||
opt.add(custom_preset);
|
||||
}
|
||||
root[ESPHOME_F("max_temp")] =
|
||||
(value_accuracy_to_buf(temp_buf, traits.get_visual_max_temperature(), target_accuracy), temp_buf);
|
||||
root[ESPHOME_F("min_temp")] =
|
||||
(value_accuracy_to_buf(temp_buf, traits.get_visual_min_temperature(), target_accuracy), temp_buf);
|
||||
root[ESPHOME_F("step")] = traits.get_visual_target_temperature_step();
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
bool has_state = false;
|
||||
root[ESPHOME_F("mode")] = PSTR_LOCAL(climate_mode_to_string(obj->mode));
|
||||
root[ESPHOME_F("max_temp")] =
|
||||
(value_accuracy_to_buf(temp_buf, traits.get_visual_max_temperature(), target_accuracy), temp_buf);
|
||||
root[ESPHOME_F("min_temp")] =
|
||||
(value_accuracy_to_buf(temp_buf, traits.get_visual_min_temperature(), target_accuracy), temp_buf);
|
||||
root[ESPHOME_F("step")] = traits.get_visual_target_temperature_step();
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
|
||||
root[ESPHOME_F("action")] = PSTR_LOCAL(climate_action_to_string(obj->action));
|
||||
root[ESPHOME_F("state")] = root[ESPHOME_F("action")];
|
||||
@@ -1922,6 +1925,9 @@ std::string WebServer::water_heater_json_(water_heater::WaterHeater *obj, JsonDe
|
||||
JsonArray modes = root[ESPHOME_F("modes")].to<JsonArray>();
|
||||
for (auto m : traits.get_supported_modes())
|
||||
modes.add(PSTR_LOCAL(water_heater::water_heater_mode_to_string(m)));
|
||||
root[ESPHOME_F("min_temp")] = traits.get_min_temperature();
|
||||
root[ESPHOME_F("max_temp")] = traits.get_max_temperature();
|
||||
root[ESPHOME_F("step")] = traits.get_target_temperature_step();
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
@@ -1944,10 +1950,6 @@ std::string WebServer::water_heater_json_(water_heater::WaterHeater *obj, JsonDe
|
||||
root[ESPHOME_F("target_temperature")] = target;
|
||||
}
|
||||
|
||||
root[ESPHOME_F("min_temperature")] = traits.get_min_temperature();
|
||||
root[ESPHOME_F("max_temperature")] = traits.get_max_temperature();
|
||||
root[ESPHOME_F("step")] = traits.get_target_temperature_step();
|
||||
|
||||
if (traits.get_supports_away_mode()) {
|
||||
root[ESPHOME_F("away")] = obj->is_away();
|
||||
}
|
||||
|
||||
@@ -186,14 +186,7 @@ class DeferredUpdateEventSourceList : public std::list<DeferredUpdateEventSource
|
||||
* under the '/light/...', '/sensor/...', ... URLs. A full documentation for this API
|
||||
* can be found under https://esphome.io/web-api/.
|
||||
*/
|
||||
class WebServer : public Controller,
|
||||
public Component,
|
||||
public AsyncWebHandler
|
||||
#ifdef USE_LOGGER
|
||||
,
|
||||
public logger::LogListener
|
||||
#endif
|
||||
{
|
||||
class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||
#if !defined(USE_ESP32) && defined(USE_ARDUINO)
|
||||
friend class DeferredUpdateEventSourceList;
|
||||
#endif
|
||||
@@ -254,7 +247,7 @@ class WebServer : public Controller,
|
||||
void dump_config() override;
|
||||
|
||||
#ifdef USE_LOGGER
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override;
|
||||
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len);
|
||||
#endif
|
||||
|
||||
/// MQTT setup priority.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user