Skip to content
This repository has been archived by the owner on Dec 8, 2024. It is now read-only.

Commit

Permalink
refactor: rename auspost -> user, do_everything() -> run_user_session()
Browse files Browse the repository at this point in the history
  • Loading branch information
LimaoC committed Oct 15, 2024
1 parent 5eb1c06 commit b8c8878
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 67 deletions.
3 changes: 2 additions & 1 deletion client/drivers/data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

class ControlledData:
"""
Data for passing around in client/drivers/main.do_everything().
Data for passing around in client/drivers/main.run_user_session().
There should only ever be one object of this class at a time.
Expand Down Expand Up @@ -171,6 +171,7 @@ def accept_new_posture_data(
for datum in posture_data:
self._posture_data.put_nowait(datum)


class HardwareComponents:
"""
Hardware components packaged together into a class.
Expand Down
124 changes: 58 additions & 66 deletions client/drivers/pi_overlord.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

#: Number of milliseconds between the user successfully logging out and returning to main().
LOGOUT_SUCCESS_DELAY = 3000
#: Minimum delay between reading posture data from the SQLite database, in do_everything().
#: Minimum delay between reading posture data from the SQLite database, in run_user_session().
GET_POSTURE_DATA_TIMEOUT = timedelta(milliseconds=10000)
#: Proportion of the time the user must be in frame for any feedback to be given. FIXME: Fine-tune this value later.
PROPORTION_IN_FRAME_THRESHOLD = 0.3
Expand All @@ -65,13 +65,8 @@
#: the plant will move down.
#: FIXME: Fine-tune this value later.
PLANT_PROPORTION_GOOD_THRESHOLD = 0.5
"""
Threshold for I. Jensen Plant Mover 10000 feedback. If the proportion of "good" sitting posture is below this,
the plant will move down.
FIXME: Fine-tune this value later.
"""

#: DEBUG Number of milliseconds between each loop iteration in do_everything().
#: DEBUG Number of milliseconds between each loop iteration in run_user_session().
DEBUG_DO_EVERYTHING_INTERVAL = 1000

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -123,8 +118,7 @@ def main():

logger.debug("Login successful")

# Run user session
do_everything(user)
run_user_session(user)

# Let the posture tracking process if the user has logged out
if not args.no_posture_model:
Expand Down Expand Up @@ -164,21 +158,21 @@ def initialise_hardware() -> HardwareComponents:
# SECTION: Control for the logged-in user


def do_everything(auspost: ControlledData) -> None:
def run_user_session(user: ControlledData) -> None:
"""
Main control flow once a user is logged in.
Args:
auspost: data encapsulating the current state of the program.
user: data encapsulating the current state of the program.
Requires:
! auspost.is_failed()
! user.is_failed()
"""
LOGIN_MESSAGE = "Logged in with user id: " + str(auspost.get_user_id())
LOGOUT_MESSAGE = "Logged out user id " + str(auspost.get_user_id())
LOGIN_MESSAGE = "Logged in with user id: " + str(user.get_user_id())
LOGOUT_MESSAGE = "Logged out user id " + str(user.get_user_id())

# Initialise posture graph for the current session
hardware.initialise_posture_graph(auspost.get_user_id())
hardware.initialise_posture_graph(user.get_user_id())

# Wind plant down all the way
hardware.wind_plant_safe()
Expand All @@ -195,7 +189,7 @@ def do_everything(auspost: ControlledData) -> None:
# Set up initial display
hardware.display.fill(0)
hardware.oled_display_texts(
hardware.get_control_messages(auspost.get_user_id()), 0, 0, 1
hardware.get_control_messages(user.get_user_id()), 0, 0, 1
)
hardware.display.show()

Expand All @@ -206,17 +200,17 @@ def do_everything(auspost: ControlledData) -> None:
hardware.oled_display_text(LOGOUT_MESSAGE, 0, 0, 1)
hardware.display.show()
sleep_ms(LOGOUT_SUCCESS_DELAY)
print("<!> END do_everything()")
print("<!> END run_user_session()")
return

update_display_screen(auspost)
handle_posture_graph(auspost)
handle_feedback(auspost)
update_display_screen(user)
handle_posture_graph(user)
handle_feedback(user)

sleep_ms(DEBUG_DO_EVERYTHING_INTERVAL)


