> ## Documentation Index
> Fetch the complete documentation index at: https://docs.samstudio.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Python API for SAM Script: Control Hardware Blocks

> Use Python in SAM Script to control SAM Labs hardware blocks. Learn the sam module API, how to read sensors, drive outputs, and respond to events.

SAM Script's Python mode lets you control SAM Labs hardware using straightforward, readable Python code. You import the built-in `sam` module, connect to your blocks by name, and call methods to set outputs or read sensor values. If you've used Python in class or in another project, the syntax will feel immediately familiar — and the `sam` module keeps hardware interactions simple and direct.

<Note>
  Python in SAM Script uses **snake\_case** method names (for example, `set_color`, `get_value`). This is different from the JavaScript API, which uses **camelCase** (for example, `setColor`, `getValue`). If you switch between languages, keep this naming difference in mind.
</Note>

***

## Importing and connecting

Start every SAM Script Python program by importing the `sam` module. Then use `sam.connect()` to link up with a hardware block:

```python theme={null}
import sam

led = sam.connect('led')
```

Store the result in a variable. You'll use that variable for every subsequent call to that block.

<Tip>
  If SAM Studio detects more than one block of the same type nearby, it will ask you to choose which physical block to connect to when `sam.connect()` runs.
</Tip>

***

## Controlling hardware blocks

### LED

Control the LED's colour and brightness. Pass red, green, and blue values, each between **0** and **255**:

```python theme={null}
import sam

led = sam.connect('led')

led.set_color(255, 0, 0)      # Red
sam.wait(1000)                 # Hold for 1 second
led.set_brightness(50)         # Reduce brightness to 50 %
sam.wait(1000)
led.set_color(0, 255, 0)      # Green at 50 % brightness
sam.wait(1000)
led.turn_off()                 # Turn off completely
```

| Method                  | Description                                 |
| ----------------------- | ------------------------------------------- |
| `set_color(r, g, b)`    | Sets the LED colour. Each channel is 0–255. |
| `set_brightness(level)` | Sets brightness as a percentage (0–100).    |
| `turn_off()`            | Turns the LED off.                          |

### Button

Connect to a button and define functions to run each time it is pressed or released:

```python theme={null}
import sam

button = sam.connect('button')

def on_press():
    print('Button pressed!')

def on_release():
    print('Button released!')

button.on_press(on_press)
button.on_release(on_release)
```

Pass the function itself — not the result of calling it — to `on_press()` and `on_release()`. Notice there are no parentheses after the function names in the last two lines.

You can also check the button's state at any point in a loop:

```python theme={null}
held = button.is_pressed()
print('Held down:', held)
```

| Method                 | Description                                          |
| ---------------------- | ---------------------------------------------------- |
| `on_press(callback)`   | Calls `callback` each time the button is pressed.    |
| `on_release(callback)` | Calls `callback` each time the button is released.   |
| `is_pressed()`         | Returns `True` if the button is currently held down. |

### DC motor

Control the speed and direction of a DC motor:

```python theme={null}
import sam

motor = sam.connect('dc_motor')

motor.set_direction('forward')  # Set direction first
motor.set_speed(75)             # Run at 75 %
sam.wait(3000)                  # Run for 3 seconds
motor.stop()                    # Stop immediately
```

| Method               | Description                                   |
| -------------------- | --------------------------------------------- |
| `set_speed(percent)` | Sets motor speed as a percentage (0–100).     |
| `set_direction(dir)` | Sets direction — `'forward'` or `'backward'`. |
| `stop()`             | Stops the motor immediately.                  |

### Servo

Move a servo to a specific angle between **0** and **180** degrees:

```python theme={null}
import sam

servo = sam.connect('servo')

servo.set_angle(90)    # Centre position
sam.wait(1000)
servo.set_angle(0)     # Rotate to 0 °
sam.wait(1000)
servo.set_angle(180)   # Rotate to 180 °
```

| Method               | Description                                 |
| -------------------- | ------------------------------------------- |
| `set_angle(degrees)` | Moves the servo to the given angle (0–180). |

### Light sensor

Read the current light level or register a callback that fires whenever the value changes:

```python theme={null}
import sam

light = sam.connect('light_sensor')

# Read the current value once
value = light.get_value()
print('Light level:', value)

# React every time the value changes
def on_change(new_value):
    print('New light level:', new_value)

light.on_change(on_change)
```

| Method                | Description                                              |
| --------------------- | -------------------------------------------------------- |
| `get_value()`         | Returns the current light level (0–100).                 |
| `on_change(callback)` | Calls `callback` with the new value whenever it changes. |

### Buzzer

Play musical notes or raw frequencies on a buzzer block:

```python theme={null}
import sam

buzzer = sam.connect('buzzer')

# Play a note by name and duration (milliseconds)
buzzer.play_note('C4', 500)
sam.wait(500)

# Play a raw frequency (Hz) for a duration (ms)
buzzer.play_frequency(440, 1000)   # Concert A for 1 second
```

