mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	| @@ -3,3 +3,4 @@ include README.md | |||||||
| include esphome/dashboard/templates/*.html | include esphome/dashboard/templates/*.html | ||||||
| recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE | recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE | ||||||
| recursive-include esphome *.cpp *.h *.tcc | recursive-include esphome *.cpp *.h *.tcc | ||||||
|  | recursive-include esphome LICENSE.txt | ||||||
|   | |||||||
| @@ -208,5 +208,30 @@ void I2CDevice::set_i2c_parent(I2CComponent *parent) { this->parent_ = parent; } | |||||||
| uint8_t next_i2c_bus_num_ = 0; | uint8_t next_i2c_bus_num_ = 0; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | I2CRegister &I2CRegister::operator=(uint8_t value) { | ||||||
|  |   this->parent_->write_byte(this->register_, value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | I2CRegister &I2CRegister::operator&=(uint8_t value) { | ||||||
|  |   this->parent_->write_byte(this->register_, this->get() & value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | I2CRegister &I2CRegister::operator|=(uint8_t value) { | ||||||
|  |   this->parent_->write_byte(this->register_, this->get() | value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t I2CRegister::get() { | ||||||
|  |   uint8_t value = 0x00; | ||||||
|  |   this->parent_->read_byte(this->register_, &value); | ||||||
|  |   return value; | ||||||
|  | } | ||||||
|  | I2CRegister &I2CRegister::operator=(const std::vector<uint8_t> &value) { | ||||||
|  |   this->parent_->write_bytes(this->register_, value); | ||||||
|  |   return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
| }  // namespace i2c | }  // namespace i2c | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -134,6 +134,24 @@ class I2CComponent : public Component { | |||||||
| extern uint8_t next_i2c_bus_num_; | extern uint8_t next_i2c_bus_num_; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | class I2CDevice; | ||||||
|  |  | ||||||
|  | class I2CRegister { | ||||||
|  |  public: | ||||||
|  |   I2CRegister(I2CDevice *parent, uint8_t a_register) : parent_(parent), register_(a_register) {} | ||||||
|  |  | ||||||
|  |   I2CRegister &operator=(uint8_t value); | ||||||
|  |   I2CRegister &operator=(const std::vector<uint8_t> &value); | ||||||
|  |   I2CRegister &operator&=(uint8_t value); | ||||||
|  |   I2CRegister &operator|=(uint8_t value); | ||||||
|  |  | ||||||
|  |   uint8_t get(); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   I2CDevice *parent_; | ||||||
|  |   uint8_t register_; | ||||||
|  | }; | ||||||
|  |  | ||||||
| /** All components doing communication on the I2C bus should subclass I2CDevice. | /** All components doing communication on the I2C bus should subclass I2CDevice. | ||||||
|  * |  * | ||||||
|  * This class stores 1. the address of the i2c device and has a helper function to allow |  * This class stores 1. the address of the i2c device and has a helper function to allow | ||||||
| @@ -153,6 +171,8 @@ class I2CDevice { | |||||||
|   /// Manually set the parent i2c bus for this device. |   /// Manually set the parent i2c bus for this device. | ||||||
|   void set_i2c_parent(I2CComponent *parent); |   void set_i2c_parent(I2CComponent *parent); | ||||||
|  |  | ||||||
|  |   I2CRegister reg(uint8_t a_register) { return {this, a_register}; } | ||||||
|  |  | ||||||
|   /** Read len amount of bytes from a register into data. Optionally with a conversion time after |   /** Read len amount of bytes from a register into data. Optionally with a conversion time after | ||||||
|    * writing the register value to the bus. |    * writing the register value to the bus. | ||||||
|    * |    * | ||||||
|   | |||||||
							
								
								
									
										80
									
								
								esphome/components/vl53l0x/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								esphome/components/vl53l0x/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | Most of the code in this integration is based on the VL53L0x library | ||||||
|  | by Pololu (Pololu Corporation), which in turn is based on the VL53L0X | ||||||
|  | API from ST. The code has been adapted to work with ESPHome's i2c APIs. | ||||||
|  | Please see the top-level LICENSE.txt for information about ESPHome's license. | ||||||
|  | The licenses for Pololu's and ST's software are included below. | ||||||
|  | Orignally taken from https://github.com/pololu/vl53l0x-arduino (accessed 20th october 2019). | ||||||
|  |  | ||||||
|  | ================================================================= | ||||||
|  |  | ||||||
|  | Copyright (c) 2017 Pololu Corporation.  For more information, see | ||||||
|  |  | ||||||
|  | https://www.pololu.com/ | ||||||
|  | https://forum.pololu.com/ | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person | ||||||
|  | obtaining a copy of this software and associated documentation | ||||||
|  | files (the "Software"), to deal in the Software without | ||||||
|  | restriction, including without limitation the rights to use, | ||||||
|  | copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the | ||||||
|  | Software is furnished to do so, subject to the following | ||||||
|  | conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be | ||||||
|  | included in all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|  | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||||||
|  | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|  | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||||||
|  | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||||
|  | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||||
|  | OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  | ||||||
|  | ================================================================= | ||||||
|  |  | ||||||
|  | Most of the functionality of this library is based on the VL53L0X | ||||||
|  | API provided by ST (STSW-IMG005), and some of the explanatory | ||||||
|  | comments are quoted or paraphrased from the API source code, API | ||||||
|  | user manual (UM2039), and the VL53L0X datasheet. | ||||||
|  |  | ||||||
|  | The following applies to source code reproduced or derived from | ||||||
|  | the API: | ||||||
|  |  | ||||||
|  | ----------------------------------------------------------------- | ||||||
|  |  | ||||||
|  | Copyright © 2016, STMicroelectronics International N.V.  All | ||||||
|  | rights reserved. | ||||||
|  |  | ||||||
|  | Redistribution and use in source and binary forms, with or | ||||||
|  | without modification, are permitted provided that the following | ||||||
|  | conditions are met: | ||||||
|  | * Redistributions of source code must retain the above copyright | ||||||
|  | notice, this list of conditions and the following disclaimer. | ||||||
|  | * Redistributions in binary form must reproduce the above | ||||||
|  | copyright notice, this list of conditions and the following | ||||||
|  | disclaimer in the documentation and/or other materials provided | ||||||
|  | with the distribution. | ||||||
|  | * Neither the name of STMicroelectronics nor the | ||||||
|  | names of its contributors may be used to endorse or promote | ||||||
|  | products derived from this software without specific prior | ||||||
|  | written permission. | ||||||
|  |  | ||||||
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||||||
|  | CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||||||
|  | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||||
|  | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND | ||||||
|  | NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED. | ||||||
|  | IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE | ||||||
|  | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||||
|  | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | ||||||
|  | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||||||
|  | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||||
|  | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||||||
|  | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||||||
|  | DAMAGE. | ||||||
|  |  | ||||||
|  | ----------------------------------------------------------------- | ||||||
							
								
								
									
										0
									
								
								esphome/components/vl53l0x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/vl53l0x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										24
									
								
								esphome/components/vl53l0x/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								esphome/components/vl53l0x/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | 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 | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ['i2c'] | ||||||
|  |  | ||||||
|  | vl53l0x_ns = cg.esphome_ns.namespace('vl53l0x') | ||||||
|  | VL53L0XSensor = vl53l0x_ns.class_('VL53L0XSensor', sensor.Sensor, cg.PollingComponent, | ||||||
|  |                                   i2c.I2CDevice) | ||||||
|  |  | ||||||
|  | CONF_SIGNAL_RATE_LIMIT = 'signal_rate_limit' | ||||||
|  | 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) | ||||||
|  | }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     yield cg.register_component(var, config) | ||||||
|  |     yield sensor.register_sensor(var, config) | ||||||
|  |     yield i2c.register_i2c_device(var, config) | ||||||
							
								
								
									
										249
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | |||||||
|  | #include "vl53l0x_sensor.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Most of the code in this integration is based on the VL53L0x library | ||||||
|  |  * by Pololu (Pololu Corporation), which in turn is based on the VL53L0X | ||||||
|  |  * API from ST. | ||||||
|  |  * | ||||||
|  |  * For more information about licensing, please view the included LICENSE.txt file | ||||||
|  |  * in the vl53l0x integration directory. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace vl53l0x { | ||||||
|  |  | ||||||
|  | static const char *TAG = "vl53l0x"; | ||||||
|  |  | ||||||
|  | void VL53L0XSensor::dump_config() { | ||||||
|  |   LOG_SENSOR("", "VL53L0X", this); | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  | } | ||||||
|  | void VL53L0XSensor::setup() { | ||||||
|  |   reg(0x89) |= 0x01; | ||||||
|  |   reg(0x88) = 0x00; | ||||||
|  |  | ||||||
|  |   reg(0x80) = 0x01; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x00) = 0x00; | ||||||
|  |   stop_variable_ = reg(0x91).get(); | ||||||
|  |  | ||||||
|  |   reg(0x00) = 0x01; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x80) = 0x00; | ||||||
|  |   reg(0x60) |= 0x12; | ||||||
|  |  | ||||||
|  |   auto rate_value = static_cast<uint16_t>(signal_rate_limit_ * 128); | ||||||
|  |   write_byte_16(0x44, rate_value); | ||||||
|  |  | ||||||
|  |   reg(0x01) = 0xFF; | ||||||
|  |  | ||||||
|  |   // getSpadInfo() | ||||||
|  |   reg(0x80) = 0x01; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x00) = 0x00; | ||||||
|  |   reg(0xFF) = 0x06; | ||||||
|  |   reg(0x83) |= 0x04; | ||||||
|  |   reg(0xFF) = 0x07; | ||||||
|  |   reg(0x81) = 0x01; | ||||||
|  |   reg(0x80) = 0x01; | ||||||
|  |   reg(0x94) = 0x6B; | ||||||
|  |   reg(0x83) = 0x00; | ||||||
|  |  | ||||||
|  |   while (reg(0x83).get() == 0x00) | ||||||
|  |     yield(); | ||||||
|  |  | ||||||
|  |   reg(0x83) = 0x01; | ||||||
|  |   uint8_t tmp = reg(0x92).get(); | ||||||
|  |   uint8_t spad_count = tmp & 0x7F; | ||||||
|  |   bool spad_type_is_aperture = tmp & 0x80; | ||||||
|  |  | ||||||
|  |   reg(0x81) = 0x00; | ||||||
|  |   reg(0xFF) = 0x06; | ||||||
|  |   reg(0x83) &= ~0x04; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x00) = 0x01; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x80) = 0x00; | ||||||
|  |  | ||||||
|  |   uint8_t ref_spad_map[6]; | ||||||
|  |   this->read_bytes(0xB0, ref_spad_map, 6); | ||||||
|  |  | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x4F) = 0x00; | ||||||
|  |   reg(0x4E) = 0x2C; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0xB6) = 0xB4; | ||||||
|  |  | ||||||
|  |   uint8_t first_spad_to_enable = spad_type_is_aperture ? 12 : 0; | ||||||
|  |   uint8_t spads_enabled = 0; | ||||||
|  |   for (int i = 0; i < 48; i++) { | ||||||
|  |     uint8_t &val = ref_spad_map[i / 8]; | ||||||
|  |     uint8_t mask = 1 << (i % 8); | ||||||
|  |  | ||||||
|  |     if (i < first_spad_to_enable || spads_enabled == spad_count) | ||||||
|  |       val &= ~mask; | ||||||
|  |     else if (val & mask) | ||||||
|  |       spads_enabled += 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   this->write_bytes(0xB0, ref_spad_map, 6); | ||||||
|  |  | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x00) = 0x00; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x09) = 0x00; | ||||||
|  |   reg(0x10) = 0x00; | ||||||
|  |   reg(0x11) = 0x00; | ||||||
|  |   reg(0x24) = 0x01; | ||||||
|  |   reg(0x25) = 0xFF; | ||||||
|  |   reg(0x75) = 0x00; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x4E) = 0x2C; | ||||||
|  |   reg(0x48) = 0x00; | ||||||
|  |   reg(0x30) = 0x20; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x30) = 0x09; | ||||||
|  |   reg(0x54) = 0x00; | ||||||
|  |   reg(0x31) = 0x04; | ||||||
|  |   reg(0x32) = 0x03; | ||||||
|  |   reg(0x40) = 0x83; | ||||||
|  |   reg(0x46) = 0x25; | ||||||
|  |   reg(0x60) = 0x00; | ||||||
|  |   reg(0x27) = 0x00; | ||||||
|  |   reg(0x50) = 0x06; | ||||||
|  |   reg(0x51) = 0x00; | ||||||
|  |   reg(0x52) = 0x96; | ||||||
|  |   reg(0x56) = 0x08; | ||||||
|  |   reg(0x57) = 0x30; | ||||||
|  |   reg(0x61) = 0x00; | ||||||
|  |   reg(0x62) = 0x00; | ||||||
|  |   reg(0x64) = 0x00; | ||||||
|  |   reg(0x65) = 0x00; | ||||||
|  |   reg(0x66) = 0xA0; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x22) = 0x32; | ||||||
|  |   reg(0x47) = 0x14; | ||||||
|  |   reg(0x49) = 0xFF; | ||||||
|  |   reg(0x4A) = 0x00; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x7A) = 0x0A; | ||||||
|  |   reg(0x7B) = 0x00; | ||||||
|  |   reg(0x78) = 0x21; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x23) = 0x34; | ||||||
|  |   reg(0x42) = 0x00; | ||||||
|  |   reg(0x44) = 0xFF; | ||||||
|  |   reg(0x45) = 0x26; | ||||||
|  |   reg(0x46) = 0x05; | ||||||
|  |   reg(0x40) = 0x40; | ||||||
|  |   reg(0x0E) = 0x06; | ||||||
|  |   reg(0x20) = 0x1A; | ||||||
|  |   reg(0x43) = 0x40; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x34) = 0x03; | ||||||
|  |   reg(0x35) = 0x44; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x31) = 0x04; | ||||||
|  |   reg(0x4B) = 0x09; | ||||||
|  |   reg(0x4C) = 0x05; | ||||||
|  |   reg(0x4D) = 0x04; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x44) = 0x00; | ||||||
|  |   reg(0x45) = 0x20; | ||||||
|  |   reg(0x47) = 0x08; | ||||||
|  |   reg(0x48) = 0x28; | ||||||
|  |   reg(0x67) = 0x00; | ||||||
|  |   reg(0x70) = 0x04; | ||||||
|  |   reg(0x71) = 0x01; | ||||||
|  |   reg(0x72) = 0xFE; | ||||||
|  |   reg(0x76) = 0x00; | ||||||
|  |   reg(0x77) = 0x00; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x0D) = 0x01; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x80) = 0x01; | ||||||
|  |   reg(0x01) = 0xF8; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |   reg(0x8E) = 0x01; | ||||||
|  |   reg(0x00) = 0x01; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x80) = 0x00; | ||||||
|  |  | ||||||
|  |   reg(0x0A) = 0x04; | ||||||
|  |   reg(0x84) &= ~0x10; | ||||||
|  |   reg(0x0B) = 0x01; | ||||||
|  |  | ||||||
|  |   measurement_timing_budget_us_ = get_measurement_timing_budget_(); | ||||||
|  |   reg(0x01) = 0xE8; | ||||||
|  |   set_measurement_timing_budget_(measurement_timing_budget_us_); | ||||||
|  |   reg(0x01) = 0x01; | ||||||
|  |  | ||||||
|  |   if (!perform_single_ref_calibration_(0x40)) { | ||||||
|  |     ESP_LOGW(TAG, "1st reference calibration failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   reg(0x01) = 0x02; | ||||||
|  |   if (!perform_single_ref_calibration_(0x00)) { | ||||||
|  |     ESP_LOGW(TAG, "2nd reference calibration failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   reg(0x01) = 0xE8; | ||||||
|  | } | ||||||
|  | void VL53L0XSensor::update() { | ||||||
|  |   if (this->initiated_read_ || this->waiting_for_interrupt_) { | ||||||
|  |     this->publish_state(NAN); | ||||||
|  |     this->status_set_warning(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // initiate single shot measurement | ||||||
|  |   reg(0x80) = 0x01; | ||||||
|  |   reg(0xFF) = 0x01; | ||||||
|  |  | ||||||
|  |   reg(0x00) = 0x00; | ||||||
|  |   reg(0x91) = stop_variable_; | ||||||
|  |   reg(0x00) = 0x01; | ||||||
|  |   reg(0xFF) = 0x00; | ||||||
|  |   reg(0x80) = 0x00; | ||||||
|  |  | ||||||
|  |   reg(0x00) = 0x01; | ||||||
|  |   this->waiting_for_interrupt_ = false; | ||||||
|  |   this->initiated_read_ = true; | ||||||
|  |   // wait for timeout | ||||||
|  | } | ||||||
|  | void VL53L0XSensor::loop() { | ||||||
|  |   if (this->initiated_read_) { | ||||||
|  |     if (reg(0x00).get() & 0x01) { | ||||||
|  |       // waiting | ||||||
|  |     } else { | ||||||
|  |       // done | ||||||
|  |       // wait until reg(0x13) & 0x07 is set | ||||||
|  |       this->initiated_read_ = false; | ||||||
|  |       this->waiting_for_interrupt_ = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (this->waiting_for_interrupt_) { | ||||||
|  |     if (reg(0x13).get() & 0x07) { | ||||||
|  |       uint16_t range_mm; | ||||||
|  |       this->read_byte_16(0x14 + 10, &range_mm); | ||||||
|  |       reg(0x0B) = 0x01; | ||||||
|  |       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()); | ||||||
|  |         this->publish_state(NAN); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       float range_m = range_mm / 1e3f; | ||||||
|  |       ESP_LOGD(TAG, "'%s' - Got distance %.3f m", this->name_.c_str(), range_m); | ||||||
|  |       this->publish_state(range_m); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace vl53l0x | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										257
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace vl53l0x { | ||||||
|  |  | ||||||
|  | struct SequenceStepEnables { | ||||||
|  |   bool tcc, msrc, dss, pre_range, final_range; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct SequenceStepTimeouts { | ||||||
|  |   uint16_t pre_range_vcsel_period_pclks, final_range_vcsel_period_pclks; | ||||||
|  |  | ||||||
|  |   uint16_t msrc_dss_tcc_mclks, pre_range_mclks, final_range_mclks; | ||||||
|  |   uint32_t msrc_dss_tcc_us, pre_range_us, final_range_us; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |  | ||||||
|  |   void dump_config() override; | ||||||
|  |   float get_setup_priority() const override { return setup_priority::DATA; } | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void loop() override; | ||||||
|  |  | ||||||
|  |   void set_signal_rate_limit(float signal_rate_limit) { signal_rate_limit_ = signal_rate_limit; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint32_t get_measurement_timing_budget_() { | ||||||
|  |     SequenceStepEnables enables{}; | ||||||
|  |     SequenceStepTimeouts timeouts{}; | ||||||
|  |  | ||||||
|  |     uint16_t start_overhead = 1910; | ||||||
|  |     uint16_t end_overhead = 960; | ||||||
|  |     uint16_t msrc_overhead = 660; | ||||||
|  |     uint16_t tcc_overhead = 590; | ||||||
|  |     uint16_t dss_overhead = 690; | ||||||
|  |     uint16_t pre_range_overhead = 660; | ||||||
|  |     uint16_t final_range_overhead = 550; | ||||||
|  |  | ||||||
|  |     // "Start and end overhead times always present" | ||||||
|  |     uint32_t budget_us = start_overhead + end_overhead; | ||||||
|  |  | ||||||
|  |     get_sequence_step_enables_(&enables); | ||||||
|  |     get_sequence_step_timeouts_(&enables, &timeouts); | ||||||
|  |  | ||||||
|  |     if (enables.tcc) | ||||||
|  |       budget_us += (timeouts.msrc_dss_tcc_us + tcc_overhead); | ||||||
|  |  | ||||||
|  |     if (enables.dss) | ||||||
|  |       budget_us += 2 * (timeouts.msrc_dss_tcc_us + dss_overhead); | ||||||
|  |     else if (enables.msrc) | ||||||
|  |       budget_us += (timeouts.msrc_dss_tcc_us + msrc_overhead); | ||||||
|  |  | ||||||
|  |     if (enables.pre_range) | ||||||
|  |       budget_us += (timeouts.pre_range_us + pre_range_overhead); | ||||||
|  |  | ||||||
|  |     if (enables.final_range) | ||||||
|  |       budget_us += (timeouts.final_range_us + final_range_overhead); | ||||||
|  |  | ||||||
|  |     measurement_timing_budget_us_ = budget_us;  // store for internal reuse | ||||||
|  |     return budget_us; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool set_measurement_timing_budget_(uint32_t budget_us) { | ||||||
|  |     SequenceStepEnables enables{}; | ||||||
|  |     SequenceStepTimeouts timeouts{}; | ||||||
|  |  | ||||||
|  |     uint16_t start_overhead = 1320;  // note that this is different than the value in get_ | ||||||
|  |     uint16_t end_overhead = 960; | ||||||
|  |     uint16_t msrc_overhead = 660; | ||||||
|  |     uint16_t tcc_overhead = 590; | ||||||
|  |     uint16_t dss_overhead = 690; | ||||||
|  |     uint16_t pre_range_overhead = 660; | ||||||
|  |     uint16_t final_range_overhead = 550; | ||||||
|  |  | ||||||
|  |     uint32_t min_timing_budget = 20000; | ||||||
|  |  | ||||||
|  |     if (budget_us < min_timing_budget) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     uint32_t used_budget_us = start_overhead + end_overhead; | ||||||
|  |  | ||||||
|  |     get_sequence_step_enables_(&enables); | ||||||
|  |     get_sequence_step_timeouts_(&enables, &timeouts); | ||||||
|  |  | ||||||
|  |     if (enables.tcc) { | ||||||
|  |       used_budget_us += (timeouts.msrc_dss_tcc_us + tcc_overhead); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (enables.dss) { | ||||||
|  |       used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + dss_overhead); | ||||||
|  |     } else if (enables.msrc) { | ||||||
|  |       used_budget_us += (timeouts.msrc_dss_tcc_us + msrc_overhead); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (enables.pre_range) { | ||||||
|  |       used_budget_us += (timeouts.pre_range_us + pre_range_overhead); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (enables.final_range) { | ||||||
|  |       used_budget_us += final_range_overhead; | ||||||
|  |  | ||||||
|  |       // "Note that the final range timeout is determined by the timing | ||||||
|  |       // budget and the sum of all other timeouts within the sequence. | ||||||
|  |       // If there is no room for the final range timeout, then an error | ||||||
|  |       // will be set. Otherwise the remaining time will be applied to | ||||||
|  |       // the final range." | ||||||
|  |  | ||||||
|  |       if (used_budget_us > budget_us) { | ||||||
|  |         // "Requested timeout too big." | ||||||
|  |         return false; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       uint32_t final_range_timeout_us = budget_us - used_budget_us; | ||||||
|  |  | ||||||
|  |       // set_sequence_step_timeout() begin | ||||||
|  |       // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) | ||||||
|  |  | ||||||
|  |       // "For the final range timeout, the pre-range timeout | ||||||
|  |       //  must be added. To do this both final and pre-range | ||||||
|  |       //  timeouts must be expressed in macro periods MClks | ||||||
|  |       //  because they have different vcsel periods." | ||||||
|  |  | ||||||
|  |       uint16_t final_range_timeout_mclks = | ||||||
|  |           timeout_microseconds_to_mclks_(final_range_timeout_us, timeouts.final_range_vcsel_period_pclks); | ||||||
|  |  | ||||||
|  |       if (enables.pre_range) { | ||||||
|  |         final_range_timeout_mclks += timeouts.pre_range_mclks; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       write_byte_16(0x71, encode_timeout_(final_range_timeout_mclks)); | ||||||
|  |  | ||||||
|  |       // set_sequence_step_timeout() end | ||||||
|  |  | ||||||
|  |       measurement_timing_budget_us_ = budget_us;  // store for internal reuse | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void get_sequence_step_enables_(SequenceStepEnables *enables) { | ||||||
|  |     uint8_t sequence_config = reg(0x01).get(); | ||||||
|  |     enables->tcc = (sequence_config >> 4) & 0x1; | ||||||
|  |     enables->dss = (sequence_config >> 3) & 0x1; | ||||||
|  |     enables->msrc = (sequence_config >> 2) & 0x1; | ||||||
|  |     enables->pre_range = (sequence_config >> 6) & 0x1; | ||||||
|  |     enables->final_range = (sequence_config >> 7) & 0x1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   enum VcselPeriodType { VCSEL_PERIOD_PRE_RANGE, VCSEL_PERIOD_FINAL_RANGE }; | ||||||
|  |  | ||||||
|  |   void get_sequence_step_timeouts_(SequenceStepEnables const *enables, SequenceStepTimeouts *timeouts) { | ||||||
|  |     timeouts->pre_range_vcsel_period_pclks = get_vcsel_pulse_period_(VCSEL_PERIOD_PRE_RANGE); | ||||||
|  |  | ||||||
|  |     timeouts->msrc_dss_tcc_mclks = reg(0x46).get() + 1; | ||||||
|  |     timeouts->msrc_dss_tcc_us = | ||||||
|  |         timeout_mclks_to_microseconds_(timeouts->msrc_dss_tcc_mclks, timeouts->pre_range_vcsel_period_pclks); | ||||||
|  |  | ||||||
|  |     uint16_t value; | ||||||
|  |     read_byte_16(0x51, &value); | ||||||
|  |     timeouts->pre_range_mclks = decode_timeout_(value); | ||||||
|  |     timeouts->pre_range_us = | ||||||
|  |         timeout_mclks_to_microseconds_(timeouts->pre_range_mclks, timeouts->pre_range_vcsel_period_pclks); | ||||||
|  |  | ||||||
|  |     timeouts->final_range_vcsel_period_pclks = get_vcsel_pulse_period_(VCSEL_PERIOD_FINAL_RANGE); | ||||||
|  |  | ||||||
|  |     read_byte_16(0x71, &value); | ||||||
|  |     timeouts->final_range_mclks = decode_timeout_(value); | ||||||
|  |  | ||||||
|  |     if (enables->pre_range) { | ||||||
|  |       timeouts->final_range_mclks -= timeouts->pre_range_mclks; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     timeouts->final_range_us = | ||||||
|  |         timeout_mclks_to_microseconds_(timeouts->final_range_mclks, timeouts->final_range_vcsel_period_pclks); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint8_t get_vcsel_pulse_period_(VcselPeriodType type) { | ||||||
|  |     uint8_t vcsel; | ||||||
|  |     if (type == VCSEL_PERIOD_PRE_RANGE) | ||||||
|  |       vcsel = reg(0x50).get(); | ||||||
|  |     else if (type == VCSEL_PERIOD_FINAL_RANGE) | ||||||
|  |       vcsel = reg(0x70).get(); | ||||||
|  |     else | ||||||
|  |       return 255; | ||||||
|  |  | ||||||
|  |     return (vcsel + 1) << 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint32_t get_macro_period_(uint8_t vcsel_period_pclks) { | ||||||
|  |     return ((2304UL * vcsel_period_pclks * 1655UL) + 500UL) / 1000UL; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint32_t timeout_mclks_to_microseconds_(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks) { | ||||||
|  |     uint32_t macro_period_ns = get_macro_period_(vcsel_period_pclks); | ||||||
|  |     return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000; | ||||||
|  |   } | ||||||
|  |   uint32_t timeout_microseconds_to_mclks_(uint32_t timeout_period_us, uint8_t vcsel_period_pclks) { | ||||||
|  |     uint32_t macro_period_ns = get_macro_period_(vcsel_period_pclks); | ||||||
|  |     return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   uint16_t decode_timeout_(uint16_t reg_val) { | ||||||
|  |     // format: "(LSByte * 2^MSByte) + 1" | ||||||
|  |     uint8_t msb = (reg_val >> 8) & 0xFF; | ||||||
|  |     uint8_t lsb = (reg_val >> 0) & 0xFF; | ||||||
|  |     return (uint16_t(lsb) << msb) + 1; | ||||||
|  |   } | ||||||
|  |   uint16_t encode_timeout_(uint16_t timeout_mclks) { | ||||||
|  |     // format: "(LSByte * 2^MSByte) + 1" | ||||||
|  |     uint32_t ls_byte = 0; | ||||||
|  |     uint16_t ms_byte = 0; | ||||||
|  |  | ||||||
|  |     if (timeout_mclks <= 0) | ||||||
|  |       return 0; | ||||||
|  |  | ||||||
|  |     ls_byte = timeout_mclks - 1; | ||||||
|  |  | ||||||
|  |     while ((ls_byte & 0xFFFFFF00) > 0) { | ||||||
|  |       ls_byte >>= 1; | ||||||
|  |       ms_byte++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return (ms_byte << 8) | (ls_byte & 0xFF); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool perform_single_ref_calibration_(uint8_t vhv_init_byte) { | ||||||
|  |     reg(0x00) = 0x01 | vhv_init_byte;  // VL53L0X_REG_SYSRANGE_MODE_START_STOP | ||||||
|  |  | ||||||
|  |     uint32_t start = millis(); | ||||||
|  |     while ((reg(0x13).get() & 0x07) == 0) { | ||||||
|  |       if (millis() - start > 1000) | ||||||
|  |         return false; | ||||||
|  |       yield(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     reg(0x0B) = 0x01; | ||||||
|  |     reg(0x00) = 0x00; | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   float signal_rate_limit_; | ||||||
|  |   uint32_t measurement_timing_budget_us_; | ||||||
|  |   bool initiated_read_{false}; | ||||||
|  |   bool waiting_for_interrupt_{false}; | ||||||
|  |   uint8_t stop_variable_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace vl53l0x | ||||||
|  | }  // namespace esphome | ||||||
		Reference in New Issue
	
	Block a user