Current version of the OpenAuto Pro is 12
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Day / night switching (OAP & AA) and brightness control using a TSL2561 sensor
#1
Day / night switching (OAP & AA) and brightness control using a TSL2561 sensor

Based on the excellent script originally posted by plasmaflow - https://bluewavestudio.io/community/show...hp?tid=672

I have updated the script so that in addition to automatically changing the screen brightness based on light levels it also toggles / triggers day night mode (also based on light level). Day / night mode is toggled / triggered by setting a nominated GPIO pin (which is monitored by OAP) high or low.

This method suits me as I cannot use headlights on to trigger Day / Night mode as headlights are required 24/7 where I live. I did try using the inbuilt TSL2561 functionality under OAP to switch day / night mode but was unable to get this to work satisfactorily (and in addition I wanted the screen brightness to also change depending on light level). I was also unable to get the phone to control Day / Night mode in AA under Android 11.

With the script night mode is set when the light level drops below a customisable level - so not only sunset but also when driving into a tunnel or dark car park etc. On sunrise or exit from tunnel etc. day mode and the appropriate brightness level is again automatically set. To stop the screen brightness fluctuating continuously /flapping (e.g. when driving in and out of shade or trees etc.) the interval between checks is customisable.

As the script runs independently of OAP it is not necessary to configure TSL2561 sensor support under OAP.

Configuration under OAP involves setting Day / Night mode for both OAP and AA to GPIO and setting the GPIO pin to be monitored as appropriate.

It is necessary to have a working / configured TSL2561 sensor under Raspberry Pi OS before starting.

Script and service files attached below.


README:

Written by PlasmaFlow with sources form Crankshaft and others.
Date 1/22/2019 plasmaflow@ivns.net
Updated 09/11/2020 by 765GHF to enable GPIO based Day / Night mode switching

This software allows the use of a TSL2561 Sensor to set Day / Night mode (using GPIO) and to control screen brightness automatically (based on light level).

The service writes the brightness value to the brightness file on the Pi at:

/sys/class/backlight/rpi_backlight/brightness

The service toggles the state of the nominated GPIO pin in order to set Day / Night mode (Day / Night mode under OAP must be configured to use GPIO)


Files included are:

readme - this file
lightsensor_env.sh - settings file py.
lightsensor.service - Service definition file.
service_lightsensor.py - script


### Prerequisites

Working / configured TSL2561 under Raspberry Pi OS
Ensure selected GPIO pin isn't already in use


### Software

The software is installed with the following commands:

    sudo mkdir -p /opt/lightsensor
    Copy lightsensor_env.sh & service_lightsensor.py to /opt/lightsensor
    sudo chmod +x service_lightsensor.py
    sudo chmod +x lightsensor_env.sh
    sudo cp lightsensor.service /etc/systemd/system

    - Edit (use sudo) /opt/lightsensor/lightsensor_env.sh and set the monitored GPIO pin(e.g. 21) 
    - Edit (use sudo) /opt/lightsensor/service_lightsensor.py and modify TSL2561 address if required
    - Under OAP, Settings, Day / Night enable GPIO mode for OAP and AA 
    - Under OAP, Settings, Day / Night set GPIO Pin (e.g. 21) 
      
    sudo systemctl enable lightsensor.service
    sudo systemctl start lightsensor.service

- check output in /var/log/daemon



### Sample Service Status

pi@raspberrypi:/opt/lightsensor $ sudo service lightsensor status
? lightsensor.service - Pi Lightsensor Service
  Loaded: loaded (/etc/systemd/system/lightsensor.service; enabled; vendor preset: enabled)
  Active: active (running) since Mon 2020-11-09 10:50:44 CET; 24s ago
  Process: 1384 ExecStartPost=/bin/touch /tmp/auto_brightness_active (code=exited, status=0/SUCCESS)
Main PID: 1383 (python3)
    Tasks: 1 (limit: 1173)
  CGroup: /system.slice/lightsensor.service
          +-1383 /usr/bin/python3 /opt/lightsensor/service_lightsensor.py

Nov 09 10:50:44 raspberrypi systemd[1]: Starting Pi Lightsensor Service...
Nov 09 10:50:44 raspberrypi systemd[1]: Started Pi Lightsensor Service.
Nov 09 10:50:45 raspberrypi python3[1383]: 2020/11/09 10:50:45: INFO: Lux = 2 | Level 1 | Setting Night mode (1)
Nov 09 10:51:06 raspberrypi python3[1383]: 2020/11/09 10:51:06: INFO: Lux = 643 | Level 5 | Setting Day mode (0)


SETTINGS FILE (lightsensor_env.sh): 

# Originally Used in Crankshaft.
# Kudos to the guys at Crankshaft for giving me a headstart for controlling the  brightness using the TSL2561
#
# Updated 09/11/2020 by 765GHF
#


