From 16ebe4a6702e74b71a97dc1c058dc59e6932303f Mon Sep 17 00:00:00 2001 From: Maximilian Giller Date: Fri, 24 Nov 2023 18:27:05 +0100 Subject: [PATCH] Implemented generic setup file and VL53L3CX Sensor --- src/console_counter.py | 6 ++-- src/measurer.py | 16 ++++----- src/sensors/__init__.py | 1 + src/sensors/vl53l3cx_sensor.py | 61 ++++++++++++++++++++++++++++++++++ src/setup.py | 28 ++++++++++++++++ src/simple_hue_counter.py | 17 ++-------- src/smart_hue_counter.py | 31 +++-------------- 7 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 src/sensors/vl53l3cx_sensor.py create mode 100644 src/setup.py diff --git a/src/console_counter.py b/src/console_counter.py index 3a39b87..d9595d1 100644 --- a/src/console_counter.py +++ b/src/console_counter.py @@ -1,12 +1,10 @@ from sensors.people_counter import PeopleCounter -from sensors.vl53l1x_sensor import VL53L1XSensor import logging +from setup import sensor -counter = PeopleCounter(VL53L1XSensor()) +counter = PeopleCounter(sensor) peopleCount = 0 -logging.getLogger().setLevel(logging.INFO) - def countChange(change: int) -> None: global peopleCount diff --git a/src/measurer.py b/src/measurer.py index 57fb10f..7986cfe 100644 --- a/src/measurer.py +++ b/src/measurer.py @@ -1,30 +1,26 @@ -from sensors import Directions, VL53L1XSensor +from sensors import Directions from time import sleep +from setup import sensor import logging DELAY_SECONDS = 1 -logging.getLogger().setLevel(logging.INFO) - - -sensor = VL53L1XSensor() sensor.open() try: while True: sensor.setDirection(Directions.INSIDE) distance_inside = sensor.getDistance() - + sensor.setDirection(Directions.OUTSIDE) distance_outside = sensor.getDistance() - + logging.info("----------") logging.info(f"Inside: {distance_inside} cm") logging.info(f"Outside: {distance_outside} cm") - + sleep(DELAY_SECONDS) - + finally: sensor.close() - diff --git a/src/sensors/__init__.py b/src/sensors/__init__.py index b581f29..e384597 100644 --- a/src/sensors/__init__.py +++ b/src/sensors/__init__.py @@ -1,3 +1,4 @@ from sensors.vl53l1x_sensor import VL53L1XSensor +from sensors.vl53l3cx_sensor import VL53L3CXSensor from sensors.people_counter import PeopleCounter from sensors.tof_sensor import Directions diff --git a/src/sensors/vl53l3cx_sensor.py b/src/sensors/vl53l3cx_sensor.py new file mode 100644 index 0000000..0a0d974 --- /dev/null +++ b/src/sensors/vl53l3cx_sensor.py @@ -0,0 +1,61 @@ +from sensors.tof_sensor import Directions, ToFSensor +import VL53L1X + +# Reference: https://github.com/pimoroni/vl53l1x-python +# +# Left, right, top and bottom are relative to the SPAD matrix coordinates, +# which will be mirrored in real scene coordinates. +# (or even rotated, depending on the VM53L1X element alignment on the board and on the board position) +# +# ROI in SPAD matrix coords: +# +# 15 top-left +# | X____ +# | | | +# | |____X +# | bottom-right +# 0__________15 +# + + +class VL53L3CXSensor(ToFSensor): + def __init__(self) -> None: + super().__init__() + + def open(self, ranging_mode: int = 3) -> None: + self.sensor = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x52) + self.sensor.open() + self.roi = VL53L1X.VL53L1xUserRoi() + + # Optionally set an explicit timing budget + # These values are measurement time in microseconds, + # and inter-measurement time in milliseconds. + # If you uncomment the line below to set a budget you + # should use `tof.start_ranging(0)` + # tof.set_timing(66000, 70) + self.ranging = ranging_mode + # 0 = Unchanged + # 1 = Short Range + # 2 = Medium Range + # 3 = Long Range + + def setDirection(self, direction: Directions) -> None: + """Configure sensor to pick up the distance in a specific direction.""" + direction_roi = { + Directions.INSIDE: VL53L1X.VL53L1xUserRoi(6, 3, 9, 0), + Directions.OUTSIDE: VL53L1X.VL53L1xUserRoi(6, 15, 9, 12), + } + + self.roi = direction_roi[direction] + + def getDistance(self) -> float: + """Returns new distance in cm.""" + self.sensor.set_user_roi(self.roi) + self.sensor.start_ranging(self.ranging) + distance = self.sensor.get_distance() + self.sensor.stop_ranging() + + return distance / 10 + + def close(self) -> None: + self.sensor.close() diff --git a/src/setup.py b/src/setup.py new file mode 100644 index 0000000..69849cb --- /dev/null +++ b/src/setup.py @@ -0,0 +1,28 @@ +from sensors import VL53L1XSensor, VL53L3CXSensor +from datetime import time +import logging + +LOG_FILE_PATH = "log.txt" # Path for logs +logging.getLogger().setLevel(logging.INFO) +sensor = VL53L3CXSensor() + +# Should lights already turn on where there is any kind of motion in the sensor +ENABLE_MOTION_TRIGGERED_LIGHT = True + +# Should lights change when a certain time in the schedule is reached +ENABLE_SCHEDULE_TRIGGERS = ( + False # Not working correctly at the moment, so turned off by default +) + +# Schedule (Key is time after scene should be used. Value is scene name to be used.) +# Needs to be sorted chronologically +SCHEDULE: dict[time, str] = {} + +# Philips Hue configuration +hue_conf = { + "bridge_ip": "", + "transition_time": 10, # seconds + "light_group": "", + # If file exists, application is considered 'registered' at the bridge + "registered_file": "smart_light_registered.bridge", +} # Custom configuration for philips hue diff --git a/src/simple_hue_counter.py b/src/simple_hue_counter.py index ecfd431..38bb607 100644 --- a/src/simple_hue_counter.py +++ b/src/simple_hue_counter.py @@ -1,28 +1,15 @@ from datetime import datetime from services.philips_hue import PhilipsHue from sensors.people_counter import PeopleCounter -from sensors.vl53l1x_sensor import VL53L1XSensor import logging import json - - -LOG_FILE_PATH = "log.txt" # Path for logs -hue_conf = { - "bridge_ip": "", - "transition_time": 10, # seconds - # Light group to control - "light_group": "", - # If file exists, application is considered 'registered' at the bridge - "registered_file": "smart_light_registered.bridge", -} # Custom configuration for philips hue +from setup import sensor, hue_conf, LOG_FILE_PATH hue: PhilipsHue = PhilipsHue(hue_conf) # Light interface -counter: PeopleCounter = PeopleCounter(VL53L1XSensor()) # Sensor object +counter: PeopleCounter = PeopleCounter(sensor) # Sensor object peopleCount: int = 0 # Global count of people on the inside -logging.getLogger().setLevel(logging.INFO) - def change_cb(countChange: int, directionState: dict): """Handles basic logging of event data for later analysis. diff --git a/src/smart_hue_counter.py b/src/smart_hue_counter.py index 0698bfe..b219205 100644 --- a/src/smart_hue_counter.py +++ b/src/smart_hue_counter.py @@ -1,36 +1,15 @@ from datetime import datetime, time, timedelta +from typing import Optional from services.philips_hue import PhilipsHue from sensors import PeopleCounter, Directions, VL53L1XSensor import logging import json from timeloop import Timeloop - - -# Should lights already turn on where there is any kind of motion in the sensor -ENABLE_MOTION_TRIGGERED_LIGHT = True - -# Should lights change when a certain time in the schedule is reached -ENABLE_SCHEDULE_TRIGGERS = ( - False # Not working correctly at the moment, so turned off by default -) - -# Schedule (Key is time after scene should be used. Value is scene name to be used.) -# Needs to be sorted chronologically -SCHEDULE: dict[time, str] = {} - - -LOG_FILE_PATH = "log.txt" # Path for logs -hue_conf = { - "bridge_ip": "", - "transition_time": 10, # seconds - "light_group": "", - # If file exists, application is considered 'registered' at the bridge - "registered_file": "smart_light_registered.bridge", -} # Custom configuration for philips hue +from setup import sensor, hue_conf, LOG_FILE_PATH, SCHEDULE, ENABLE_SCHEDULE_TRIGGERS hue: PhilipsHue = PhilipsHue(hue_conf) # Light interface -counter: PeopleCounter = PeopleCounter(VL53L1XSensor()) # Sensor object +counter: PeopleCounter = PeopleCounter(sensor) # Sensor object peopleCount: int = 0 # Global count of people on the inside motion_triggered_lights = False # Is light on because of any detected motion timeloop: Timeloop = Timeloop() # Used for time triggered schedule @@ -55,7 +34,7 @@ def time_minus_time(time_a: time, time_b: time) -> timedelta: return dt_a - dt_b -def get_scene_for_time(time: time) -> str: +def get_scene_for_time(time: time) -> Optional[str]: """Determines the correct scene to activate for a given time. Args: @@ -185,7 +164,7 @@ def trigger_change(triggerState: dict): motion_triggered_lights = target_light_state -def set_light_scene(target_scene: str) -> bool: +def set_light_scene(target_scene: str) -> None: """Sets the lights to the given scene, but only, if lights are already on. Does not correct count if lights are in an unexpected state. Args: