Added in mmc5603 code (#4175)

* added in mmc5603 code

* added in codeowner

* fix linter errors

* whitespace linter errors

* added codeowner

* clang format

* remove clang format from python code

* fix whitespace

* add tests

* fix test

* make requested edits

* remove status manipulation

---------

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Ben Hoff 2023-04-03 22:34:14 -04:00 committed by GitHub
parent 9c9bc58c16
commit 42401775e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 307 additions and 0 deletions

View file

@ -159,6 +159,7 @@ esphome/components/midea/* @dudanov
esphome/components/midea_ir/* @dudanov
esphome/components/mitsubishi/* @RubyBailey
esphome/components/mlx90393/* @functionpointer
esphome/components/mmc5603/* @benhoff
esphome/components/modbus_controller/* @martgras
esphome/components/modbus_controller/binary_sensor/* @martgras
esphome/components/modbus_controller/number/* @martgras

View file

@ -0,0 +1 @@
CODEOWNERS = ["@benhoff"]

View file

@ -0,0 +1,162 @@
#include "mmc5603.h"
#include "esphome/core/log.h"
namespace esphome {
namespace mmc5603 {
static const char *const TAG = "mmc5603";
static const uint8_t MMC5603_ADDRESS = 0x30;
static const uint8_t MMC56X3_PRODUCT_ID = 0x39;
static const uint8_t MMC56X3_DEFAULT_ADDRESS = 0x30;
static const uint8_t MMC56X3_CHIP_ID = 0x10;
static const uint8_t MMC56X3_ADDR_XOUT0 = 0x00;
static const uint8_t MMC56X3_ADDR_XOUT1 = 0x01;
static const uint8_t MMC56X3_ADDR_XOUT2 = 0x06;
static const uint8_t MMC56X3_ADDR_YOUT0 = 0x02;
static const uint8_t MMC56X3_ADDR_YOUT1 = 0x03;
static const uint8_t MMC56X3_ADDR_YOUT2 = 0x07;
static const uint8_t MMC56X3_ADDR_ZOUT0 = 0x04;
static const uint8_t MMC56X3_ADDR_ZOUT1 = 0x05;
static const uint8_t MMC56X3_ADDR_ZOUT2 = 0x08;
static const uint8_t MMC56X3_OUT_TEMP = 0x09;
static const uint8_t MMC56X3_STATUS_REG = 0x18;
static const uint8_t MMC56X3_CTRL0_REG = 0x1B;
static const uint8_t MMC56X3_CTRL1_REG = 0x1C;
static const uint8_t MMC56X3_CTRL2_REG = 0x1D;
static const uint8_t MMC5603_ODR_REG = 0x1A;
void MMC5603Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up MMC5603...");
uint8_t id = 0;
if (!this->read_byte(MMC56X3_PRODUCT_ID, &id)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (id != MMC56X3_CHIP_ID) {
ESP_LOGCONFIG(TAG, "Chip Wrong");
this->error_code_ = ID_REGISTERS;
this->mark_failed();
return;
}
if (!this->write_byte(MMC56X3_CTRL1_REG, 0x80)) { // turn on set bit
ESP_LOGCONFIG(TAG, "Control 1 Failed for set bit");
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (!this->write_byte(MMC56X3_CTRL0_REG, 0x08)) { // turn on set bit
ESP_LOGCONFIG(TAG, "Control 0 Failed for set bit");
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (!this->write_byte(MMC56X3_CTRL0_REG, 0x10)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
uint8_t ctrl_2 = 0;
ctrl_2 &= ~0x10; // turn off cmm_en bit
if (!this->write_byte(MMC56X3_CTRL2_REG, ctrl_2)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
}
void MMC5603Component::dump_config() {
ESP_LOGCONFIG(TAG, "MMC5603:");
LOG_I2C_DEVICE(this);
if (this->error_code_ == COMMUNICATION_FAILED) {
ESP_LOGE(TAG, "Communication with MMC5603 failed!");
} else if (this->error_code_ == ID_REGISTERS) {
ESP_LOGE(TAG, "The ID registers don't match - Is this really an MMC5603?");
}
LOG_UPDATE_INTERVAL(this);
LOG_SENSOR(" ", "X Axis", this->x_sensor_);
LOG_SENSOR(" ", "Y Axis", this->y_sensor_);
LOG_SENSOR(" ", "Z Axis", this->z_sensor_);
LOG_SENSOR(" ", "Heading", this->heading_sensor_);
}
float MMC5603Component::get_setup_priority() const { return setup_priority::DATA; }
void MMC5603Component::update() {
if (!this->write_byte(MMC56X3_CTRL0_REG, 0x01)) {
this->status_set_warning();
return;
}
uint8_t status = 0;
if (!this->read_byte(MMC56X3_STATUS_REG, &status)) {
this->status_set_warning();
return;
}
uint8_t buffer[9] = {0};
if (!this->read_byte(MMC56X3_ADDR_XOUT0, &buffer[0]) || !this->read_byte(MMC56X3_ADDR_XOUT1, &buffer[1]) ||
!this->read_byte(MMC56X3_ADDR_XOUT2, &buffer[2])) {
this->status_set_warning();
return;
}
if (!this->read_byte(MMC56X3_ADDR_YOUT0, &buffer[3]) || !this->read_byte(MMC56X3_ADDR_YOUT1, &buffer[4]) ||
!this->read_byte(MMC56X3_ADDR_YOUT2, &buffer[5])) {
this->status_set_warning();
return;
}
if (!this->read_byte(MMC56X3_ADDR_ZOUT0, &buffer[6]) || !this->read_byte(MMC56X3_ADDR_ZOUT1, &buffer[7]) ||
!this->read_byte(MMC56X3_ADDR_ZOUT2, &buffer[8])) {
this->status_set_warning();
return;
}
int32_t raw_x = 0;
raw_x |= buffer[0] << 12;
raw_x |= buffer[1] << 4;
raw_x |= buffer[2] << 0;
const float x = 0.0625 * (raw_x - 524288);
int32_t raw_y = 0;
raw_y |= buffer[3] << 12;
raw_y |= buffer[4] << 4;
raw_y |= buffer[5] << 0;
const float y = 0.0625 * (raw_y - 524288);
int32_t raw_z = 0;
raw_z |= buffer[6] << 12;
raw_z |= buffer[7] << 4;
raw_z |= buffer[8] << 0;
const float z = 0.0625 * (raw_z - 524288);
const float heading = atan2f(0.0f - x, y) * 180.0f / M_PI;
ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f°", x, y, z, heading);
if (this->x_sensor_ != nullptr)
this->x_sensor_->publish_state(x);
if (this->y_sensor_ != nullptr)
this->y_sensor_->publish_state(y);
if (this->z_sensor_ != nullptr)
this->z_sensor_->publish_state(z);
if (this->heading_sensor_ != nullptr)
this->heading_sensor_->publish_state(heading);
}
} // namespace mmc5603
} // namespace esphome

View file

@ -0,0 +1,43 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace mmc5603 {
enum MMC5603Datarate {
MMC5603_DATARATE_75_0_HZ,
MMC5603_DATARATE_150_0_HZ,
MMC5603_DATARATE_255_0_HZ,
};
class MMC5603Component : public PollingComponent, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override;
void update() override;
void set_datarate(MMC5603Datarate datarate) { datarate_ = datarate; }
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; }
void set_heading_sensor(sensor::Sensor *heading_sensor) { heading_sensor_ = heading_sensor; }
protected:
MMC5603Datarate datarate_;
sensor::Sensor *x_sensor_{nullptr};
sensor::Sensor *y_sensor_{nullptr};
sensor::Sensor *z_sensor_{nullptr};
sensor::Sensor *heading_sensor_{nullptr};
enum ErrorCode {
NONE = 0,
COMMUNICATION_FAILED,
ID_REGISTERS,
} error_code_;
};
} // namespace mmc5603
} // namespace esphome

View file

@ -0,0 +1,91 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, sensor
from esphome.const import (
CONF_ADDRESS,
CONF_ID,
ICON_MAGNET,
STATE_CLASS_MEASUREMENT,
UNIT_MICROTESLA,
UNIT_DEGREES,
ICON_SCREEN_ROTATION,
CONF_UPDATE_INTERVAL,
)
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_(
"MMC5603Component", cg.PollingComponent, i2c.I2CDevice
)
MMC5603Datarate = mmc5603_ns.enum("MMC5603Datarate")
MMC5603Datarates = {
75: MMC5603Datarate.MMC5603_DATARATE_75_0_HZ,
150: MMC5603Datarate.MMC5603_DATARATE_150_0_HZ,
255: MMC5603Datarate.MMC5603_DATARATE_255_0_HZ,
}
field_strength_schema = sensor.sensor_schema(
unit_of_measurement=UNIT_MICROTESLA,
icon=ICON_MAGNET,
accuracy_decimals=1,
state_class=STATE_CLASS_MEASUREMENT,
)
heading_schema = sensor.sensor_schema(
unit_of_measurement=UNIT_DEGREES,
icon=ICON_SCREEN_ROTATION,
accuracy_decimals=1,
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(MMC5603Component),
cv.Optional(CONF_ADDRESS): cv.i2c_address,
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,
cv.Optional(CONF_HEADING): heading_schema,
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x1E))
)
def auto_data_rate(config):
interval_msec = config[CONF_UPDATE_INTERVAL].total_milliseconds
interval_hz = 1000.0 / interval_msec
for datarate in sorted(MMC5603Datarates.keys()):
if float(datarate) >= interval_hz:
return MMC5603Datarates[datarate]
return MMC5603Datarates[75]
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)
cg.add(var.set_datarate(auto_data_rate(config)))
if CONF_FIELD_STRENGTH_X in config:
sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_X])
cg.add(var.set_x_sensor(sens))
if CONF_FIELD_STRENGTH_Y in config:
sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y])
cg.add(var.set_y_sensor(sens))
if CONF_FIELD_STRENGTH_Z in config:
sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z])
cg.add(var.set_z_sensor(sens))
if CONF_HEADING in config:
sens = await sensor.new_sensor(config[CONF_HEADING])
cg.add(var.set_heading_sensor(sens))

View file

@ -831,6 +831,15 @@ sensor:
temperature:
name: MPU6886 Temperature
i2c_id: i2c_bus
- platform: mmc5603
address: 0x30
field_strength_x:
name: HMC5883L Field Strength X
field_strength_y:
name: HMC5883L Field Strength Y
field_strength_z:
name: HMC5883L Field Strength Z
i2c_id: i2c_bus
- platform: dps310
temperature:
name: DPS310 Temperature