Skip to content

Commit

Permalink
#93 deprecate/hide transitions.
Browse files Browse the repository at this point in the history
  • Loading branch information
digitaltrails committed Sep 26, 2024
1 parent e3174c4 commit face6a2
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 29 deletions.
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ others). The UI attempts to adapt to the quirks of the different tray implementa
Named ``Preset`` configurations can be saved for later recall. For example, a user could create
presets for night, day, photography, movies, and so forth. Presets may be automatically triggered
according to solar elevation, and can be further constrained by local weather conditions (as
reported by [https://wttr.in](https://wttr.in)). Presets can be set to transition immediately or
gradually. Presets may also be activated by UNIX signals.
reported by [https://wttr.in](https://wttr.in)). Presets may also be activated by UNIX signals.

From any application window, use `F1` to access help, and `F10` to access the context-menu. The
context menu is also available via the right-mouse button in the main-window, the hamburger-menu item
Expand All @@ -103,10 +102,10 @@ Repeatably altering VDU settings might affect VDU lifespan. Possible reasons
include the consumption of NVRAM write cycles, stressing the VDU power-supply,
or increasing the LED panel burn-in.

I have a VDU manufactured in 2010 that allows settings to be adjusted, but
reverts to factory defaults whenever it loses power. This VDU was used intensively
for testing vdu_controls over the past four years. This gives credence to the
possibility of exhausting VDU NVRAM, at least in VDUs of that vintage.
In respect to exhausting NVRAM, I can confirm that a vintage-2010 VDU used for
testing vdu_controls now reverts to factory defaults whenever it loses power.
This is after four years of use in development testing. I've subsequently
implemented the ___initialization-preset___ feature to work around the issue.

All that said, ``vdu_controls`` does include a number of features that can be used
to reduce the frequency of writes to VDU NVRAM:
Expand All @@ -115,14 +114,15 @@ to reduce the frequency of writes to VDU NVRAM:

+ Slider and spin-box controls only update the VDU when adjustments become slow or stop (when no change occurs in 0.5 seconds).
+ Preset restoration only updates the VDU values that differ from its current values.
+ Transitioning smoothly has been disabled by default and deprecated for version 2.1.0 onward.
+ Transitioning effects and transition controls have been disabled by default and are
deprecated for version 2.1.0 onward.
+ Automatic ambient brightness adjustment only triggers a change when the proposed brightness differs from the current brightness by at least 10%.

#### Electable mitigations:

+ Choose to restore pre-prepared ‘presets’ instead of dragging sliders.
+ Refrain from adding transitions to presets.
+ If using the ambient-light brightness response curves, tune the settings and curves to minimise frequent small changes.
+ If using the ambient-light brightness response curves, tune the settings and curves to avoid frequent small changes.
+ If using a light-meter, disengage metered automatic adjustment when faced with rapidly fluctuating levels of ambient brightness.
+ Consider adjusting the ambient lighting instead of the VDU.

Expand Down Expand Up @@ -329,18 +329,22 @@ Michael Hamilton
Version History
---------------
* 2.1.0
* Preset _smooth transitions_ have been deprecated. All presets are now restored instantly no
matter how they have been set to transition. The deprecated smooth-transitions can be
re-enabled by disabling `protect-nvram` in ___Settings___. Unless objections are forthcoming,
preset transition related settings will be removed in a future version.
* Preset restoration now includes additional checks to avoid unnecessarily setting VCP values when
they already the same as those in VDU.
* Preset _transitions_ have been deprecated. All presets are now restored instantly no
matter how they have been set to transition. The Preset-Dialog controls for assiging
transitions have been hidden. Transitions and related controls can be
re-enabled by disabling `protect-nvram` in the _Settings-Dialog_. __All
transition related code may be removed in a future version, please contact me
or comment on issue #93 if you prefer transitions to be retained.__
* To avoid unecessary updates, preset restoration always queries the VDU's existing
values. This may slow down preset restoration.
* Lux-metered auto adjustment has been defaulted to 10 minute intervals (up from 5).
* Color-Preset (VCP code 0x14) has been added to the list of standard controls.
* Added VDU a ___Initializer-Preset___ feature to provide a replacement for dead NVRAM and
a way to restore settings not persisted in VDU NVRAM. A VDU's initializer-preset is
automatically run if the target VDU is present at startup or is subsequently detected.
* The ___Preset-Dialog___ now includes a tool-button to the right of the preset-name entry
that will create VDU specific ___Initializer-Preset___.
that will create VDU specific ___Initializer-Preset___.
* 2.0.4
* The About-Dialog now refreshes the ddcutil version info on each invocation.
Expand Down
40 changes: 26 additions & 14 deletions vdu_controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
--dbus-signals|--no-dbus-signals
enable D-Bus ddcutil-service VDU-connectivity-change signals
``--dbus-signals`` is the default
--protect-nvram|--no-protect-nvram
alter options and defaults to minimize VDU NVRAM writes
--create-config-files
if they do not exist, create template config INI files
in $HOME/.config/vdu_controls/
Expand Down Expand Up @@ -811,7 +813,7 @@
QSplashScreen, QPushButton, QProgressBar, QComboBox, QSystemTrayIcon, QMenu, QStyle, QTextEdit, QDialog, QTabWidget, \
QCheckBox, QPlainTextEdit, QGridLayout, QSizePolicy, QAction, QMainWindow, QToolBar, QToolButton, QFileDialog, \
QWidgetItem, QScrollArea, QGroupBox, QFrame, QSplitter, QSpinBox, QDoubleSpinBox, QInputDialog, QStatusBar, qApp, QShortcut, \
QDesktopWidget
QDesktopWidget, QSpacerItem

APPNAME = "VDU Controls"
VDU_CONTROLS_VERSION = '2.1.0'
Expand Down Expand Up @@ -2016,6 +2018,7 @@ def mousePressEvent(self, event):
'60': VcpCapability('60', QT_TR_NOOP('input source'), SNC, causes_config_change=True),
'D6': VcpCapability('D6', QT_TR_NOOP('power mode'), SNC, causes_config_change=True),
'CC': VcpCapability('CC', QT_TR_NOOP('OSD language'), SNC),
'14': VcpCapability('14', QT_TR_NOOP('color preset'), SNC),
'0C': VcpCapability('0C', QT_TR_NOOP('color temperature'), CON, icon_source=COLOR_TEMPERATURE_SVG, enabled=True),
}}

Expand Down Expand Up @@ -2187,7 +2190,7 @@ class ConfOption(Enum): # TODO Enum is used for convenience for scope/iteration
conf_type=CI.TYPE_LONG_TEXT, cmdline_arg='DISALLOWED',
tip=QT_TR_NOOP('override/cache for ddcutil capabilities text'))
PROTECT_NVRAM_ENABLED = conf_opt_def(cname=QT_TR_NOOP('protect-nvram'), default="yes", restart=True,
tip=QT_TR_NOOP('alter options and defaults to maximise VDU NVRAM lifespan'))
tip=QT_TR_NOOP('alter options and defaults to minimize VDU NVRAM writes'))
UNKNOWN = conf_opt_def(cname="UNKNOWN", section=CI.UNKNOWN_SECTION, conf_type=CI.TYPE_BOOL, cmdline_arg='DISALLOWED', tip='')

