From 1d89ca18f9cfc135334a7edcab4c6e4b2273ef4d Mon Sep 17 00:00:00 2001 From: Jason Antman Date: Thu, 13 Jun 2024 18:46:50 -0400 Subject: [PATCH] WIP --- .idea/.gitignore | 3 + .idea/encodings.xml | 6 ++ .idea/inspectionProfiles/Project_Default.xml | 28 +++++++ .../inspectionProfiles/profiles_settings.xml | 6 ++ .idea/machine-access-control.iml | 15 ++++ .idea/misc.xml | 10 +++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 ++ src/dm_mac/machine_state.py | 73 +++++++++++++++++++ src/dm_mac/views/machine.py | 30 ++++++++ 10 files changed, 185 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/machine-access-control.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 src/dm_mac/machine_state.py create mode 100644 src/dm_mac/views/machine.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..0139ff8 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,28 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/machine-access-control.iml b/.idea/machine-access-control.iml new file mode 100644 index 0000000..edd0bee --- /dev/null +++ b/.idea/machine-access-control.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..6f5c713 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..cb68354 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/dm_mac/machine_state.py b/src/dm_mac/machine_state.py new file mode 100644 index 0000000..993ca76 --- /dev/null +++ b/src/dm_mac/machine_state.py @@ -0,0 +1,73 @@ +"""Classes and functions related to machine state.""" +from typing import Optional +from logging import getLogger, Logger +from time import time + + +logger: Logger = getLogger(__name__) + +DEFAULT_DISPLAY_TEXT: str = 'Please Insert\nRFID Card' + + +class MachineState: + """Object representing frozen state in time of a machine.""" + + def __init__(self, machine_name: str): + """Initialize a new MachineState instance.""" + logger.debug('Instantiating new MachineState for %s', machine_name) + #: The name of the machine + self.name: str = machine_name + #: Float timestamp of the machine's last checkin time + self.last_checkin: Optional[float] = None + #: Float timestamp of the last time that machine state changed, + #: not counting `current_amps` or timestamps. + self.last_update: Optional[float] = None + #: Value of the RFID card/fob in use, or None if not present. + self.rfid_value: Optional[str] = None + #: Float timestamp when `rfid_value` last changed to a non-None value. + self.rfid_present_since: Optional[float] = None + #: Whether the output relay is on or not. + self.relay_is_on: bool = False + #: Whether the output relay should be on or not. + self.relay_desired_state: bool = False + #: Whether the machine's Oops button has been pressed. + self.is_oopsed: bool = False + #: Whether the machine is locked out from use. + self.is_locked_out: bool = False + #: Whether the machine is force-enabled without RFID present. + self.is_force_enabled: bool = False + #: Last reported output ammeter reading (if equipped). + self.current_amps: float = 0 + #: Text currently displayed on the machine LCD screen + self.display_text: str = DEFAULT_DISPLAY_TEXT + self._load_from_cache() + + def _save_cache(self): + """Save machine state cache to disk.""" + raise NotImplementedError() + + def update_has_changes( + self, rfid_value: str, relay_state: bool, oops: bool, amps: float + ) -> bool: + """Return whether or not the update causes changes to significant state values.""" + if ( + rfid_value != self.rfid_value or + relay_state != self.relay_is_on or + oops != self.is_oopsed + ): + return True + return False + + def noop_update(self, amps: float): + """Just update amps and last_checkin and save cache.""" + self.current_amps = amps + self.last_checkin = time() + self._save_cache() + + @property + def machine_response(self) -> dict: + """Return the response dict to send to the machine.""" + return { + 'relay': self.relay_desired_state, + 'display': self.display_text + } diff --git a/src/dm_mac/views/machine.py b/src/dm_mac/views/machine.py new file mode 100644 index 0000000..bb503f4 --- /dev/null +++ b/src/dm_mac/views/machine.py @@ -0,0 +1,30 @@ +"""Views related to machine endpoints.""" +from typing import Any, Dict +from flask import Blueprint, request, app + + +machine: Blueprint = Blueprint("machine", __name__, url_prefix="/machine") + + +@machine.route("/update", methods=['POST']) +def update(): + """ + API method to update machine state. + + Accepts POSTed JSON containing the following key/value pairs: + + - "name" (string) - name of the machine sending the update + - "rfid_value" (string) - value of the RFID fob/card that is currently + present in the machine, or empty string if none present + - "relay_state" (boolean) - the current on/off (true/false) state of the + relay + - "oops" (boolean) - whether the oops button is pressed, or has been pressed + since the last check-in + - "amps" (float) - amperage value from the current clamp ammeter, if present, + or 0.0 otherwise. + """ + data: Dict[str, Any] = request.json + machine_name: str = data.pop('name') + # get the MachineState object for this machine, or else return an error + # that error should be formatted for display on the device (helper method for this) + # check if this data would update the state; if not, just call noop_update() and return the same display value