def update_display_screen(auspost: ControlledData) -> bool:
def update_display_screen(user: ControlledData) -> bool:
"""
Update the display screen with whatever needs to be on there.
Expand All @@ -225,54 +219,54 @@ def update_display_screen(auspost: ControlledData) -> bool:
Current-session posture graph
Args:
auspost: data encapsulating the current state of the program.
user: data encapsulating the current state of the program.
Returns:
True, always. If you get a False return value, then something has gone VERY wrong.
Requires:
! auspost.is_failed()
! user.is_failed()
Ensures:
! auspost.is_failed()
! user.is_failed()
"""
while (
not auspost.get_posture_data().empty()
not user.get_posture_data().empty()
): # NOTE: This is much more robust than getting a fixed number of things out of the queue
hardware.display.fill(0)
hardware.oled_display_texts(
hardware.get_control_messages(auspost.get_user_id()), 0, 0, 1
hardware.get_control_messages(user.get_user_id()), 0, 0, 1
)
hardware.display.updateGraph2D(
hardware.posture_graph, auspost.get_posture_data().get_nowait()
hardware.posture_graph, user.get_posture_data().get_nowait()
)
hardware.display.show()

return True


def handle_posture_graph(auspost: ControlledData) -> bool:
def handle_posture_graph(user: ControlledData) -> bool:
"""
Get a snapshot of the user's posture data.
Use this information to update the data for the posture graph.
Args:
(auspost : ControlledData): Data encapsulating the current state of the program.
(user : ControlledData): Data encapsulating the current state of the program.
Returns:
(bool): True, always. If you get a False return value, then something has gone VERY wrong.
Requires:
! auspost.is_failed()
! user.is_failed()
Ensures:
! auspost.is_failed()
! user.is_failed()
TODO: Check this
"""
now = datetime.now()

if now > auspost.get_last_snapshot_time() + GET_POSTURE_DATA_TIMEOUT:
if now > user.get_last_snapshot_time() + GET_POSTURE_DATA_TIMEOUT:
# Get the most recent posture data for the user
recent_posture_data = get_user_postures(
auspost.get_user_id(),
user.get_user_id(),
num=-1,
period_start=now - GET_POSTURE_DATA_TIMEOUT,
period_end=now,
Expand All @@ -291,7 +285,7 @@ def handle_posture_graph(auspost: ControlledData) -> bool:
print(
"<!> Exiting handle_posturing_monitoring_new() early: Not in frame for a high enough proportion of time."
)
auspost.set_last_snapshot_time(datetime.now())
user.set_last_snapshot_time(datetime.now())
return True

# Sort the list by period_start
Expand All @@ -309,7 +303,7 @@ def handle_posture_graph(auspost: ControlledData) -> bool:
# Calculate the interval length
interval = total_time / POSTURE_GRAPH_DATUM_WIDTH

# Setup sublists, where each sublist is a portion of the overall data
# Setup sublists, where each sublist is a portion of the overall data
split_posture_lists: list[list[Posture]]
split_posture_lists = [[] for _ in range(POSTURE_GRAPH_DATUM_WIDTH)]

Expand All @@ -332,62 +326,60 @@ def handle_posture_graph(auspost: ControlledData) -> bool:
[posture.prop_good for posture in posture_list]
) / len(posture_list)
new_prop_good_data += [average_prop_good] * POSTURE_GRAPH_DATUM_WIDTH
auspost.accept_new_posture_data(new_prop_good_data)
user.accept_new_posture_data(new_prop_good_data)

auspost.set_last_snapshot_time(now)
user.set_last_snapshot_time(now)

return True

def handle_feedback(auspost: ControlledData) -> bool:

def handle_feedback(user: ControlledData) -> bool:
"""
Provide feedback to the user if necessary.
Args:
auspost: Data encapsulating the current state of the program.
user: Data encapsulating the current state of the program.
Returns:
(bool): True, always. If you get a False return value, then something has gone VERY wrong.
Requires:
! auspost.is_failed()
! user.is_failed()
Ensures:
! auspost.is_failed()
! user.is_failed()
"""
if (
datetime.now()
> auspost.get_last_cushion_time() + HANDLE_CUSHION_FEEDBACK_TIMEOUT
):
if not handle_cushion_feedback(auspost):
if datetime.now() > user.get_last_cushion_time() + HANDLE_CUSHION_FEEDBACK_TIMEOUT:
if not handle_cushion_feedback(user):
return False
if datetime.now() > auspost.get_last_plant_time() + HANDLE_PLANT_FEEDBACK_TIMEOUT:
if not handle_plant_feedback(auspost):
if datetime.now() > user.get_last_plant_time() + HANDLE_PLANT_FEEDBACK_TIMEOUT:
if not handle_plant_feedback(user):
return False

return True


