From 42012753a11b95df5279c0ce531bb5217c2fb69b Mon Sep 17 00:00:00 2001 From: Sam Redfern Date: Mon, 5 May 2025 22:12:44 +1000 Subject: [PATCH] Implement initial project structure and setup --- __init__.py | 3 +++ sen0590.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sensor.py | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 __init__.py create mode 100644 sen0590.cpp create mode 100644 sensor.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..a68d23f --- /dev/null +++ b/__init__.py @@ -0,0 +1,3 @@ +"""SEN0590 laser distance sensor component.""" + +DEPENDENCIES = ["i2c"] \ No newline at end of file diff --git a/sen0590.cpp b/sen0590.cpp new file mode 100644 index 0000000..08026c3 --- /dev/null +++ b/sen0590.cpp @@ -0,0 +1,55 @@ +#include "esphome/core/log.h" +#include "esphome/core/hal.h" +#include "esphome/core/component.h" +#include "esphome/components/i2c/i2c.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace sen0590 { + +static const char *const TAG = "sen0590"; +static const uint8_t COMMAND_REG = 0x10; +static const uint8_t DATA_REG = 0x02; +static const uint8_t MEASURE_COMMAND = 0xB0; + +class SEN0590Component : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { + public: + void setup() override { + ESP_LOGD(TAG, "Setting up SEN0590 laser distance sensor..."); + // Power-on delay time is ≤800ms according to specs + delay(800); + } + + void update() override { + // Send measurement command + if (!this->write_byte(COMMAND_REG, MEASURE_COMMAND)) { + ESP_LOGE(TAG, "Failed to write command"); + this->status_set_warning(); + return; + } + + // Wait for measurement to complete + delay(50); + + // Read measurement result + uint8_t buffer[2]; + if (!this->read_bytes(DATA_REG, buffer, 2)) { + ESP_LOGE(TAG, "Failed to read distance data"); + this->status_set_warning(); + return; + } + + // Calculate distance in mm and convert to cm + int distance_mm = (buffer[0] << 8) + buffer[1] + 10; + float distance_cm = distance_mm / 10.0f; + + ESP_LOGD(TAG, "Distance: %.1f cm", distance_cm); + this->publish_state(distance_cm); + this->status_clear_warning(); + } + + float get_setup_priority() const override { return setup_priority::DATA; } +}; + +} // namespace sen0590 +} // namespace esphome \ No newline at end of file diff --git a/sensor.py b/sensor.py new file mode 100644 index 0000000..bc5daf3 --- /dev/null +++ b/sensor.py @@ -0,0 +1,35 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_DISTANCE, + STATE_CLASS_MEASUREMENT, + UNIT_CENTIMETER, + ICON_ARROW_EXPAND_HORIZONTAL, +) + +DEPENDENCIES = ["i2c"] + +sen0590_ns = cg.esphome_ns.namespace("sen0590") +SEN0590Component = sen0590_ns.class_( + "SEN0590Component", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + SEN0590Component, + unit_of_measurement=UNIT_CENTIMETER, + icon=ICON_ARROW_EXPAND_HORIZONTAL, + accuracy_decimals=1, + device_class=DEVICE_CLASS_DISTANCE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend(cv.polling_component_schema("100ms")) + .extend(i2c.i2c_device_schema(0x74)) +) + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) \ No newline at end of file