switch off display via xorg.xset
parent
0d085862db
commit
0b4afd4899
|
@ -13,7 +13,8 @@
|
|||
version = "0.0.1";
|
||||
src = ./src;
|
||||
propagatedBuildInputs = with pkgs.python311Packages; [
|
||||
pkgs.brightnessctl
|
||||
pkgs.light
|
||||
pkgs.xorg.xset
|
||||
|
||||
coloredlogs
|
||||
configargparse
|
||||
|
@ -26,7 +27,8 @@
|
|||
devShells.default = pkgs.mkShell {
|
||||
name = "development shell";
|
||||
nativeBuildInputs = with pkgs.python311Packages; [
|
||||
pkgs.brightnessctl
|
||||
pkgs.light
|
||||
pkgs.xorg.xset
|
||||
|
||||
coloredlogs
|
||||
configargparse
|
||||
|
|
|
@ -2,6 +2,7 @@ import asyncio
|
|||
import enum
|
||||
import evdev
|
||||
import logging
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import ha_mqtt_discoverable
|
||||
|
@ -22,13 +23,18 @@ class DisplayBrightnessManager():
|
|||
brightness_mode = BrightnessMode.MODE_AUTO
|
||||
brightness_mode_new = BrightnessMode.MODE_AUTO
|
||||
brightness_level = BrightnessLevel.LEVEL_BRIGHT
|
||||
brightness_value = 0
|
||||
brightness_value_new = 50
|
||||
mqtt_entity = None
|
||||
|
||||
display_device = None
|
||||
display_switched_off = False
|
||||
touch_device = None
|
||||
logger = None
|
||||
|
||||
def __init__(self, device, touch_device, logger: logging.Logger):
|
||||
def __init__(self, device, display_device, touch_device, logger: logging.Logger):
|
||||
self.logger = logger
|
||||
self.display_device = display_device
|
||||
self.touch_device = self.get_touch_device(touch_device)
|
||||
|
||||
force_display_on_info = ha_mqtt_discoverable.sensors.SwitchInfo(
|
||||
|
@ -39,7 +45,10 @@ class DisplayBrightnessManager():
|
|||
self.mqtt_entity = ha_mqtt_discoverable.sensors.Switch(switch_settings, self.switch_callback)
|
||||
self.mqtt_entity.set_availability(True)
|
||||
|
||||
def get_touch_device(self, touch_device: str) -> evdev.InputDevice:
|
||||
def get_touch_device(self, touch_device) -> evdev.InputDevice:
|
||||
if touch_device is None:
|
||||
return None
|
||||
|
||||
if '/dev/input' in touch_device:
|
||||
return evdev.InputDevice(touch_device)
|
||||
|
||||
|
@ -61,19 +70,29 @@ class DisplayBrightnessManager():
|
|||
self.set_mode(BrightnessMode.MODE_AUTO)
|
||||
self.mqtt_entity.off()
|
||||
|
||||
def get_last_input(self):
|
||||
return self.last_input
|
||||
def get_brightness_value(self) -> float:
|
||||
return self.brightness_value
|
||||
|
||||
def get_level(self) -> BrightnessLevel:
|
||||
return self.brightness_level
|
||||
|
||||
def get_mode(self) -> BrightnessMode:
|
||||
return self.brightness_mode
|
||||
def set_brightness_value(self):
|
||||
res = subprocess.run(['light', '-S', f'{ number }%'])
|
||||
if res.returncode != 0:
|
||||
logger.warn(f'failed to set brightness: exit code { res.returncode }')
|
||||
|
||||
def set_mode(self, mode: BrightnessMode):
|
||||
self.brightness_mode_new = mode
|
||||
logging.info(f'brightness mode: {self.brightness_mode}, new mode: {self.brightness_mode_new}')
|
||||
|
||||
async def switch_display_on(self):
|
||||
self.logger.info('switching screen on')
|
||||
self.display_switched_off = False
|
||||
await asyncio.create_subprocess_exec('xset', '-display', self.display_device, 'dpms', 'force', 'on')
|
||||
|
||||
async def switch_display_off(self):
|
||||
self.logger.info('switching screen off')
|
||||
self.display_switched_off = True
|
||||
await asyncio.create_subprocess_exec('xset', '-display', self.display_device, 'dpms', 'force', 'off')
|
||||
|
||||
|
||||
async def input_device_loop(self):
|
||||
async for ev in self.touch_device.async_read_loop():
|
||||
now = time.time()
|
||||
|
@ -83,23 +102,46 @@ class DisplayBrightnessManager():
|
|||
|
||||
async def dim_screen(self, to_value):
|
||||
self.logger.debug(f'dimming screen to {to_value}')
|
||||
self.brightness_value = to_value
|
||||
self.brightness_value_new = to_value
|
||||
from_value = 0
|
||||
if self.brightness_level == BrightnessLevel.LEVEL_DIM:
|
||||
from_value = 5
|
||||
elif self.brightness_level == BrightnessLevel.LEVEL_BRIGHT:
|
||||
from_value = 50
|
||||
|
||||
step_val=(to_value-from_value)/25
|
||||
for i in range(1, 25):
|
||||
if to_value != 0 and self.display_switched_off:
|
||||
await self.switch_display_on()
|
||||
return
|
||||
|
||||
self.logger.info(f'dimming screen from {from_value} to {to_value}')
|
||||
step_val=(to_value-from_value)/20
|
||||
last_val = from_value
|
||||
for i in range(1, 20):
|
||||
new_val = "{:.0f}".format(from_value + i*step_val)
|
||||
await asyncio.create_subprocess_exec('brightnessctl', 'set', f'{new_val}%', stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL)
|
||||
if new_val != last_val:
|
||||
await asyncio.create_subprocess_exec('light', '-S', f'{new_val}%', stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL)
|
||||
|
||||
await asyncio.sleep(0.005)
|
||||
last_val = new_val
|
||||
|
||||
if to_value == 0:
|
||||
await self.switch_display_off()
|
||||
await asyncio.sleep(0.1)
|
||||
self.logger.info(f'setting initial brightness to 50%')
|
||||
await asyncio.create_subprocess_exec('light', '-S', '50%', stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.DEVNULL)
|
||||
|
||||
async def brightness_loop(self):
|
||||
self.logger.info('starting brightness loop')
|
||||
res = subprocess.run(['light', '-G'], capture_output=True)
|
||||
self.brightness_value = float(res.stdout.decode('utf-8'))
|
||||
|
||||
while True:
|
||||
if self.brightness_value != self.brightness_value_new:
|
||||
await self.dim_screen(self.brightness_value_new)
|
||||
|
||||
if self.brightness_mode != self.brightness_mode_new:
|
||||
self.logger.info(f'brightness mode changede to {self.brightness_mode_new}')
|
||||
self.logger.info(f'brightness mode changed to {self.brightness_mode_new}')
|
||||
if self.brightness_mode_new == BrightnessMode.MODE_MAN:
|
||||
await self.dim_screen(50)
|
||||
self.brightness_level = BrightnessLevel.LEVEL_BRIGHT
|
||||
|
@ -108,6 +150,7 @@ class DisplayBrightnessManager():
|
|||
self.brightness_mode = self.brightness_mode_new
|
||||
|
||||
if self.brightness_mode == BrightnessMode.MODE_AUTO:
|
||||
self.logger.debug(f'brightness loop begin: {self.last_input}, {time.time()}')
|
||||
if self.last_input + 30 < time.time():
|
||||
if self.brightness_level != BrightnessLevel.LEVEL_OFF:
|
||||
await self.dim_screen(0)
|
||||
|
@ -123,11 +166,12 @@ class DisplayBrightnessManager():
|
|||
await asyncio.sleep(0.1)
|
||||
|
||||
async def run(self):
|
||||
if not self.touch_device:
|
||||
self.logger.warn('exiting display event loop: no touch device set')
|
||||
return
|
||||
tasks = [self.brightness_loop()]
|
||||
|
||||
self.logger.info('starting loops')
|
||||
|
||||
asyncio.gather(self.input_device_loop(), self.brightness_loop())
|
||||
if self.touch_device:
|
||||
tasks.append(self.input_device_loop())
|
||||
else:
|
||||
self.logger.warn('not starting display event loop: no touch device set')
|
||||
|
||||
asyncio.gather(*tasks)
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ async def main():
|
|||
parser.add_argument("--mqtt-port", dest='mqtt_port', default=os.environ.get('MQTT_PORT', 1883))
|
||||
parser.add_argument("--mqtt-user", dest='mqtt_user', default=os.environ.get('MQTT_USER'))
|
||||
parser.add_argument("--mqtt-pass", dest='mqtt_pass', default=os.environ.get('MQTT_PASS'))
|
||||
parser.add_argument("--touch-device", dest='touch_device', default=os.environ.get('TOUCH_DEVICE'))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
@ -54,23 +55,25 @@ async def main():
|
|||
|
||||
mqtt_settings = ha_mqtt_discoverable.Settings.MQTT(**mqtt_args)
|
||||
device = Device(args.device_name, args.device_id, mqtt_settings)
|
||||
sensor_entities = {
|
||||
'battery': sensor.BatterySensor(device),
|
||||
'display_brightness': sensor.DisplayBrightnessSensor(device),
|
||||
'ip_address': sensor.IPAddressSensor(device),
|
||||
'temperature': sensor.TemperatureSensor(device)
|
||||
};
|
||||
|
||||
|
||||
tasks = []
|
||||
dbm = None
|
||||
if args.display_device:
|
||||
dbm = DisplayBrightnessManager(device, args.display_device, logger)
|
||||
dbm = DisplayBrightnessManager(device, args.display_device, args.touch_device, logger)
|
||||
tasks.append(dbm.run())
|
||||
|
||||
sensor_entities = {
|
||||
'battery': sensor.BatterySensor(device),
|
||||
'display_brightness': sensor.DisplayBrightnessSensor(device, dbm),
|
||||
'ip_address': sensor.IPAddressSensor(device),
|
||||
'temperature': sensor.TemperatureSensor(device)
|
||||
};
|
||||
|
||||
tasks.append(sensor_loop(logger, sensor_entities))
|
||||
|
||||
logger.info('finished setup, starting tasks')
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
asyncio.run(main())
|
||||
|
|
|
@ -10,6 +10,7 @@ import ha_mqtt_discoverable
|
|||
import ha_mqtt_discoverable.sensors
|
||||
|
||||
from device import Device
|
||||
from display import DisplayBrightnessManager
|
||||
from paho.mqtt.client import Client, MQTTMessage
|
||||
|
||||
|
||||
|
@ -63,10 +64,13 @@ class BatterySensor():
|
|||
|
||||
|
||||
class DisplayBrightnessSensor():
|
||||
value = -1
|
||||
value = 0
|
||||
dbm = None
|
||||
mqtt_sensor = None
|
||||
|
||||
def __init__(self, device: Device):
|
||||
def __init__(self, device: Device, dbm: DisplayBrightnessManager):
|
||||
self.dbm = dbm
|
||||
|
||||
display_brightness_info = ha_mqtt_discoverable.sensors.NumberInfo(
|
||||
name="Display Brightness",
|
||||
min=0,
|
||||
|
@ -80,35 +84,21 @@ class DisplayBrightnessSensor():
|
|||
self.mqtt_sensor.set_availability(True)
|
||||
|
||||
def update_value(self):
|
||||
res = subprocess.run(['brightnessctl', '-m', 'info'], capture_output=True)
|
||||
if res.returncode != 0:
|
||||
logger.warn(f'failed to get brightness: exit code { res.returncode }')
|
||||
return
|
||||
|
||||
stdout = res.stdout.decode("utf-8")
|
||||
brightPerc = float(stdout.split(',')[3].split('%')[0])
|
||||
|
||||
brightPerc = self.dbm.get_brightness_value()
|
||||
if brightPerc != self.value:
|
||||
self.mqtt_sensor.set_value(brightPerc)
|
||||
|
||||
self.value = brightPerc
|
||||
|
||||
def set_display_brightness(self, number: float) -> float:
|
||||
res = subprocess.run(['brightnessctl', '-m', 'set', f'{ number }%'], capture_output=True)
|
||||
if res.returncode != 0:
|
||||
logger.warn(f'failed to set brightness: exit code { res.returncode }')
|
||||
return -1
|
||||
|
||||
stdout = res.stdout.decode("utf-8")
|
||||
brightPerc = float(stdout.split(',')[3].split('%')[0])
|
||||
return brightPerc
|
||||
def set_display_brightness(self, number: float):
|
||||
self.dbm.set_brightness_value(number)
|
||||
|
||||
# To receive number updates from HA, define a callback function:
|
||||
def display_brightness_callback(self, client: Client, user_data, message: MQTTMessage):
|
||||
number = int(message.payload.decode())
|
||||
logging.info(f"received new value {number} for display brightness")
|
||||
new_brightness = self.set_display_brightness(number)
|
||||
self.mqtt_sensor.set_value(new_brightness)
|
||||
self.set_display_brightness(number)
|
||||
self.mqtt_sensor.set_value(number)
|
||||
|
||||
|
||||
class IPAddressSensor():
|
||||
|
|
Loading…
Reference in New Issue