reefab / lunarsensor

Server that mimics a Lunar ambient light sensor, with support for multiple lux data sources

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Lunar Sensor

Create a custom Ambient Light Sensor on any device


This is a server that implements a custom Ambient Light Sensor for adapting monitor brightness with the Lunar macOS app.

Requirements

  • Python 3.6+
  • Access to binding port 80

Running the server

# Installs dependencies and runs the server
make

# Runs the server without installing dependencies
make run

# If IPv6 is not available use HOST
make run HOST=0.0.0.0

# Listen on another port using the PORT variable
make run PORT=8080

Implementing light sensor reading

The file lunarsensor.py contains a server that reads lux values using the read_lux() function at the bottom of the file.

Your actual sensor reading logic should be written in that function.

Testing the server

  • Check if one-shot lux reading works
❯ curl lunarsensor.local/sensor/ambient_light

{"id":"sensor-ambient_light", "state":"0 lx", "value":0.000000}
  • Check if the EventSource is sending lux values every 2 seconds
❯ curl lunarsensor.local/events

event: state
data: {"id": "sensor-ambient_light", "state": "400.0 lx", "value": 400.0}

event: state
data: {"id": "sensor-ambient_light", "state": "400.0 lx", "value": 400.0}

event: state
data: {"id": "sensor-ambient_light", "state": "400.0 lx", "value": 400.0}

Implementation examples

Reading from a BH1750 I²C sensor

pip3 install adafruit-circuitpython-bh1750
# Do the sensor reading logic below

import board
import adafruit_bh1750

i2c = board.I2C()
sensor = adafruit_bh1750.BH1750(i2c)

def dynamic_adjust_resolution(lux):
    if lux > 300:
        sensor.resolution = adafruit_bh1750.Resolution.LOW
    elif lux > 20:
        sensor.resolution = adafruit_bh1750.Resolution.MEDIUM
    else:
        sensor.resolution = adafruit_bh1750.Resolution.HIGH

async def read_lux():
    lux = sensor.lux
    dynamic_adjust_resolution(lux)

    return lux

Reading from a VEML7700 I²C sensor

pip3 install adafruit-circuitpython-veml7700
# Do the sensor reading logic below

import board
import adafruit_veml7700

i2c = board.I2C()
sensor = adafruit_veml7700.VEML7700(i2c)

def dynamic_adjust_resolution(lux):
    if lux > 300:
        sensor.light_integration_time = adafruit_veml7700.ALS_25MS
        sensor.light_gain = adafruit_veml7700.ALS_GAIN_1_8
    elif lux > 100:
        sensor.light_integration_time = adafruit_veml7700.ALS_50MS
        sensor.light_gain = adafruit_veml7700.ALS_GAIN_1_4
    elif lux > 20:
        sensor.light_integration_time = adafruit_veml7700.ALS_100MS
        sensor.light_gain = adafruit_veml7700.ALS_GAIN_1
    elif lux > 10:
        sensor.light_integration_time = adafruit_veml7700.ALS_200MS
        sensor.light_gain = adafruit_veml7700.ALS_GAIN_1
    else:
        sensor.light_integration_time = adafruit_veml7700.ALS_400MS
        sensor.light_gain = adafruit_veml7700.ALS_GAIN_2

async def read_lux():
    lux = sensor.lux
    dynamic_adjust_resolution(lux)

    return lux

Reading from a HomeAssistant lux sensor

# Do the sensor reading logic below

HOME_ASSISTANT_URL = "http://homeassistant.local:8123"  # Replace with your HomeAssistant server URL
TOKEN = "your.jwt.token"  # Replace with your long-lived HomeAssistant API token
SENSOR_ENTITY_ID = "sensor.living_room_ambient_light"  # Replace with your sensor entity id

async def read_lux():
    async with CLIENT.get(f"{HOME_ASSISTANT_URL}/api/states/{SENSOR_ENTITY_ID}", headers={"Authorization": f"Bearer {TOKEN}"}) as response:
        sensor = await response.json()
        if not json:
            return None

        return float(sensor["state"])

Pointing Lunar to the sensor server

Lunar expects to find the sensor at the lunarsensor.local address by default.

Lunar v6

This can be changed using the defaults command on the Mac where Lunar is running.

There are three settings that affect where Lunar looks for the sensor:

  • sensorHostname set by default to lunarsensor.local
  • sensorPort set by default to 80
  • sensorPathPrefix set by default to /

For example, if you would like to have Lunar listen for sensor events at homeassistant.local:8123/lunar/events you would run the following commands:

defaults write fyi.lunar.Lunar sensorHostname homeassistant.local
defaults write fyi.lunar.Lunar sensorPort 8123
defaults write fyi.lunar.Lunar sensorPathPrefix /lunar

Lunar v5

You can map the hostname to the sensor server IP using the /etc/hosts file on the Mac device where Lunar is running.

Example of /etc/hosts change at the end
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost
For example, if you would like to have Lunar listen for sensor events at `homeassistant.local:8123/lunar/events` you would run the follo  wing commands:

+ # Added for Lunar sensor server
+ 192.168.0.203    lunarsensor.local

About

Server that mimics a Lunar ambient light sensor, with support for multiple lux data sources


Languages

Language:Python 85.4%Language:Makefile 7.3%Language:Dockerfile 4.5%Language:Shell 2.8%