# GPIO Trigger for Day/Night
# GPIO wich triggers Day (open gpio)/Night (closed to gnd) of GUI
DAYNIGHT_PIN=21

### Screen ###
# Brightness related stuff
# brightness file (default for rpi display: /sys/class/backlight/rpi_backlight/brightness)
BRIGHTNESS_FILE=/sys/class/backlight/rpi_backlight/brightness

# brightness values
BR_MIN=30
BR_MAX=255
BR_STEP=25
BR_DAY=255
BR_NIGHT=30

# Custom brightness control
# Note: this command is called after every brightness change - can slow down for example the brightness
# slider depending on execution speed - the process is called with "&" so call is not waiting for exit!
# Sample call which will be executed on request: "CUSTOM_BRIGHTNESS_COMMAND brightnessvalue &"
#
# Note: To allow backup and restore your command must be located on /boot/crankshaft/custom/
# otherwise it will not be transfered during updates!
#
# To disable leave empty
CUSTOM_BRIGHTNESS_COMMAND=

# Auto brightness control based on tsl2561 light sensor
# Check interval sensor 5,10,15,20,25,30
TSL2561_CHECK_INTERVAL=5
# Switch to night on this level or lower (0 = disabled / 1-5)
TSL2561_DAYNIGHT_ON_STEP=2
# Switch levels for brightness sensor in lux
LUX_LEVEL_1=5
LUX_LEVEL_2=20
LUX_LEVEL_3=100
LUX_LEVEL_4=200
LUX_LEVEL_5=500
# Set this display brightness by switch levels
DISP_BRIGHTNESS_1=30
DISP_BRIGHTNESS_2=90
DISP_BRIGHTNESS_3=150
DISP_BRIGHTNESS_4=210
DISP_BRIGHTNESS_5=255



SERVICE FILE (lightsensor.service):

[Unit]
Description=Pi Lightsensor Service
ConditionPathExists=/opt/lightsensor/service_lightsensor.py
ConditionPathExists=/opt/lightsensor/lightsensor_env.sh
ConditionPathExists=/sys/class/backlight/rpi_backlight/brightness

[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/lightsensor/service_lightsensor.py
ExecStartPost=/bin/touch /tmp/auto_brightness_active
ExecStop=/bin/rm /tmp/auto_brightness_active
Restart=on-failure
StartLimitInterval=60
RestartSec=5
StartLimitBurst=3

[Install]
WantedBy=multi-user.target


SCRIPT (service_lightsensor.py):

#!/usr/bin/python3 -u

import RPi.GPIO as GPIO 
import smbus
import os
import subprocess
from time import sleep
import logging

LOG_LEVEL = 'DEBUG'

DayNight = 2

# Originally Used in Crankshaft.
# Kudos to the guys at Crankshaft for giving me a headstart for controlling the  brightness using the TSL2561
#
# This file was re written to write the brightness variable in /sys/class/backlight/rpi_backlight/brightness
# re written by PlasmaFlow 1/22/19
#
# Hacked 09/11/2020 by 765GHF to set Day/Night mode in OAP / AA based on light level using GPIO
#

def get_var(varname):
    try:
        CMD = 'echo $(source /opt/lightsensor/lightsensor_env.sh; echo $%s)' % varname
        p = subprocess.Popen(CMD, stdout=subprocess.PIPE, shell=True, executable='/bin/bash')
        return int(p.stdout.readlines()[0].strip())
    except:
        CMD = 'echo $(source /opt/lightsensor/lightsensor_default_env.sh; echo $%s)' % varname
        p = subprocess.Popen(CMD, stdout=subprocess.PIPE, shell=True, executable='/bin/bash')
        return int(p.stdout.readlines()[0].strip())

# ---------------------------------
# the addresss of TSL2561 can be
# 0x29, 0x39 or 0x49
BUS = 1
TSL2561_ADDR = 0x39
# ---------------------------------

i2cBus = smbus.SMBus(BUS)
daynight_gpio = get_var('DAYNIGHT_PIN')
sleep_time = get_var('TSL2561_CHECK_INTERVAL')


# GPIO set up

# specify pin numbering format
GPIO.setmode(GPIO.BCM)

# set pin to output mode
GPIO.setup(daynight_gpio, GPIO.OUT)

# Logging setup
logging.basicConfig(
  format='%(asctime)s: %(levelname)s: %(message)s',
  datefmt='%Y/%m/%d %H:%M:%S', 
  level=LOG_LEVEL
  )

# Start messure with 402 ms
# (scale factor 1)
i2cBus.write_byte_data(TSL2561_ADDR, 0x80, 0x03)
lastvalue = 0

GPIO.output(daynight_gpio,0)

file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
file.write(str(get_var('DISP_BRIGHTNESS_5')))
file.close()
sleep (1)
file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
file.write(str(get_var('DISP_BRIGHTNESS_4')))
file.close()
sleep (1)
file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
file.write(str(get_var('DISP_BRIGHTNESS_3')))
file.close()
sleep (1)
file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
file.write(str(get_var('DISP_BRIGHTNESS_2')))
file.close()
GPIO.output(daynight_gpio,1)
sleep (1)
file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
file.write(str(get_var('DISP_BRIGHTNESS_1')))
file.close()
sleep (3)


while True:
 
  # Have to set GPIO mode each iteration as OAP sets mode to input
  GPIO.setup(daynight_gpio, GPIO.OUT)

# read global brightness read low byte
  LSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8C)
