Created proper sensor package
This commit is contained in:
parent
4886983f96
commit
e9db6ec497
4 changed files with 38 additions and 37 deletions
|
@ -1,2 +1 @@
|
||||||
from sensors.tof_sensor import ToFSensor, Directions
|
from sensors.tof_sensor import ToFSensor, Directions
|
||||||
from sensors.people_counter import PeopleCounter
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from typing import Dict
|
|
||||||
from sensors import ToFSensor, Directions
|
from sensors import ToFSensor, Directions
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import threading
|
import threading
|
||||||
|
@ -13,11 +12,11 @@ TRIGGER_DISTANCES = "trigger_distances"
|
||||||
END_DISTANCE = "end_distance"
|
END_DISTANCE = "end_distance"
|
||||||
|
|
||||||
|
|
||||||
class PeopleCounter ():
|
class PeopleCounter:
|
||||||
def __init__(self, sensor: ToFSensor) -> None:
|
def __init__(self, sensor: ToFSensor) -> None:
|
||||||
self.sensor = sensor
|
self.sensor = sensor
|
||||||
self.callbacks = {COUNTING_CB: [], TRIGGER_CB: [], CHANGE_CB: []}
|
self.callbacks = {COUNTING_CB: [], TRIGGER_CB: [], CHANGE_CB: []}
|
||||||
self.maxTriggerDistance = 120 # In cm
|
self.maxTriggerDistance = 120 # In cm
|
||||||
|
|
||||||
def hookCounting(self, cb) -> None:
|
def hookCounting(self, cb) -> None:
|
||||||
self.callbacks[COUNTING_CB].append(cb)
|
self.callbacks[COUNTING_CB].append(cb)
|
||||||
|
@ -37,11 +36,8 @@ class PeopleCounter ():
|
||||||
def unhookChange(self, cb) -> None:
|
def unhookChange(self, cb) -> None:
|
||||||
self.callbacks[CHANGE_CB].remove(cb)
|
self.callbacks[CHANGE_CB].remove(cb)
|
||||||
|
|
||||||
def getInitialDirectionState(self) -> Dict:
|
def getInitialDirectionState(self) -> dict[Directions, list]:
|
||||||
return {
|
return {Directions.INSIDE: [], Directions.OUTSIDE: []}
|
||||||
Directions.INSIDE: [],
|
|
||||||
Directions.OUTSIDE: []
|
|
||||||
}
|
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
self.keepRunning = True
|
self.keepRunning = True
|
||||||
|
@ -60,13 +56,15 @@ class PeopleCounter ():
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
countChange: int = self.getCountChange(self.directionState)
|
countChange: int = self.getCountChange(self.directionState)
|
||||||
|
|
||||||
# Hooks
|
# Hooks
|
||||||
th = threading.Thread(target=self.handleCallbacks, args=(countChange,))
|
th = threading.Thread(target=self.handleCallbacks, args=(countChange,))
|
||||||
th.start()
|
th.start()
|
||||||
|
|
||||||
# Reset state if state is finalised
|
# Reset state if state is finalised
|
||||||
if not self.isDirectionTriggered(Directions.INSIDE) and not self.isDirectionTriggered(Directions.OUTSIDE):
|
if not self.isDirectionTriggered(
|
||||||
|
Directions.INSIDE
|
||||||
|
) and not self.isDirectionTriggered(Directions.OUTSIDE):
|
||||||
self.directionState = self.getInitialDirectionState()
|
self.directionState = self.getInitialDirectionState()
|
||||||
|
|
||||||
self.sensor.close()
|
self.sensor.close()
|
||||||
|
@ -79,8 +77,11 @@ class PeopleCounter ():
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Did every record start and end?
|
# Did every record start and end?
|
||||||
if directionState[direction][0][START_TIME] is None or directionState[direction][-1][END_TIME] is None:
|
if (
|
||||||
return 0 # Return no change if not valid
|
directionState[direction][0][START_TIME] is None
|
||||||
|
or directionState[direction][-1][END_TIME] is None
|
||||||
|
):
|
||||||
|
return 0 # Return no change if not valid
|
||||||
|
|
||||||
# Get times into variables
|
# Get times into variables
|
||||||
insideStart = directionState[Directions.INSIDE][0][START_TIME]
|
insideStart = directionState[Directions.INSIDE][0][START_TIME]
|
||||||
|
@ -131,7 +132,7 @@ class PeopleCounter ():
|
||||||
def isTriggerDistance(self, distance: float) -> bool:
|
def isTriggerDistance(self, distance: float) -> bool:
|
||||||
#! TODO: Should be based on the distance from the ground, not from the sensor
|
#! TODO: Should be based on the distance from the ground, not from the sensor
|
||||||
return distance <= self.maxTriggerDistance
|
return distance <= self.maxTriggerDistance
|
||||||
|
|
||||||
def handleCallbacks(self, countChange: int):
|
def handleCallbacks(self, countChange: int):
|
||||||
self.handleChangeCallbacks(countChange)
|
self.handleChangeCallbacks(countChange)
|
||||||
self.handleCountingCallbacks(countChange)
|
self.handleCountingCallbacks(countChange)
|
||||||
|
@ -148,34 +149,39 @@ class PeopleCounter ():
|
||||||
def handleTriggerCallbacks(self) -> None:
|
def handleTriggerCallbacks(self) -> None:
|
||||||
triggerState = {
|
triggerState = {
|
||||||
Directions.INSIDE: self.isDirectionTriggered(Directions.INSIDE),
|
Directions.INSIDE: self.isDirectionTriggered(Directions.INSIDE),
|
||||||
Directions.OUTSIDE: self.isDirectionTriggered(Directions.OUTSIDE)
|
Directions.OUTSIDE: self.isDirectionTriggered(Directions.OUTSIDE),
|
||||||
}
|
}
|
||||||
|
|
||||||
for cb in self.callbacks[TRIGGER_CB]:
|
for cb in self.callbacks[TRIGGER_CB]:
|
||||||
cb(triggerState)
|
cb(triggerState)
|
||||||
|
|
||||||
def handleChangeCallbacks(self, countChange: int) -> None:
|
def handleChangeCallbacks(self, countChange: int) -> None:
|
||||||
for cb in self.callbacks[CHANGE_CB]:
|
for cb in self.callbacks[CHANGE_CB]:
|
||||||
cb(countChange, self.directionState)
|
cb(countChange, self.directionState)
|
||||||
|
|
||||||
def isDirectionTriggered(self, direction: Directions) -> bool:
|
def isDirectionTriggered(self, direction: Directions) -> bool:
|
||||||
return len(self.directionState[direction]) > 0 and self.directionState[direction][-1][END_TIME] is None
|
return (
|
||||||
|
len(self.directionState[direction]) > 0
|
||||||
|
and self.directionState[direction][-1][END_TIME] is None
|
||||||
|
)
|
||||||
|
|
||||||
def updateState(self, direction: Directions, distance: float) -> bool:
|
def updateState(self, direction: Directions, distance: float) -> bool:
|
||||||
triggered: bool = self.isTriggerDistance(distance)
|
triggered: bool = self.isTriggerDistance(distance)
|
||||||
|
|
||||||
previouslyTriggered = False
|
previouslyTriggered = False
|
||||||
if len(self.directionState[direction]) > 0:
|
if len(self.directionState[direction]) > 0:
|
||||||
previouslyTriggered = self.directionState[direction][-1][END_TIME] is None
|
previouslyTriggered = self.directionState[direction][-1][END_TIME] is None
|
||||||
|
|
||||||
if triggered and not previouslyTriggered:
|
if triggered and not previouslyTriggered:
|
||||||
# Set as new beginning for this direction
|
# Set as new beginning for this direction
|
||||||
self.directionState[direction].append({
|
self.directionState[direction].append(
|
||||||
START_TIME: datetime.now(),
|
{
|
||||||
END_TIME: None,
|
START_TIME: datetime.now(),
|
||||||
TRIGGER_DISTANCES: [distance],
|
END_TIME: None,
|
||||||
END_DISTANCE: None
|
TRIGGER_DISTANCES: [distance],
|
||||||
})
|
END_DISTANCE: None,
|
||||||
|
}
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
elif not triggered and previouslyTriggered:
|
elif not triggered and previouslyTriggered:
|
||||||
# Set as end for this direction
|
# Set as end for this direction
|
||||||
|
|
|
@ -5,7 +5,7 @@ class Directions(str, Enum):
|
||||||
INSIDE = "indoor"
|
INSIDE = "indoor"
|
||||||
OUTSIDE = "outdoor"
|
OUTSIDE = "outdoor"
|
||||||
|
|
||||||
def other(direction: 'Direction') -> 'Direction':
|
def other(direction: "Directions") -> "Directions":
|
||||||
if direction is Directions.INSIDE:
|
if direction is Directions.INSIDE:
|
||||||
return Directions.OUTSIDE
|
return Directions.OUTSIDE
|
||||||
else:
|
else:
|
||||||
|
@ -20,13 +20,11 @@ class ToFSensor:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def setDirection(self, direction: Directions) -> None:
|
def setDirection(self, direction: Directions) -> None:
|
||||||
"""Configure sensor to pick up the distance in a specific direction.
|
"""Configure sensor to pick up the distance in a specific direction."""
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def getDistance(self) -> float:
|
def getDistance(self) -> float:
|
||||||
"""Returns new distance in cm.
|
"""Returns new distance in cm."""
|
||||||
"""
|
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from sensor.tof_sensor import Directions, ToFSensor
|
from sensors import Directions, ToFSensor
|
||||||
import VL53L1X
|
import VL53L1X
|
||||||
|
|
||||||
# Reference: https://github.com/pimoroni/vl53l1x-python
|
# Reference: https://github.com/pimoroni/vl53l1x-python
|
||||||
|
@ -18,7 +18,7 @@ import VL53L1X
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class VL53L1XSensor (ToFSensor):
|
class VL53L1XSensor(ToFSensor):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
@ -39,11 +39,10 @@ class VL53L1XSensor (ToFSensor):
|
||||||
# 3 = Long Range
|
# 3 = Long Range
|
||||||
|
|
||||||
def setDirection(self, direction: Directions) -> None:
|
def setDirection(self, direction: Directions) -> None:
|
||||||
"""Configure sensor to pick up the distance in a specific direction.
|
"""Configure sensor to pick up the distance in a specific direction."""
|
||||||
"""
|
|
||||||
direction_roi = {
|
direction_roi = {
|
||||||
Directions.INSIDE: VL53L1X.VL53L1xUserRoi(6, 3, 9, 0),
|
Directions.INSIDE: VL53L1X.VL53L1xUserRoi(6, 3, 9, 0),
|
||||||
Directions.OUTSIDE: VL53L1X.VL53L1xUserRoi(6, 15, 9, 12)
|
Directions.OUTSIDE: VL53L1X.VL53L1xUserRoi(6, 15, 9, 12),
|
||||||
}
|
}
|
||||||
|
|
||||||
roi = direction_roi[direction]
|
roi = direction_roi[direction]
|
||||||
|
@ -53,8 +52,7 @@ class VL53L1XSensor (ToFSensor):
|
||||||
self.sensor.start_ranging(self.ranging)
|
self.sensor.start_ranging(self.ranging)
|
||||||
|
|
||||||
def getDistance(self) -> float:
|
def getDistance(self) -> float:
|
||||||
"""Returns new distance in cm.
|
"""Returns new distance in cm."""
|
||||||
"""
|
|
||||||
distance = self.sensor.get_distance()
|
distance = self.sensor.get_distance()
|
||||||
|
|
||||||
return distance / 10
|
return distance / 10
|
||||||
|
|
Loading…
Reference in a new issue