digitaltrails / vdu_controls

VDU controls - a control panel for monitor brightness/contrast/...
GNU General Public License v3.0
114 stars 3 forks source link

GY30/BH1750 + Arduino Lux metering potential options #45

Closed digitaltrails closed 1 year ago

digitaltrails commented 1 year ago

A simple light meter can be build using an Arduino and a GY30/BH1750 sensor. [Removed reference to dead link]

This raises some possibilities for vdu_controls to initiate transitions depending on metered light levels.

Today I built a meter using an Arduino Nano - image of wiring: 20230304_171125b

A simple Sketch using Christopher Laws' BH1750 library can be uploaded to the Arduino to retrieve a feed of Lux values:

#include <BH1750.h>
#include <Wire.h>

BH1750 lightMeter;

void setup() {
…  // Serial.println(F("BH1750 Lux values stream..."));
}

void loop() {
  float lux = lightMeter.readLightLevel();
  Serial.println(lux);
  delay(1000);
}

The feed of Lux values can be read from the USB tty on a Linux host. This feed can be used to trigger presets by issuing Linux signals (an existing capability of vdu_controls):

import os
import time

import serial
from serial import SerialException
import psutil

class Level:

    def __init__(self, min_level, max_level, signal) -> None:
        super().__init__()
        self.min = min_level
        self.max = max_level
        self.signal = signal

# (Min light level, max light level, UNIX signal number for Preset)
LEVELS = [Level(100, 200, 40), 
          Level(201, 300, 41),
          Level(300, 900, 42)]

def signal_vdu_controls(signal: int) -> bool:
    for proc in psutil.process_iter():
        if 'vdu_controls' in proc.name():
            pid = proc.pid
            os.kill(pid, signal)
            return True
    return False

try:
    current_level = None
    with serial.Serial('/dev/ttyUSB0') as gy30:
        while True:
            try:
                buffer = gy30.readline()
                value = float(buffer.decode('utf-8').replace("\r\n", ''))
                print(f"lux={value:6.2f}")
                for level in LEVELS:
                    if level != current_level:
                        if level.min <= value <= level.max:
                            print("signal")
                            if signal_vdu_controls(level.signal):
                                current_level = level
                            time.sleep(120)
            except ValueError as ve:
                print(ve, buffer)
except SerialException as se:
    print(se)

The above works and triggers presets according to the specified levels.

The issue is, how best to integrate this:

Parking all of the above, pending time to properly investigate it.

digitaltrails commented 1 year ago

OK, in case anyone is interested in this issue, I've added the following to vdu_controls...

Screenshot_20230319_175353-1a

digitaltrails commented 1 year ago

Integrating Presets to lux metering - one possible approach:

digitaltrails commented 1 year ago

OK, third approach to connecting presets to lux metering:

This seems to work quite well and I will proceed with completing/testing this approach. Working code has been pushed to v1.10 - it appears to be quite stable, but might error on exception cases, such as if a participating preset is altered or deleted:

image

digitaltrails commented 1 year ago

Implemented in version 1.10