ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
motion_component.h
Go to the documentation of this file.
1#pragma once
2
7#include <array>
8#include <cmath>
9#include <numbers> // required for generated lambda code
10
11namespace esphome::motion {
12
13// ---Data class
14
15struct MotionData {
16 float acceleration[3]{NAN, NAN, NAN};
17 float angular_rate[3]{NAN, NAN, NAN};
18 // TODO - compass
19};
20
21// indices into data arrays
22static constexpr uint8_t X_AXIS = 0;
23static constexpr uint8_t Y_AXIS = 1;
24static constexpr uint8_t Z_AXIS = 2;
25
26// Persisted calibration. `base_hash` ties the stored matrix to the build-time
27// (axis_map / transform_matrix) base; if the base changes the saved calibration
28// is ignored. Stored under a stable, ID-derived key so it overwrites in place.
33
34// Main component class
36 public:
37 // Lifecycle
38 void setup() override;
39 void update() override;
40 void dump_config() override;
41 float get_setup_priority() const override { return setup_priority::DATA; }
42
43 void set_matrix(const std::array<float, 9> &m) {
44 memcpy(this->base_matrix_, m.data(), sizeof(this->base_matrix_));
45 memcpy(this->matrix_, m.data(), sizeof(this->matrix_));
46 }
47 void set_calibration_key(uint32_t key) { this->pref_key_ = key; }
48
50 bool calibrate_level();
52 bool calibrate_heading();
54 bool save_calibration();
56 void clear_calibration();
57
58 template<typename F> void add_listener(F &&cb) { this->motion_data_callback_.add(std::forward<F>(cb)); }
59
60 protected:
61 // platforms must implement this method to update raw data.
62 virtual bool update_data(MotionData &data) = 0;
63
64 // for mapping axes
65 float matrix_[9]{
66 1, 0, 0, 0, 1, 0, 0, 0, 1,
67 };
68 // build-time base (axis_map / transform_matrix); used to detect config changes
69 // and to restore on clear_calibration().
70 float base_matrix_[9]{
71 1, 0, 0, 0, 1, 0, 0, 0, 1,
72 };
73
74 void map_axes_(float output[3], const float input[3]) const {
75 output[0] = input[X_AXIS] * this->matrix_[0] + input[Y_AXIS] * this->matrix_[1] + input[Z_AXIS] * this->matrix_[2];
76 output[1] = input[X_AXIS] * this->matrix_[3] + input[Y_AXIS] * this->matrix_[4] + input[Z_AXIS] * this->matrix_[5];
77 output[2] = input[X_AXIS] * this->matrix_[6] + input[Y_AXIS] * this->matrix_[7] + input[Z_AXIS] * this->matrix_[8];
78 }
79
82 uint32_t base_hash_{0}; // hash of base_matrix_, captured in setup()
84};
85
86// --- Actions ---
87
88template<typename... Ts> class CalibrateLevelAction : public Action<Ts...> {
89 public:
90 explicit CalibrateLevelAction(MotionComponent *parent) : parent_(parent) {}
91 void set_save(bool save) { this->save_ = save; }
94
95 protected:
96 void play(const Ts &...) override {
97 if (this->parent_->calibrate_level()) {
98 // if not saving, calibration success is enough. If save required only report success after that succeeds too.
99 if (!this->save_ || this->parent_->save_calibration()) {
101 return;
102 }
103 }
104 this->error_trigger_.trigger();
105 }
106
110 bool save_{false};
111};
112
113template<typename... Ts> class CalibrateHeadingAction : public Action<Ts...> {
114 public:
115 explicit CalibrateHeadingAction(MotionComponent *parent) : parent_(parent) {}
116 void set_save(bool save) { this->save_ = save; }
119
120 protected:
121 void play(const Ts &...) override {
122 if (this->parent_->calibrate_heading()) {
123 // if not saving, calibration success is enough. If save required only report success after that succeeds too.
124 if (!this->save_ || this->parent_->save_calibration()) {
126 return;
127 }
128 }
129 this->error_trigger_.trigger();
130 }
131
135 bool save_{false};
136};
137
138template<typename... Ts> class ClearCalibrationAction : public Action<Ts...> {
139 public:
140 explicit ClearCalibrationAction(MotionComponent *parent) : parent_(parent) {}
141 void set_save(bool save) { this->save_ = save; }
142
143 protected:
144 void play(const Ts &...) override {
145 this->parent_->clear_calibration();
146 if (this->save_)
147 this->parent_->save_calibration();
148 }
149
151 bool save_{false};
152};
153
154} // namespace esphome::motion
uint8_t m
Definition bl0906.h:1
This class simplifies creating components that periodically check a state.
Definition component.h:585
void trigger(const Ts &...x) ESPHOME_ALWAYS_INLINE
Inform the parent automation that the event has triggered.
Definition automation.h:461
CalibrateHeadingAction(MotionComponent *parent)
CalibrateLevelAction(MotionComponent *parent)
void play(const Ts &...) override
ClearCalibrationAction(MotionComponent *parent)
LazyCallbackManager< void(MotionData &)> motion_data_callback_
void map_axes_(float output[3], const float input[3]) const
bool calibrate_heading()
Assuming Y-axis rotation only, correct the heading so X/Y align correctly.
float get_setup_priority() const override
void set_matrix(const std::array< float, 9 > &m)
virtual bool update_data(MotionData &data)=0
bool calibrate_level()
Calibrate the matrix so the current reading maps to [0, 0, 1] (device flat).
void clear_calibration()
Restore the build-time (axis_map / transform_matrix) base, discarding calibration.
bool save_calibration()
Save the current matrix to NVS.
struct esphome::motion::CalibrationPref PACKED
constexpr float DATA
For components that import data from directly connected sensors like DHT.
Definition component.h:43
static void uint32_t