mirror of
https://github.com/Threnklyn/esphome-dev.git
synced 2026-06-01 10:38:27 +02:00
feat: add AS5600 component/sensor (#5174)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_MAGNET,
|
||||
ICON_ROTATE_RIGHT,
|
||||
CONF_GAIN,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
CONF_MAGNITUDE,
|
||||
CONF_STATUS,
|
||||
CONF_POSITION,
|
||||
)
|
||||
from .. import as5600_ns, AS5600Component
|
||||
|
||||
CODEOWNERS = ["@ammmze"]
|
||||
DEPENDENCIES = ["as5600"]
|
||||
|
||||
AS5600Sensor = as5600_ns.class_("AS5600Sensor", sensor.Sensor, cg.PollingComponent)
|
||||
|
||||
CONF_ANGLE = "angle"
|
||||
CONF_RAW_ANGLE = "raw_angle"
|
||||
CONF_RAW_POSITION = "raw_position"
|
||||
CONF_WATCHDOG = "watchdog"
|
||||
CONF_POWER_MODE = "power_mode"
|
||||
CONF_SLOW_FILTER = "slow_filter"
|
||||
CONF_FAST_FILTER = "fast_filter"
|
||||
CONF_PWM_FREQUENCY = "pwm_frequency"
|
||||
CONF_BURN_COUNT = "burn_count"
|
||||
CONF_START_POSITION = "start_position"
|
||||
CONF_END_POSITION = "end_position"
|
||||
CONF_OUT_OF_RANGE_MODE = "out_of_range_mode"
|
||||
|
||||
OutOfRangeMode = as5600_ns.enum("OutRangeMode")
|
||||
OUT_OF_RANGE_MODES = {
|
||||
"MIN_MAX": OutOfRangeMode.OUT_RANGE_MODE_MIN_MAX,
|
||||
"NAN": OutOfRangeMode.OUT_RANGE_MODE_NAN,
|
||||
}
|
||||
|
||||
|
||||
CONF_AS5600_ID = "as5600_id"
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
AS5600Sensor,
|
||||
accuracy_decimals=0,
|
||||
icon=ICON_ROTATE_RIGHT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(CONF_AS5600_ID): cv.use_id(AS5600Component),
|
||||
cv.Optional(CONF_OUT_OF_RANGE_MODE): cv.enum(
|
||||
OUT_OF_RANGE_MODES, upper=True, space="_"
|
||||
),
|
||||
cv.Optional(CONF_RAW_POSITION): sensor.sensor_schema(
|
||||
accuracy_decimals=0,
|
||||
icon=ICON_ROTATE_RIGHT,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_GAIN): sensor.sensor_schema(
|
||||
accuracy_decimals=0,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
),
|
||||
cv.Optional(CONF_MAGNITUDE): sensor.sensor_schema(
|
||||
accuracy_decimals=0,
|
||||
icon=ICON_MAGNET,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
),
|
||||
cv.Optional(CONF_STATUS): sensor.sensor_schema(
|
||||
accuracy_decimals=0,
|
||||
icon=ICON_MAGNET,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_parented(var, config[CONF_AS5600_ID])
|
||||
await cg.register_component(var, config)
|
||||
await sensor.register_sensor(var, config)
|
||||
|
||||
if out_of_range_mode_config := config.get(CONF_OUT_OF_RANGE_MODE):
|
||||
cg.add(var.set_out_of_range_mode(out_of_range_mode_config))
|
||||
|
||||
if angle_config := config.get(CONF_ANGLE):
|
||||
sens = await sensor.new_sensor(angle_config)
|
||||
cg.add(var.set_angle_sensor(sens))
|
||||
|
||||
if raw_angle_config := config.get(CONF_RAW_ANGLE):
|
||||
sens = await sensor.new_sensor(raw_angle_config)
|
||||
cg.add(var.set_raw_angle_sensor(sens))
|
||||
|
||||
if position_config := config.get(CONF_POSITION):
|
||||
sens = await sensor.new_sensor(position_config)
|
||||
cg.add(var.set_position_sensor(sens))
|
||||
|
||||
if raw_position_config := config.get(CONF_RAW_POSITION):
|
||||
sens = await sensor.new_sensor(raw_position_config)
|
||||
cg.add(var.set_raw_position_sensor(sens))
|
||||
|
||||
if gain_config := config.get(CONF_GAIN):
|
||||
sens = await sensor.new_sensor(gain_config)
|
||||
cg.add(var.set_gain_sensor(sens))
|
||||
|
||||
if magnitude_config := config.get(CONF_MAGNITUDE):
|
||||
sens = await sensor.new_sensor(magnitude_config)
|
||||
cg.add(var.set_magnitude_sensor(sens))
|
||||
|
||||
if status_config := config.get(CONF_STATUS):
|
||||
sens = await sensor.new_sensor(status_config)
|
||||
cg.add(var.set_status_sensor(sens))
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "as5600_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace as5600 {
|
||||
|
||||
static const char *const TAG = "as5600.sensor";
|
||||
|
||||
// Configuration registers
|
||||
static const uint8_t REGISTER_ZMCO = 0x00; // 8 bytes / R
|
||||
static const uint8_t REGISTER_ZPOS = 0x01; // 16 bytes / RW
|
||||
static const uint8_t REGISTER_MPOS = 0x03; // 16 bytes / RW
|
||||
static const uint8_t REGISTER_MANG = 0x05; // 16 bytes / RW
|
||||
static const uint8_t REGISTER_CONF = 0x07; // 16 bytes / RW
|
||||
|
||||
// Output registers
|
||||
static const uint8_t REGISTER_ANGLE_RAW = 0x0C; // 16 bytes / R
|
||||
static const uint8_t REGISTER_ANGLE = 0x0E; // 16 bytes / R
|
||||
|
||||
// Status registers
|
||||
static const uint8_t REGISTER_STATUS = 0x0B; // 8 bytes / R
|
||||
static const uint8_t REGISTER_AGC = 0x1A; // 8 bytes / R
|
||||
static const uint8_t REGISTER_MAGNITUDE = 0x1B; // 16 bytes / R
|
||||
|
||||
float AS5600Sensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
void AS5600Sensor::dump_config() {
|
||||
LOG_SENSOR("", "AS5600 Sensor", this);
|
||||
ESP_LOGCONFIG(TAG, " Out of Range Mode: %u", this->out_of_range_mode_);
|
||||
if (this->angle_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Angle Sensor", this->angle_sensor_);
|
||||
}
|
||||
if (this->raw_angle_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Raw Angle Sensor", this->raw_angle_sensor_);
|
||||
}
|
||||
if (this->position_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Position Sensor", this->position_sensor_);
|
||||
}
|
||||
if (this->raw_position_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Raw Position Sensor", this->raw_position_sensor_);
|
||||
}
|
||||
if (this->gain_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Gain Sensor", this->gain_sensor_);
|
||||
}
|
||||
if (this->magnitude_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Magnitude Sensor", this->magnitude_sensor_);
|
||||
}
|
||||
if (this->status_sensor_ != nullptr) {
|
||||
LOG_SENSOR(" ", "Status Sensor", this->status_sensor_);
|
||||
}
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void AS5600Sensor::update() {
|
||||
if (this->gain_sensor_ != nullptr) {
|
||||
this->gain_sensor_->publish_state(this->parent_->reg(REGISTER_AGC).get());
|
||||
}
|
||||
|
||||
if (this->magnitude_sensor_ != nullptr) {
|
||||
uint16_t value = 0;
|
||||
this->parent_->read_byte_16(REGISTER_MAGNITUDE, &value);
|
||||
this->magnitude_sensor_->publish_state(value);
|
||||
}
|
||||
|
||||
// 2 = magnet not detected
|
||||
// 4 = magnet just right
|
||||
// 5 = magnet too strong
|
||||
// 6 = magnet too weak
|
||||
if (this->status_sensor_ != nullptr) {
|
||||
this->status_sensor_->publish_state(this->parent_->read_magnet_status());
|
||||
}
|
||||
|
||||
auto pos = this->parent_->read_position();
|
||||
if (!pos.has_value()) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
auto raw = this->parent_->read_raw_position();
|
||||
if (!raw.has_value()) {
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->out_of_range_mode_ == OUT_RANGE_MODE_NAN) {
|
||||
this->publish_state(this->parent_->in_range(raw.value()) ? pos.value() : NAN);
|
||||
} else {
|
||||
this->publish_state(pos.value());
|
||||
}
|
||||
|
||||
if (this->raw_position_sensor_ != nullptr) {
|
||||
this->raw_position_sensor_->publish_state(raw.value());
|
||||
}
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
} // namespace as5600
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/as5600/as5600.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace as5600 {
|
||||
|
||||
class AS5600Sensor : public PollingComponent, public Parented<AS5600Component>, public sensor::Sensor {
|
||||
public:
|
||||
void update() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
void set_angle_sensor(sensor::Sensor *angle_sensor) { this->angle_sensor_ = angle_sensor; }
|
||||
void set_raw_angle_sensor(sensor::Sensor *raw_angle_sensor) { this->raw_angle_sensor_ = raw_angle_sensor; }
|
||||
void set_position_sensor(sensor::Sensor *position_sensor) { this->position_sensor_ = position_sensor; }
|
||||
void set_raw_position_sensor(sensor::Sensor *raw_position_sensor) {
|
||||
this->raw_position_sensor_ = raw_position_sensor;
|
||||
}
|
||||
void set_gain_sensor(sensor::Sensor *gain_sensor) { this->gain_sensor_ = gain_sensor; }
|
||||
void set_magnitude_sensor(sensor::Sensor *magnitude_sensor) { this->magnitude_sensor_ = magnitude_sensor; }
|
||||
void set_status_sensor(sensor::Sensor *status_sensor) { this->status_sensor_ = status_sensor; }
|
||||
void set_out_of_range_mode(OutRangeMode oor_mode) { this->out_of_range_mode_ = oor_mode; }
|
||||
OutRangeMode get_out_of_range_mode() { return this->out_of_range_mode_; }
|
||||
|
||||
protected:
|
||||
sensor::Sensor *angle_sensor_{nullptr};
|
||||
sensor::Sensor *raw_angle_sensor_{nullptr};
|
||||
sensor::Sensor *position_sensor_{nullptr};
|
||||
sensor::Sensor *raw_position_sensor_{nullptr};
|
||||
sensor::Sensor *gain_sensor_{nullptr};
|
||||
sensor::Sensor *magnitude_sensor_{nullptr};
|
||||
sensor::Sensor *status_sensor_{nullptr};
|
||||
OutRangeMode out_of_range_mode_{OUT_RANGE_MODE_MIN_MAX};
|
||||
};
|
||||
|
||||
} // namespace as5600
|
||||
} // namespace esphome
|
||||
Reference in New Issue
Block a user