[motion] Use register_apply_action for motion.clear_calibration (#19700)

This commit is contained in:
J. Nick Koston
2026-09-25 20:32:57 -04:00
committed by GitHub
parent 447348d617
commit 01a2aaef08
6 changed files with 20 additions and 68 deletions
+2 -10
View File
@@ -25,7 +25,6 @@ CONF_TRANSFORM_MATRIX = "transform_matrix"
CalibrateLevelAction = motion_ns.class_("CalibrateLevelAction", automation.Action)
CalibrateHeadingAction = motion_ns.class_("CalibrateHeadingAction", automation.Action)
ClearCalibrationAction = motion_ns.class_("ClearCalibrationAction", automation.Action)
KEY_ACCELEROMETER = "accelerometer"
KEY_GYROSCOPE = "gyroscope"
@@ -207,15 +206,8 @@ CLEAR_ACTION_SCHEMA = cv.Schema(
)
@automation.register_action(
automation.register_apply_action(
"motion.clear_calibration",
ClearCalibrationAction,
CLEAR_ACTION_SCHEMA,
synchronous=True,
automation.ApplyField(CONF_SAVE, "clear_calibration", cg.bool_),
)
async def clear_calibration_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, parent)
if config.get(CONF_SAVE):
cg.add(var.set_save(True))
return var
@@ -56,10 +56,13 @@ bool MotionComponent::save_calibration() {
ESP_LOGW(TAG, "Calibration save failed");
return false;
}
void MotionComponent::clear_calibration() {
void MotionComponent::clear_calibration(bool save) {
memcpy(this->matrix_, this->base_matrix_, sizeof(this->matrix_));
ESP_LOGI(TAG, "Calibration reset to build-time matrix");
log_matrix(this->matrix_);
if (save) {
this->save_calibration();
}
}
void MotionComponent::update() {
if (this->is_failed())
+3 -18
View File
@@ -52,8 +52,9 @@ class MotionComponent : public PollingComponent {
bool calibrate_heading();
/// Save the current matrix to NVS.
bool save_calibration();
/// Restore the build-time (axis_map / transform_matrix) base, discarding calibration.
void clear_calibration();
/// Restore the build-time (axis_map / transform_matrix) base, discarding calibration,
/// and persist that base when `save` is set.
void clear_calibration(bool save = false);
template<typename F> void add_listener(F &&cb) { this->motion_data_callback_.add(std::forward<F>(cb)); }
@@ -135,20 +136,4 @@ template<typename... Ts> class CalibrateHeadingAction final : public Action<Ts..
bool save_{false};
};
template<typename... Ts> class ClearCalibrationAction final : public Action<Ts...> {
public:
explicit ClearCalibrationAction(MotionComponent *parent) : parent_(parent) {}
void set_save(bool save) { this->save_ = save; }
protected:
void play(const Ts &...) override {
this->parent_->clear_calibration();
if (this->save_)
this->parent_->save_calibration();
}
MotionComponent *parent_;
bool save_{false};
};
} // namespace esphome::motion
@@ -18,7 +18,6 @@ from esphome.components.motion import (
_build_calibrate_action,
_transform_matrix,
_validate_matrix_options,
clear_calibration_to_code,
)
from esphome.components.motion.sensor import (
_ACCELERATIONS,
@@ -785,44 +784,6 @@ class TestClearActionSchema:
assert result[CONF_SAVE] is False
@pytest.fixture
def mock_clear_codegen():
"""Mock cg functions used by clear_calibration_to_code."""
mock_var = MagicMock()
mock_parent = MagicMock()
with (
patch(
"esphome.components.motion.cg.get_variable",
new_callable=AsyncMock,
return_value=mock_parent,
),
patch(
"esphome.components.motion.cg.new_Pvariable",
return_value=mock_var,
) as mock_new_pvar,
patch("esphome.components.motion.cg.add") as mock_add,
):
yield {"new_Pvariable": mock_new_pvar, "add": mock_add, "var": mock_var}
@pytest.mark.asyncio
async def test_clear_action_without_save(mock_clear_codegen):
"""With save=False, set_save should not be emitted."""
config = {CONF_ID: MagicMock(), CONF_SAVE: False}
result = await clear_calibration_to_code(config, MagicMock(), MagicMock(), [])
assert result is mock_clear_codegen["var"]
mock_clear_codegen["add"].assert_not_called()
@pytest.mark.asyncio
async def test_clear_action_with_save(mock_clear_codegen):
"""With save=True, set_save(True) should be emitted exactly once."""
config = {CONF_ID: MagicMock(), CONF_SAVE: True}
await clear_calibration_to_code(config, MagicMock(), MagicMock(), [])
mock_clear_codegen["var"].set_save.assert_called_once_with(True)
mock_clear_codegen["add"].assert_called_once()
# --- Calibration persistence invalidation ---
#
# The C++ side stores a hash of the build-time base matrix alongside the saved
@@ -0,0 +1,7 @@
button:
- platform: template
name: Clear motion calibration
on_press:
- motion.clear_calibration:
- motion.clear_calibration:
save: true
@@ -0,0 +1,4 @@
packages:
i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml
qmi8658: !include common.yaml
actions: !include common-actions.yaml