diff --git a/client/py/synnax/control/controller.py b/client/py/synnax/control/controller.py index 35adbdb556..0a135ca503 100644 --- a/client/py/synnax/control/controller.py +++ b/client/py/synnax/control/controller.py @@ -259,7 +259,7 @@ def wait_until( """ return self._internal_wait_until(cond, timeout) - def while_true( + def wait_while( self, cond: Callable[[Controller], bool], timeout: CrudeTimeSpan = None, diff --git a/client/py/tests/test_control.py b/client/py/tests/test_control.py index c87df2aa3b..f8465c4c53 100644 --- a/client/py/tests/test_control.py +++ b/client/py/tests/test_control.py @@ -287,7 +287,7 @@ def daq(ev: threading.Event): assert assertions["seq_second_ack"] assert assertions["remained_true"] - def test_while_true(self, client: sy.Synnax): + def test_wait_while(self, client: sy.Synnax): """Test that the controller can wait for a condition to be true for a certain amount of time""" press_end_cmd_time, press_en_cmd, press_en, daq_time = create_valve_set(client) @@ -318,7 +318,7 @@ def is_closed(auto): c += 1 return not auto[press_en.key] - remained_true = auto.while_true(is_closed) + remained_true = auto.wait_while(is_closed) assertions["remained_true"] = remained_true assertions["remained_true_count"] = c diff --git a/docs/site/src/pages/reference/concepts/writes.mdx b/docs/site/src/pages/reference/concepts/writes.mdx index ba414fd7f9..61e859e8a4 100644 --- a/docs/site/src/pages/reference/concepts/writes.mdx +++ b/docs/site/src/pages/reference/concepts/writes.mdx @@ -427,9 +427,6 @@ never share the same timestamp, and cannot share the same index. It's almost always necessary to use a separate index for each command channel, or use a virtual channel that does not require an index. - - - ## Dynamic Control - Write Authorities diff --git a/docs/site/src/pages/reference/control/sequence-basics.mdx b/docs/site/src/pages/reference/control/sequence-basics.mdx index eb741f9f0b..856197b363 100644 --- a/docs/site/src/pages/reference/control/sequence-basics.mdx +++ b/docs/site/src/pages/reference/control/sequence-basics.mdx @@ -3,7 +3,7 @@ layout: "@/layouts/MainLayout.astro" title: "Control Sequences" heading: "Control Sequence Basics" --- -import { Divider } from "@synnaxlabs/pluto"; +import { Divider, Note } from "@synnaxlabs/pluto"; import { Image } from "@/components/Media"; import Table from "@/components/Table.astro"; import Code from "@/components/code/Code.astro"; @@ -18,8 +18,11 @@ process of writing your first control sequence. ## Prerequisites -Before you can start writing control sequences, you'll need to have the Synnax Python -client installed +Before you can start writing control sequences, you'll need to have: + +- A Synnax [cluster](/reference/cluster/quick-start) running +- The Synnax [Python Client](/reference/python-client/get-started) installed + @@ -123,7 +126,7 @@ The `wait_until` method allows you to wait for a condition to be met before cont This method accepts a function that takes in the current sensor values and returns a boolean. -#### Lambda Expressions +### Lambda Expressions We recommend relying on `lambda` expressions to keep your code simple. A lambda expression is a simple way to define a function in one line. Here's an example @@ -152,7 +155,7 @@ with client.control.acquire( controller.wait_until(lambda sv: sv["pressure_1"] > 25) ``` -#### Adding a Timeout +### Adding a Timeout The `wait_until` method will continuously check the condition on every new value until it returns `True`. If you'd like to add a timeout to the wait, you can pass in a `timeout` @@ -169,4 +172,74 @@ method: timed_out = controller.wait_until(lambda sv: sv["pressure_1"] > 25, timeout=10) if timed_out: print("The condition timed out") +``` + + + +## Blocking While a Condition is True + +The `wait_while` method allows you to block the control sequence until a condition is +no longer true. This method is useful for waiting for a sensor value to reach a certain +point before continuing. Here's an example of how you can use the `wait_while` method: + +```python +with client.control.acquire( + read=["pressure_1", "daq_do_1_state"], + write=["daq_do_1_cmd"] + write_authorities=[sy.Authority.ABSOLUTE] +) as controller: + # Wait until the pressure sensor value is above 25 + controller.wait_while(lambda sv: sv["pressure_1"] < 25) +``` + +In many ways, you can think of the `wait_while` method as the opposite of the `wait_until` +method. + + + +## Asserting a Condition Remains True + +The `remains_true_for` method allows you to assert that a condition remains true for a +certain duration. This method is useful for ensuring that a sensor value remains within +a certain range for a period of time. Here's an example of how you can use the +`remains_true_for` method: + +```python +with client.control.acquire( + read=["pressure_1", "daq_do_1_state"], + write=["daq_do_1_cmd"] + write_authorities=[sy.Authority.ABSOLUTE] +) as controller: + # Assert that the pressure sensor value remains above 25 for 10 seconds + controller.remains_true_for(lambda sv: sv["pressure_1"] > 25, duration=10) +``` + + +The `duration` argument should be treated as a minimum duration, as the block is not +guaranteed to sleep for exactly the provided duration. The actual duration may be longer +due to the operating system's scheduler. This block will _not_ sleep for less than the +provided duration unless the condition is no longer true. + + +### Remains True for a Certain Percentage of Samples + +The `remains_true_for` method also accepts a `percentage` argument, which is a decimal +value that allows you to specify the percentage of samples that must meet the condition. +This is useful for ensuring that a sensor value remains within a certain range for at +least a certain percentage of the duration. Here's an example of how you can use the +`percentage` argument: + +```python +with client.control.acquire( + read=["pressure_1", "daq_do_1_state"], + write=["daq_do_1_cmd"] + write_authorities=[sy.Authority.ABSOLUTE] +) as controller: + # Assert that the pressure sensor value remains above 25 for 10 seconds + # for at least 90% of the samples + controller.remains_true_for( + lambda sv: sv["pressure_1"] > 25, + duration=10, + percentage=0.9 + ) ``` \ No newline at end of file diff --git a/pluto/src/note/Note.css b/pluto/src/note/Note.css index 53f6886736..612254be92 100644 --- a/pluto/src/note/Note.css +++ b/pluto/src/note/Note.css @@ -21,7 +21,7 @@ &.pluto--warning { background: var(--pluto-warning-z-10); - border-color: var(--pluto-warning-z-); + border-color: var(--pluto-warning-z-70); } &.pluto--error {