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.
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.
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:
import sam
led = sam.connect('led')
Store the result in a variable. You’ll use that variable for every subsequent call to that block.
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.
Controlling hardware blocks
LED
Control the LED’s colour and brightness. Pass red, green, and blue values, each between 0 and 255:
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. |
Connect to a button and define functions to run each time it is pressed or released:
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:
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:
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:
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:
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:
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:
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:
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)
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.
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:
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
Event-driven
Polling loop
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.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)
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.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)
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) |
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.