mirror of
https://github.com/esphome/esphome.git
synced 2024-12-25 06:54:52 +01:00
Implement sensor component for MMC5983 (#5361)
This commit is contained in:
parent
aba3cd557a
commit
af62c2d9cf
10 changed files with 249 additions and 9 deletions
|
@ -186,6 +186,7 @@ esphome/components/mitsubishi/* @RubyBailey
|
|||
esphome/components/mlx90393/* @functionpointer
|
||||
esphome/components/mlx90614/* @jesserockz
|
||||
esphome/components/mmc5603/* @benhoff
|
||||
esphome/components/mmc5983/* @agoode
|
||||
esphome/components/modbus_controller/* @martgras
|
||||
esphome/components/modbus_controller/binary_sensor/* @martgras
|
||||
esphome/components/modbus_controller/number/* @martgras
|
||||
|
|
|
@ -3,6 +3,9 @@ import esphome.config_validation as cv
|
|||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_FIELD_STRENGTH_X,
|
||||
CONF_FIELD_STRENGTH_Y,
|
||||
CONF_FIELD_STRENGTH_Z,
|
||||
CONF_ID,
|
||||
CONF_OVERSAMPLING,
|
||||
CONF_RANGE,
|
||||
|
@ -18,9 +21,6 @@ DEPENDENCIES = ["i2c"]
|
|||
|
||||
hmc5883l_ns = cg.esphome_ns.namespace("hmc5883l")
|
||||
|
||||
CONF_FIELD_STRENGTH_X = "field_strength_x"
|
||||
CONF_FIELD_STRENGTH_Y = "field_strength_y"
|
||||
CONF_FIELD_STRENGTH_Z = "field_strength_z"
|
||||
CONF_HEADING = "heading"
|
||||
|
||||
HMC5883LComponent = hmc5883l_ns.class_(
|
||||
|
|
|
@ -3,6 +3,9 @@ import esphome.config_validation as cv
|
|||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_FIELD_STRENGTH_X,
|
||||
CONF_FIELD_STRENGTH_Y,
|
||||
CONF_FIELD_STRENGTH_Z,
|
||||
CONF_ID,
|
||||
ICON_MAGNET,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
|
@ -16,9 +19,6 @@ DEPENDENCIES = ["i2c"]
|
|||
|
||||
mmc5603_ns = cg.esphome_ns.namespace("mmc5603")
|
||||
|
||||
CONF_FIELD_STRENGTH_X = "field_strength_x"
|
||||
CONF_FIELD_STRENGTH_Y = "field_strength_y"
|
||||
CONF_FIELD_STRENGTH_Z = "field_strength_z"
|
||||
CONF_HEADING = "heading"
|
||||
|
||||
MMC5603Component = mmc5603_ns.class_(
|
||||
|
|
1
esphome/components/mmc5983/__init__.py
Normal file
1
esphome/components/mmc5983/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
CODEOWNERS = ["@agoode"]
|
141
esphome/components/mmc5983/mmc5983.cpp
Normal file
141
esphome/components/mmc5983/mmc5983.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
// See https://github.com/sparkfun/SparkFun_MMC5983MA_Magnetometer_Arduino_Library/tree/main
|
||||
// for datasheets and an Arduino implementation.
|
||||
|
||||
#include "mmc5983.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mmc5983 {
|
||||
|
||||
static const char *const TAG = "mmc5983";
|
||||
|
||||
namespace {
|
||||
constexpr uint8_t IC0_ADDR = 0x09;
|
||||
constexpr uint8_t IC1_ADDR = 0x0a;
|
||||
constexpr uint8_t IC2_ADDR = 0x0b;
|
||||
constexpr uint8_t IC3_ADDR = 0x0c;
|
||||
constexpr uint8_t PRODUCT_ID_ADDR = 0x2f;
|
||||
|
||||
float convert_data_to_millitesla(uint8_t data_17_10, uint8_t data_9_2, uint8_t data_1_0) {
|
||||
int32_t counts = (data_17_10 << 10) | (data_9_2 << 2) | data_1_0;
|
||||
counts -= 131072; // "Null Field Output" from datasheet.
|
||||
|
||||
// Sensitivity is 16384 counts/gauss, which is 163840 counts/mT.
|
||||
return counts / 163840.0f;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void MMC5983Component::update() {
|
||||
// Schedule a SET/RESET. This will recalibrate the sensor.
|
||||
// We are supposed to be able to set this once, and have it automatically continue every reading, but
|
||||
// this does not appear to work in continuous mode, even with En_prd_set turned on in Internal Control 2.
|
||||
// Bit 5 = Auto_SR_en (automatic SET/RESET enable).
|
||||
const uint8_t ic0_value = 0b10000;
|
||||
i2c::ErrorCode err = this->write_register(IC0_ADDR, &ic0_value, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGW(TAG, "Writing Internal Control 0 failed with i2c error %d", err);
|
||||
this->status_set_warning();
|
||||
}
|
||||
|
||||
// Read out the data, 7 bytes starting from 0x00.
|
||||
uint8_t data[7];
|
||||
err = this->read_register(0x00, data, sizeof(data));
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGW(TAG, "Reading data failed with i2c error %d", err);
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
|
||||
// Unpack the data and publish to sensors.
|
||||
// Data is in this format:
|
||||
// data[0]: Xout[17:10]
|
||||
// data[1]: Xout[9:2]
|
||||
// data[2]: Yout[17:10]
|
||||
// data[3]: Yout[9:2]
|
||||
// data[4]: Zout[17:10]
|
||||
// data[5]: Zout[9:2]
|
||||
// data[6]: { Xout[1], Xout[0], Yout[1], Yout[0], Zout[1], Zout[0], 0, 0 }
|
||||
if (this->x_sensor_) {
|
||||
this->x_sensor_->publish_state(convert_data_to_millitesla(data[0], data[1], (data[6] & 0b11000000) >> 6));
|
||||
}
|
||||
if (this->y_sensor_) {
|
||||
this->y_sensor_->publish_state(convert_data_to_millitesla(data[2], data[3], (data[6] & 0b00110000) >> 4));
|
||||
}
|
||||
if (this->z_sensor_) {
|
||||
this->z_sensor_->publish_state(convert_data_to_millitesla(data[4], data[5], (data[6] & 0b00001100) >> 2));
|
||||
}
|
||||
}
|
||||
|
||||
void MMC5983Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up MMC5983...");
|
||||
|
||||
// Verify product id.
|
||||
const uint8_t mmc5983_product_id = 0x30;
|
||||
uint8_t id;
|
||||
i2c::ErrorCode err = this->read_register(PRODUCT_ID_ADDR, &id, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Reading product id failed with i2c error %d", err);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
if (id != mmc5983_product_id) {
|
||||
ESP_LOGE(TAG, "Product id 0x%02x does not match expected value 0x%02x", id, mmc5983_product_id);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize Internal Control registers to 0.
|
||||
// Internal Control 0.
|
||||
const uint8_t zero = 0;
|
||||
err = this->write_register(IC0_ADDR, &zero, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Initializing Internal Control 0 failed with i2c error %d", err);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
// Internal Control 1.
|
||||
err = this->write_register(IC1_ADDR, &zero, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Initializing Internal Control 1 failed with i2c error %d", err);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
// Internal Control 2.
|
||||
err = this->write_register(IC2_ADDR, &zero, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Initializing Internal Control 2 failed with i2c error %d", err);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
// Internal Control 3.
|
||||
err = this->write_register(IC3_ADDR, &zero, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Initializing Internal Control 3 failed with i2c error %d", err);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable continuous mode at 100 Hz, using Internal Control 2.
|
||||
// Bit 3 = Cmm_en (continuous mode enable).
|
||||
// Bit [2:0] = Cm_freq. 0b101 = 100 Hz, the fastest reading speed at Bandwidth=100 Hz.
|
||||
const uint8_t ic2_value = 0b00001101;
|
||||
err = this->write_register(IC2_ADDR, &ic2_value, 1);
|
||||
if (err != i2c::ErrorCode::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Writing Internal Control 2 failed with i2c error %d", err);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MMC5983Component::dump_config() {
|
||||
ESP_LOGD(TAG, "MMC5983:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
LOG_SENSOR(" ", "X", this->x_sensor_);
|
||||
LOG_SENSOR(" ", "Y", this->y_sensor_);
|
||||
LOG_SENSOR(" ", "Z", this->z_sensor_);
|
||||
}
|
||||
|
||||
float MMC5983Component::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
} // namespace mmc5983
|
||||
} // namespace esphome
|
28
esphome/components/mmc5983/mmc5983.h
Normal file
28
esphome/components/mmc5983/mmc5983.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace mmc5983 {
|
||||
|
||||
class MMC5983Component : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void update() override;
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
void set_x_sensor(sensor::Sensor *x_sensor) { x_sensor_ = x_sensor; }
|
||||
void set_y_sensor(sensor::Sensor *y_sensor) { y_sensor_ = y_sensor; }
|
||||
void set_z_sensor(sensor::Sensor *z_sensor) { z_sensor_ = z_sensor; }
|
||||
|
||||
protected:
|
||||
sensor::Sensor *x_sensor_{nullptr};
|
||||
sensor::Sensor *y_sensor_{nullptr};
|
||||
sensor::Sensor *z_sensor_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace mmc5983
|
||||
} // namespace esphome
|
55
esphome/components/mmc5983/sensor.py
Normal file
55
esphome/components/mmc5983/sensor.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_FIELD_STRENGTH_X,
|
||||
CONF_FIELD_STRENGTH_Y,
|
||||
CONF_FIELD_STRENGTH_Z,
|
||||
CONF_ID,
|
||||
ICON_MAGNET,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_MICROTESLA,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
mmc5983_ns = cg.esphome_ns.namespace("mmc5983")
|
||||
MMC5983Component = mmc5983_ns.class_(
|
||||
"MMC5983Component", cg.PollingComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
field_strength_schema = sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_MICROTESLA,
|
||||
icon=ICON_MAGNET,
|
||||
accuracy_decimals=4,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(MMC5983Component),
|
||||
cv.Optional(CONF_FIELD_STRENGTH_X): field_strength_schema,
|
||||
cv.Optional(CONF_FIELD_STRENGTH_Y): field_strength_schema,
|
||||
cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema,
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(i2c.i2c_device_schema(0x30))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
if x_config := config.get(CONF_FIELD_STRENGTH_X):
|
||||
sens = await sensor.new_sensor(x_config)
|
||||
cg.add(var.set_x_sensor(sens))
|
||||
if y_config := config.get(CONF_FIELD_STRENGTH_Y):
|
||||
sens = await sensor.new_sensor(y_config)
|
||||
cg.add(var.set_y_sensor(sens))
|
||||
if z_config := config.get(CONF_FIELD_STRENGTH_Z):
|
||||
sens = await sensor.new_sensor(z_config)
|
||||
cg.add(var.set_z_sensor(sens))
|
|
@ -3,6 +3,9 @@ import esphome.config_validation as cv
|
|||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_FIELD_STRENGTH_X,
|
||||
CONF_FIELD_STRENGTH_Y,
|
||||
CONF_FIELD_STRENGTH_Z,
|
||||
CONF_ID,
|
||||
CONF_OVERSAMPLING,
|
||||
CONF_RANGE,
|
||||
|
@ -18,9 +21,6 @@ DEPENDENCIES = ["i2c"]
|
|||
|
||||
qmc5883l_ns = cg.esphome_ns.namespace("qmc5883l")
|
||||
|
||||
CONF_FIELD_STRENGTH_X = "field_strength_x"
|
||||
CONF_FIELD_STRENGTH_Y = "field_strength_y"
|
||||
CONF_FIELD_STRENGTH_Z = "field_strength_z"
|
||||
CONF_HEADING = "heading"
|
||||
|
||||
QMC5883LComponent = qmc5883l_ns.class_(
|
||||
|
|
|
@ -265,6 +265,9 @@ CONF_FAN_ONLY_MODE = "fan_only_mode"
|
|||
CONF_FAN_WITH_COOLING = "fan_with_cooling"
|
||||
CONF_FAN_WITH_HEATING = "fan_with_heating"
|
||||
CONF_FAST_CONNECT = "fast_connect"
|
||||
CONF_FIELD_STRENGTH_X = "field_strength_x"
|
||||
CONF_FIELD_STRENGTH_Y = "field_strength_y"
|
||||
CONF_FIELD_STRENGTH_Z = "field_strength_z"
|
||||
CONF_FILE = "file"
|
||||
CONF_FILES = "files"
|
||||
CONF_FILTER = "filter"
|
||||
|
|
|
@ -1482,6 +1482,17 @@ sensor:
|
|||
name: "Loop Time"
|
||||
psram:
|
||||
name: "PSRAM Free"
|
||||
- platform: mmc5983
|
||||
i2c_id: i2c_bus
|
||||
field_strength_x:
|
||||
name: "Magnet X"
|
||||
id: magnet_x
|
||||
field_strength_y:
|
||||
name: "Magnet Y"
|
||||
id: magnet_y
|
||||
field_strength_z:
|
||||
name: "Magnet Z"
|
||||
id: magnet_z
|
||||
|
||||
esp32_touch:
|
||||
setup_mode: false
|
||||
|
|
Loading…
Reference in a new issue