#include "knx_dali_channel.h" #include "dali_define.hpp" #include "knxprod.h" #include "dali_helper.h" #include "esp_log.h" #include "esp_timer.h" namespace gateway { namespace knx_dali_gw { KnxDaliChannel::KnxDaliChannel() = default; KnxDaliChannel::~KnxDaliChannel() = default; void KnxDaliChannel::init(uint8_t channel_index, bool is_group, DaliGatewayBridge& bridge) { index_ = channel_index; is_group_ = is_group; dali_ = &bridge; } void KnxDaliChannel::setup() { if (dali_ == nullptr) return; // Query initial state DaliTarget target = is_group_ ? DaliTarget{DaliTargetKind::kGroup, static_cast(index_)} : DaliTarget{DaliTargetKind::kShortAddress, static_cast(index_)}; (void)target; // Will be used in full port } void KnxDaliChannel::loop() { if (dali_ == nullptr) return; loopDimming(); loopStaircase(); loopQueryLevel(); } void KnxDaliChannel::processInputKo(GroupObject& ko) { uint16_t asap = ko.asap(); int slot = static_cast(asap) - (is_group_ ? GRP_KoOffset : ADR_KoOffset) - index_ * (is_group_ ? GRP_KoBlockSize : ADR_KoBlockSize); // TODO: Full slot-to-handler mapping from DaliChannel.cpp // For now, delegate to basic handlers switch (slot) { case 0: koHandleSwitch(ko); break; // ... more slots default: break; } } // ---- Dimming ---- void KnxDaliChannel::loopDimming() { if (dimm_direction_ == DimmDirection::kNone) return; uint64_t now = esp_timer_get_time() / 1000ULL; if (now - dimm_last_ < dimm_interval_) return; dimm_last_ = now; DaliTarget target = is_group_ ? DaliTarget{DaliTargetKind::kGroup, static_cast(index_)} : DaliTarget{DaliTargetKind::kShortAddress, static_cast(index_)}; if (dimm_direction_ == DimmDirection::kUp) { if (current_step_ < max_) current_step_++; dali_->setArc(target, current_step_); } else { if (current_step_ > min_) current_step_--; dali_->setArc(target, current_step_); } } // ---- Staircase ---- void KnxDaliChannel::loopStaircase() { if (interval_ == 0 || !current_state_) return; uint64_t now = esp_timer_get_time() / 1000ULL; if (now - start_time_ >= interval_ * 1000ULL) { current_state_ = false; interval_ = 0; DaliTarget target = is_group_ ? DaliTarget{DaliTargetKind::kGroup, static_cast(index_)} : DaliTarget{DaliTargetKind::kShortAddress, static_cast(index_)}; dali_->off(target); } } // ---- Query Level ---- void KnxDaliChannel::loopQueryLevel() { // Periodic status query — simplified for now } // ---- Switch State ---- void KnxDaliChannel::setSwitchState(bool value, bool is_switch_command) { if (current_is_locked_) return; current_state_ = value; DaliTarget target = is_group_ ? DaliTarget{DaliTargetKind::kGroup, static_cast(index_)} : DaliTarget{DaliTargetKind::kShortAddress, static_cast(index_)}; if (value) { dali_->on(target); } else { dali_->off(target); } if (value) { start_time_ = esp_timer_get_time() / 1000ULL; } } // ---- Configuration setters ---- void KnxDaliChannel::setOnValue(uint8_t value) { on_day_ = value; on_night_ = value / 2; } void KnxDaliChannel::setGroups(uint16_t groups) { groups_ = groups; } void KnxDaliChannel::setGroupState(uint8_t group, bool state) { if (state) groups_ |= (1 << group); else groups_ &= ~(1 << group); } void KnxDaliChannel::setGroupState(uint8_t group, uint8_t) {} void KnxDaliChannel::setMinMax(uint8_t min, uint8_t max) { min_ = min; max_ = max; } void KnxDaliChannel::setMinArc(uint8_t min) { min_ = min; } void KnxDaliChannel::setHcl(uint8_t curve, uint16_t temp, uint8_t) { hcl_curve_ = curve; hcl_current_temp_ = temp; } // ---- Dimm State ---- void KnxDaliChannel::setDimmState(uint8_t value, bool, bool) { current_step_ = value; } // ---- Color ---- void KnxDaliChannel::sendColor() { if (dali_ == nullptr) return; dali_->setColourRGB(static_cast(index_), current_color_[0], current_color_[1], current_color_[2]); } // ---- KO Handlers ---- void KnxDaliChannel::koHandleSwitch(GroupObject& ko) { bool on = static_cast(ko.value()); setSwitchState(on); } void KnxDaliChannel::koHandleDimmRel(GroupObject& ko) { int step = static_cast(static_cast(ko.value())); if (step > 0) { dimm_direction_ = DimmDirection::kUp; dimm_step_ = static_cast(step); } else if (step < 0) { dimm_direction_ = DimmDirection::kDown; dimm_step_ = static_cast(-step); } else { dimm_direction_ = DimmDirection::kNone; } dimm_last_ = esp_timer_get_time() / 1000ULL; } void KnxDaliChannel::koHandleDimmAbs(GroupObject& ko) { uint8_t value = static_cast(static_cast(ko.value()) * 255.0f / 100.0f); setDimmState(value); dimm_direction_ = DimmDirection::kNone; DaliTarget target = is_group_ ? DaliTarget{DaliTargetKind::kGroup, static_cast(index_)} : DaliTarget{DaliTargetKind::kShortAddress, static_cast(index_)}; dali_->setArc(target, value); } void KnxDaliChannel::koHandleLock(GroupObject& ko) { bool lock = static_cast(ko.value()); current_is_locked_ = lock; } void KnxDaliChannel::koHandleColor(GroupObject& ko) { KNXValue val = ko.value(); if (true) { // RGB packed in float or raw bytes // Simplified: store and send sendColor(); } } } // namespace knx_dali_gw } // namespace gateway