def handle_cushion_feedback(auspost: ControlledData) -> bool:
def handle_cushion_feedback(user: ControlledData) -> bool:
"""
Vibrate cushion (if necessary), and update the timestamp of when cushion feedback was last given.
Args:
auspost: Data encapsulating the current state of the program.
user: Data encapsulating the current state of the program.
Returns:
True, always. If you get a False return value, then something has gone VERY wrong.
Requires:
! auspost.is_failed()
! user.is_failed()
Ensures:
! auspost.is_failed()
! user.is_failed()
"""
print("<!> handle_cushion_feedback()")

# Load posture records within the last HANDLE_CUSHION_FEEDBACK_TIMEOUT
now = datetime.now()
recent_posture_data = get_user_postures(
auspost.get_user_id(),
user.get_user_id(),
num=-1,
period_start=now - HANDLE_CUSHION_FEEDBACK_TIMEOUT,
period_end=now,
Expand All @@ -396,7 +388,7 @@ def handle_cushion_feedback(auspost: ControlledData) -> bool:
# Conditions for exiting early
if len(recent_posture_data) == 0:
print("<!> Exiting handle_cushion_feedback() early: No data")
auspost.set_last_cushion_time(datetime.now())
user.set_last_cushion_time(datetime.now())
return True
average_prop_in_frame = sum(
[posture.prop_in_frame for posture in recent_posture_data]
Expand All @@ -405,14 +397,14 @@ def handle_cushion_feedback(auspost: ControlledData) -> bool:
print(
"<!> Exiting handle_cushion_feedback() early: Not in frame for a high enough proportion of time."
)
auspost.set_last_cushion_time(datetime.now())
user.set_last_cushion_time(datetime.now())
return True
average_prop_good = sum(
[posture.prop_good for posture in recent_posture_data]
) / len(recent_posture_data)
if average_prop_good >= CUSHION_PROPORTION_GOOD_THRESHOLD:
print("<!> Exiting handle_cushion_feedback() early: You sat well :)")
auspost.set_last_cushion_time(datetime.now())
user.set_last_cushion_time(datetime.now())
return True

buzzer_start_time = datetime.now()
Expand All @@ -424,34 +416,34 @@ def handle_cushion_feedback(auspost: ControlledData) -> bool:
GPIO.output(CUSHION_GPIO_PIN, GPIO.LOW)
print("<!> buzzer off")

auspost.set_last_cushion_time(datetime.now())
user.set_last_cushion_time(datetime.now())
return True


def handle_plant_feedback(auspost: ControlledData) -> bool:
def handle_plant_feedback(user: ControlledData) -> bool:
"""
Set the plant height according to short-term current session data, and update the timestamp
of when plant feedback was last given.
Args:
auspost: Data encapsulating the current state of the program.
user: Data encapsulating the current state of the program.
Returns:
(bool): True, always. If you get a False return value, then something has gone VERY wrong.
Requires:
! auspost.is_failed()
! user.is_failed()
Ensures:
! auspost.is_failed()
! user.is_failed()
"""
print("<!> handle_plant_feedback()")

now = datetime.now()

if now > auspost.get_last_plant_time() + HANDLE_PLANT_FEEDBACK_TIMEOUT:
if now > user.get_last_plant_time() + HANDLE_PLANT_FEEDBACK_TIMEOUT:
# Get the most recent posture data for the user
recent_posture_data = get_user_postures(
auspost.get_user_id(),
user.get_user_id(),
num=-1,
period_start=now - GET_POSTURE_DATA_TIMEOUT,
period_end=now,
Expand All @@ -460,7 +452,7 @@ def handle_plant_feedback(auspost: ControlledData) -> bool:
# Conditions for exiting early
if len(recent_posture_data) == 0:
print("<!> Exiting handle_plant_feedback() early: No data")
auspost.set_last_plant_time(datetime.now())
user.set_last_plant_time(datetime.now())
return True

average_prop_in_frame = sum(
Expand All @@ -470,7 +462,7 @@ def handle_plant_feedback(auspost: ControlledData) -> bool:
print(
"<!> Exiting handle_plant_feedback() early: Not in frame for a high enough proportion of time."
)
auspost.set_last_plant_time(datetime.now())
user.set_last_plant_time(datetime.now())
return True

# Calculate average proportion
Expand All @@ -484,7 +476,7 @@ def handle_plant_feedback(auspost: ControlledData) -> bool:
else:
hardware.set_plant_height(hardware.plant_height - 1)

auspost.set_last_plant_time(datetime.now())
user.set_last_plant_time(datetime.now())

return True

Expand Down

0 comments on commit b8c8878

Please sign in to comment.