mirror of
https://github.com/esphome/esphome.git
synced 2025-10-29 14:13:51 +00:00
🏗 Merge C++ into python codebase (#504)
## Description: Move esphome-core codebase into esphome (and a bunch of other refactors). See https://github.com/esphome/feature-requests/issues/97 Yes this is a shit ton of work and no there's no way to automate it :( But it will be worth it 👍 Progress: - Core support (file copy etc): 80% - Base Abstractions (light, switch): ~50% - Integrations: ~10% - Working? Yes, (but only with ported components). Other refactors: - Moves all codegen related stuff into a single class: `esphome.codegen` (imported as `cg`) - Rework coroutine syntax - Move from `component/platform.py` to `domain/component.py` structure as with HA - Move all defaults out of C++ and into config validation. - Remove `make_...` helpers from Application class. Reason: Merge conflicts with every single new integration. - Pointer Variables are stored globally instead of locally in setup(). Reason: stack size limit. Future work: - Rework const.py - Move all `CONF_...` into a conf class (usage `conf.UPDATE_INTERVAL` vs `CONF_UPDATE_INTERVAL`). Reason: Less convoluted import block - Enable loading from `custom_components` folder. **Related issue (if applicable):** https://github.com/esphome/feature-requests/issues/97 **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
This commit is contained in:
0
esphome/components/hmc5883l/__init__.py
Normal file
0
esphome/components/hmc5883l/__init__.py
Normal file
145
esphome/components/hmc5883l/hmc5883l.cpp
Normal file
145
esphome/components/hmc5883l/hmc5883l.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "hmc5883l.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace hmc5883l {
|
||||
|
||||
static const char *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 = 0x03;
|
||||
static const uint8_t HMC5883L_REGISTER_DATA_X_LSB = 0x04;
|
||||
static const uint8_t HMC5883L_REGISTER_DATA_Z_MSB = 0x05;
|
||||
static const uint8_t HMC5883L_REGISTER_DATA_Z_LSB = 0x06;
|
||||
static const uint8_t HMC5883L_REGISTER_DATA_Y_MSB = 0x07;
|
||||
static const uint8_t HMC5883L_REGISTER_DATA_Y_LSB = 0x08;
|
||||
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() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up HMC5583L...");
|
||||
uint8_t id[3];
|
||||
if (!this->read_byte(HMC5883L_REGISTER_IDENTIFICATION_A, &id[0]) ||
|
||||
!this->read_byte(HMC5883L_REGISTER_IDENTIFICATION_B, &id[1]) ||
|
||||
!this->read_byte(HMC5883L_REGISTER_IDENTIFICATION_C, &id[2])) {
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (id[0] != 0x48 || id[1] != 0x34 || id[2] != 0x33) {
|
||||
this->error_code_ = ID_REGISTERS;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t config_a = 0;
|
||||
// 0b0xx00000 << 5 Sample Averaging - 0b00=1 sample, 0b11=8 samples
|
||||
config_a |= 0b01100000;
|
||||
// 0b000xxx00 << 2 Data Output Rate - 0b100=15Hz
|
||||
config_a |= 0b00010000;
|
||||
// 0b000000xx << 0 Measurement Mode - 0b00=high impedance on load
|
||||
config_a |= 0b00000000;
|
||||
if (!this->write_byte(HMC5883L_REGISTER_CONFIG_A, config_a)) {
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t config_b = 0;
|
||||
config_b |= this->range_ << 5;
|
||||
if (!this->write_byte(HMC5883L_REGISTER_CONFIG_B, config_b)) {
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t mode = 0;
|
||||
// Continuous Measurement Mode
|
||||
mode |= 0b00;
|
||||
|
||||
if (!this->write_byte(HMC5883L_REGISTER_MODE, mode)) {
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
void HMC5883LComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "HMC5883L:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
if (this->error_code_ == COMMUNICATION_FAILED) {
|
||||
ESP_LOGE(TAG, "Communication with HMC5883L failed!");
|
||||
} 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
|
||||
50
esphome/components/hmc5883l/hmc5883l.h
Normal file
50
esphome/components/hmc5883l/hmc5883l.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace hmc5883l {
|
||||
|
||||
enum HMC5883LRange {
|
||||
HMC5883L_RANGE_88_UT = 0b000,
|
||||
HMC5883L_RANGE_130_UT = 0b001,
|
||||
HMC5883L_RANGE_190_UT = 0b010,
|
||||
HMC5883L_RANGE_250_UT = 0b011,
|
||||
HMC5883L_RANGE_400_UT = 0b100,
|
||||
HMC5883L_RANGE_470_UT = 0b101,
|
||||
HMC5883L_RANGE_560_UT = 0b110,
|
||||
HMC5883L_RANGE_810_UT = 0b111,
|
||||
};
|
||||
|
||||
class HMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
HMC5883LComponent(uint32_t update_interval) : PollingComponent(update_interval) {}
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
void update() override;
|
||||
|
||||
void set_range(HMC5883LRange range) { range_ = range; }
|
||||
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:
|
||||
HMC5883LRange range_{HMC5883L_RANGE_130_UT};
|
||||
sensor::Sensor *x_sensor_;
|
||||
sensor::Sensor *y_sensor_;
|
||||
sensor::Sensor *z_sensor_;
|
||||
sensor::Sensor *heading_sensor_;
|
||||
enum ErrorCode {
|
||||
NONE = 0,
|
||||
COMMUNICATION_FAILED,
|
||||
ID_REGISTERS,
|
||||
} error_code_;
|
||||
};
|
||||
|
||||
} // namespace hmc5883l
|
||||
} // namespace esphome
|
||||
71
esphome/components/hmc5883l/sensor.py
Normal file
71
esphome/components/hmc5883l/sensor.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# coding=utf-8
|
||||
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, CONF_RANGE, CONF_UPDATE_INTERVAL, \
|
||||
ICON_MAGNET, UNIT_MICROTESLA, UNIT_DEGREES, ICON_SCREEN_ROTATION
|
||||
|
||||
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_('HMC5883LComponent', cg.PollingComponent, i2c.I2CDevice)
|
||||
|
||||
HMC5883LRange = hmc5883l_ns.enum('HMC5883LRange')
|
||||
HMC5883L_RANGES = {
|
||||
88: HMC5883LRange.HMC5883L_RANGE_88_UT,
|
||||
130: HMC5883LRange.HMC5883L_RANGE_130_UT,
|
||||
190: HMC5883LRange.HMC5883L_RANGE_190_UT,
|
||||
250: HMC5883LRange.HMC5883L_RANGE_250_UT,
|
||||
400: HMC5883LRange.HMC5883L_RANGE_400_UT,
|
||||
470: HMC5883LRange.HMC5883L_RANGE_470_UT,
|
||||
560: HMC5883LRange.HMC5883L_RANGE_560_UT,
|
||||
810: HMC5883LRange.HMC5883L_RANGE_810_UT,
|
||||
}
|
||||
|
||||
|
||||
def validate_range(value):
|
||||
value = cv.string(value)
|
||||
if value.endswith(u'µT') or value.endswith('uT'):
|
||||
value = value[:-2]
|
||||
return cv.one_of(*HMC5883L_RANGES, int=True)(value)
|
||||
|
||||
|
||||
field_strength_schema = sensor.sensor_schema(UNIT_MICROTESLA, ICON_MAGNET, 1)
|
||||
heading_schema = sensor.sensor_schema(UNIT_DEGREES, ICON_SCREEN_ROTATION, 1)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema({
|
||||
cv.GenerateID(): cv.declare_variable_id(HMC5883LComponent),
|
||||
cv.Optional(CONF_ADDRESS): cv.i2c_address,
|
||||
cv.Optional(CONF_FIELD_STRENGTH_X): cv.nameable(field_strength_schema),
|
||||
cv.Optional(CONF_FIELD_STRENGTH_Y): cv.nameable(field_strength_schema),
|
||||
cv.Optional(CONF_FIELD_STRENGTH_Z): cv.nameable(field_strength_schema),
|
||||
cv.Optional(CONF_HEADING): cv.nameable(heading_schema),
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default='60s'): cv.update_interval,
|
||||
cv.Optional(CONF_RANGE, default='130uT'): validate_range,
|
||||
}).extend(cv.COMPONENT_SCHEMA).extend(i2c.i2c_device_schema(0x1E))
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
|
||||
yield cg.register_component(var, config)
|
||||
yield i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_range(HMC5883L_RANGES[config[CONF_RANGE]]))
|
||||
if CONF_FIELD_STRENGTH_X in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_X])
|
||||
cg.add(var.set_x_sensor(sens))
|
||||
if CONF_FIELD_STRENGTH_Y in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y])
|
||||
cg.add(var.set_y_sensor(sens))
|
||||
if CONF_FIELD_STRENGTH_Z in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z])
|
||||
cg.add(var.set_z_sensor(sens))
|
||||
if CONF_HEADING in config:
|
||||
sens = yield sensor.new_sensor(config[CONF_HEADING])
|
||||
cg.add(var.set_heading_sensor(sens))
|
||||
Reference in New Issue
Block a user