# Get started

> Create and run your first Arc automation

This page walks you through creating, deploying, and running your first Arc automation. By the end, you’ll have a working program that reads sensor data, processes it, and writes the result to another channel.

## Create an Arc automation

Open the command palette (`Ctrl/Cmd + Shift + P`) and search for “Create an Arc automation”. You can also click the “+” button in the toolbar or right-click a Driver in the resources panel.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/control/arc/get-started/create-automation-dark.mp4#t=0.001)

Choose a name and select **Text** for the editor mode.

## Your first program

Copy this code into the editor:

```arc
import time

func scale_reading(value f64) f64 {
    return value * 2.0
}

func create_reading() {
    count f64 $= 10
    count += 1
    data_channel = count
}
// Drive data writes
time.interval{period=200ms} -> create_reading{}

// React on every channel write
data_channel -> scale_reading{} -> data_scaled
```

This program has two parts that work together:

1. **A data generator** -> every 200 milliseconds, `output_reading` increments a counter (11, 12, 13, …) and writes the value to `tank_pressure`
2. **A processing pipeline** -> whenever `tank_pressure` updates, Arc automatically runs `scale_reading` (which doubles the value) and writes the result to `pressure_scaled`

The result: `pressure_scaled` will show 22, 24, 26, 28, … updating five times per second. This demonstrates Arc’s reactive model. You declare how data flows, and Arc handles the scheduling.

You’ll likely see red squiggly lines under `tank_pressure` and `pressure_scaled`. This indicates the channels don’t exist in your cluster yet. To run this program, you’ll need to create them first.

### Creating the channels

Open the command palette (`Ctrl/Cmd + Shift + P`) and search for “Create channel”. Create two [virtual channels](https://docs.synnaxlabs.com/reference/concepts/channels#virtual-channels):

| Name              | Virtual | Data type |
| ----------------- | ------- | --------- |
| `tank_pressure`   | Yes     | `float64` |
| `pressure_scaled` | Yes     | `float64` |

`float64` is a 64-bit floating-point number, the [channel data type](https://docs.synnaxlabs.com/reference/concepts/channels#data-type) that corresponds to Arc’s [`f64` type](https://docs.synnaxlabs.com/reference/control/arc/reference/types#floating-point-types). Use `float64` for channels that store decimal values like sensor readings.

Virtual channels don’t persist data to disk, making them ideal for testing automations. For more details on channel types and creation options, see the [channels page](https://docs.synnaxlabs.com/reference/client/channels).

Once created, the red squiggles will disappear and your program is ready to deploy.

## Understanding the syntax

Let’s break down the key parts:

### Function with input and output

```arc
func scale_reading(value f64) f64 {
    return value * 2.0
}
```

* `func` starts a function declaration
* `scale_reading` is the function name
* `(value f64)` means the function takes one input named `value` of type `f64`
* The second `f64` after the parentheses is the return type
* `return value * 2.0` sends the computed result back

### Stateful variables

```arc
func output_reading() {
    count f64 $= 10
    count += 1
    count_chan = count
}
```

The `$=` operator creates a [**stateful variable**](https://docs.synnaxlabs.com/reference/control/arc/reference/variables#stateful), a value that persists across invocations. Regular variables (`:=`) reset every time the function runs, but stateful variables remember their value.

Here, `count` starts at 10 the first time `output_reading` runs. Each subsequent call increments it: 11, 12, 13, and so on. The function then writes this value to `tank_pressure`.

### Flow statements

```arc
tank_pressure -> scale_reading{} -> pressure_scaled
```

The `->` arrow creates a **flow**, a reactive connection that runs whenever the source produces a value:

* `tank_pressure` is the source channel
* `scale_reading{}` processes each value (the `{}` instantiates the function)
* `pressure_scaled` receives the result

Whenever something writes to `tank_pressure`, Arc automatically runs `scale_reading` and updates `pressure_scaled`.

### Interval timer

```arc
time.interval{period=200ms} -> output_reading{}
```

`time.interval` fires on a schedule. Here it triggers every 200 milliseconds, which runs `output_reading` five times per second.

This pattern (an interval driving a function) is common for control loops, periodic sampling, and generating test data.

## Deploy to a Driver

Arc automations run on a [Driver](https://docs.synnaxlabs.com/reference/driver/get-started), the process that manages your hardware. To deploy:

1. Select a Driver from the dropdown in the editor toolbar
2. Click **Configure** to upload the automation to Synnax
3. Click the **Play** button to start execution

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/control/arc/get-started/deploy-automation-dark.mp4#t=0.001)

The status indicator shows whether your automation is running, stopped, or has errors. You can stop execution at any time with the **Pause** button.

## A threshold alarm

Here’s a more practical example that triggers a notification when pressure exceeds a limit. This builds on our previous example by adding alarm logic:

```arc
import status
import time

func output_reading() {
    count f64 $= 10
    count += 1
    tank_pressure = count
}

func check_pressure{limit f64} (reading f64) bool {
    return reading > limit
}

tank_pressure -> check_pressure{limit=15.0} => status.set{
    key_or_name = "Tank Pressure Alarm",
    variant = "warning",
    message = "Tank pressure exceeded 15"
}

time.interval{period=200ms} -> output_reading{}
```

This program reuses `tank_pressure` from before, but now checks if the value exceeds 15. Since our counter starts at 10 and increments each cycle, you’ll see the warning trigger after about one second (when count reaches 16).

New concepts in this example:

* **Input parameter** (`{limit f64}`): A constant set when the function is instantiated. Here, `limit=15.0` sets the threshold
* **Return type `bool`**: The comparison `reading > limit` returns `true` or `false`
* **Conditional edge** (`=>`) -> fires the target while the source is truthy. Unlike `->`, which fires whenever the source produces a value, `=>` only fires on ticks where the source expression holds
* **Standard library function** (`status.set`): Publishes a status notification to the Core. It lives in the `status` module, so the program imports it with `import status` at the top

## What’s next

You’ve created a basic Arc automation. The real power of Arc comes from **sequences**, which let you build multi-step procedures that progress through stages based on conditions.

**Recommended next step**: [Sequences and Stages](https://docs.synnaxlabs.com/reference/control/arc/concepts/sequences-and-stages) to learn how to build test procedures, startup routines, and state machines.

Or explore other topics:

* **[Reactive execution](https://docs.synnaxlabs.com/reference/control/arc/concepts/reactive-execution)** -> how Arc schedules computations and the difference between continuous (`->`) and conditional (`=>`) edges
* **[Channels and Series](https://docs.synnaxlabs.com/reference/control/arc/concepts/channels-and-series)**: Work with telemetry data and array operations
* **[Stateful variables](https://docs.synnaxlabs.com/reference/control/arc/reference/variables#stateful)**: Persist values across executions for counters and rate-of-change detection