| Method                         | Description                                                       |
| ------------------------------ | ----------------------------------------------------------------- |
| `play_note(note, duration)`    | Plays a note (e.g. `'C4'`, `'G#3'`) for the given duration in ms. |
| `play_frequency(hz, duration)` | Plays a raw frequency in hertz for the given duration in ms.      |

***

## Pausing your program

Use `sam.wait()` to pause execution for a number of milliseconds:

```python theme={null}
sam.wait(1000)   # Pause for 1 second
sam.wait(250)    # Pause for a quarter second
```

***

## Loops and conditions

Use standard Python `while` loops and `if` statements to keep your program running and respond to sensor readings:

```python theme={null}
import sam

led = sam.connect('led')
button = sam.connect('button')

while True:
    if button.is_pressed():
        led.set_color(0, 255, 0)   # Green while pressed
    else:
        led.turn_off()             # Off when released
    sam.wait(100)
```

<Note>
  Always include a `sam.wait()` call inside a `while True` loop. Without it, your program sends commands to the hardware as fast as possible, which can overwhelm the Bluetooth connection. A wait of **50–200 ms** is usually a good balance between responsiveness and reliability.
</Note>

***

## Full example — light-reactive LED

This example reads a light sensor continuously and changes the LED colour depending on how bright or dark the room is:

```python theme={null}
import sam

led = sam.connect('led')
light = sam.connect('light_sensor')

while True:
    level = light.get_value()

    if level > 50:
        led.set_color(255, 255, 0)   # Yellow when bright
    else:
        led.set_color(0, 0, 255)     # Blue when dark

    sam.wait(200)   # Update 5 times per second
```

Try holding your hand over the light sensor to see the LED switch from yellow to blue, then move your hand away to watch it switch back.

***

## Common patterns

<Tabs>
  <Tab title="Event-driven">
    Register callback functions that fire automatically when something happens. Your program doesn't need to check inputs in a loop.

    **Best for:** responding to button presses or other discrete events.

    ```python theme={null}
    import sam

    button = sam.connect('button')
    led = sam.connect('led')

    def on_press():
        led.set_color(128, 0, 255)   # Purple on press
        sam.wait(500)
        led.turn_off()               # Off after 500 ms

    def on_release():
        print('Button released')

    button.on_press(on_press)
    button.on_release(on_release)
    ```
  </Tab>

  <Tab title="Polling loop">
    Check sensor values on a regular schedule inside a `while True` loop and act on what you find.

    **Best for:** sensors that produce a continuous stream of changing values, like light, temperature, or distance.

    ```python theme={null}
    import sam

    light = sam.connect('light_sensor')
    led = sam.connect('led')

    while True:
        level = light.get_value()

        if level > 70:
            led.set_color(255, 255, 0)   # Yellow — very bright
        elif level > 40:
            led.set_color(255, 100, 0)   # Orange — medium light
        else:
            led.set_color(0, 0, 255)     # Blue — dark

        sam.wait(200)
    ```
  </Tab>
</Tabs>

***

## JavaScript vs Python: naming conventions

If you use both languages in SAM Script, you'll notice that the APIs are equivalent but named differently. Python follows PEP 8 conventions and uses **snake\_case**; JavaScript uses **camelCase**.

| Action                  | JavaScript                              | Python                             |
| ----------------------- | --------------------------------------- | ---------------------------------- |
| Connect                 | `SAM.connect('led')`                    | `sam.connect('led')`               |
| Set LED colour          | `led.setColor(r, g, b)`                 | `led.set_color(r, g, b)`           |
| Set brightness          | `led.setBrightness(n)`                  | `led.set_brightness(n)`            |
| Turn LED off            | `led.turnOff()`                         | `led.turn_off()`                   |
| Button press callback   | `button.onPress(fn)`                    | `button.on_press(fn)`              |
| Button release callback | `button.onRelease(fn)`                  | `button.on_release(fn)`            |
| Check if pressed        | `await button.isPressed()`              | `button.is_pressed()`              |
| Set motor speed         | `motor.setSpeed(n)`                     | `motor.set_speed(n)`               |
| Set motor direction     | `motor.setDirection(dir)`               | `motor.set_direction(dir)`         |
| Stop motor              | `motor.stop()`                          | `motor.stop()`                     |
| Set servo angle         | `servo.setAngle(deg)`                   | `servo.set_angle(deg)`             |
| Read light sensor       | `await light.getValue()`                | `light.get_value()`                |
| React to light changes  | `light.onChange(fn)`                    | `light.on_change(fn)`              |
| Play a note             | `await buzzer.playNote('C4', 500)`      | `buzzer.play_note('C4', 500)`      |
| Play a frequency        | `await buzzer.playFrequency(440, 1000)` | `buzzer.play_frequency(440, 1000)` |
| Wait                    | `await SAM.wait(ms)`                    | `sam.wait(ms)`                     |

<Tip>
  Use `print()` to send messages to the console panel at the bottom of the SAM Script editor. This is the easiest way to inspect sensor readings or check that your program is reaching a certain point.
</Tip>
