From b91723344ea88b69ff720d2a5a3b0a10e088f073 Mon Sep 17 00:00:00 2001 From: Kurt Kellner Date: Thu, 25 Feb 2021 15:12:06 -0700 Subject: [PATCH] Vl53l0x change address (#1126) * Added vl53l0x change address and timeout * Added vl53l0x change address and timeout * vl53l0x code cleanup and update test * remove executable bit * lint code cleanup * code review fixes including timeout default to 10ms * Code review cleanup and change a WARN log level message to DEBUG * Fix issue where warn should be temporary * Added name of sensor to warning message * Fix blacklist lint issue * Remove unused import --- esphome/components/vl53l0x/sensor.py | 41 +++++++++--- esphome/components/vl53l0x/vl53l0x_sensor.cpp | 63 +++++++++++++++++-- esphome/components/vl53l0x/vl53l0x_sensor.h | 13 ++++ tests/test3.yaml | 2 + 4 files changed, 107 insertions(+), 12 deletions(-) diff --git a/esphome/components/vl53l0x/sensor.py b/esphome/components/vl53l0x/sensor.py index 209016fe40..62208eef53 100644 --- a/esphome/components/vl53l0x/sensor.py +++ b/esphome/components/vl53l0x/sensor.py @@ -1,7 +1,9 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import i2c, sensor -from esphome.const import CONF_ID, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL +from esphome.const import (CONF_ID, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, CONF_ADDRESS, + CONF_TIMEOUT, CONF_ENABLE_PIN) +from esphome import pins DEPENDENCIES = ['i2c'] @@ -12,12 +14,31 @@ VL53L0XSensor = vl53l0x_ns.class_('VL53L0XSensor', sensor.Sensor, cg.PollingComp CONF_SIGNAL_RATE_LIMIT = 'signal_rate_limit' CONF_LONG_RANGE = 'long_range' -CONFIG_SCHEMA = sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({ - cv.GenerateID(): cv.declare_id(VL53L0XSensor), - cv.Optional(CONF_SIGNAL_RATE_LIMIT, default=0.25): cv.float_range( - min=0.0, max=512.0, min_included=False, max_included=False), - cv.Optional(CONF_LONG_RANGE, default=False): cv.boolean, -}).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29)) + +def check_keys(obj): + if obj[CONF_ADDRESS] != 0x29 and CONF_ENABLE_PIN not in obj: + msg = "Address other then 0x29 requires enable_pin definition to allow sensor\r" + msg += "re-addressing. Also if you have more then one VL53 device on the same\r" + msg += "i2c bus, then all VL53 devices must have enable_pin defined." + raise cv.Invalid(msg) + return obj + + +def check_timeout(value): + value = cv.positive_time_period_microseconds(value) + if value.total_seconds > 60: + raise cv.Invalid("Maximum timeout can not be greater then 60 seconds") + return value + + +CONFIG_SCHEMA = cv.All(sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({ + cv.GenerateID(): cv.declare_id(VL53L0XSensor), + cv.Optional(CONF_SIGNAL_RATE_LIMIT, default=0.25): cv.float_range( + min=0.0, max=512.0, min_included=False, max_included=False), + cv.Optional(CONF_LONG_RANGE, default=False): cv.boolean, + cv.Optional(CONF_TIMEOUT, default='10ms'): check_timeout, + cv.Optional(CONF_ENABLE_PIN): pins.gpio_output_pin_schema, + }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29)), check_keys) def to_code(config): @@ -25,5 +46,11 @@ def to_code(config): yield cg.register_component(var, config) cg.add(var.set_signal_rate_limit(config[CONF_SIGNAL_RATE_LIMIT])) cg.add(var.set_long_range(config[CONF_LONG_RANGE])) + cg.add(var.set_timeout_us(config[CONF_TIMEOUT])) + + if CONF_ENABLE_PIN in config: + enable = yield cg.gpio_pin_expression(config[CONF_ENABLE_PIN]) + cg.add(var.set_enable_pin(enable)) + yield sensor.register_sensor(var, config) yield i2c.register_i2c_device(var, config) diff --git a/esphome/components/vl53l0x/vl53l0x_sensor.cpp b/esphome/components/vl53l0x/vl53l0x_sensor.cpp index 8ce822352f..1926f7d113 100644 --- a/esphome/components/vl53l0x/vl53l0x_sensor.cpp +++ b/esphome/components/vl53l0x/vl53l0x_sensor.cpp @@ -14,20 +14,55 @@ namespace esphome { namespace vl53l0x { static const char *TAG = "vl53l0x"; +std::list VL53L0XSensor::vl53_sensors; +bool VL53L0XSensor::enable_pin_setup_complete = false; + +VL53L0XSensor::VL53L0XSensor() { VL53L0XSensor::vl53_sensors.push_back(this); } void VL53L0XSensor::dump_config() { LOG_SENSOR("", "VL53L0X", this); LOG_UPDATE_INTERVAL(this); LOG_I2C_DEVICE(this); + if (this->enable_pin_ != nullptr) { + LOG_PIN(" Enable Pin: ", this->enable_pin_); + } + ESP_LOGCONFIG(TAG, " Timeout: %u%s", this->timeout_us_, this->timeout_us_ > 0 ? "us" : " (no timeout)"); } + void VL53L0XSensor::setup() { + ESP_LOGD(TAG, "'%s' - setup BEGIN", this->name_.c_str()); + + if (!esphome::vl53l0x::VL53L0XSensor::enable_pin_setup_complete) { + for (auto &vl53_sensor : vl53_sensors) { + if (vl53_sensor->enable_pin_ != nullptr) { + // Disable the enable pin to force vl53 to HW Standby mode + ESP_LOGD(TAG, "i2c vl53l0x disable enable pins: GPIO%u", (vl53_sensor->enable_pin_)->get_pin()); + // Set enable pin as OUTPUT and disable the enable pin to force vl53 to HW Standby mode + vl53_sensor->enable_pin_->setup(); + vl53_sensor->enable_pin_->digital_write(false); + } + } + esphome::vl53l0x::VL53L0XSensor::enable_pin_setup_complete = true; + } + + if (this->enable_pin_ != nullptr) { + // Enable the enable pin to cause FW boot (to get back to 0x29 default address) + this->enable_pin_->digital_write(true); + delayMicroseconds(100); + } + + // Save the i2c address we want and force it to use the default 0x29 + // until we finish setup, then re-address to final desired address. + uint8_t final_address = address_; + this->set_i2c_address(0x29); + reg(0x89) |= 0x01; reg(0x88) = 0x00; reg(0x80) = 0x01; reg(0xFF) = 0x01; reg(0x00) = 0x00; - stop_variable_ = reg(0x91).get(); + this->stop_variable_ = reg(0x91).get(); reg(0x00) = 0x01; reg(0xFF) = 0x00; @@ -52,8 +87,15 @@ void VL53L0XSensor::setup() { reg(0x94) = 0x6B; reg(0x83) = 0x00; - while (reg(0x83).get() == 0x00) + this->timeout_start_us_ = micros(); + while (reg(0x83).get() == 0x00) { + if (this->timeout_us_ > 0 && ((uint16_t)(micros() - this->timeout_start_us_) > this->timeout_us_)) { + ESP_LOGE(TAG, "'%s' - setup timeout", this->name_.c_str()); + this->mark_failed(); + return; + } yield(); + } reg(0x83) = 0x01; uint8_t tmp = reg(0x92).get(); @@ -205,11 +247,22 @@ void VL53L0XSensor::setup() { return; } reg(0x01) = 0xE8; + + // Set the sensor to the desired final address + // The following is different for VL53L0X vs VL53L1X + // I2C_SXXXX_DEVICE_ADDRESS = 0x8A for VL53L0X + // I2C_SXXXX__DEVICE_ADDRESS = 0x0001 for VL53L1X + reg(0x8A) = final_address & 0x7F; + this->set_i2c_address(final_address); + + ESP_LOGD(TAG, "'%s' - setup END", this->name_.c_str()); } void VL53L0XSensor::update() { if (this->initiated_read_ || this->waiting_for_interrupt_) { this->publish_state(NAN); - this->status_set_warning(); + this->status_momentary_warning("update", 5000); + ESP_LOGW(TAG, "%s - update called before prior reading complete - initiated:%d waiting_for_interrupt:%d", + this->name_.c_str(), this->initiated_read_, this->waiting_for_interrupt_); } // initiate single shot measurement @@ -217,7 +270,7 @@ void VL53L0XSensor::update() { reg(0xFF) = 0x01; reg(0x00) = 0x00; - reg(0x91) = stop_variable_; + reg(0x91) = this->stop_variable_; reg(0x00) = 0x01; reg(0xFF) = 0x00; reg(0x80) = 0x00; @@ -246,7 +299,7 @@ void VL53L0XSensor::loop() { this->waiting_for_interrupt_ = false; if (range_mm >= 8190) { - ESP_LOGW(TAG, "'%s' - Distance is out of range, please move the target closer", this->name_.c_str()); + ESP_LOGD(TAG, "'%s' - Distance is out of range, please move the target closer", this->name_.c_str()); this->publish_state(NAN); return; } diff --git a/esphome/components/vl53l0x/vl53l0x_sensor.h b/esphome/components/vl53l0x/vl53l0x_sensor.h index 4939a9806c..2662b768ae 100644 --- a/esphome/components/vl53l0x/vl53l0x_sensor.h +++ b/esphome/components/vl53l0x/vl53l0x_sensor.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/i2c/i2c.h" @@ -20,6 +22,8 @@ struct SequenceStepTimeouts { class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { public: + VL53L0XSensor(); + void setup() override; void dump_config() override; @@ -30,6 +34,8 @@ class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c void set_signal_rate_limit(float signal_rate_limit) { signal_rate_limit_ = signal_rate_limit; } void set_long_range(bool long_range) { long_range_ = long_range; } + void set_timeout_us(uint32_t timeout_us) { this->timeout_us_ = timeout_us; } + void set_enable_pin(GPIOPin *enable) { this->enable_pin_ = enable; } protected: uint32_t get_measurement_timing_budget_() { @@ -249,10 +255,17 @@ class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c float signal_rate_limit_; bool long_range_; + GPIOPin *enable_pin_{nullptr}; uint32_t measurement_timing_budget_us_; bool initiated_read_{false}; bool waiting_for_interrupt_{false}; uint8_t stop_variable_; + + uint16_t timeout_start_us_; + uint16_t timeout_us_{}; + + static std::list vl53_sensors; + static bool enable_pin_setup_complete; }; } // namespace vl53l0x diff --git a/tests/test3.yaml b/tests/test3.yaml index 46b2d6b3a0..30578b451d 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -229,6 +229,8 @@ sensor: name: 'VL53L0x Distance' address: 0x29 update_interval: 60s + enable_pin: GPIO13 + timeout: 200us - platform: apds9960 type: clear name: APDS9960 Clear