Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for screen to dim after a certain amount of time #2

Open
geerlingguy opened this issue Nov 4, 2024 · 22 comments
Open

Allow for screen to dim after a certain amount of time #2

geerlingguy opened this issue Nov 4, 2024 · 22 comments

Comments

@geerlingguy
Copy link
Owner

For this feature to be useful:

  1. A timeout could be configured, after which (if there's no activity), the screen could dim to a preconfigured level (e.g. 10%).
  2. Tapping anywhere on the display while the screen is dimmed would first 'wake' the display and bring it to full brightness, then after that's done, the user could touch elements on the display.

That latter point would require a bit more work—not sure if the Pi Touch Display 2 has integration into Linux itself to have some kind of automatic screen dimming support out of the box (or failing that, turn it off or dim it to 0%)...

@geerlingguy geerlingguy changed the title Allow for screen to dim (or go to 0% brightness) after a certain amount of time Allow for screen to dim after a certain amount of time Nov 4, 2024
@geerlingguy
Copy link
Owner Author

Note: There is built-in screen blanking functionality (settings for it are in the Pi Configuration app, or in raspi-config), but it doesn't seem to include much configurability... or the option of making the screen go dim instead of off.

@geerlingguy
Copy link
Owner Author

geerlingguy commented Nov 7, 2024

Might be configurable with xset? (Does that work under Wayland?)

pi@pi-touch:~ $ DISPLAY=:0 xset q
Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  00000000
  XKB indicators:
    00: Caps Lock: off
  auto repeat delay:  600    repeat rate:  25
  auto repeating keys:  00ffffffdffffbbf
                        fadfffefffedffff
                        9fffffffffffffff
                        fff7ffffffffffff
  bell percent:  50    bell pitch:  400    bell duration:  100
Pointer Control:
  acceleration:  2/1    threshold:  4
Screen Saver:
  prefer blanking:  yes    allow exposures:  yes
  timeout:  0    cycle:  0
Colors:
  default colormap:  0x2b    BlackPixel:  0x0    WhitePixel:  0xffffff
Font Path:
  /usr/share/fonts/X11/Type1,built-ins
DPMS (Energy Star):
  Server does not have the DPMS Extension

See this StackExchange answer.

@geerlingguy
Copy link
Owner Author

I did find the command swayidle -w timeout 600 'wlopm --off \*' resume 'wlopm --on \*' & tucked away inside ~/.config/labwc/autostart. If the timeout is 10 minutes, that may be where it's set...

@geerlingguy
Copy link
Owner Author

geerlingguy commented Nov 7, 2024

Indeed, changing that value changes the screen timeout, and persists across reboots.

HOWEVER, I did a quick test to see if a tap on the blank screen just wakes the screen, or is sent through as a normal 'click'. And annoyingly, it's sent through as a 'click'.

So 'tap to wake' is not really an option, at least unless you designate a 'safe area' on your UI that you can tap to wake... or if you design a circuit that jiggles a mouse input when vibration is detected, and you tap the side of the display, something like that :/

Demo:

tap-to-wake-screen.MOV

Going to ask on the forums: 'Tap to wake' Touch Display is risky

@geerlingguy
Copy link
Owner Author

From @6by9 on the Pi Forums:

I suspect this is will be common across any touch device under labwc or Wayfire, and wants to be masked at that level.
The tricky part is likely to be that a single touch almost always ends up moving slightly, and is registering effectively "button down". So effectively you've had a first "movement" that is potentially ignored as we unblank, but unlike a mouse you've now got more "down" events triggering things. So you actually want to ignore events until the first "up" response has been received. Not my area of knowledge for how that is implemented.

So it sounds like a fix could be made, but it may be a little complicated. It'd be awesome to have that fix on the OS level so I don't have to do some weird shenanigans with a system service.

For now, I'm just touching in a part of the screen where I know there are no buttons.

@gabeklavans
Copy link

gabeklavans commented Nov 8, 2024

It's probably broken now that everything is wayland, but you can take a look at my fork of this pi-touchscreen-dimmer, maybe just for some more inspiration. I've been using it to get auto dimming on my pi for years now https://github.com/gabeklavans/pi-touchscreen-dimmer. It doesn't quite achieve your 2. goal because the first tap both "wakes" and registers as a normal tap, but it's close.

Just tested it on a latest raspberry pi OS with wayland, dimming works, but the touch event doesn't. Might need more tinkering. I think any of the logic there can be lifted for this project pretty easily.

@rohtua
Copy link

rohtua commented Nov 10, 2024

It's more of a workaround than fix but I've setup an automation in Home Assistant that will turn the display on/off when motion is detected. It doesn't fix the issue however does mean that when someone's in the room and may want to use the panel the display is on so they don't accidentally press a button when waking the screen up.

I'm using a Pi 3B with Bookworm 64bit installed and the original Raspberry Pi display so there may be some difference.

You can turn the backlight on or off by changing the value in /sys/class/backlight/10-0045/bl_power
Note: the 10-0045 may change with the version/type of screen along with the values of bl_power

For my display setting bl_power to 0 = on and 4 = off. Although from testing it appears that as long as the value is set to anything other than 0 it turns the display off but not 100% sure if its doing something else in the background with the value. I established my values by turning on screen blanking in raspi-config and checking the value when it turned the screen off.

To setup the automation I setup passwordless SSH authentication between Home Assistant and the Pi.

On the Pi I then created two scripts and changed the permissions for bl_power:

sudo chmod 777 /sys/class/backlight/10-0045/bl_power

Backlight On

#!/bin/bash
echo 0 > /sys/class/backlight/10-0045/bl_power

Backlight Off

#!/bin/bash
echo 4 > /sys/class/backlight/10-0045/bl_power

I had to create them as scripts on the Pi as running the command directly through Home Assistant would fail whereas calling the script didn't.

Then I setup shell commands in Home Assistant by adding the below to my configuration.yaml

shell_command:
    cp_backlight_off: ssh -i /config/.ssh/id_rsa -o 'StrictHostKeyChecking=no' {USER}@192.168.1.127 /home/{USER}/kiosk/backlight_off.sh
    cp_backlight_on: ssh -i /config/.ssh/id_rsa -o 'StrictHostKeyChecking=no' {USER}@192.168.1.127 /home/{USER}/kiosk/backlight_on.sh

You can run the command directly from the Home Assistant terminal with the -o 'StrictHostKeyChecking=no' option however when run as part of an automation it is required (at least I couldn't figure out how to get round it).

After a restart of HA to get the shell commands to appear I created two automations.

alias: Control Panel Backlight On
description: Turn on the control panel backlight
triggers:
  - type: motion
    device_id: 5edc0dfac74a3d66ca014d9842f949bc
    entity_id: 6d291b8c0219488b10f4d1bca8271668
    domain: binary_sensor
    trigger: device
conditions: []
actions:
  - action: shell_command.cp_backlight_on
    metadata: {}
    data: {}
mode: single
alias: Control Panel Backlight Off
description: Turn off the control panel backlight
triggers:
  - type: no_motion
    device_id: 5edc0dfac74a3d66ca014d9842f949bc
    entity_id: 6d291b8c0219488b10f4d1bca8271668
    domain: binary_sensor
    trigger: device
conditions: []
actions:
  - action: shell_command.cp_backlight_off
    metadata: {}
    data: {}
mode: single

Now whenever motion is detected the screen comes on and goes off when people leave the room. Like I said it doesn't fix the issue but depending on use case it may do the job. A possible next step would be to present the backlight controls to HA as entities that could then be used as part of a normal motion-activated blueprint rather than create two seperate automations.

@geerlingguy
Copy link
Owner Author

Something like this might be just the ticket.

Couple it with radar-based presence sensors (I've been testing some Everything Presence sensors around the studio), and you could have the screen only come on while someone is detected in the room a bit more reliably than standard PIR sensors too.

Otherwise I could tie it into my Simplisafe automation (when 'Off', turn on the display...).

@rohtua
Copy link

rohtua commented Nov 10, 2024

Indeed, one other thing I've found is that the permissions on bl_power appear to reset after a reboot of the kiosk pi so I might add a cronjob to it to open the permissions up after a reboot but other than that it's been working as expected so far.

@pghpete
Copy link

pghpete commented Nov 11, 2024

I am using a rpi 4 and the older screen as well as the official case for both. (hacked a bit to hold a pwm fan) I think I am going to use one of two methods...

  1. It's manual and a bit crude but I think i'm simply going to put a tiny push button (that has a light glowing led) on the left hand side of the screen, in the blank section that is suppose to be used for a camera. I plan to have the button press simply trigger a xset dpms force off or xset dpms force on

  2. Or a more automatic way (that is already integrated into my home assistant)... the "24GHz mmWave Sensor - Human Static Presence Module Lite" $6.90 sensor from seeedstudio. SImply set the screen to come on if the room is occupied and to turn it off if it isn't.

Neither option is fantastic but it should get me by in the meantime.

@scruffyOrc
Copy link

scruffyOrc commented Nov 13, 2024

Could you use an HC-SR04 distance sensor, and rather than use tap to wake, just have the display turn on when there's something within x distance? That way, it's not only off when you're away from the building but remains off if you're nowhere near the screen, that might be even more useful than tap to wake.

@Consolatis
Copy link

Consolatis commented Nov 16, 2024

Swayidle sounds like the right approach. You can execute multiple actions on different timeouts as well. Example

Regarding the wake-up button press also being passed through to Chromium: maybe you could spawn some kind of "lockscreen" which doesn't require a password and just unlocks everything once it receives any input. If its started shortly before disabling the output via wlopm that should eat the wake-up event. In case there is no lockscreen that supports unlock-on-input, something like this might work for you instead:

test_screen_block.py
#!/usr/bin/env python3

import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")
from gi.repository import Gtk, Gdk

class ScreenSaver(Gtk.Window):
	def __init__(self):
		super().__init__()
		self.connect('motion-notify-event', Gtk.main_quit)
		self.connect('button-release-event', Gtk.main_quit)
		self.set_events(Gdk.EventMask.POINTER_MOTION_MASK)
		self.fullscreen()
		self.show()

if __name__ == '__main__':
	win = ScreenSaver()
	Gtk.main()

@thebishop85
Copy link

This seems like a great idea, but apparently we would need to run the following everytime the Pi is rebooted?

sudo chmod 777 /sys/class/backlight/10-0045/bl_power

Or is there a way to make the permission persistent?

@6by9
Copy link

6by9 commented Dec 11, 2024

This seems like a great idea, but apparently we would need to run the following everytime the Pi is rebooted?

sudo chmod 777 /sys/class/backlight/10-0045/bl_power

Or is there a way to make the permission persistent?

You need a udev rule if you want to use bl_power and the permissions are wrong.

I think brightness already has one, and could be used for the same purpose (although you need to remember the "on" brightness).
https://github.com/torvalds/linux/blob/master/Documentation/ABI/stable/sysfs-class-backlight

@thebishop85
Copy link

This seems like a great idea, but apparently we would need to run the following everytime the Pi is rebooted?

sudo chmod 777 /sys/class/backlight/10-0045/bl_power

Or is there a way to make the permission persistent?

You need a udev rule if you want to use bl_power and the permissions are wrong.

I think brightness already has one, and could be used for the same purpose (although you need to remember the "on" brightness). https://github.com/torvalds/linux/blob/master/Documentation/ABI/stable/sysfs-class-backlight

Thanks for your input!

I'm a bit of a newbie in Linux. I found out that I could possibly create a udev rule, but couldn't figure out how to do it for this specific permission(didn't find an example for this parameter). Unfortunately, I also can't figure out how to leverage the info in the link you provided.
Can anyone help with instructions or a link that explains how to do it?

Thanks in advance

@6by9
Copy link

6by9 commented Dec 11, 2024

If you look at /etc/udev/rules.d/99-com.rules, you'll see a number of lines at the start

SUBSYSTEM=="input", GROUP="input", MODE="0660"
SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660"
SUBSYSTEM=="spidev", GROUP="spi", MODE="0660"
SUBSYSTEM=="*gpiomem*", GROUP="gpio", MODE="0660"
SUBSYSTEM=="rpivid-*", GROUP="video", MODE="0660"

SUBSYSTEM is probably "backlight" (you can use udevadm to confirm).
Best to add it to the "video" group, as that is what is used for the /dev/dri display pipeline nodes.
Mode is the permissions that you want, which is probably 0664 rather than 777 (you don't need to be able to execute it).

@rohtua
Copy link

rohtua commented Dec 11, 2024

I don’t know whether I’m missing something but is it not just simplest to put a cronjob in that changes the permissions on each reboot?

All I’ve done is add the below to roots crontab and it’s doing the job.

@reboot chmod 777 /sys/class/backlight/10-0045/bl_power

@6by9
Copy link

6by9 commented Dec 11, 2024

I don’t know whether I’m missing something but is it not just simplest to put a cronjob in that changes the permissions on each reboot?

Using cron fails if the module is unloaded and reloaded. That may be an unusual situation, but it's possible.

As I've said to thebishop85, 777 is incorrect for the permissions as you should not be able to execute that device.

@leukipp
Copy link

leukipp commented Dec 17, 2024

I found out that I could possibly create a udev rule, but couldn't figure out how to do it for this specific permission.
Can anyone help with instructions or a link that explains how to do it?

@thebishop85: Something like this will probably work to make the permissions permanent:

echo 'SUBSYSTEM=="backlight", KERNEL=="10-0045", RUN+="/bin/chmod 666 /sys/class/backlight/%k/brightness"' | sudo tee -a /etc/udev/rules.d/backlight-permissions.rules

I use something similar for my touch kiosk project, which also provides a Home Assistant integration to directly control the display brightness (using a dimmable light sensor):

mqtt

HOWEVER, I did a quick test to see if a tap on the blank screen just wakes the screen, or is sent through as a normal 'click'. And annoyingly, it's sent through as a 'click'.

@geerlingguy: I addressed this issue by removing focus from the kiosk window. As a result, the first click will focus the window instead of sending a click command into the webview. However, I still view this as a temporary workaround rather than a proper solution.

@nj-dunn
Copy link

nj-dunn commented Jan 4, 2025

To summarize a few previous points here, and at least get the screen dimming working via udev and the default labwc's autostart file, this was what I had to do:

Add a new file /etc/udev/rules.d/99-kiosk.rules

SUBSYSTEM=="backlight", GROUP="video", MODE="0664"`

Append the following to $HOME/.config/labwc/autostart:

MAX_BRIGHTNESS=$(cat /sys/class/backlight/10-0045/max_brightness)
MIN_BRIGHTNESS=1
echo $MIN_BRIGHTNESS > /sys/class/backlight/10-0045/brightness
# There's a few weird behaviors going on here:
#     1. I could only get this working by running in a bash subshell.
#        labwc is executing this file by 'sh', which on Pi OS is dash
#        but everything here should be posix compatible.
#     2. The absolute path was also required for swayidle
#     3. Even with 1 and 2, if you tap the screen too early (ie, before
#        home assistant appears), swayidle never appears to take effect
/bin/bash -c "/usr/bin/swayidle -w timeout 20 'echo $MIN_BRIGHTNESS > /sys/class/backlight/10-0045/brightness' resume 'echo $MAX_BRIGHTNESS > /sys/class/backlight/10-0045/brightness' &"

@Taomyn
Copy link

Taomyn commented Jan 9, 2025

Thanks @nj-dunn I followed your steps and managed to get it all working at the first attempt - touch kiosk is so much better than using the browser, and I like the MQTT integration.

@johanneslerch
Copy link

I've got it working with turning the screen backlight off when being unused and back on when swiping over the screen - it's not waking up on a tap. Not sure why, but I'm quite happy with that.
Like you, I was initially facing the problem that a tap to wake up the screen would result in a click into something on the dashboard.

Have a look at ~/.config/labwc/rc.xml
For me the important part was to add
<touch deviceName="11-005d Goodix Capacitive TouchScreen" mapToOutput="DSI-2" mouseEmulation="no"/>
whereas disabling mouse emulation is the important part.

I've also added a device with category touch, which allows me to have gestures like zooming with to fingers, panning, etc.:

<libinput>
        <device category="default">
            <pointerSpeed>0,000000</pointerSpeed>
            <leftHanded>no</leftHanded>
        </device>
        <device category="touch">
            <pointerSpeed>1.0</pointerSpeed>
            <leftHanded>no</leftHanded>
            <tap>yes</tap> <!-- Enable tap-to-click -->
            <tapButtonMap>lmr</tapButtonMap> <!-- Map tap to left, middle, right buttons -->
            <clickMethod>clickfinger</clickMethod> <!-- Enable long-press (right-click) -->
            <sendEventsMode>yes</sendEventsMode>
        </device>
    </libinput>

Not sure if all of these are needed, but that's what I have right now and it's working.

For completeness, I have in ~/.config/labwc/autostart
swayidle -w timeout 60 'wlopm --off \*' resume 'wlopm --on \*'

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

No branches or pull requests