def __init__(self, conf_name: str, section: str, cmdline_arg: str, conf_type: str, default: str | None,
Expand Down Expand Up @@ -4568,7 +4571,7 @@ def update_location(self, location: GeoLocation) -> None:

class PresetChooseTransitionWidget(QWidget):

def __init__(self, protect_nvram: bool) -> None:
def __init__(self) -> None:
super().__init__()
layout = QHBoxLayout()
self.setLayout(layout)
Expand All @@ -4577,7 +4580,6 @@ def __init__(self, protect_nvram: bool) -> None:
self.button_menu = QMenu()
self.transition_type = PresetTransitionFlag.NONE
self.is_setting = False
self.protect_nvram = protect_nvram

for transition_type in PresetTransitionFlag.ALWAYS.component_values():
action = QAction(transition_type.description(), self.button_menu)
Expand All @@ -4598,12 +4600,10 @@ def __init__(self, protect_nvram: bool) -> None:
def update_value(self, checked: bool) -> None:
if self.is_setting:
return
if checked and self.protect_nvram:
if checked:
alert = MessageBox(QMessageBox.Warning)
alert.setText(tr('Transtions have been deprecated to protect VDU NVRAM.'))
alert.setInformativeText('Setting this transition will have no effect '
'until protect-nvram is disabled in the Settings-Dialog.\n\n'
'Transitions are slated for removal, please '
alert.setText(tr('Transitions have been deprecated to minimize wear on VDU NVRAM.'))
alert.setInformativeText('Transitions are slated for removal, please '
'contact the developer if you wish to retain them.')
alert.exec()
for act in self.button_menu.actions():
Expand Down Expand Up @@ -5109,8 +5109,11 @@ def __init__(self, main_controller: VduAppController, main_config: VduControlsCo
self.editor_layout.addWidget(self.controls_title_widget)
self.editor_layout.addWidget(self.editor_controls_widget)

self.editor_transitions_widget = PresetChooseTransitionWidget(self.main_config.is_set(ConfOption.PROTECT_NVRAM_ENABLED))
self.editor_layout.addWidget(self.editor_transitions_widget)
self.editor_transitions_widget = PresetChooseTransitionWidget()
if self.main_config.is_set(ConfOption.PROTECT_NVRAM_ENABLED):
self.editor_layout.addItem(QSpacerItem(1,10))
else:
self.editor_layout.addWidget(self.editor_transitions_widget)

self.editor_trigger_widget = PresetChooseElevationWidget(self.main_config)
self.editor_layout.addWidget(self.editor_trigger_widget)
Expand Down Expand Up @@ -6203,7 +6206,7 @@ class LuxAutoWorker(WorkerThread): # Why is this so complicated?

_lux_dialog_message_qtsignal = pyqtSignal(str, int, MsgDestination)

def __init__(self, auto_controller: LuxAutoController, single_shot: bool = False) -> None:
def __init__(self, auto_controller: LuxAutoController, single_shot: bool = False, protect_nvram: bool = True) -> None:
super().__init__(task_body=self._adjust_for_lux, task_finished=self._adjust_for_lux_finished)
self.single_shot = single_shot # Called for an on-demand single time assessment with immediate effect.
self.main_controller = auto_controller.main_controller
Expand All @@ -6228,7 +6231,12 @@ def get_prop(prop: str, fallback: bool | int | float | str) -> bool | int | floa
self.sensitivity_percent = get_prop('interpolation-sensitivity-percent', fallback=10)
self.convergence_divisor = get_prop('convergence-divisor', fallback=2)
self.step_pause_millis = get_prop('step-pause-millis', fallback=100)
self.max_brightness_jump = get_prop('max-brightness-jump', fallback=100)
if protect_nvram:
log_info("LuxAutoWorker: protect-nvram enabled, ignoring max-brightness-jump")
self.max_brightness_jump = 100
else:
self.max_brightness_jump = get_prop('max-brightness-jump', 20)
log_warning(f"LuxAutoWorker: protect-nvram={protect_nvram} max-brightness-jump={self.max_brightness_jump}")
self._lux_dialog_message_qtsignal.connect(LuxDialog.lux_dialog_message)
self._lux_dialog_message_qtsignal.connect(self.main_controller.main_window.status_message)
self.status_message(f"{TIMER_RUNNING_SYMBOL} 00:00", 0, MsgDestination.COUNTDOWN)
Expand Down Expand Up @@ -6279,6 +6287,7 @@ def stepping_brightness(self, lux_config: LuxConfig, lux_meter: LuxMeterDevice)
change_count, last_change_count = 0, -1
start_of_cycle = True
profile_preset_name = None
vdu_changes_count = {}
while change_count != last_change_count: # while brightness changing
last_change_count = change_count
if metered_lux := lux_meter.get_value():
Expand All @@ -6297,10 +6306,12 @@ def stepping_brightness(self, lux_config: LuxConfig, lux_meter: LuxMeterDevice)
profile_brightness, profile_preset_name = self.determine_brightness(vdu_sid, smoothed_lux, lux_profile)
if self.step_one_vdu(vdu_sid, profile_brightness, profile_preset_name, lux_summary_text, start_of_cycle):
change_count += 1
vdu_changes_count[vdu_sid] = vdu_changes_count.get(vdu_sid, 0) + 1
else:
log_debug(f"LuxAutoWorker: finished {vdu_sid=} VCP-changes={vdu_changes_count.get(vdu_sid, 0)})")
start_of_cycle = False
self.doze(self.step_pause_millis / 1000.0) # Let i2c settle down, then continue - TODO is this really necessary?
if change_count != 0: # If any work was done in previous steps, finish up the remaining tasks
log_info(f"LuxAutoWorker: stepping completed {change_count} VCP-changes, {profile_preset_name=}")
self.status_message(tr("Brightness adjustment completed"), timeout=5000)
if profile_preset_name is not None: # if a point had a Preset attached, activate it now
# Restoring the Preset's non-brightness settings. Invoke now, so it will happen in this thread's sleep period.
Expand All @@ -6311,6 +6322,7 @@ def stepping_brightness(self, lux_config: LuxConfig, lux_meter: LuxMeterDevice)
scheduled_activity=True)
else: # No work done, no adjustment necessary
self.status_message(f"{SUN_SYMBOL} {SUCCESS_SYMBOL}", timeout=3000)
log_info(f"LuxAutoWorker: adjustments completed {change_count} VCP-changes, {profile_preset_name=}")

def step_one_vdu(self, vdu_sid: VduStableId, profile_brightness: int, profile_preset_name: str | None,
lux_summary_text: str, first_step: bool) -> bool:
Expand Down

0 comments on commit face6a2

Please sign in to comment.