Skip to content

feat(ambient-brightness): add ambient light sensor based auto brightn… - #118

Open
fly602 wants to merge 1 commit into
linuxdeepin:masterfrom
fly602:master
Open

feat(ambient-brightness): add ambient light sensor based auto brightn…#118
fly602 wants to merge 1 commit into
linuxdeepin:masterfrom
fly602:master

Conversation

@fly602

@fly602 fly602 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

…ess plugin

Add a new ambient-brightness plugin that reads lux from iio-sensor-proxy, applies filtering, hysteresis, and debouncing, and publishes recommended brightness via DBus (org.deepin.dde.AmbientBrightness1). Refactor the power plugin to remove the old DConfig-based ambient brightness toggle, add isAmbientBrightnessActive() guard to PowerSavePlan so brightness save-plan operations don't conflict with ambient auto brightness. Remove redundant auto-brightness disable logic from dde-shortcut-tool since Display1.ChangeBrightness already calls prepareManualBrightnessChange() which disables ambient brightness via DBus.

新增环境光自动亮度插件,从 iio-sensor-proxy 读取 lux 值,经过滤波、滞回
和防抖处理后通过 DBus 发布推荐亮度。重构 power 插件,删除旧的 DConfig
自动亮度开关,在 PowerSavePlan 中添加 isAmbientBrightnessActive 守卫避免 省电计划与自动亮度冲突。移除 dde-shortcut-tool 中冗余的自动亮度关闭逻辑
(Display1.ChangeBrightness 已通过 prepareManualBrightnessChange 处理)。

Log: add ambient brightness plugin and refactor power/shortcut for auto brightness

Summary by Sourcery

Introduce a new ambient brightness plugin that exposes automatic brightness recommendations over DBus and integrates it with existing power and shortcut components.

New Features:

  • Add a session-level ambient-brightness plugin that reads lux from iio-sensor-proxy, applies filtering and hysteresis, and publishes recommended brightness via org.deepin.dde.AmbientBrightness1 on DBus.

Enhancements:

  • Integrate ambient brightness state with the power manager so power save brightness adjustments are skipped while auto brightness is active.
  • Remove legacy DConfig-based ambient auto brightness toggles and redundant manual disable logic from power and shortcut components, relying on the new ambient brightness service instead.
  • Add build and test infrastructure for the ambient-brightness plugin, including CMake setup, unit tests and Python-based tooling for sensor simulation and scenario testing.

Build:

  • Extend top-level and plugin CMake configuration to build and install the new ambient-brightness module and its tests.

Documentation:

  • Add README documentation for the ambient-brightness plugin and its continuous policy, configuration, lifecycle, and testing tools.

Tests:

  • Add unit tests for the continuous ambient light policy, brightness curve mapping, lifecycle state handling, model behavior, and ramp application tooling.
  • Add shell/Python-based scenario test scripts and tools to simulate ambient light changes and validate auto brightness ramp behavior.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @fly602, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fly602

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

Add a new ambient-brightness plugin that exposes org.deepin.dde.AmbientBrightness1 on D-Bus, implements continuous ambient light based brightness recommendation with hysteresis/debounce and lifecycle handling, wires it into the Qt plugin build, and refactors existing power and shortcut code to rely on the new DBus state instead of the old DConfig toggle, preventing conflicts with power save brightness adjustments.

Sequence diagram for ambient brightness recommendation and power-plan guard

sequenceDiagram
    participant SensorProxy as net_hadess_SensorProxy
    participant AmbientBrightnessService
    participant AmbientBrightnessModel
    participant ContinuousAmbientLightPolicy
    participant AmbientBrightness1 as org_deepin_dde_AmbientBrightness1
    participant SessionDBusProxy
    participant PowerManager
    participant PowerSavePlan

    SensorProxy->>AmbientBrightnessService: PropertiesChanged(LightLevel)
    AmbientBrightnessService->>AmbientBrightnessModel: submitSample(lux, timestamp)
    AmbientBrightnessModel->>ContinuousAmbientLightPolicy: update(SensorSample)
    ContinuousAmbientLightPolicy-->>AmbientBrightnessModel: Recommendation
    AmbientBrightnessModel-->>AmbientBrightnessService: recommendedBrightnessChanged(brightness)
    AmbientBrightnessService-->>AmbientBrightness1: PropertiesChanged(State=Active, RecommendedBrightness)

    PowerSavePlan->>PowerManager: isAmbientBrightnessActive()
    PowerManager->>SessionDBusProxy: isAmbientBrightnessActive()
    SessionDBusProxy->>AmbientBrightness1: get Property(State)
    AmbientBrightness1-->>SessionDBusProxy: State
    SessionDBusProxy-->>PowerManager: bool
    alt ambient brightness active
        PowerSavePlan-->>PowerSavePlan: [skip brightness change]
    else inactive
        PowerSavePlan-->>PowerSavePlan: applyBrightnessDrop()/resetBrightness()
    end
