mirror of
https://github.com/esphome/esphome.git
synced 2025-10-30 14:43:51 +00:00
Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
@@ -23,7 +23,7 @@ void APDS9960::setup() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (id != 0xAB && id != 0x9C && id != 0xA8) { // APDS9960 all should have one of these IDs
|
||||
if (id != 0xAB && id != 0x9C && id != 0xA8 && id != 0x9E) { // APDS9960 all should have one of these IDs
|
||||
this->error_code_ = WRONG_ID;
|
||||
this->mark_failed();
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from esphome import automation, pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import time
|
||||
from esphome.components import esp32, time
|
||||
from esphome.components.esp32 import get_esp32_variant
|
||||
from esphome.components.esp32.const import (
|
||||
VARIANT_ESP32,
|
||||
@@ -116,12 +116,20 @@ def validate_pin_number(value):
|
||||
return value
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
if get_esp32_variant() == VARIANT_ESP32C3 and CONF_ESP32_EXT1_WAKEUP in config:
|
||||
raise cv.Invalid("ESP32-C3 does not support wakeup from touch.")
|
||||
if get_esp32_variant() == VARIANT_ESP32C3 and CONF_TOUCH_WAKEUP in config:
|
||||
raise cv.Invalid("ESP32-C3 does not support wakeup from ext1")
|
||||
return config
|
||||
def _validate_ex1_wakeup_mode(value):
|
||||
if value == "ALL_LOW":
|
||||
esp32.only_on_variant(supported=[VARIANT_ESP32], msg_prefix="ALL_LOW")(value)
|
||||
if value == "ANY_LOW":
|
||||
esp32.only_on_variant(
|
||||
supported=[
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
VARIANT_ESP32C6,
|
||||
VARIANT_ESP32H2,
|
||||
],
|
||||
msg_prefix="ANY_LOW",
|
||||
)(value)
|
||||
return value
|
||||
|
||||
|
||||
deep_sleep_ns = cg.esphome_ns.namespace("deep_sleep")
|
||||
@@ -148,6 +156,7 @@ WAKEUP_PIN_MODES = {
|
||||
esp_sleep_ext1_wakeup_mode_t = cg.global_ns.enum("esp_sleep_ext1_wakeup_mode_t")
|
||||
Ext1Wakeup = deep_sleep_ns.struct("Ext1Wakeup")
|
||||
EXT1_WAKEUP_MODES = {
|
||||
"ANY_LOW": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ANY_LOW,
|
||||
"ALL_LOW": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ALL_LOW,
|
||||
"ANY_HIGH": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ANY_HIGH,
|
||||
}
|
||||
@@ -187,16 +196,28 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All(
|
||||
cv.only_on_esp32,
|
||||
esp32.only_on_variant(
|
||||
unsupported=[VARIANT_ESP32C3], msg_prefix="Wakeup from ext1"
|
||||
),
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_PINS): cv.ensure_list(
|
||||
pins.internal_gpio_input_pin_schema, validate_pin_number
|
||||
),
|
||||
cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True),
|
||||
cv.Required(CONF_MODE): cv.All(
|
||||
cv.enum(EXT1_WAKEUP_MODES, upper=True),
|
||||
_validate_ex1_wakeup_mode,
|
||||
),
|
||||
}
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean),
|
||||
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(
|
||||
cv.only_on_esp32,
|
||||
esp32.only_on_variant(
|
||||
unsupported=[VARIANT_ESP32C3], msg_prefix="Wakeup from touch"
|
||||
),
|
||||
cv.boolean,
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]),
|
||||
|
||||
@@ -189,7 +189,7 @@ def get_download_types(storage_json):
|
||||
]
|
||||
|
||||
|
||||
def only_on_variant(*, supported=None, unsupported=None):
|
||||
def only_on_variant(*, supported=None, unsupported=None, msg_prefix="This feature"):
|
||||
"""Config validator for features only available on some ESP32 variants."""
|
||||
if supported is not None and not isinstance(supported, list):
|
||||
supported = [supported]
|
||||
@@ -200,11 +200,11 @@ def only_on_variant(*, supported=None, unsupported=None):
|
||||
variant = get_esp32_variant()
|
||||
if supported is not None and variant not in supported:
|
||||
raise cv.Invalid(
|
||||
f"This feature is only available on {', '.join(supported)}"
|
||||
f"{msg_prefix} is only available on {', '.join(supported)}"
|
||||
)
|
||||
if unsupported is not None and variant in unsupported:
|
||||
raise cv.Invalid(
|
||||
f"This feature is not available on {', '.join(unsupported)}"
|
||||
f"{msg_prefix} is not available on {', '.join(unsupported)}"
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ void ESP32TouchComponent::loop() {
|
||||
|
||||
// Only publish if state changed - this filters out repeated events
|
||||
if (new_state != child->last_state_) {
|
||||
child->initial_state_published_ = true;
|
||||
child->last_state_ = new_state;
|
||||
child->publish_state(new_state);
|
||||
// Original ESP32: ISR only fires when touched, release is detected by timeout
|
||||
@@ -175,6 +176,9 @@ void ESP32TouchComponent::on_shutdown() {
|
||||
void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
||||
ESP32TouchComponent *component = static_cast<ESP32TouchComponent *>(arg);
|
||||
|
||||
uint32_t mask = 0;
|
||||
touch_ll_read_trigger_status_mask(&mask);
|
||||
touch_ll_clear_trigger_status_mask();
|
||||
touch_pad_clear_status();
|
||||
|
||||
// INTERRUPT BEHAVIOR: On ESP32 v1 hardware, the interrupt fires when ANY configured
|
||||
@@ -184,6 +188,11 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
||||
// as any pad remains touched. This allows us to detect both new touches and
|
||||
// continued touches, but releases must be detected by timeout in the main loop.
|
||||
|
||||
// IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2!
|
||||
// ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE
|
||||
// Therefore: touched = (value < threshold)
|
||||
// This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold)
|
||||
|
||||
// Process all configured pads to check their current state
|
||||
// Note: ESP32 v1 doesn't tell us which specific pad triggered the interrupt,
|
||||
// so we must scan all configured pads to find which ones were touched
|
||||
@@ -201,19 +210,12 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
||||
value = touch_ll_read_raw_data(pad);
|
||||
}
|
||||
|
||||
// Skip pads with 0 value - they haven't been measured in this cycle
|
||||
// This is important: not all pads are measured every interrupt cycle,
|
||||
// only those that the hardware has updated
|
||||
if (value == 0) {
|
||||
// Skip pads that aren’t in the trigger mask
|
||||
bool is_touched = (mask >> pad) & 1;
|
||||
if (!is_touched) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// IMPORTANT: ESP32 v1 touch detection logic - INVERTED compared to v2!
|
||||
// ESP32 v1: Touch is detected when capacitance INCREASES, causing the measured value to DECREASE
|
||||
// Therefore: touched = (value < threshold)
|
||||
// This is opposite to ESP32-S2/S3 v2 where touched = (value > threshold)
|
||||
bool is_touched = value < child->get_threshold();
|
||||
|
||||
// Always send the current state - the main loop will filter for changes
|
||||
// We send both touched and untouched states because the ISR doesn't
|
||||
// track previous state (to keep ISR fast and simple)
|
||||
|
||||
0
esphome/components/gl_r01_i2c/__init__.py
Normal file
0
esphome/components/gl_r01_i2c/__init__.py
Normal file
68
esphome/components/gl_r01_i2c/gl_r01_i2c.cpp
Normal file
68
esphome/components/gl_r01_i2c/gl_r01_i2c.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "gl_r01_i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gl_r01_i2c {
|
||||
|
||||
static const char *const TAG = "gl_r01_i2c";
|
||||
|
||||
// Register definitions from datasheet
|
||||
static const uint8_t REG_VERSION = 0x00;
|
||||
static const uint8_t REG_DISTANCE = 0x02;
|
||||
static const uint8_t REG_TRIGGER = 0x10;
|
||||
static const uint8_t CMD_TRIGGER = 0xB0;
|
||||
static const uint8_t RESTART_CMD1 = 0x5A;
|
||||
static const uint8_t RESTART_CMD2 = 0xA5;
|
||||
static const uint8_t READ_DELAY = 40; // minimum milliseconds from datasheet to safely read measurement result
|
||||
|
||||
void GLR01I2CComponent::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up GL-R01 I2C...");
|
||||
// Verify sensor presence
|
||||
if (!this->read_byte_16(REG_VERSION, &this->version_)) {
|
||||
ESP_LOGE(TAG, "Failed to communicate with GL-R01 I2C sensor!");
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Found GL-R01 I2C with version 0x%04X", this->version_);
|
||||
}
|
||||
|
||||
void GLR01I2CComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "GL-R01 I2C:");
|
||||
ESP_LOGCONFIG(TAG, " Firmware Version: 0x%04X", this->version_);
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_SENSOR(" ", "Distance", this);
|
||||
}
|
||||
|
||||
void GLR01I2CComponent::update() {
|
||||
// Trigger a new measurement
|
||||
if (!this->write_byte(REG_TRIGGER, CMD_TRIGGER)) {
|
||||
ESP_LOGE(TAG, "Failed to trigger measurement!");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule reading the result after the read delay
|
||||
this->set_timeout(READ_DELAY, [this]() { this->read_distance_(); });
|
||||
}
|
||||
|
||||
void GLR01I2CComponent::read_distance_() {
|
||||
uint16_t distance = 0;
|
||||
if (!this->read_byte_16(REG_DISTANCE, &distance)) {
|
||||
ESP_LOGE(TAG, "Failed to read distance value!");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance == 0xFFFF) {
|
||||
ESP_LOGW(TAG, "Invalid measurement received!");
|
||||
this->status_set_warning();
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Distance: %umm", distance);
|
||||
this->publish_state(distance);
|
||||
this->status_clear_warning();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gl_r01_i2c
|
||||
} // namespace esphome
|
||||
22
esphome/components/gl_r01_i2c/gl_r01_i2c.h
Normal file
22
esphome/components/gl_r01_i2c/gl_r01_i2c.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gl_r01_i2c {
|
||||
|
||||
class GLR01I2CComponent : public sensor::Sensor, public i2c::I2CDevice, public PollingComponent {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
void read_distance_();
|
||||
uint16_t version_{0};
|
||||
};
|
||||
|
||||
} // namespace gl_r01_i2c
|
||||
} // namespace esphome
|
||||
36
esphome/components/gl_r01_i2c/sensor.py
Normal file
36
esphome/components/gl_r01_i2c/sensor.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_MILLIMETER,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@pkejval"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
gl_r01_i2c_ns = cg.esphome_ns.namespace("gl_r01_i2c")
|
||||
GLR01I2CComponent = gl_r01_i2c_ns.class_(
|
||||
"GLR01I2CComponent", i2c.I2CDevice, cg.PollingComponent
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
GLR01I2CComponent,
|
||||
unit_of_measurement=UNIT_MILLIMETER,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_DISTANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(i2c.i2c_device_schema(0x74))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
0
esphome/components/lps22/__init__.py
Normal file
0
esphome/components/lps22/__init__.py
Normal file
75
esphome/components/lps22/lps22.cpp
Normal file
75
esphome/components/lps22/lps22.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "lps22.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace lps22 {
|
||||
|
||||
static constexpr const char *const TAG = "lps22";
|
||||
|
||||
static constexpr uint8_t WHO_AM_I = 0x0F;
|
||||
static constexpr uint8_t LPS22HB_ID = 0xB1;
|
||||
static constexpr uint8_t LPS22HH_ID = 0xB3;
|
||||
static constexpr uint8_t CTRL_REG2 = 0x11;
|
||||
static constexpr uint8_t CTRL_REG2_ONE_SHOT_MASK = 0b1;
|
||||
static constexpr uint8_t STATUS = 0x27;
|
||||
static constexpr uint8_t STATUS_T_DA_MASK = 0b10;
|
||||
static constexpr uint8_t STATUS_P_DA_MASK = 0b01;
|
||||
static constexpr uint8_t TEMP_L = 0x2b;
|
||||
static constexpr uint8_t PRES_OUT_XL = 0x28;
|
||||
static constexpr uint8_t REF_P_XL = 0x28;
|
||||
static constexpr uint8_t READ_ATTEMPTS = 10;
|
||||
static constexpr uint8_t READ_INTERVAL = 5;
|
||||
static constexpr float PRESSURE_SCALE = 1.0f / 4096.0f;
|
||||
static constexpr float TEMPERATURE_SCALE = 0.01f;
|
||||
|
||||
void LPS22Component::setup() {
|
||||
uint8_t value = 0x00;
|
||||
this->read_register(WHO_AM_I, &value, 1);
|
||||
if (value != LPS22HB_ID && value != LPS22HH_ID) {
|
||||
ESP_LOGW(TAG, "device IDs as %02x, which isn't a known LPS22HB or LPS22HH ID", value);
|
||||
this->mark_failed();
|
||||
}
|
||||
}
|
||||
|
||||
void LPS22Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "LPS22:");
|
||||
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
|
||||
LOG_SENSOR(" ", "Pressure", this->pressure_sensor_);
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void LPS22Component::update() {
|
||||
uint8_t value = 0x00;
|
||||
this->read_register(CTRL_REG2, &value, 1);
|
||||
value |= CTRL_REG2_ONE_SHOT_MASK;
|
||||
this->write_register(CTRL_REG2, &value, 1);
|
||||
this->set_retry(READ_INTERVAL, READ_ATTEMPTS, [this](uint8_t _) { return this->try_read_(); });
|
||||
}
|
||||
|
||||
RetryResult LPS22Component::try_read_() {
|
||||
uint8_t value = 0x00;
|
||||
this->read_register(STATUS, &value, 1);
|
||||
const uint8_t expected_status_mask = STATUS_T_DA_MASK | STATUS_P_DA_MASK;
|
||||
if ((value & expected_status_mask) != expected_status_mask) {
|
||||
ESP_LOGD(TAG, "STATUS not ready: %x", value);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
|
||||
if (this->temperature_sensor_ != nullptr) {
|
||||
uint8_t t_buf[2]{0};
|
||||
this->read_register(TEMP_L, t_buf, 2);
|
||||
int16_t encoded = static_cast<int16_t>(encode_uint16(t_buf[1], t_buf[0]));
|
||||
float temp = TEMPERATURE_SCALE * static_cast<float>(encoded);
|
||||
this->temperature_sensor_->publish_state(temp);
|
||||
}
|
||||
if (this->pressure_sensor_ != nullptr) {
|
||||
uint8_t p_buf[3]{0};
|
||||
this->read_register(PRES_OUT_XL, p_buf, 3);
|
||||
uint32_t p_lsb = encode_uint24(p_buf[2], p_buf[1], p_buf[0]);
|
||||
this->pressure_sensor_->publish_state(PRESSURE_SCALE * static_cast<float>(p_lsb));
|
||||
}
|
||||
return RetryResult::DONE;
|
||||
}
|
||||
|
||||
} // namespace lps22
|
||||
} // namespace esphome
|
||||
27
esphome/components/lps22/lps22.h
Normal file
27
esphome/components/lps22/lps22.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace lps22 {
|
||||
|
||||
class LPS22Component : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
|
||||
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { this->pressure_sensor_ = pressure_sensor; }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
sensor::Sensor *temperature_sensor_{nullptr};
|
||||
sensor::Sensor *pressure_sensor_{nullptr};
|
||||
|
||||
RetryResult try_read_();
|
||||
};
|
||||
|
||||
} // namespace lps22
|
||||
} // namespace esphome
|
||||
58
esphome/components/lps22/sensor.py
Normal file
58
esphome/components/lps22/sensor.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_PRESSURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_HECTOPASCAL,
|
||||
ICON_THERMOMETER,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@nagisa"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
lps22 = cg.esphome_ns.namespace("lps22")
|
||||
|
||||
LPS22Component = lps22.class_("LPS22Component", cg.PollingComponent, i2c.I2CDevice)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(LPS22Component),
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_CELSIUS,
|
||||
icon=ICON_THERMOMETER,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_PRESSURE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_HECTOPASCAL,
|
||||
accuracy_decimals=2,
|
||||
device_class=DEVICE_CLASS_PRESSURE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(i2c.i2c_device_schema(0x5D)) # can also be 0x5C
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if temperature_config := config.get(CONF_TEMPERATURE):
|
||||
sens = await sensor.new_sensor(temperature_config)
|
||||
cg.add(var.set_temperature_sensor(sens))
|
||||
|
||||
if pressure_config := config.get(CONF_PRESSURE):
|
||||
sens = await sensor.new_sensor(pressure_config)
|
||||
cg.add(var.set_pressure_sensor(sens))
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "nfc.h"
|
||||
#include <cstdio>
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -7,29 +8,9 @@ namespace nfc {
|
||||
|
||||
static const char *const TAG = "nfc";
|
||||
|
||||
std::string format_uid(std::vector<uint8_t> &uid) {
|
||||
char buf[(uid.size() * 2) + uid.size() - 1];
|
||||
int offset = 0;
|
||||
for (size_t i = 0; i < uid.size(); i++) {
|
||||
const char *format = "%02X";
|
||||
if (i + 1 < uid.size())
|
||||
format = "%02X-";
|
||||
offset += sprintf(buf + offset, format, uid[i]);
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
std::string format_uid(const std::vector<uint8_t> &uid) { return format_hex_pretty(uid, '-', false); }
|
||||
|
||||
std::string format_bytes(std::vector<uint8_t> &bytes) {
|
||||
char buf[(bytes.size() * 2) + bytes.size() - 1];
|
||||
int offset = 0;
|
||||
for (size_t i = 0; i < bytes.size(); i++) {
|
||||
const char *format = "%02X";
|
||||
if (i + 1 < bytes.size())
|
||||
format = "%02X ";
|
||||
offset += sprintf(buf + offset, format, bytes[i]);
|
||||
}
|
||||
return std::string(buf);
|
||||
}
|
||||
std::string format_bytes(const std::vector<uint8_t> &bytes) { return format_hex_pretty(bytes, ' ', false); }
|
||||
|
||||
uint8_t guess_tag_type(uint8_t uid_length) {
|
||||
if (uid_length == 4) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "ndef_record.h"
|
||||
#include "ndef_message.h"
|
||||
#include "ndef_record.h"
|
||||
#include "nfc_tag.h"
|
||||
|
||||
#include <vector>
|
||||
@@ -53,8 +53,8 @@ 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};
|
||||
|
||||
std::string format_uid(std::vector<uint8_t> &uid);
|
||||
std::string format_bytes(std::vector<uint8_t> &bytes);
|
||||
std::string format_uid(const std::vector<uint8_t> &uid);
|
||||
std::string format_bytes(const std::vector<uint8_t> &bytes);
|
||||
|
||||
uint8_t guess_tag_type(uint8_t uid_length);
|
||||
uint8_t get_mifare_classic_ndef_start_index(std::vector<uint8_t> &data);
|
||||
|
||||
@@ -78,7 +78,7 @@ enum JsonDetail { DETAIL_ALL, DETAIL_STATE };
|
||||
This is because only minimal changes were made to the ESPAsyncWebServer lib_dep, it was undesirable to put deferred
|
||||
update logic into that library. We need one deferred queue per connection so instead of one AsyncEventSource with
|
||||
multiple clients, we have multiple event sources with one client each. This is slightly awkward which is why it's
|
||||
implemented in a more straightforward way for ESP-IDF. Arudino platform will eventually go away and this workaround
|
||||
implemented in a more straightforward way for ESP-IDF. Arduino platform will eventually go away and this workaround
|
||||
can be forgotten.
|
||||
*/
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
@@ -4,7 +4,7 @@ from enum import Enum
|
||||
|
||||
from esphome.enum import StrEnum
|
||||
|
||||
__version__ = "2025.7.0-dev"
|
||||
__version__ = "2025.8.0-dev"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
||||
@@ -263,7 +263,7 @@ std::string format_hex_pretty(const uint8_t *data, size_t length, char separator
|
||||
return "";
|
||||
std::string ret;
|
||||
uint8_t multiple = separator ? 3 : 2; // 3 if separator is not \0, 2 otherwise
|
||||
ret.resize(multiple * length - 1);
|
||||
ret.resize(multiple * length - (separator ? 1 : 0));
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
ret[multiple * i] = format_hex_pretty_char((data[i] & 0xF0) >> 4);
|
||||
ret[multiple * i + 1] = format_hex_pretty_char(data[i] & 0x0F);
|
||||
@@ -283,7 +283,7 @@ std::string format_hex_pretty(const uint16_t *data, size_t length, char separato
|
||||
return "";
|
||||
std::string ret;
|
||||
uint8_t multiple = separator ? 5 : 4; // 5 if separator is not \0, 4 otherwise
|
||||
ret.resize(multiple * length - 1);
|
||||
ret.resize(multiple * length - (separator ? 1 : 0));
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
ret[multiple * i] = format_hex_pretty_char((data[i] & 0xF000) >> 12);
|
||||
ret[multiple * i + 1] = format_hex_pretty_char((data[i] & 0x0F00) >> 8);
|
||||
@@ -304,7 +304,7 @@ std::string format_hex_pretty(const std::string &data, char separator, bool show
|
||||
return "";
|
||||
std::string ret;
|
||||
uint8_t multiple = separator ? 3 : 2; // 3 if separator is not \0, 2 otherwise
|
||||
ret.resize(multiple * data.length() - 1);
|
||||
ret.resize(multiple * data.length() - (separator ? 1 : 0));
|
||||
for (size_t i = 0; i < data.length(); i++) {
|
||||
ret[multiple * i] = format_hex_pretty_char((data[i] & 0xF0) >> 4);
|
||||
ret[multiple * i + 1] = format_hex_pretty_char(data[i] & 0x0F);
|
||||
|
||||
Reference in New Issue
Block a user