# read high byte
  MSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8D)
  Ambient = (MSB << 8) + LSB
  logging.debug('Ambient:%s' %Ambient)
# read infra red read low byte
  LSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8E)
# read high byte
  MSB = i2cBus.read_byte_data(TSL2561_ADDR, 0x8F)
  Infrared = (MSB << 8) + LSB
  logging.debug('Infrared:%s' %Infrared)
# Calc visible spectrum
  Visible = Ambient - Infrared
  logging.debug('Visible:%s' %Visible)
# Calc factor Infrared/Ambient
  Ratio = 0
  Lux = 0
  if Ambient != 0:
    Ratio = float(Infrared)/float(Ambient)
    logging.debug('Ratio:%s' %Ratio)
    # Calc lux based on data sheet TSL2561T T, FN, and CL Package
  if 0 < Ratio <= 0.50:
    Lux = 0.0304*float(Ambient) - 0.062*float(Ambient)*(Ratio**1.4)
  elif 0.50 < Ratio <= 0.61:
    Lux = 0.0224*float(Ambient) - 0.031*float(Infrared)
  elif 0.61 < Ratio <= 0.80:
    Lux = 0.0128*float(Ambient) - 0.0153*float(Infrared)
  elif 0.80 < Ratio <= 1.3:
    Lux = 0.00146*float(Ambient) - 0.00112*float(Infrared)
  else:
    Lux = 0

  Luxrounded = round(Lux,1)
  logging.debug('Lux = %s' %Luxrounded)
  if lastvalue != Luxrounded:
    lastvalue = Luxrounded
 
  #Set display brightness
  if Luxrounded <= get_var('LUX_LEVEL_1'):
    file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
    file.write(str(get_var('DISP_BRIGHTNESS_1')))
    file.close()
    step = 1
    logging.debug('Setting brightness to step %d' %step)
  elif Luxrounded > get_var('LUX_LEVEL_1') and Luxrounded < get_var('LUX_LEVEL_2'):
    file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
    file.write(str(get_var('DISP_BRIGHTNESS_2')))
    file.close()
    step = 2
    logging.debug('Setting brightness to step %d' %step)
  elif Luxrounded >= get_var('LUX_LEVEL_2') and Luxrounded < get_var('LUX_LEVEL_3'):
    file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
    file.write(str(get_var('DISP_BRIGHTNESS_3')))
    file.close()
    step = 3
    logging.debug('Setting brightness to step %d' %step)
  elif Luxrounded >= get_var('LUX_LEVEL_3') and Luxrounded < get_var('LUX_LEVEL_4'):
    file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
    file.write( str(get_var('DISP_BRIGHTNESS_4')))
    file.close()
    step = 4
    logging.debug('Setting brightness to step %d' %step)
  elif Luxrounded >= get_var('LUX_LEVEL_5'):
    file = open("/sys/class/backlight/rpi_backlight/brightness", "w")
    file.write(str(get_var('DISP_BRIGHTNESS_5')))
    file.close()
    step = 5
    logging.debug('Setting brightness to step %d' %step)

  logging.debug('GPIO pin is %s' %daynight_gpio)
  logging.debug('GPIO status is %s' %GPIO.input(daynight_gpio))
  logging.debug('Step to change to night is %s' %get_var('TSL2561_DAYNIGHT_ON_STEP'))
  logging.debug('Step is %s' %step)
  logging.debug('Day / Night mode is %d' %DayNight)

  # Set day / night mode based on step
  if step <= get_var('TSL2561_DAYNIGHT_ON_STEP') and DayNight != 1:
    logging.info('Lux = %d | Level %d | Setting Night mode (1)', Luxrounded, step)
    GPIO.output(daynight_gpio,1)
    DayNight = 1
  elif step > get_var('TSL2561_DAYNIGHT_ON_STEP') and DayNight !=0:
    logging.info('Lux = %d | Level %d | Setting Day mode (0)', Luxrounded, step)
    GPIO.output(daynight_gpio,0)
    DayNight = 0

  sleep (sleep_time)

GPIO.cleanup()


Attached Files
.zip   TSL2561 brightness.zip (Size: 4.39 KB / Downloads: 9)
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)