Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add abort api #194

Merged
merged 7 commits into from
Oct 25, 2024
Merged

Add abort api #194

merged 7 commits into from
Oct 25, 2024

Conversation

amitschang
Copy link
Member

@amitschang amitschang commented Oct 16, 2024

Sets up API for abort, which would put all devices into a stopped state (whatever that means for a particular device still in the powered-on state). The device-level action both stops the control components of loop and also the all devices, while the web-app (application-level) aborts the device and writes out the control disablement to config, such that a restart would not inadvertently continue normal operation without user intervention (given the current mainline behavior of the system)

Resolves #121

Copy link

codecov bot commented Oct 16, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

📢 Thoughts on this report? Let us know!

app.state.evolver.abort()
# Disable commit also in persistent config in case application needs to restart
app.state.evolver.config_model.enable_commit = False
app.state.evolver.config_model.save(app_settings.CONFIG_FILE)
Copy link
Member

@jamienoss jamienoss Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll need to repon that convo about stashing state vs configuration, as in #185.

There seems to be some flip-flopping on what app_settings.CONFIG_FILE is for. I was initially led to believe that it was for state, however, during #185 it was argued that it very much isn't for state, but for updating the configuration, but only as intended bu the user. The latter point emphasized by the fact that only the update endpoint should clobber app_settings.CONFIG_FILE as this is the only place where configuration is intentionally changed by the user.

We should not conflate state and configuration as I did before. Updating the configuration file here from the evolver's dynamic state (which can very much differ from its configuration) is exactly the same as having done so in #185.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is config, and the abort should update like here - but I see the point about potential internal changes between update and abort. I will change it to update directly from the file

@amitschang amitschang changed the title abort wip Add abort api Oct 22, 2024
@amitschang amitschang marked this pull request as ready for review October 22, 2024 16:10
@amitschang amitschang requested a review from a team as a code owner October 22, 2024 16:10
@amitschang amitschang requested a review from imaitland October 22, 2024 16:10
def commit(self):
self.comitted = copy(self.proposal)

def abort(self):
self.aborted = True
Copy link
Member

@jamienoss jamienoss Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this attr for?
Doesn't this need to go in the interface class to be adequately utilized?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the demo, the attr is specifically for testing

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be misleading to someone interpreting the "demo" as something to mimic in their implementations, which they shouldn't.

This would be better off in the test code itself, e.g., via a monkeypatch or something similar.

Comment on lines +39 to +41
cmd = [b"0"] * self.slots
with self.serial as comm:
comm.communicate(SerialData(addr=self.addr, data=cmd))
Copy link
Member

@jamienoss jamienoss Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like more than just abort code, as mentioned before, couldn't this go in another abstractmethod named, e.g., "reset", "idle", "off", or "init", etc, that then abort just calls? abort wouldn't have to be abstract.

Looks to me like these should be called upon initialization as a way for controlling a baseline on the hardware's physical state.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the above is what it takes to abort the operation of the device. Do you mean like naming it off since that would look less alarming if called upon initialization (if we do so in the future)?

Copy link
Member

@jamienoss jamienoss Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely, but kinda yeah, I meant that we both mentioned in #197 it might be desirable to exec these commands upon initial startup, in which case it's not really an "abort" but more of a ground/rest/init/off state.

Technically it's not aborting anything as we have to actually send a commit to command the hardware to some state. Evolver.abort is an "abort" but HardwareDriver.abort isn't.

Either way, I didn't mean anything complicated just something like the following:

class HardwareDriver(...):
  @abstractmethod
  def init(self, *args, **kwargs):  # could be called "reset"
     """ Implement to command hardware to its ground/off state. This could be called upon startup/abort."""
    ...
   
  def abort(self):
    self.init()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the device abort does send the command directly, no commit required. I'm not sure yet what we will do at startup, but I can definitely rename the device method to off instead. "abort" speaks to the immediacy of it though...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed driver method to off and added docstring for method expectations. I will defer doing anything with startup in this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the device abort does send the command directly, no commit required.

I only meant that it still has to send a command period and not just block subsequent commands. That these hardware methods don't alter the config, they themselves don't "block" future commanding at all etc, and that they are in fact completely oblivious to this concept (at least they should be). They only alter the hardware to some specific state, a state in this instance that is encoded in the semantics of this function name - which isn't "abort".

"abort" speaks to the immediacy of it though...

Agreed, and evolver.device.Evolver.abort is cool to be named such as it does actually "abort" subsequent control etc, though there's still scope for argument around the fact that it still pings the hardware and reads data so doesn't completely "abort", see #199 #196.

"abort" speaks to the immediacy of it though...

At the same time, however, this isn't entirely true due to the significant (1-2s) latency per call and the fact that these are turned off in sequence rather than proposals being set and committed all at once.

config = Evolver.Config.load(app_settings.CONFIG_FILE)
config.enable_control = False
config.enable_commit = False
config.save(app_settings.CONFIG_FILE)
Copy link
Member

@jamienoss jamienoss Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that whilst the user can hit this endpoint to stop the control, they have to use the update endpoint to start/restart it and have to specifically do so by (hopefully) only manually changing these two flags to True every time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a sufficient user interface and have opened #198 to add a "start" endpoint.

Comment on lines 152 to 153
def patched_abort(self):
self.aborted = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to still call the original abort here, to future-proof the test if something actually gets added to NoOpEffectorDriver.abort, rather than circumvent the test, no?

app.state.evolver.abort()
# Disable commit also in persistent config in case application needs to restart
config = Evolver.Config.load(app_settings.CONFIG_FILE)
config.enable_control = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI I've opened #199 for us to also consider aborting the read.

Copy link
Member

@jamienoss jamienoss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@amitschang amitschang merged commit 864bd43 into main Oct 25, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add start/stop/pause functionality to backend and app
2 participants