mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
[qmi8658] Motion platform for QMI8658 IMU (#16889)
This commit is contained in:
@@ -405,6 +405,7 @@ esphome/components/psram/* @esphome/core
|
|||||||
esphome/components/pulse_meter/* @cstaahl @stevebaxter @TrentHouliston
|
esphome/components/pulse_meter/* @cstaahl @stevebaxter @TrentHouliston
|
||||||
esphome/components/pvvx_mithermometer/* @pasiz
|
esphome/components/pvvx_mithermometer/* @pasiz
|
||||||
esphome/components/pylontech/* @functionpointer
|
esphome/components/pylontech/* @functionpointer
|
||||||
|
esphome/components/qmi8658/* @clydebarrow
|
||||||
esphome/components/qmp6988/* @andrewpc
|
esphome/components/qmp6988/* @andrewpc
|
||||||
esphome/components/qr_code/* @wjtje
|
esphome/components/qr_code/* @wjtje
|
||||||
esphome/components/qspi_dbi/* @clydebarrow
|
esphome/components/qspi_dbi/* @clydebarrow
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import i2c
|
||||||
|
from esphome.components.motion import MotionComponent
|
||||||
|
|
||||||
|
CODEOWNERS = ["@clydebarrow"]
|
||||||
|
DEPENDENCIES = ["i2c", "motion"]
|
||||||
|
|
||||||
|
CONF_QMI8658_ID = "qmi8658_id"
|
||||||
|
# C++ namespace / class
|
||||||
|
qmi8658_ns = cg.esphome_ns.namespace("qmi8658")
|
||||||
|
QMI8658Component = qmi8658_ns.class_("QMI8658Component", MotionComponent, i2c.I2CDevice)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = {}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import i2c
|
||||||
|
from esphome.components.const import (
|
||||||
|
CONF_ACCELEROMETER_ODR,
|
||||||
|
CONF_ACCELEROMETER_RANGE,
|
||||||
|
CONF_GYROSCOPE_ODR,
|
||||||
|
CONF_GYROSCOPE_RANGE,
|
||||||
|
)
|
||||||
|
from esphome.components.motion import motion_schema, new_motion_component
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
|
||||||
|
from . import QMI8658Component, qmi8658_ns
|
||||||
|
|
||||||
|
# Enum proxies (must match the C++ enum values exactly)
|
||||||
|
QMI8658AccelRange = qmi8658_ns.enum("QMI8658AccelRange")
|
||||||
|
ACCEL_RANGE_OPTIONS = {
|
||||||
|
"2G": QMI8658AccelRange.QMI8658_ACCEL_RANGE_2G,
|
||||||
|
"4G": QMI8658AccelRange.QMI8658_ACCEL_RANGE_4G,
|
||||||
|
"8G": QMI8658AccelRange.QMI8658_ACCEL_RANGE_8G,
|
||||||
|
"16G": QMI8658AccelRange.QMI8658_ACCEL_RANGE_16G,
|
||||||
|
}
|
||||||
|
|
||||||
|
QMI8658GyroRange = qmi8658_ns.enum("QMI8658GyroRange")
|
||||||
|
GYRO_RANGE_OPTIONS = {
|
||||||
|
"16DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_16,
|
||||||
|
"32DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_32,
|
||||||
|
"64DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_64,
|
||||||
|
"128DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_128,
|
||||||
|
"256DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_256,
|
||||||
|
"512DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_512,
|
||||||
|
"1024DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_1024,
|
||||||
|
"2048DPS": QMI8658GyroRange.QMI8658_GYRO_RANGE_2048,
|
||||||
|
}
|
||||||
|
|
||||||
|
QMI8658AccelODR = qmi8658_ns.enum("QMI8658AccelODR")
|
||||||
|
ACCEL_ODR_OPTIONS = {
|
||||||
|
"31_25HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_31_25,
|
||||||
|
"62_5HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_62_5,
|
||||||
|
"125HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_125,
|
||||||
|
"250HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_250,
|
||||||
|
"500HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_500,
|
||||||
|
"1000HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_1000,
|
||||||
|
"2000HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_2000,
|
||||||
|
"4000HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_4000,
|
||||||
|
"8000HZ": QMI8658AccelODR.QMI8658_ACCEL_ODR_8000,
|
||||||
|
}
|
||||||
|
|
||||||
|
QMI8658GyroODR = qmi8658_ns.enum("QMI8658GyroODR")
|
||||||
|
GYRO_ODR_OPTIONS = {
|
||||||
|
"31_25HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_31_25,
|
||||||
|
"62_5HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_62_5,
|
||||||
|
"125HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_125,
|
||||||
|
"250HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_250,
|
||||||
|
"500HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_500,
|
||||||
|
"1000HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_1000,
|
||||||
|
"2000HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_2000,
|
||||||
|
"4000HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_4000,
|
||||||
|
"8000HZ": QMI8658GyroODR.QMI8658_GYRO_ODR_8000,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Top-level CONFIG_SCHEMA
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
motion_schema(QMI8658Component, has_accel=True, has_gyro=True)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_ACCELEROMETER_RANGE, default="4G"): cv.enum(
|
||||||
|
ACCEL_RANGE_OPTIONS, upper=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_ACCELEROMETER_ODR, default="1000HZ"): cv.enum(
|
||||||
|
ACCEL_ODR_OPTIONS, upper=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GYROSCOPE_RANGE, default="2048DPS"): cv.enum(
|
||||||
|
GYRO_RANGE_OPTIONS, upper=True
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_GYROSCOPE_ODR, default="1000HZ"): cv.enum(
|
||||||
|
GYRO_ODR_OPTIONS, upper=True
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(i2c.i2c_device_schema(0x6B))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Code generation
|
||||||
|
async def to_code(config):
|
||||||
|
var = await new_motion_component(config)
|
||||||
|
await i2c.register_i2c_device(var, config)
|
||||||
|
|
||||||
|
# Hardware configuration
|
||||||
|
cg.add(var.set_accel_range(config[CONF_ACCELEROMETER_RANGE]))
|
||||||
|
cg.add(var.set_accel_odr(config[CONF_ACCELEROMETER_ODR]))
|
||||||
|
cg.add(var.set_gyro_range(config[CONF_GYROSCOPE_RANGE]))
|
||||||
|
cg.add(var.set_gyro_odr(config[CONF_GYROSCOPE_ODR]))
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#include "qmi8658.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
|
||||||
|
namespace esphome::qmi8658 {
|
||||||
|
|
||||||
|
static const char *const TAG = "qmi8658";
|
||||||
|
|
||||||
|
// Acceleration scale (g per LSB), indexed by accel_range_ >> 4.
|
||||||
|
// Full-scale = range_g, mapped over a signed 16-bit value (2^15 counts).
|
||||||
|
static constexpr float ACCEL_SCALE[] = {
|
||||||
|
2.0f / 32768.0f,
|
||||||
|
4.0f / 32768.0f,
|
||||||
|
8.0f / 32768.0f,
|
||||||
|
16.0f / 32768.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Angular rate scale (°/s per LSB), indexed by gyro_range_ >> 4.
|
||||||
|
static constexpr float GYRO_SCALE[] = {
|
||||||
|
16.0f / 32768.0f, 32.0f / 32768.0f, 64.0f / 32768.0f, 128.0f / 32768.0f,
|
||||||
|
256.0f / 32768.0f, 512.0f / 32768.0f, 1024.0f / 32768.0f, 2048.0f / 32768.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
void QMI8658Component::setup() {
|
||||||
|
MotionComponent::setup();
|
||||||
|
|
||||||
|
// 1. Verify chip ID
|
||||||
|
uint8_t who_am_i = 0;
|
||||||
|
if (!this->read_byte(QMI8658_REG_WHO_AM_I, &who_am_i)) {
|
||||||
|
ESP_LOGE(TAG, "Failed to read chip ID - check wiring / address");
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (who_am_i != QMI8658_WHO_AM_I_VALUE) {
|
||||||
|
ESP_LOGE(TAG, "Wrong chip ID: 0x%02X (expected 0x%02X)", who_am_i, QMI8658_WHO_AM_I_VALUE);
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Soft reset
|
||||||
|
if (!this->write_byte(QMI8658_REG_RESET, QMI8658_RESET_CMD)) {
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delay(15); // spec: wait for reset to complete
|
||||||
|
|
||||||
|
// 3. Serial interface: enable register address auto-increment
|
||||||
|
if (!this->write_byte(QMI8658_REG_CTRL1, QMI8658_CTRL1_VALUE)) {
|
||||||
|
this->mark_failed(LOG_STR("Failed to write REG_CTRL1"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Configure accelerometer (CTRL2 = range | ODR)
|
||||||
|
if (!this->write_byte(QMI8658_REG_CTRL2, (uint8_t) (this->accel_range_) | (uint8_t) (this->accel_odr_))) {
|
||||||
|
this->mark_failed(LOG_STR("Failed to write REG_CTRL2"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Configure gyroscope (CTRL3 = range | ODR)
|
||||||
|
if (!this->write_byte(QMI8658_REG_CTRL3, (uint8_t) (this->gyro_range_) | (uint8_t) (this->gyro_odr_))) {
|
||||||
|
this->mark_failed(LOG_STR("Failed to write REG_CTRL3"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Disable the built-in low-pass filters (leave raw data to the motion pipeline)
|
||||||
|
if (!this->write_byte(QMI8658_REG_CTRL5, 0x00)) {
|
||||||
|
this->mark_failed(LOG_STR("Failed to write REG_CTRL5"));
|
||||||
|
this->mark_failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Enable accelerometer and gyroscope
|
||||||
|
if (!this->write_byte(QMI8658_REG_CTRL7, QMI8658_CTRL7_ACC_EN | QMI8658_CTRL7_GYR_EN)) {
|
||||||
|
this->mark_failed(LOG_STR("Failed to write REG_CTRL7"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGCONFIG(TAG, "QMI8658 initialised successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
void QMI8658Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "QMI8658 IMU:");
|
||||||
|
LOG_I2C_DEVICE(this);
|
||||||
|
if (this->is_failed()) {
|
||||||
|
ESP_LOGE(TAG, " Communication failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr const char *const ACCEL_RANGE_STRS[] = {"±2g", "±4g", "±8g", "±16g"};
|
||||||
|
static constexpr const char *const GYRO_RANGE_STRS[] = {"±16°/s", "±32°/s", "±64°/s", "±128°/s",
|
||||||
|
"±256°/s", "±512°/s", "±1024°/s", "±2048°/s"};
|
||||||
|
|
||||||
|
ESP_LOGCONFIG(TAG, " Accel range : %s", ACCEL_RANGE_STRS[this->accel_range_ >> 4]);
|
||||||
|
ESP_LOGCONFIG(TAG, " Gyro range : %s", GYRO_RANGE_STRS[this->gyro_range_ >> 4]);
|
||||||
|
MotionComponent::dump_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QMI8658Component::update_data(motion::MotionData &data) {
|
||||||
|
if (this->is_failed())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Read temperature + accel + gyro in one contiguous block starting at TEMP_L.
|
||||||
|
uint8_t raw_data[REG_READ_LEN];
|
||||||
|
if (!this->read_bytes(QMI8658_REG_TEMP_L, raw_data, REG_READ_LEN)) {
|
||||||
|
ESP_LOGW(TAG, "Failed to read IMU data");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data is little-endian (low byte first).
|
||||||
|
float scale = ACCEL_SCALE[this->accel_range_ >> 4];
|
||||||
|
int16_t raw_x = encode_uint16(raw_data[ACC_OFFS + 1], raw_data[ACC_OFFS + 0]);
|
||||||
|
int16_t raw_y = encode_uint16(raw_data[ACC_OFFS + 3], raw_data[ACC_OFFS + 2]);
|
||||||
|
int16_t raw_z = encode_uint16(raw_data[ACC_OFFS + 5], raw_data[ACC_OFFS + 4]);
|
||||||
|
ESP_LOGV(TAG, "Read raw accel data: %d, %d, %d", raw_x, raw_y, raw_z);
|
||||||
|
data.acceleration[motion::X_AXIS] = raw_x * scale;
|
||||||
|
data.acceleration[motion::Y_AXIS] = raw_y * scale;
|
||||||
|
data.acceleration[motion::Z_AXIS] = raw_z * scale;
|
||||||
|
|
||||||
|
scale = GYRO_SCALE[this->gyro_range_ >> 4];
|
||||||
|
raw_x = encode_uint16(raw_data[GYR_OFFS + 1], raw_data[GYR_OFFS + 0]);
|
||||||
|
raw_y = encode_uint16(raw_data[GYR_OFFS + 3], raw_data[GYR_OFFS + 2]);
|
||||||
|
raw_z = encode_uint16(raw_data[GYR_OFFS + 5], raw_data[GYR_OFFS + 4]);
|
||||||
|
ESP_LOGV(TAG, "Read raw gyro data: %d, %d, %d", raw_x, raw_y, raw_z);
|
||||||
|
data.angular_rate[motion::X_AXIS] = raw_x * scale;
|
||||||
|
data.angular_rate[motion::Y_AXIS] = raw_y * scale;
|
||||||
|
data.angular_rate[motion::Z_AXIS] = raw_z * scale;
|
||||||
|
|
||||||
|
if (this->temperature_callback_.empty())
|
||||||
|
return true;
|
||||||
|
// Temperature: signed 16-bit, °C = raw / 256
|
||||||
|
int16_t raw_t = (int16_t) ((raw_data[TEMP_OFFS + 1] << 8) | raw_data[TEMP_OFFS + 0]);
|
||||||
|
this->temperature_callback_.call(raw_t / 256.0f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome::qmi8658
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/motion/motion_component.h"
|
||||||
|
#include "esphome/components/i2c/i2c.h"
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
|
namespace esphome::qmi8658 {
|
||||||
|
|
||||||
|
// Register map
|
||||||
|
static constexpr uint8_t QMI8658_REG_WHO_AM_I = 0x00;
|
||||||
|
static constexpr uint8_t QMI8658_REG_REVISION = 0x01;
|
||||||
|
static constexpr uint8_t QMI8658_REG_CTRL1 = 0x02; // serial interface / auto-increment
|
||||||
|
static constexpr uint8_t QMI8658_REG_CTRL2 = 0x03; // accelerometer ODR / range
|
||||||
|
static constexpr uint8_t QMI8658_REG_CTRL3 = 0x04; // gyroscope ODR / range
|
||||||
|
static constexpr uint8_t QMI8658_REG_CTRL5 = 0x06; // low-pass filter
|
||||||
|
static constexpr uint8_t QMI8658_REG_CTRL7 = 0x08; // sensor enable
|
||||||
|
static constexpr uint8_t QMI8658_REG_STATUS0 = 0x2E;
|
||||||
|
static constexpr uint8_t QMI8658_REG_TEMP_BASE = 0x33; // start of the data block
|
||||||
|
static constexpr uint8_t QMI8658_REG_TEMP_L = 0x33; // Low byte of temperature
|
||||||
|
static constexpr uint8_t QMI8658_REG_AX_L = 0x35;
|
||||||
|
static constexpr uint8_t QMI8658_REG_GX_L = 0x3B;
|
||||||
|
static constexpr uint8_t QMI8658_REG_RESET = 0x60;
|
||||||
|
|
||||||
|
// One contiguous read covers temperature (2) + accel (6) + gyro (6) starting at TEMP_L.
|
||||||
|
static constexpr uint8_t REG_READ_LEN = QMI8658_REG_GX_L + 6 - QMI8658_REG_TEMP_BASE; // 0x41 - 0x33 = 14
|
||||||
|
static constexpr uint8_t TEMP_OFFS = QMI8658_REG_TEMP_L - QMI8658_REG_TEMP_BASE; // 0
|
||||||
|
static constexpr uint8_t ACC_OFFS = QMI8658_REG_AX_L - QMI8658_REG_TEMP_BASE; // 2
|
||||||
|
static constexpr uint8_t GYR_OFFS = QMI8658_REG_GX_L - QMI8658_REG_TEMP_BASE; // 8
|
||||||
|
|
||||||
|
static constexpr uint8_t QMI8658_WHO_AM_I_VALUE = 0x05;
|
||||||
|
static constexpr uint8_t QMI8658_RESET_CMD = 0xB0;
|
||||||
|
// CTRL1: bit6 ADDR_AI (register address auto-increment); little-endian, 4-wire SPI
|
||||||
|
static constexpr uint8_t QMI8658_CTRL1_VALUE = 0x40;
|
||||||
|
// CTRL7: aEN (bit0) | gEN (bit1)
|
||||||
|
static constexpr uint8_t QMI8658_CTRL7_ACC_EN = 0x01;
|
||||||
|
static constexpr uint8_t QMI8658_CTRL7_GYR_EN = 0x02;
|
||||||
|
|
||||||
|
// Accelerometer range options (CTRL2 bits 6:4)
|
||||||
|
enum QMI8658AccelRange : uint8_t {
|
||||||
|
QMI8658_ACCEL_RANGE_2G = 0x00,
|
||||||
|
QMI8658_ACCEL_RANGE_4G = 0x10,
|
||||||
|
QMI8658_ACCEL_RANGE_8G = 0x20,
|
||||||
|
QMI8658_ACCEL_RANGE_16G = 0x30,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Accelerometer ODR options (CTRL2 bits 3:0)
|
||||||
|
enum QMI8658AccelODR : uint8_t {
|
||||||
|
QMI8658_ACCEL_ODR_8000 = 0x00,
|
||||||
|
QMI8658_ACCEL_ODR_4000 = 0x01,
|
||||||
|
QMI8658_ACCEL_ODR_2000 = 0x02,
|
||||||
|
QMI8658_ACCEL_ODR_1000 = 0x03,
|
||||||
|
QMI8658_ACCEL_ODR_500 = 0x04,
|
||||||
|
QMI8658_ACCEL_ODR_250 = 0x05,
|
||||||
|
QMI8658_ACCEL_ODR_125 = 0x06,
|
||||||
|
QMI8658_ACCEL_ODR_62_5 = 0x07,
|
||||||
|
QMI8658_ACCEL_ODR_31_25 = 0x08,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gyroscope range options (CTRL3 bits 6:4)
|
||||||
|
enum QMI8658GyroRange : uint8_t {
|
||||||
|
QMI8658_GYRO_RANGE_16 = 0x00,
|
||||||
|
QMI8658_GYRO_RANGE_32 = 0x10,
|
||||||
|
QMI8658_GYRO_RANGE_64 = 0x20,
|
||||||
|
QMI8658_GYRO_RANGE_128 = 0x30,
|
||||||
|
QMI8658_GYRO_RANGE_256 = 0x40,
|
||||||
|
QMI8658_GYRO_RANGE_512 = 0x50,
|
||||||
|
QMI8658_GYRO_RANGE_1024 = 0x60,
|
||||||
|
QMI8658_GYRO_RANGE_2048 = 0x70,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gyroscope ODR options (CTRL3 bits 3:0)
|
||||||
|
enum QMI8658GyroODR : uint8_t {
|
||||||
|
QMI8658_GYRO_ODR_8000 = 0x00,
|
||||||
|
QMI8658_GYRO_ODR_4000 = 0x01,
|
||||||
|
QMI8658_GYRO_ODR_2000 = 0x02,
|
||||||
|
QMI8658_GYRO_ODR_1000 = 0x03,
|
||||||
|
QMI8658_GYRO_ODR_500 = 0x04,
|
||||||
|
QMI8658_GYRO_ODR_250 = 0x05,
|
||||||
|
QMI8658_GYRO_ODR_125 = 0x06,
|
||||||
|
QMI8658_GYRO_ODR_62_5 = 0x07,
|
||||||
|
QMI8658_GYRO_ODR_31_25 = 0x08,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main component class
|
||||||
|
class QMI8658Component : public motion::MotionComponent, public i2c::I2CDevice {
|
||||||
|
public:
|
||||||
|
// Lifecycle
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||||
|
|
||||||
|
// Configuration setters
|
||||||
|
void set_accel_range(QMI8658AccelRange r) { this->accel_range_ = r; }
|
||||||
|
void set_accel_odr(QMI8658AccelODR o) { this->accel_odr_ = o; }
|
||||||
|
void set_gyro_range(QMI8658GyroRange r) { this->gyro_range_ = r; }
|
||||||
|
void set_gyro_odr(QMI8658GyroODR o) { this->gyro_odr_ = o; }
|
||||||
|
template<typename F> void add_temperature_listener(F &&cb) { this->temperature_callback_.add(std::forward<F>(cb)); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool update_data(motion::MotionData &data) override;
|
||||||
|
|
||||||
|
// Config
|
||||||
|
QMI8658AccelRange accel_range_{QMI8658_ACCEL_RANGE_4G};
|
||||||
|
QMI8658AccelODR accel_odr_{QMI8658_ACCEL_ODR_1000};
|
||||||
|
QMI8658GyroRange gyro_range_{QMI8658_GYRO_RANGE_2048};
|
||||||
|
QMI8658GyroODR gyro_odr_{QMI8658_GYRO_ODR_1000};
|
||||||
|
|
||||||
|
LazyCallbackManager<void(float)> temperature_callback_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace esphome::qmi8658
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# YAML config keys
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import sensor
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_TEMPERATURE,
|
||||||
|
CONF_TYPE,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
ICON_THERMOMETER,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
UNIT_CELSIUS,
|
||||||
|
)
|
||||||
|
from esphome.cpp_generator import MockObj
|
||||||
|
|
||||||
|
from . import CONF_QMI8658_ID, QMI8658Component
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = sensor.sensor_schema(
|
||||||
|
unit_of_measurement=UNIT_CELSIUS,
|
||||||
|
icon=ICON_THERMOMETER,
|
||||||
|
accuracy_decimals=2,
|
||||||
|
state_class=STATE_CLASS_MEASUREMENT,
|
||||||
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
|
).extend(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_TYPE): cv.one_of(CONF_TEMPERATURE),
|
||||||
|
cv.GenerateID(CONF_QMI8658_ID): cv.use_id(QMI8658Component),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await sensor.new_sensor(config)
|
||||||
|
parent = await cg.get_variable(config[CONF_QMI8658_ID])
|
||||||
|
data = MockObj("data")
|
||||||
|
value_lambda = await cg.process_lambda(
|
||||||
|
var.publish_state(data),
|
||||||
|
[(cg.float_, str(data))],
|
||||||
|
)
|
||||||
|
cg.add(parent.add_temperature_listener(value_lambda))
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
sensor:
|
||||||
|
- platform: qmi8658
|
||||||
|
name: "QMI8658 Temperature"
|
||||||
|
|
||||||
|
- platform: motion
|
||||||
|
type: acceleration_x
|
||||||
|
name: "Accel X"
|
||||||
|
accuracy_decimals: 4
|
||||||
|
filters:
|
||||||
|
- sliding_window_moving_average:
|
||||||
|
window_size: 4
|
||||||
|
send_every: 1
|
||||||
|
- platform: motion
|
||||||
|
type: acceleration_y
|
||||||
|
name: "Accel Y"
|
||||||
|
accuracy_decimals: 4
|
||||||
|
- platform: motion
|
||||||
|
type: acceleration_z
|
||||||
|
name: "Accel Z"
|
||||||
|
accuracy_decimals: 4
|
||||||
|
|
||||||
|
# Gyroscope axes (unit: °/s)
|
||||||
|
- platform: motion
|
||||||
|
type: gyroscope_x
|
||||||
|
name: "Gyro X"
|
||||||
|
- platform: motion
|
||||||
|
type: gyroscope_y
|
||||||
|
name: "Gyro Y"
|
||||||
|
- platform: motion
|
||||||
|
type: gyroscope_z
|
||||||
|
name: "Gyro Z"
|
||||||
|
|
||||||
|
- platform: motion
|
||||||
|
type: angular_rate_x
|
||||||
|
name: "Angular Rate X"
|
||||||
|
- platform: motion
|
||||||
|
type: angular_rate_y
|
||||||
|
name: "Angular Rate Y"
|
||||||
|
- platform: motion
|
||||||
|
type: angular_rate_z
|
||||||
|
name: "Angular Rate Z"
|
||||||
|
|
||||||
|
- platform: motion
|
||||||
|
type: pitch
|
||||||
|
name: "Pitch"
|
||||||
|
- platform: motion
|
||||||
|
type: roll
|
||||||
|
name: "Roll"
|
||||||
|
|
||||||
|
motion:
|
||||||
|
- platform: qmi8658
|
||||||
|
# Accelerometer full-scale range: 2G | 4G | 8G | 16G
|
||||||
|
accelerometer_range: 4G
|
||||||
|
|
||||||
|
# Accelerometer output data rate: 31_25HZ | 62_5HZ | 125HZ | 250HZ |
|
||||||
|
# 500HZ | 1000HZ | 2000HZ | 4000HZ | 8000HZ
|
||||||
|
accelerometer_odr: 1000HZ
|
||||||
|
|
||||||
|
# Gyroscope full-scale range: 16DPS | 32DPS | 64DPS | 128DPS |
|
||||||
|
# 256DPS | 512DPS | 1024DPS | 2048DPS
|
||||||
|
gyroscope_range: 2048DPS
|
||||||
|
|
||||||
|
# Gyroscope output data rate: 31_25HZ | 62_5HZ | 125HZ | 250HZ |
|
||||||
|
# 500HZ | 1000HZ | 2000HZ | 4000HZ | 8000HZ
|
||||||
|
gyroscope_odr: 1000HZ
|
||||||
|
axis_map:
|
||||||
|
x: y
|
||||||
|
y: x
|
||||||
|
z: -z
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
packages:
|
||||||
|
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
packages:
|
||||||
|
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
|
||||||
|
|
||||||
|
<<: !include common.yaml
|
||||||
Reference in New Issue
Block a user