Loading

File-Level Changes

Change Details Files
Introduce a session-level ambient brightness service and continuous policy implementation driven by iio-sensor-proxy and DConfig.
  • Implement AmbientBrightnessService to manage sensor DBus interfaces, lifecycle (lid, sleep, login1 session), algorithm configuration, and org.deepin.dde.AmbientBrightness1 properties/signals.
  • Add AmbientBrightnessModel and an AmbientBrightnessPolicy abstraction, plus a ContinuousAmbientLightPolicy with ring buffer, weighted windows/raw modes, hysteresis, debounce and brightness recommendation logic.
  • Provide BrightnessCurve for log1p(lux)-space interpolation, a policy factory that reads DConfig JSON to build and configure the continuous policy, and tests for policy, curve, model and lifecycle.
  • Add debugging/testing scripts and Python/unittest harness for ambient-light-tool ramp behavior and scenario scripts.
src/plugin-qt/ambient-brightness/ambientbrightnessservice.cpp
src/plugin-qt/ambient-brightness/ambientbrightnessservice.h
src/plugin-qt/ambient-brightness/ambientbrightnessmodel.cpp
src/plugin-qt/ambient-brightness/ambientbrightnessmodel.h
src/plugin-qt/ambient-brightness/ambientbrightnesspolicy.h
src/plugin-qt/ambient-brightness/ambientbrightnesspolicyfactory.cpp
src/plugin-qt/ambient-brightness/ambientbrightnesspolicyfactory.h
src/plugin-qt/ambient-brightness/continuous/continuousambientlightpolicy.cpp
src/plugin-qt/ambient-brightness/continuous/continuousambientlightpolicy.h
src/plugin-qt/ambient-brightness/brightnesscurve.cpp
src/plugin-qt/ambient-brightness/brightnesscurve.h
src/plugin-qt/ambient-brightness/ambientlightlifecyclestate.h
src/plugin-qt/ambient-brightness/ambientbrightnesslogging.cpp
src/plugin-qt/ambient-brightness/ambientbrightnesslogging.h
src/plugin-qt/ambient-brightness/plugin.cpp
src/plugin-qt/ambient-brightness/CMakeLists.txt
src/plugin-qt/ambient-brightness/tests/*
src/plugin-qt/ambient-brightness/scripts/*
src/plugin-qt/ambient-brightness/configs/org.deepin.dde.daemon.ambient-brightness.json
src/plugin-qt/ambient-brightness/misc/ambient-brightness.service
src/plugin-qt/ambient-brightness/misc/plugin-ambient-brightness.json
Integrate the ambient-brightness plugin into the Qt plugin build and enable CTest-based testing.
  • Include CTest at top-level and in the ambient-brightness CMake to enable BUILD_TESTING.
  • Add ambient-brightness subdirectory to src/plugin-qt/CMakeLists.txt and define a MODULE library linked against Qt Core/DBus and Dtk Core/DConfig.
  • Install the plugin module, service-manager JSON, DBus service file, and DConfig metadata into appropriate install dirs.
  • Add CMake test targets for continuous policy, brightness curve, model, lifecycle, and Python-based ambient-light-tool ramp tests.
CMakeLists.txt
src/plugin-qt/CMakeLists.txt
src/plugin-qt/ambient-brightness/CMakeLists.txt
src/plugin-qt/ambient-brightness/tests/CMakeLists.txt
Expose ambient brightness active state to the power session via DBus and guard power save brightness operations when auto brightness is active.
  • Extend SessionDBusProxy to create an org.deepin.dde.AmbientBrightness1 DDBusInterface and add isAmbientBrightnessActive() reading its State property.
  • Add PowerManager::isAmbientBrightnessActive() delegating to the proxy, and use it in PowerSavePlan::resetBrightness/applyBrightnessDrop to skip brightness changes and clear m_oldBrightness when ambient auto brightness is active.
  • Initialize login1 session and power lifecycle hooks inside AmbientBrightnessService to coordinate enabling/disabling sensor claims with power events.
src/plugin-qt/power/session/sessiondbusproxy.cpp
src/plugin-qt/power/session/sessiondbusproxy.h
src/plugin-qt/power/session/powermanager.cpp
src/plugin-qt/power/session/powermanager.h
src/plugin-qt/power/session/powersaveplan.cpp
Remove legacy DConfig-based ambient brightness toggle and redundant shortcut-side disabling logic now that Display1/ambient-brightness service coordinate auto brightness state.
  • Delete AmbientLightAdjustBrightness Q_PROPERTY, setter/getter, backing field and DConfig init wiring from PowerManager and PowerDConfig.
  • Remove the KEY_AMBIENT_LIGHT_ADJUST_BRIGHTNESS constant from dde-shortcut-tool constants.
  • Simplify DisplayController::changeBrightness by removing DConfig access and ambientLightAdjustBrightness disabling, relying on Display1.ChangeBrightness/prepareManualBrightnessChange to handle DBus-based ambient brightness disable.
  • Drop DConfig include and namespace use from dde-shortcut-tool displaycontroller.cpp.
src/plugin-qt/power/session/powermanager.cpp
src/plugin-qt/power/session/powermanager.h
src/plugin-qt/power/powerconstants.h
src/plugin-qt/shortcut/tools/dde-shortcut-tool/constant.h
src/plugin-qt/shortcut/tools/dde-shortcut-tool/displaycontroller.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@fly602
fly602 force-pushed the master branch 4 times, most recently from 8ae717f to e346e81 Compare July 31, 2026 06:59
@deepin-bot

deepin-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

TAG Bot

New tag: 1.0.37
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #124

@fly602
fly602 force-pushed the master branch 2 times, most recently from e61173a to 29e7d37 Compare August 4, 2026 07:49
1. Add an ambient brightness service backed by iio-sensor-proxy
2. Convert lux samples into stable brightness recommendations with filtering, hysteresis, and debounce
3. Coordinate sensor lifecycle with lid, sleep, session, service, and configuration state

Influence:
1. Publish automatic brightness state and recommendations through org.deepin.dde.AmbientBrightness1
2. Prevent power-saving and manual brightness paths from conflicting with ambient brightness
3. Verify sensor lifecycle and brightness policy with unit tests

fix: 支持环境光自动亮度调节

1. 新增基于iio-sensor-proxy的环境光亮度服务
2. 通过滤波、滞回和防抖将lux样本转换为稳定的亮度推荐值
3. 根据合盖、休眠、会话、传感器服务及配置状态管理光感生命周期

Influence:
1. 通过org.deepin.dde.AmbientBrightness1发布自动亮度状态及推荐值
2. 避免省电及手动亮度调节路径与环境光自动亮度冲突
3. 通过单元测试验证光感生命周期及亮度策略

PMS: BUG-372191
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码实现了环境光自动亮度插件的完整功能,架构清晰且无安全漏洞
逻辑正确、质量优秀、性能高效,因部分同步D-Bus调用可能阻塞主线程扣5分

■ 【详细分析】

  • 1.语法逻辑(完全正确)✓

代码采用C++17标准,充分利用std::optional和std::unique_ptr等现代特性避免空指针和内存泄漏。AmbientLightRingBuffer在容量不足时正确执行两倍扩容与数据迁移。状态机转换逻辑严密,各生命周期条件通过AmbientLightLifecycleState统一管理,未发现竞态条件或逻辑缺陷。
建议:将AmbientBrightnessService::connectSensor中的同步D-Bus调用ClaimLight改为异步调用,避免在主事件循环中阻塞。

  • 2.代码质量(优秀)✓

代码分层极其清晰,严格遵循插件入口、服务层、模型层、算法层的解耦设计。README.md与算法文档详尽完备,涵盖了状态机流转、配置项说明及数学公式。命名规范统一,日志分类使用Q_LOGGING_CATEGORY管理,测试用例覆盖了核心的防抖、滞回和状态重置场景。
建议:无

  • 3.代码性能(高效)✓

算法层使用固定容量的环形缓冲区存储样本,时间复杂度为O(N)的加权计算仅在窗口内少量样本上执行。服务层采用单次QTimer进行防抖确认,完全避免了无谓的轮询开销。缓冲区扩容仅在极高采样率下触发,且扩容后平摊时间复杂度为O(1)。
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码对外仅暴露D-Bus属性和简单的Enable槽函数,未提供任何提权或敏感文件操作接口。在读取DConfig外部配置时,通过readFiniteDouble函数严格过滤了NaN和Inf等非法浮点数。在解析continuousLuxCurve的JSON数据时,对数组类型、对象结构及数值存在性进行了逐层校验,有效防止了畸形数据导致的异常。

  • 建议:保持现有的防御性校验逻辑,无需额外修复

■ 【改进建议代码示例】

// ambientbrightnessservice.cpp
// 将同步的 ClaimLight 调用改为异步调用,防止主线程被 system bus 阻塞
void AmbientBrightnessService::connectSensor()
{
    disconnectSensor();
    auto systemBus = QDBusConnection::systemBus();
    m_sensor = new QDBusInterface(QString::fromLatin1(kSensorService),
                                  QString::fromLatin1(kSensorPath),
                                  QString::fromLatin1(kSensorInterface),
                                  systemBus, this);
    if (!m_sensor->isValid()) {
        qCWarning(logAmbientBrightness) << "sensor interface invalid";
        delete m_sensor;
        m_sensor = nullptr;
        m_model.makeUnavailable();
        return;
    }

    const bool hasAmbientLight = m_sensor->property("HasAmbientLight").toBool();
    const QString unit = m_sensor->property("LightLevelUnit").toString();
    if (!hasAmbientLight || (!unit.isEmpty() && unit != QLatin1String("lux"))) {
        delete m_sensor;
        m_sensor = nullptr;
        m_model.makeUnavailable();
        return;
    }

    const bool signalConnected = systemBus.connect(
        QString::fromLatin1(kSensorService), QString::fromLatin1(kSensorPath),
        QString::fromLatin1(kPropertiesInterface), QStringLiteral("PropertiesChanged"),
        this, SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
    if (!signalConnected) {
        qCWarning(logAmbientBrightness) << "failed to subscribe to sensor PropertiesChanged"
                                        << systemBus.lastError().message();
        delete m_sensor;
        m_sensor = nullptr;
        m_model.makeUnavailable();
        return;
    }

    m_waitingForInitialSample = true;
    m_claimInProgress = true;
    m_havePendingInitialSample = false;

    // 使用异步调用替代同步的 m_sensor->call(QStringLiteral("ClaimLight"))
    auto *reply = m_sensor->asyncCall(QStringLiteral("ClaimLight"));
    QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
    connect(watcher, &QDBusPendingCallWatcher::finished, this,
            [this, watcher](QDBusPendingCallWatcher *self) {
                self->deleteLater();
                m_claimInProgress = false;
                QDBusReply<void> claimReply = *self;
                if (!claimReply.isValid()) {
                    qCWarning(logAmbientBrightness) << "ClaimLight failed" << claimReply.error().message();
                    stopInitialSampleWait();
                    QDBusConnection::systemBus().disconnect(
                        QString::fromLatin1(kSensorService), QString::fromLatin1(kSensorPath),
                        QString::fromLatin1(kPropertiesInterface),
                        QStringLiteral("PropertiesChanged"), this,
                        SLOT(onPropertiesChanged(QString,QVariantMap,QStringList)));
                    delete m_sensor;
                    m_sensor = nullptr;
                    m_model.makeUnavailable();
                    return;
                }
                m_claimed = true;
                m_haveSample = false;
                m_model.waitForSample();
                qCDebug(logAmbientBrightness) << "sensor claimed async successfully";
                if (m_havePendingInitialSample) {
                    const double pendingLux = m_pendingInitialLux;
                    stopInitialSampleWait();
                    processLux(pendingLux);
                } else {
                    startInitialSampleTimeout();
                }
            });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants