Please add support for the QMC5883P 3-axis magnetometer #3307
Replies: 3 comments
-
|
🏷️ I've automatically added the |
Beta Was this translation helpful? Give feedback.
-
|
@illigtr Can you share the changes you made? Perhaps by forking ESPHome and making the changes in your fork so that I can take a look at them? |
Beta Was this translation helpful? Give feedback.
-
|
This is my modified hmc5883l.cpp file that supports the QMC5883P chip. You can compare it with the original. It is a quick hack. If you use the ESPHOME QMC5883 driver, the chip doesn't return the correct values at all. I looked at the code from the URL links above and found the code matched more closely the original HMC5883L than the QMC5883 driver.
#include "hmc5883l.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
namespace esphome {
namespace hmc5883l {
static const char *const TAG = "hmc5883l";
static const uint8_t HMC5883L_ADDRESS = 0x1E;
static const uint8_t HMC5883L_REGISTER_CONFIG_A = 0x00;
static const uint8_t HMC5883L_REGISTER_CONFIG_B = 0x01;
static const uint8_t HMC5883L_REGISTER_MODE = 0x02;
static const uint8_t HMC5883L_REGISTER_DATA_X_MSB = 0x02;
static const uint8_t HMC5883L_REGISTER_DATA_X_LSB = 0x01;
static const uint8_t HMC5883L_REGISTER_DATA_Z_MSB = 0x06;
static const uint8_t HMC5883L_REGISTER_DATA_Z_LSB = 0x05;
static const uint8_t HMC5883L_REGISTER_DATA_Y_MSB = 0x04;
static const uint8_t HMC5883L_REGISTER_DATA_Y_LSB = 0x03;
static const uint8_t HMC5883L_REGISTER_STATUS = 0x09;
static const uint8_t HMC5883L_REGISTER_IDENTIFICATION_A = 0x0A;
static const uint8_t HMC5883L_REGISTER_IDENTIFICATION_B = 0x0B;
static const uint8_t HMC5883L_REGISTER_IDENTIFICATION_C = 0x0C;
void HMC5883LComponent::setup() {
uint8_t id[3];
if (!this->read_byte(HMC5883L_REGISTER_CONFIG_A, &id[0]) ) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
if (this->get_update_interval() < App.get_loop_interval()) {
high_freq_.start();
}
if ( id[0] != 0x80) {
this->error_code_ = ID_REGISTERS;
this->mark_failed();
return;
}
// Standard-Konfiguration: 200 Hz, Continuous, ±2G
// writeReg(0x0D, 0x40); delay(10);
if (!this->write_byte(0x0D, 0x40)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
delay(10);
// writeReg(0x29, 0x06); delay(10);
if (!this->write_byte(0x29, 0x06)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
delay(10);
// writeReg(REG_CTL1, 0xCF); delay(10);
if (!this->write_byte(HMC5883L_REGISTER_IDENTIFICATION_A, 0xCF)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
delay(10);
// // writeReg(REG_CTL2, 0x00); delay(10);
if (!this->write_byte(HMC5883L_REGISTER_IDENTIFICATION_B, 0x00)) {
this->error_code_ = COMMUNICATION_FAILED;
this->mark_failed();
return;
}
delay(10);
//
}
void HMC5883LComponent::dump_config() {
ESP_LOGCONFIG(TAG, "HMC5883L:");
LOG_I2C_DEVICE(this);
if (this->error_code_ == COMMUNICATION_FAILED) {
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
} else if (this->error_code_ == ID_REGISTERS) {
ESP_LOGE(TAG, "The ID registers don't match - Is this really an HMC5883L?");
}
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 HMC5883LComponent::get_setup_priority() const { return setup_priority::DATA; }
void HMC5883LComponent::update() {
uint16_t raw_x, raw_y, raw_z;
if (!this->read_byte_16(HMC5883L_REGISTER_DATA_X_MSB, &raw_x) ||
!this->read_byte_16(HMC5883L_REGISTER_DATA_Y_MSB, &raw_y) ||
!this->read_byte_16(HMC5883L_REGISTER_DATA_Z_MSB, &raw_z)) {
this->status_set_warning();
return;
}
float mg_per_bit;
switch (this->range_) {
case HMC5883L_RANGE_88_UT:
mg_per_bit = 0.073f;
break;
case HMC5883L_RANGE_130_UT:
mg_per_bit = 0.92f;
break;
case HMC5883L_RANGE_190_UT:
mg_per_bit = 1.22f;
break;
case HMC5883L_RANGE_250_UT:
mg_per_bit = 1.52f;
break;
case HMC5883L_RANGE_400_UT:
mg_per_bit = 2.27f;
break;
case HMC5883L_RANGE_470_UT:
mg_per_bit = 2.56f;
break;
case HMC5883L_RANGE_560_UT:
mg_per_bit = 3.03f;
break;
case HMC5883L_RANGE_810_UT:
mg_per_bit = 4.35f;
break;
default:
mg_per_bit = NAN;
}
// in µT
const float x = int16_t(raw_x) * mg_per_bit * 0.1f;
const float y = int16_t(raw_y) * mg_per_bit * 0.1f;
const float z = int16_t(raw_z) * mg_per_bit * 0.1f;
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 hmc5883l
} // namespace esphome |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Component name
hmc5883l
Link to component documentation on our website
https://esphome.io/components/sensor/hmc5883l/
Describe the enhancement
I would like the QST Corporation QMC5883P to be included in the HMC5883L component. This is not the QMC5883L. It more closely resembles the ORIGINAL HMC5883L. In fact, nearly all HMC5883L "clones" from Ali-Express use this chip. It responds to 0x2C on I2C. Its addresses registers for reading and writing are nearly identical to the HMC5883L library. In fact, with only 6 line changes to the ESPHome component I have the QMC5883P fully operational under ESPHome.
Use cases
Because nearly all so-called HMC5886L sensors on the market are using this chip.
Anything else?
Additional links of interest:
https://forum.arduino.cc/t/are-all-new-gy-270-board-magnetometers-now-fake/1379276
https://www.qstcorp.com/upload/pdf/202202/%EF%BC%88%E5%B7%B2%E4%BC%A0%EF%BC%8913-52-19%20QMC5883P%20Datasheet%20Rev.C(1).pdf
https://github.com/Granddyser/QMC5883P
Beta Was this translation helpful? Give feedback.
All reactions