Created
February 4, 2025 20:19
-
-
Save cemizm/57f01d8d2f23155615d28562ea2e7edc to your computer and use it in GitHub Desktop.
ESPHome DL-Bus
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import esphome.codegen as cg | |
| import esphome.config_validation as cv | |
| from esphome import pins | |
| from esphome.const import ( | |
| CONF_ID, | |
| CONF_PIN | |
| ) | |
| dlbus_ns = cg.esphome_ns.namespace("dlbus") | |
| DlBusComponent = dlbus_ns.class_("DlBus", cg.Component) | |
| CONF_INPUT_ID = "input" | |
| INPUT_IDS = {f'S{i}':i-1 for i in range(1, 17)} | |
| CONF_OUTPUT_ID = "output" | |
| OUTPUT_IDS = {f'A{i}':i-1 for i in range(1, 17)} | |
| CONF_RPM_ID = "rpm" | |
| RPM_IDS = {"A1": 0, "A2": 1, "A6": 2, "A7": 3} | |
| CONF_POWER_ID = "power" | |
| POWER_IDS = {"P1":0, "P2":1} | |
| CONF_ENERGY_ID = "energy" | |
| ENERGY_IDS = {"E1":0, "E2":1} | |
| CONF_DLBUS_ID = "dlbus_id" | |
| CONFIG_SCHEMA = ( | |
| cv.Schema( | |
| { | |
| cv.GenerateID(): cv.declare_id(DlBusComponent) | |
| } | |
| ) | |
| .extend({cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema)}) | |
| ).extend(cv.COMPONENT_SCHEMA) | |
| async def to_code(config): | |
| var = cg.new_Pvariable(config[CONF_ID]) | |
| await cg.register_component(var, config) | |
| pin = await cg.gpio_pin_expression(config[CONF_PIN]) | |
| cg.add(var.set_pin(pin)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import esphome.codegen as cg | |
| import esphome.config_validation as cv | |
| from esphome.components import binary_sensor | |
| from esphome.const import CONF_ID, DEVICE_CLASS_TEMPERATURE, UNIT_CELSIUS, STATE_CLASS_MEASUREMENT | |
| from .. import dlbus_ns, DlBusComponent, CONF_DLBUS_ID, CONF_INPUT_ID, INPUT_IDS, CONF_OUTPUT_ID, OUTPUT_IDS | |
| DlBusBinarySensor = dlbus_ns.class_("DlBusBinarySensor", cg.Component) | |
| CONFIG_SCHEMA = ( | |
| binary_sensor.binary_sensor_schema( | |
| DlBusBinarySensor | |
| ) | |
| .extend( | |
| { | |
| cv.GenerateID(CONF_DLBUS_ID): cv.use_id(DlBusComponent), | |
| cv.Optional(CONF_INPUT_ID) : cv.enum(INPUT_IDS), | |
| cv.Optional(CONF_OUTPUT_ID) : cv.enum(OUTPUT_IDS) | |
| } | |
| ) | |
| .extend(cv.polling_component_schema("60s")) | |
| ) | |
| async def to_code(config): | |
| var = await binary_sensor.new_binary_sensor(config) | |
| await cg.register_component(var, config) | |
| dlbus = await cg.get_variable(config[CONF_DLBUS_ID]) | |
| cg.add(var.set_dlbus(dlbus)) | |
| if CONF_INPUT_ID in config: | |
| cg.add(var.set_input_id(config[CONF_INPUT_ID])) | |
| elif CONF_OUTPUT_ID in config: | |
| cg.add(var.set_output_id(config[CONF_OUTPUT_ID])) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "dlbus_binary_sensor.h" | |
| #include "esphome/core/log.h" | |
| #include "esphome/core/helpers.h" | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| static const char *const TAG = "DlBus.BinarySensor"; | |
| // different bit length per device type | |
| void DlBusBinarySensor::setup() | |
| { | |
| ESP_LOGCONFIG(TAG, "Setting up DlBusBinarySensor..."); | |
| } | |
| void DlBusBinarySensor::dump_config() | |
| { | |
| ESP_LOGCONFIG(TAG, "DlBus BinarySensor:"); | |
| if(this->input_id_ != UINT8_MAX) | |
| ESP_LOGCONFIG(TAG, " Input: S%d", this->input_id_ + 1); | |
| if(this->output_id_ != UINT8_MAX) | |
| ESP_LOGCONFIG(TAG, " Output: A%d", this->output_id_ + 1); | |
| LOG_BINARY_SENSOR(" ", "DlBusBinarySensor", this); | |
| LOG_UPDATE_INTERVAL(this); | |
| } | |
| void DlBusBinarySensor::update() | |
| { | |
| bool val = false; | |
| DlRx::UvrSensor sensor; | |
| if(this->input_id_ != UINT8_MAX && this->dlBus_->get_sensor(this->input_id_, sensor)) | |
| val = sensor.get_binary_value(); | |
| bool tmp; | |
| if(this->output_id_ != UINT8_MAX && this->dlBus_->get_output(this->output_id_, tmp)) | |
| val = tmp; | |
| publish_state(val); | |
| } | |
| float DlBusBinarySensor::get_setup_priority() const { return setup_priority::DATA; } | |
| } // namespace duty_cycle | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include "esphome/core/component.h" | |
| #include "esphome/components/binary_sensor/binary_sensor.h" | |
| #include "esphome/components/dlbus/dlbus.h" | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| class DlBusBinarySensor : public binary_sensor::BinarySensor, public PollingComponent | |
| { | |
| public: | |
| void setup() override; | |
| void dump_config() override; | |
| void update() override; | |
| float get_setup_priority() const override; | |
| void set_dlbus(DlBus *dlBus) { this->dlBus_ = dlBus; } | |
| void set_input_id(uint8_t input_id) { this->input_id_ = input_id; } | |
| void set_output_id(uint8_t output_id) { this->output_id_ = output_id; } | |
| protected: | |
| DlBus *dlBus_{nullptr}; | |
| uint8_t input_id_{UINT8_MAX}; | |
| uint8_t output_id_{UINT8_MAX}; | |
| }; | |
| } // namespace duty_cycle | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "dlbus.h" | |
| #include "esphome/core/log.h" | |
| #include "esphome/core/helpers.h" | |
| #include <cstring> | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| static const char *const TAG = "DlBus"; | |
| // different bit length per device type | |
| void DlBus::setup() | |
| { | |
| ESP_LOGCONFIG(TAG, "Setting up DlBus Component..."); | |
| dlrx_.set_frame_handler([this](uint8_t *data, uint8_t size) | |
| { | |
| memcpy(this->frame_.buffer, data, size); | |
| dataValid = true; }); | |
| dlrx_.setup(pin_); | |
| } | |
| void DlBus::dump_config() | |
| { | |
| ESP_LOGCONFIG(TAG, "DlBus Component:"); | |
| LOG_PIN(" Pin: ", this->pin_); | |
| } | |
| bool DlBus::get_sensor(uint8_t index, DlRx::UvrSensor &sensor) | |
| { | |
| if (!dataValid) | |
| return false; | |
| if (index > 16) | |
| return false; | |
| sensor = this->frame_.UVR1611.sensor[index]; | |
| return true; | |
| } | |
| bool DlBus::get_rpm(uint8_t index, float &rpm) | |
| { | |
| if (!dataValid) | |
| return false; | |
| if (index > 3) | |
| return false; | |
| rpm = this->frame_.UVR1611.rpm_output[index]; | |
| return true; | |
| } | |
| bool DlBus::get_heatmeter(uint8_t index, DlRx::UvrPower &heat) | |
| { | |
| if (!dataValid) | |
| return false; | |
| if (index > 1) | |
| return false; | |
| heat = this->frame_.UVR1611.heatmeter[index]; | |
| return true; | |
| } | |
| bool DlBus::get_output(uint8_t index, bool &state) | |
| { | |
| if (!dataValid) | |
| return false; | |
| if (index > 16) | |
| return false; | |
| uint16_t pos = (0x01 << index); | |
| state = (this->frame_.UVR1611.actor_states & pos) == pos; | |
| return true; | |
| } | |
| float DlBus::get_setup_priority() const { return setup_priority::DATA; } | |
| } // namespace duty_cycle | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include "DlRx.h" | |
| #include "esphome/core/component.h" | |
| #include "esphome/core/hal.h" | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| class DlBus : public Component | |
| { | |
| public: | |
| void setup() override; | |
| float get_setup_priority() const override; | |
| void dump_config() override; | |
| void set_pin(InternalGPIOPin *pin) { pin_ = pin; } | |
| void update_frame(uint8_t *data, uint8_t size); | |
| bool get_sensor(uint8_t index, DlRx::UvrSensor &sensor); | |
| bool get_output(uint8_t index, bool &state); | |
| bool get_rpm(uint8_t index, float &value); | |
| bool get_heatmeter(uint8_t index, DlRx::UvrPower &heat); | |
| protected: | |
| InternalGPIOPin *pin_; | |
| DlRx dlrx_; | |
| DlRx::Frame frame_; | |
| bool dataValid{false}; | |
| }; | |
| } // namespace duty_cycle | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "DlRx.h" | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| static constexpr uint16_t INIT_SAMPLES_MAX = 2000u; // number of rising edges to collect for | |
| static constexpr uint16_t INIT_SAMPLES_MIN = 100u; // collect at least this | |
| static constexpr float INIT_SAMPLES_RANGE = 0.03f; // Range of a valid bit period | |
| static constexpr uint8_t CLOCK_SYNC_SAMPLES = 16u; // number of clock synchronization bits | |
| void DlRx::setup(InternalGPIOPin *pin) | |
| { | |
| pin->setup(); | |
| this->pin_ = pin->to_isr(); | |
| pin->attach_interrupt(DlRx::pin_isr, this, gpio::INTERRUPT_ANY_EDGE); | |
| } | |
| void IRAM_ATTR DlRx::pin_isr(DlRx *arg) | |
| { | |
| const bool new_level = arg->pin_.digital_read(); | |
| if (new_level == arg->last_level_) | |
| return; | |
| arg->last_level_ = new_level; | |
| const uint32_t now = micros(); | |
| const uint32_t tick_period = now - arg->last_tick_; | |
| bool sync_lost = false; | |
| // used for transition | |
| RxState new_state = arg->state_; | |
| // run state machine | |
| switch (arg->state_) | |
| { | |
| case RxState::Initialize: | |
| // only initialize on rising edges | |
| if (new_level) | |
| { | |
| // first samples are maybe invalid, since we do not now where we started | |
| if (arg->init_samples_ > INIT_SAMPLES_MIN) | |
| { | |
| arg->tick_period_ = std::min(arg->tick_period_, tick_period); | |
| } | |
| arg->init_samples_++; | |
| // if we collect enough samples, calculate range for a valid tick period | |
| if (arg->init_samples_ == INIT_SAMPLES_MAX) | |
| { | |
| arg->calculate_valid_tick_range(); | |
| new_state = RxState::Synchronize; | |
| } | |
| arg->last_tick_ = now; | |
| } | |
| break; | |
| case RxState::Synchronize: | |
| // only synchronize on rising edges | |
| if (new_level) | |
| { | |
| if (arg->valid_tick(tick_period)) | |
| { | |
| arg->clock_sync_samples_++; | |
| } | |
| else | |
| { | |
| arg->clock_sync_samples_ = 0; | |
| } | |
| // did we receive 16 rising edges (synchronization bits) | |
| if (arg->clock_sync_samples_ == CLOCK_SYNC_SAMPLES) | |
| { | |
| new_state = RxState::Data; | |
| } | |
| arg->last_tick_ = now; | |
| } | |
| break; | |
| case RxState::Data: | |
| if (arg->valid_tick(tick_period)) | |
| { | |
| if (arg->set_next_bit(new_level)) | |
| { | |
| if (arg->byte_complete()) | |
| { | |
| if ((arg->data_byte_position_ == 0) && | |
| (arg->device_type_ == DeviceType::Unknown)) | |
| { | |
| const DeviceType device_type = static_cast<DeviceType>(arg->data_current_byte_); | |
| sync_lost = !arg->set_device_type(device_type); | |
| } | |
| if (arg->update_next_byte()) | |
| { | |
| // frame complete | |
| new_state = RxState::Synchronize; | |
| if(arg->frame_handler_) { | |
| arg->frame_handler_(arg->data_buffer_, arg->data_byte_position_); | |
| } | |
| } | |
| } | |
| } | |
| else | |
| { | |
| sync_lost = true; | |
| } | |
| arg->last_tick_ = now; | |
| } | |
| else if (arg->receive_timeout(tick_period)) | |
| { | |
| sync_lost = true; | |
| } | |
| if (sync_lost) | |
| { | |
| arg->clock_sync_lost++; | |
| new_state = RxState::Synchronize; | |
| } | |
| break; | |
| } | |
| arg->set_state(new_state); | |
| } | |
| } // namespace dlbus | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include "esphome/core/component.h" | |
| #include "esphome/core/hal.h" | |
| #include <functional> | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| static constexpr uint8_t BUFFER_SIZE = 128u; | |
| static constexpr float VALID_TICK_OFFSET = 0.05f; | |
| static constexpr uint8_t DATA_BIT_POSITION_START = 0; // start bit | |
| static constexpr uint8_t DATA_BIT_POSITION_DATA = 1; // start bit | |
| static constexpr uint8_t DATA_BIT_POSITION_STOP = 9; // stop bit | |
| enum class DeviceType : uint8_t | |
| { | |
| Unknown = 0x00, | |
| UVR42 = 0x10u, | |
| UVR64 = 0x20u, | |
| UVR31 = 0x30u, | |
| TFM66 = 0x40u, | |
| EEG30 = 0x50u, | |
| HZR65 = 0x60u, | |
| ESR21 = 0x70u, | |
| UVR1611 = 0x80u, | |
| UVR613 = 0x90u, | |
| }; | |
| enum class RxState : uint8_t | |
| { | |
| Initialize = 0u, // reconstruct clock from data | |
| Synchronize = 1u, // synchronize sample time (valid bit time) | |
| Data = 2u // read data | |
| }; | |
| using FrameReceived = std::function<void(uint8_t *data, uint8_t size)>; | |
| class DlRx | |
| { | |
| public: | |
| void setup(InternalGPIOPin *pin); | |
| DeviceType get_device_type() { return this->device_type_; } | |
| RxState get_state() { return this->state_; } | |
| uint32_t get_error() { return this->clock_sync_lost; } | |
| enum class UvrSensorType : uint8_t | |
| { | |
| Unused = 0, | |
| Digital = 1, | |
| Temperature = 2, | |
| Flowmeter = 3, | |
| Radiation = 6, | |
| RoomTemperature = 7, | |
| }; | |
| struct UvrSensor | |
| { | |
| int16_t raw; | |
| float get_value() | |
| { | |
| int16_t value = get_sign() ? (raw | 0x7000) : (raw & 0x0FFF); | |
| switch (get_val_type()) | |
| { | |
| case UvrSensorType::Temperature: | |
| case UvrSensorType::RoomTemperature: | |
| return value * .1f; | |
| case UvrSensorType::Flowmeter: | |
| return value * .4f; | |
| case UvrSensorType::Radiation: | |
| return value * 1.f; | |
| default: | |
| return 0; | |
| } | |
| } | |
| bool get_binary_value() | |
| { | |
| return (get_val_type() == UvrSensorType::Digital) && get_sign(); | |
| } | |
| bool get_sign() | |
| { | |
| return (raw & 0x8000) == 0x8000; | |
| } | |
| UvrSensorType get_val_type() | |
| { | |
| return static_cast<UvrSensorType>((raw >> 12) & 0x7); | |
| } | |
| }; | |
| static_assert(sizeof(UvrSensor) == 2u); | |
| struct UvrPower | |
| { | |
| uint8_t power[4]; | |
| uint16_t energy_kwh; | |
| uint16_t energy_mwh; | |
| float get_energy() | |
| { | |
| return ((energy_mwh * 1000.f) + (energy_kwh * .1f)); | |
| } | |
| float get_power() | |
| { | |
| float value = NAN; | |
| int32_t high = 0x10000 * power[3] + 0x100 * power[2] + power[1]; | |
| float low = (power[0] * 100.f) / 256.f; | |
| if (!(power[3] & 0x80)) | |
| { // sign positive | |
| value = static_cast<float>(100.f * high + low); | |
| } | |
| else | |
| { // sign negative | |
| value = static_cast<float>(100.f * (high - 0x10000) - low); | |
| } | |
| return value; | |
| } | |
| }; | |
| static_assert(sizeof(UvrPower) == 8u); | |
| union Frame | |
| { | |
| uint8_t buffer[BUFFER_SIZE]; | |
| struct __attribute__((__packed__)) | |
| { | |
| DeviceType device_type; | |
| uint8_t device_type_inverted; | |
| uint8_t reserved; | |
| uint8_t time_minute; | |
| uint8_t time_hour; | |
| uint8_t time_day; | |
| uint8_t time_month; | |
| uint8_t time_year; | |
| UvrSensor sensor[16]; | |
| uint16_t actor_states; | |
| uint8_t rpm_output[4]; | |
| uint8_t power_active; | |
| UvrPower heatmeter[2]; | |
| uint8_t cheksum; | |
| } UVR1611; | |
| }; | |
| static_assert(sizeof(Frame::UVR1611) == 64u); | |
| void set_frame_handler(FrameReceived frame_received) { this->frame_handler_ = frame_received; } | |
| protected: | |
| ISRInternalGPIOPin pin_; | |
| FrameReceived frame_handler_; | |
| RxState state_{RxState::Initialize}; | |
| bool last_level_{false}; | |
| uint32_t last_tick_{0}; | |
| // reconstructed tick period (usaually 2048us or 20ms) | |
| uint32_t tick_period_{UINT32_MAX}; | |
| uint32_t min_tick_period_{UINT32_MAX}; | |
| uint32_t max_tick_period_{UINT32_MAX}; | |
| uint16_t init_samples_{0}; | |
| // clock synchronization times | |
| uint8_t clock_sync_samples_{0}; | |
| uint32_t clock_sync_lost{0}; | |
| // data sampling | |
| uint8_t data_bit_position_{0}; | |
| uint8_t data_byte_position_{0}; | |
| uint8_t data_current_byte_{0}; | |
| uint8_t expected_data_size_{0}; | |
| uint8_t data_buffer_[BUFFER_SIZE]{}; | |
| DeviceType device_type_{DeviceType::Unknown}; | |
| static void pin_isr(DlRx *arg); | |
| void set_state(RxState state) | |
| { | |
| if (this->state_ == state) | |
| return; | |
| switch (state) | |
| { | |
| case RxState::Initialize: | |
| this->tick_period_ = UINT32_MAX; | |
| this->min_tick_period_ = UINT32_MAX; | |
| this->max_tick_period_ = UINT32_MAX; | |
| this->init_samples_ = 0; | |
| this->device_type_ = DeviceType::Unknown; | |
| break; | |
| case RxState::Synchronize: | |
| this->clock_sync_samples_ = 0; | |
| break; | |
| case RxState::Data: | |
| this->data_bit_position_ = 0; | |
| this->data_byte_position_ = 0; | |
| this->data_current_byte_ = 0; | |
| break; | |
| } | |
| state_ = state; | |
| } | |
| bool set_device_type(DeviceType device_type) | |
| { | |
| if (this->device_type_ == device_type) | |
| return true; | |
| switch (device_type) | |
| { | |
| case DeviceType::UVR1611: | |
| this->device_type_ = device_type; | |
| this->expected_data_size_ = 64u; | |
| return true; | |
| default: | |
| return false; | |
| } | |
| return false; | |
| } | |
| bool valid_tick(const uint32_t tick_period) const | |
| { | |
| if (this->state_ == RxState::Initialize) | |
| return false; | |
| if (tick_period < this->min_tick_period_) | |
| return false; | |
| if (tick_period > this->max_tick_period_) | |
| return false; | |
| return true; | |
| } | |
| void calculate_valid_tick_range() | |
| { | |
| this->min_tick_period_ = this->tick_period_ - (this->tick_period_ * VALID_TICK_OFFSET); | |
| this->max_tick_period_ = this->tick_period_ + (this->tick_period_ * VALID_TICK_OFFSET); | |
| } | |
| bool receive_timeout(const uint32_t tick_period) const | |
| { | |
| return tick_period > this->max_tick_period_; | |
| } | |
| bool set_next_bit(bool level) | |
| { | |
| bool result = true; | |
| // start bit | |
| if (this->data_bit_position_ == DATA_BIT_POSITION_START) | |
| { | |
| result = (level == false); | |
| } | |
| else if (this->data_bit_position_ == DATA_BIT_POSITION_STOP) | |
| { | |
| result = (level == true); | |
| } | |
| else | |
| { | |
| const uint8_t position = this->data_bit_position_ - DATA_BIT_POSITION_DATA; | |
| const uint8_t bit = level ? 1 : 0; | |
| this->data_current_byte_ |= level << position; | |
| } | |
| this->data_bit_position_++; | |
| return result; | |
| } | |
| bool byte_complete() const | |
| { | |
| return (this->data_bit_position_ > DATA_BIT_POSITION_STOP); | |
| } | |
| bool update_next_byte() | |
| { | |
| this->data_buffer_[this->data_byte_position_] = this->data_current_byte_; | |
| this->data_current_byte_ = 0; | |
| this->data_bit_position_ = 0; | |
| this->data_byte_position_++; | |
| return this->data_byte_position_ == 64; | |
| } | |
| }; | |
| } // namespace dlbus | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import esphome.codegen as cg | |
| import esphome.config_validation as cv | |
| from esphome.components import sensor | |
| from esphome.const import CONF_ID, DEVICE_CLASS_TEMPERATURE, UNIT_CELSIUS, STATE_CLASS_MEASUREMENT | |
| from .. import dlbus_ns, DlBusComponent, CONF_DLBUS_ID, CONF_INPUT_ID, INPUT_IDS, CONF_POWER_ID, POWER_IDS, CONF_RPM_ID, RPM_IDS, CONF_ENERGY_ID, ENERGY_IDS | |
| DlBusSensor = dlbus_ns.class_("DlBusSensor", cg.Component) | |
| CONFIG_SCHEMA = ( | |
| sensor.sensor_schema( | |
| DlBusSensor, | |
| unit_of_measurement=UNIT_CELSIUS, | |
| accuracy_decimals=1, | |
| device_class=DEVICE_CLASS_TEMPERATURE, | |
| state_class=STATE_CLASS_MEASUREMENT, | |
| ) | |
| .extend( | |
| { | |
| cv.GenerateID(CONF_DLBUS_ID): cv.use_id(DlBusComponent), | |
| cv.Optional(CONF_INPUT_ID) : cv.enum(INPUT_IDS), | |
| cv.Optional(CONF_POWER_ID) : cv.enum(POWER_IDS), | |
| cv.Optional(CONF_RPM_ID) : cv.enum(RPM_IDS), | |
| cv.Optional(CONF_ENERGY_ID) : cv.enum(ENERGY_IDS) | |
| } | |
| ) | |
| .extend(cv.polling_component_schema("60s")) | |
| ) | |
| async def to_code(config): | |
| var = await sensor.new_sensor(config) | |
| await cg.register_component(var, config) | |
| dlbus = await cg.get_variable(config[CONF_DLBUS_ID]) | |
| cg.add(var.set_dlbus(dlbus)) | |
| if CONF_INPUT_ID in config: | |
| cg.add(var.set_input_id(config[CONF_INPUT_ID])) | |
| elif CONF_POWER_ID in config: | |
| cg.add(var.set_power_id(config[CONF_POWER_ID])) | |
| elif CONF_RPM_ID in config: | |
| cg.add(var.set_rpm_id(config[CONF_RPM_ID])) | |
| elif CONF_ENERGY_ID in config: | |
| cg.add(var.set_energy_id(config[CONF_ENERGY_ID])) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "dlbus_sensor.h" | |
| #include "esphome/core/log.h" | |
| #include "esphome/core/helpers.h" | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| static const char *const TAG = "DlBus.sensor"; | |
| // different bit length per device type | |
| void DlBusSensor::setup() | |
| { | |
| ESP_LOGCONFIG(TAG, "Setting up DlBusSensor..."); | |
| } | |
| void DlBusSensor::dump_config() | |
| { | |
| ESP_LOGCONFIG(TAG, "DlBus Sensor:"); | |
| if (this->input_id_ != UINT8_MAX) | |
| ESP_LOGCONFIG(TAG, " Input: S%d", this->input_id_ + 1); | |
| if (this->rpm_id_ != UINT8_MAX) | |
| ESP_LOGCONFIG(TAG, " RPM: R%d", this->rpm_id_ + 1); | |
| if (this->energy_id_ != UINT8_MAX) | |
| ESP_LOGCONFIG(TAG, " Energy: E%d", this->energy_id_ + 1); | |
| if (this->power_id_ != UINT8_MAX) | |
| ESP_LOGCONFIG(TAG, " Power: P%d", this->power_id_ + 1); | |
| LOG_SENSOR(" ", "DlBusSensor", this); | |
| LOG_UPDATE_INTERVAL(this); | |
| } | |
| void DlBusSensor::update() | |
| { | |
| float value = NAN; | |
| if (this->input_id_ != UINT8_MAX) | |
| { | |
| if (this->dlBus_->get_sensor(this->input_id_, this->sensor)) | |
| value = this->sensor.get_value(); | |
| } | |
| if (this->rpm_id_ != UINT8_MAX) | |
| { | |
| if (!this->dlBus_->get_rpm(this->rpm_id_, value)) | |
| value = NAN; | |
| } | |
| if (this->energy_id_ != UINT8_MAX) | |
| { | |
| if (this->dlBus_->get_heatmeter(this->energy_id_, this->power)) | |
| value = this->power.get_energy(); | |
| } | |
| if (this->power_id_ != UINT8_MAX) | |
| { | |
| if (this->dlBus_->get_heatmeter(this->power_id_, this->power)) | |
| value = this->power.get_power(); | |
| } | |
| if (!std::isnan(value)) | |
| { | |
| publish_state(value); | |
| } | |
| } | |
| float DlBusSensor::get_setup_priority() const { return setup_priority::DATA; } | |
| } // namespace duty_cycle | |
| } // namespace esphome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| #include "esphome/core/component.h" | |
| #include "esphome/components/sensor/sensor.h" | |
| #include "esphome/components/dlbus/dlbus.h" | |
| namespace esphome | |
| { | |
| namespace dlbus | |
| { | |
| class DlBusSensor : public sensor::Sensor, public PollingComponent | |
| { | |
| public: | |
| void setup() override; | |
| void dump_config() override; | |
| void update() override; | |
| float get_setup_priority() const override; | |
| void set_dlbus(DlBus *dlBus) { this->dlBus_ = dlBus; } | |
| void set_input_id(uint8_t input_id) { this->input_id_ = input_id; } | |
| void set_rpm_id(uint8_t rpm_id) { this->rpm_id_ = rpm_id; } | |
| void set_power_id(uint8_t power_id) { this->power_id_ = power_id; } | |
| void set_energy_id(uint8_t energy_id) { this->energy_id_ = energy_id; } | |
| protected: | |
| DlBus *dlBus_{nullptr}; | |
| uint8_t input_id_{UINT8_MAX}; | |
| uint8_t rpm_id_{UINT8_MAX}; | |
| uint8_t power_id_{UINT8_MAX}; | |
| uint8_t energy_id_{UINT8_MAX}; | |
| DlRx::UvrSensor sensor; | |
| DlRx::UvrPower power; | |
| }; | |
| } // namespace duty_cycle | |
| } // namespace esphome |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment