1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-16 07:27:50 +02:00

[qmc5883l] Added drdy_pin option to allow it to run max rate (#10901)

Co-authored-by: Lamer Mortification <lamer_mortification@yahoo.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
Mort 2025-10-06 11:48:05 -04:00 committed by GitHub
parent e55df1babc
commit 7147479f90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 57 additions and 12 deletions

View File

@ -8,6 +8,7 @@ namespace esphome {
namespace qmc5883l { namespace qmc5883l {
static const char *const TAG = "qmc5883l"; static const char *const TAG = "qmc5883l";
static const uint8_t QMC5883L_ADDRESS = 0x0D; static const uint8_t QMC5883L_ADDRESS = 0x0D;
static const uint8_t QMC5883L_REGISTER_DATA_X_LSB = 0x00; static const uint8_t QMC5883L_REGISTER_DATA_X_LSB = 0x00;
@ -32,6 +33,10 @@ void QMC5883LComponent::setup() {
} }
delay(10); delay(10);
if (this->drdy_pin_) {
this->drdy_pin_->setup();
}
uint8_t control_1 = 0; uint8_t control_1 = 0;
control_1 |= 0b01 << 0; // MODE (Mode) -> 0b00=standby, 0b01=continuous control_1 |= 0b01 << 0; // MODE (Mode) -> 0b00=standby, 0b01=continuous
control_1 |= this->datarate_ << 2; control_1 |= this->datarate_ << 2;
@ -64,6 +69,7 @@ void QMC5883LComponent::setup() {
high_freq_.start(); high_freq_.start();
} }
} }
void QMC5883LComponent::dump_config() { void QMC5883LComponent::dump_config() {
ESP_LOGCONFIG(TAG, "QMC5883L:"); ESP_LOGCONFIG(TAG, "QMC5883L:");
LOG_I2C_DEVICE(this); LOG_I2C_DEVICE(this);
@ -77,11 +83,20 @@ void QMC5883LComponent::dump_config() {
LOG_SENSOR(" ", "Z Axis", this->z_sensor_); LOG_SENSOR(" ", "Z Axis", this->z_sensor_);
LOG_SENSOR(" ", "Heading", this->heading_sensor_); LOG_SENSOR(" ", "Heading", this->heading_sensor_);
LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
LOG_PIN(" DRDY Pin: ", this->drdy_pin_);
} }
float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; } float QMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; }
void QMC5883LComponent::update() { void QMC5883LComponent::update() {
i2c::ErrorCode err; i2c::ErrorCode err;
uint8_t status = false; uint8_t status = false;
// If DRDY pin is configured and the data is not ready return.
if (this->drdy_pin_ && !this->drdy_pin_->digital_read()) {
return;
}
// Status byte gets cleared when data is read, so we have to read this first. // Status byte gets cleared when data is read, so we have to read this first.
// If status and two axes are desired, it's possible to save one byte of traffic by enabling // If status and two axes are desired, it's possible to save one byte of traffic by enabling
// ROL_PNT in setup and reading 7 bytes starting at the status register. // ROL_PNT in setup and reading 7 bytes starting at the status register.

View File

@ -3,6 +3,7 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h" #include "esphome/components/i2c/i2c.h"
#include "esphome/core/hal.h"
namespace esphome { namespace esphome {
namespace qmc5883l { namespace qmc5883l {
@ -33,6 +34,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
float get_setup_priority() const override; float get_setup_priority() const override;
void update() override; void update() override;
void set_drdy_pin(GPIOPin *pin) { drdy_pin_ = pin; }
void set_datarate(QMC5883LDatarate datarate) { datarate_ = datarate; } void set_datarate(QMC5883LDatarate datarate) { datarate_ = datarate; }
void set_range(QMC5883LRange range) { range_ = range; } void set_range(QMC5883LRange range) { range_ = range; }
void set_oversampling(QMC5883LOversampling oversampling) { oversampling_ = oversampling; } void set_oversampling(QMC5883LOversampling oversampling) { oversampling_ = oversampling; }
@ -51,6 +53,7 @@ class QMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
sensor::Sensor *z_sensor_{nullptr}; sensor::Sensor *z_sensor_{nullptr};
sensor::Sensor *heading_sensor_{nullptr}; sensor::Sensor *heading_sensor_{nullptr};
sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *temperature_sensor_{nullptr};
GPIOPin *drdy_pin_{nullptr};
enum ErrorCode { enum ErrorCode {
NONE = 0, NONE = 0,
COMMUNICATION_FAILED, COMMUNICATION_FAILED,

View File

@ -1,8 +1,12 @@
import logging
from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import i2c, sensor from esphome.components import i2c, sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ADDRESS, CONF_ADDRESS,
CONF_DATA_RATE,
CONF_FIELD_STRENGTH_X, CONF_FIELD_STRENGTH_X,
CONF_FIELD_STRENGTH_Y, CONF_FIELD_STRENGTH_Y,
CONF_FIELD_STRENGTH_Z, CONF_FIELD_STRENGTH_Z,
@ -21,6 +25,10 @@ from esphome.const import (
UNIT_MICROTESLA, UNIT_MICROTESLA,
) )
_LOGGER = logging.getLogger(__name__)
CONF_DRDY_PIN = "drdy_pin"
DEPENDENCIES = ["i2c"] DEPENDENCIES = ["i2c"]
qmc5883l_ns = cg.esphome_ns.namespace("qmc5883l") qmc5883l_ns = cg.esphome_ns.namespace("qmc5883l")
@ -52,6 +60,18 @@ QMC5883LOversamplings = {
} }
def validate_config(config):
if (
config[CONF_UPDATE_INTERVAL].total_milliseconds < 15
and CONF_DRDY_PIN not in config
):
_LOGGER.warning(
"[qmc5883l] 'update_interval' is less than 15ms and 'drdy_pin' is "
"not configured, this may result in I2C errors"
)
return config
def validate_enum(enum_values, units=None, int=True): def validate_enum(enum_values, units=None, int=True):
_units = [] _units = []
if units is not None: if units is not None:
@ -88,7 +108,7 @@ temperature_schema = sensor.sensor_schema(
state_class=STATE_CLASS_MEASUREMENT, state_class=STATE_CLASS_MEASUREMENT,
) )
CONFIG_SCHEMA = ( CONFIG_SCHEMA = cv.All(
cv.Schema( cv.Schema(
{ {
cv.GenerateID(): cv.declare_id(QMC5883LComponent), cv.GenerateID(): cv.declare_id(QMC5883LComponent),
@ -104,29 +124,25 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema, cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema,
cv.Optional(CONF_HEADING): heading_schema, cv.Optional(CONF_HEADING): heading_schema,
cv.Optional(CONF_TEMPERATURE): temperature_schema, cv.Optional(CONF_TEMPERATURE): temperature_schema,
cv.Optional(CONF_DRDY_PIN): pins.gpio_input_pin_schema,
cv.Optional(CONF_DATA_RATE, default="200hz"): validate_enum(
QMC5883LDatarates, units=["hz", "Hz"]
),
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x0D)) .extend(i2c.i2c_device_schema(0x0D)),
validate_config,
) )
def auto_data_rate(config):
interval_sec = config[CONF_UPDATE_INTERVAL].total_milliseconds / 1000
interval_hz = 1.0 / interval_sec
for datarate in sorted(QMC5883LDatarates.keys()):
if float(datarate) >= interval_hz:
return QMC5883LDatarates[datarate]
return QMC5883LDatarates[200]
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
await i2c.register_i2c_device(var, config) await i2c.register_i2c_device(var, config)
cg.add(var.set_oversampling(config[CONF_OVERSAMPLING])) cg.add(var.set_oversampling(config[CONF_OVERSAMPLING]))
cg.add(var.set_datarate(auto_data_rate(config))) cg.add(var.set_datarate(config[CONF_DATA_RATE]))
cg.add(var.set_range(config[CONF_RANGE])) cg.add(var.set_range(config[CONF_RANGE]))
if CONF_FIELD_STRENGTH_X in config: if CONF_FIELD_STRENGTH_X in config:
sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_X]) sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_X])
@ -143,3 +159,6 @@ async def to_code(config):
if CONF_TEMPERATURE in config: if CONF_TEMPERATURE in config:
sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
cg.add(var.set_temperature_sensor(sens)) cg.add(var.set_temperature_sensor(sens))
if CONF_DRDY_PIN in config:
pin = await cg.gpio_pin_expression(config[CONF_DRDY_PIN])
cg.add(var.set_drdy_pin(pin))

View File

@ -17,5 +17,7 @@ sensor:
temperature: temperature:
name: QMC5883L Temperature name: QMC5883L Temperature
range: 800uT range: 800uT
data_rate: 200Hz
oversampling: 256x oversampling: 256x
update_interval: 15s update_interval: 15s
drdy_pin: ${drdy_pin}

View File

@ -1,5 +1,6 @@
substitutions: substitutions:
scl_pin: GPIO16 scl_pin: GPIO16
sda_pin: GPIO17 sda_pin: GPIO17
drdy_pin: GPIO18
<<: !include common.yaml <<: !include common.yaml

View File

@ -1,5 +1,6 @@
substitutions: substitutions:
scl_pin: GPIO5 scl_pin: GPIO5
sda_pin: GPIO4 sda_pin: GPIO4
drdy_pin: GPIO6
<<: !include common.yaml <<: !include common.yaml

View File

@ -1,5 +1,6 @@
substitutions: substitutions:
scl_pin: GPIO5 scl_pin: GPIO5
sda_pin: GPIO4 sda_pin: GPIO4
drdy_pin: GPIO6
<<: !include common.yaml <<: !include common.yaml

View File

@ -1,5 +1,6 @@
substitutions: substitutions:
scl_pin: GPIO16 scl_pin: GPIO16
sda_pin: GPIO17 sda_pin: GPIO17
drdy_pin: GPIO18
<<: !include common.yaml <<: !include common.yaml

View File

@ -1,5 +1,6 @@
substitutions: substitutions:
scl_pin: GPIO5 scl_pin: GPIO5
sda_pin: GPIO4 sda_pin: GPIO4
drdy_pin: GPIO2
<<: !include common.yaml <<: !include common.yaml

View File

@ -1,5 +1,6 @@
substitutions: substitutions:
scl_pin: GPIO5 scl_pin: GPIO5
sda_pin: GPIO4 sda_pin: GPIO4
drdy_pin: GPIO2
<<: !include common.yaml <<: !include common.yaml